目次

1. บทนำ

Docker และ Dockerfile คืออะไร?

ในช่วงไม่กี่ปีที่ผ่านมา Docker ได้รับความนิยมอย่างรวดเร็วในฐานะวิธีที่มีประสิทธิภาพในการจัดเตรียมสภาพแวดล้อมการพัฒนาและปรับใช้แอปพลิเคชัน Docker มีจุดเด่นคือการบรรจุแอปพลิเคชันและส่วนประกอบที่เกี่ยวข้องไว้ใน “คอนเทนเนอร์” เดียว ทำให้สามารถรันในสภาพแวดล้อมเดียวกันได้ทุกที่

การสร้าง Docker container จำเป็นต้องมี “Dockerfile” ซึ่งเป็นเหมือนแผนผังการสร้าง Dockerfile เป็นไฟล์ข้อความที่ระบุ OS พื้นฐาน ซอฟต์แวร์ที่ต้องติดตั้ง และการตั้งค่าต่าง ๆ นักพัฒนาสามารถใช้ไฟล์นี้เพื่อสร้างสภาพแวดล้อมที่ปรับแต่งเองโดยอัตโนมัติ

เหตุผลที่ใช้ Ubuntu เป็นพื้นฐาน

เมื่อสร้าง Dockerfile จำเป็นต้องระบุ OS พื้นฐาน ซึ่ง Ubuntu เป็นหนึ่งในตัวเลือกยอดนิยม Ubuntu เป็น Linux distribution ที่พัฒนาบนพื้นฐาน Debian โดดเด่นเรื่องใช้งานง่ายและมีแพ็คเกจจำนวนมาก เหมาะกับการปรับแต่งสภาพแวดล้อม

ข้อดีของการสร้าง Dockerfile ที่ใช้ Ubuntu เป็นพื้นฐาน มีดังนี้:

  • มีเอกสารจากทั้งทางการและชุมชนจำนวนมาก ทำให้เรียนรู้ได้ง่าย
  • สามารถติดตั้งแพ็คเกจและเครื่องมือผ่าน APT ได้อย่างสะดวก
  • มี official image ที่มีขนาดเล็ก เช่น ubuntu:20.04, ubuntu:24.04 ให้เลือกใช้

วัตถุประสงค์และกลุ่มผู้อ่านของบทความนี้

บทความนี้จะอธิบายวิธีสร้าง Dockerfile ที่ใช้ Ubuntu เป็นฐาน โดยเน้นคีย์เวิร์ด “Dockerfile Ubuntu” ให้เข้าใจง่ายแม้เป็นมือใหม่

เนื้อหาจะครอบคลุมตั้งแต่โครงสร้างพื้นฐานของ Dockerfile ขั้นตอนการสร้างสภาพแวดล้อม Ubuntu ตัวอย่างการติดตั้งแอปพลิเคชัน เช่น Python รวมถึงข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข

บทความนี้เหมาะสำหรับ:

  • ผู้ที่เริ่มสร้างสภาพแวดล้อมด้วย Dockerfile เป็นครั้งแรก
  • ผู้ที่ต้องการสร้างสภาพแวดล้อม Ubuntu ที่สามารถทำซ้ำได้
  • ผู้ที่ต้องการเรียนรู้วิธีแก้ปัญหาเมื่อเกิดข้อผิดพลาด
年収訴求

2. โครงสร้างพื้นฐานของ Dockerfile

Dockerfile คืออะไร? เข้าใจบทบาทหน้าที่

Dockerfile คือไฟล์สูตรสำหรับสร้าง Docker image โดยจะระบุว่าใช้ OS อะไร ติดตั้งซอฟต์แวร์ใด และมีการตั้งค่าอะไรบ้าง

เมื่อใช้ docker build กับไฟล์นี้ จะสามารถสร้างสภาพแวดล้อมสำหรับพัฒนา/รันแอปพลิเคชันที่เหมือนกันทุกครั้งได้อย่างง่ายดาย

ข้อดีของการใช้ Dockerfile:

  • อัตโนมัติ ไม่ต้องตั้งค่าสภาพแวดล้อมด้วยตนเอง
  • ลดปัญหาความแตกต่างของสภาพแวดล้อมเมื่อทำงานร่วมกันหลายคน
  • เหมาะสำหรับนำไปใช้ใน CI/CD pipeline

คำสั่งพื้นฐานที่ใช้บ่อยใน Dockerfile

Dockerfile มีคำสั่ง (directive) หลายแบบ ตัวอย่างที่ใช้บ่อยมีดังนี้ ซึ่งสามารถใช้สร้าง Dockerfile ที่ใช้ Ubuntu เป็นฐานได้อย่างยืดหยุ่น

คำสั่งคำอธิบาย
FROMระบุ image พื้นฐาน เช่น FROM ubuntu:24.04
RUNรันคำสั่ง shell ใช้ติดตั้งแพ็คเกจต่าง ๆ
COPYคัดลอกไฟล์จากเครื่องไปใน image
ADDเหมือนกับ COPY แต่รองรับการดาวน์โหลดไฟล์หรือคลาย zip/archive
WORKDIRกำหนด working directory
ENVตั้งค่าตัวแปรสภาพแวดล้อม (Environment variable)
CMDคำสั่งที่จะถูกรันเมื่อ container เริ่มต้น (สามารถ override ได้)
ENTRYPOINTเหมือน CMD แต่บังคับให้รันคำสั่งที่กำหนดเสมอ

ตัวอย่าง Dockerfile แบบสั้นที่ใช้ Ubuntu เป็นฐาน

ตัวอย่าง Dockerfile พื้นฐานที่ใช้ Ubuntu:

FROM ubuntu:24.04

RUN apt-get update && apt-get install -y 
    curl 
    vim

CMD ["/bin/bash"]

Dockerfile นี้จะใช้ Ubuntu 24.04 เป็นฐาน ติดตั้ง curl และ vim และรัน bash shell เมื่อเริ่มคอนเทนเนอร์

3. ปฏิบัติจริง: การสร้าง Dockerfile ที่ใช้ Ubuntu เป็นฐาน

ติดตั้งแพ็คเกจที่จำเป็นในสภาพแวดล้อม Ubuntu

เมื่อสร้างสภาพแวดล้อม Ubuntu ด้วย Dockerfile มักจำเป็นต้องติดตั้งแพ็คเกจเสริม สำหรับพัฒนา ตัวอย่างเช่น:

  • curl: สำหรับดาวน์โหลดไฟล์และตรวจสอบ API
  • vim: โปรแกรมแก้ไขข้อความ
  • git: ระบบควบคุมเวอร์ชัน (Version Control)
  • build-essential: เครื่องมือสำหรับ build C/C++

สามารถติดตั้งด้วยคำสั่ง RUN ใน Dockerfile ดังนี้:

FROM ubuntu:24.04

RUN apt-get update && apt-get install -y 
    curl 
    vim 
    git 
    build-essential

การรัน apt-get update ก่อน จะช่วยให้แน่ใจว่าแพ็คเกจที่ติดตั้งเป็นเวอร์ชันล่าสุด

ตั้งค่าการติดตั้งแบบ non-interactive

โดยปกติการติดตั้ง apt-get install ใน Ubuntu อาจต้องมีการป้อนข้อมูลผู้ใช้ แต่กระบวนการ build Docker ไม่สามารถตอบสนองได้ จึงแนะนำให้ตั้งค่าต่อไปนี้เพื่อเปิดใช้งานโหมด non-interactive:

ENV DEBIAN_FRONTEND=noninteractive

ช่วยข้ามขั้นตอน prompt ต่าง ๆ เช่นการตั้งค่าภูมิภาค ทำให้การติดตั้งราบรื่นขึ้น

ลบแคชที่ไม่จำเป็นเพื่อลดขนาด image

เมื่อใช้ APT จะมีไฟล์ชั่วคราวหลงเหลืออยู่ใน image ส่งผลให้ image มีขนาดใหญ่ขึ้น ควรเพิ่มคำสั่งเพื่อลบแคชหลังติดตั้งแพ็คเกจ:

RUN apt-get update && apt-get install -y 
    curl 
    vim 
    && rm -rf /var/lib/apt/lists/*

การรวมหลายคำสั่งใน RUN เดียวกัน ยังช่วยลดจำนวนเลเยอร์ของ image ด้วย

Best Practices: วิธีเขียน Dockerfile ที่ดี

แนวปฏิบัติสำหรับการเขียน Dockerfile ที่แนะนำในงานจริง:

  • ควรรวม RUN หลายคำสั่งในบรรทัดเดียว เพื่อลดเลเยอร์
  • ใช้ ENV ระบุเวอร์ชันและ config ชัดเจน
  • เพิ่มคอมเมนต์เพื่ออธิบายขั้นตอน
  • ลบไฟล์ที่ไม่จำเป็นและใช้ --no-install-recommends เพื่อลดขนาด image

ตัวอย่าง:

RUN apt-get update && apt-get install -y --no-install-recommends 
    curl 
    git 
    && rm -rf /var/lib/apt/lists/*

จะช่วยให้ได้ Dockerfile ที่เบา ดูแลและขยายต่อได้ง่าย

4. การ build และตรวจสอบ Docker image

Build Docker image จาก Dockerfile

เมื่อเขียน Dockerfile เสร็จแล้ว ขั้นตอนถัดไปคือสร้าง Docker image โดยใช้คำสั่ง docker build ใน directory ที่มี Dockerfile อยู่:

docker build -t my-ubuntu-image .
  • ออปชั่น -t ใช้ตั้งชื่อ (tag) image เช่น my-ubuntu-image
  • . หมายถึง directory ปัจจุบันที่มี Dockerfile

Docker จะอ่านคำสั่งใน Dockerfile และสร้าง image ตามขั้นตอนที่ระบุไว้

ตรวจสอบ image ที่ build เสร็จแล้ว

เมื่อ build image เสร็จ สามารถตรวจสอบได้ด้วยคำสั่ง:

docker images

จะแสดงรายการ Docker image ทั้งหมดในเครื่อง พร้อมข้อมูล:

  • REPOSITORY (ชื่อ image)
  • TAG (แท็ก)
  • IMAGE ID (รหัสเฉพาะ)
  • CREATED (วันเวลาสร้าง)
  • SIZE (ขนาด)

ตัวอย่างผลลัพธ์:

REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
my-ubuntu-image   latest    abcd1234abcd   5 minutes ago    189MB

ยืนยันว่า image ที่สร้างเสร็จมีอยู่ในระบบ

รัน Docker container เพื่อตรวจสอบการทำงาน

เพื่อเช็คว่า image ที่สร้างทำงานได้ดีหรือไม่ ให้รัน container ด้วยคำสั่งนี้:

docker run -it my-ubuntu-image
  • ใช้ -it เพื่อเข้าสู่โหมด interactive กับ terminal
  • ถ้ารันสำเร็จ จะเข้าสู่ bash prompt ของ Ubuntu ใน container

ภายใน container สามารถรันคำสั่งเหล่านี้เพื่อตรวจสอบ:

curl --version
vim --version

ถ้าทุกอย่างทำงานได้ แสดงว่า Dockerfile ถูกต้อง

จัดการ image และ container ที่ไม่ใช้งาน

เมื่อ build และทดลองหลายครั้ง จะมี image และ container ที่ไม่ได้ใช้งานค้างอยู่ในเครื่อง ควรลบออกเป็นระยะด้วยคำสั่งต่อไปนี้:

  • ลบ container ที่หยุดทำงาน:
docker container prune
  • ลบ image ที่ไม่ได้ใช้งาน:
docker image prune
  • ลบทุกอย่างที่ไม่ได้ใช้งาน (โปรดระวัง):
docker system prune

ช่วยประหยัดพื้นที่ดิสก์และลดปัญหาที่อาจเกิดขึ้น

5. ขั้นสูง: การติดตั้ง Python environment

ใช้ Dockerfile ติดตั้ง Python ใน Ubuntu

การเพิ่มenvironment สำหรับรัน Python ใน Dockerfile ช่วยให้พัฒนาหรือทดสอบ machine learning, data science และแอปอื่น ๆ ได้สะดวก แม้ Ubuntu จะมี Python อยู่แล้วในบางเวอร์ชัน แต่โดยทั่วไปจะนิยมติดตั้งและจัดการเวอร์ชันเองเพื่อความยืดหยุ่น

ติดตั้ง Python ด้วย apt

วิธีง่ายที่สุดคือติดตั้งผ่าน apt ตัวอย่าง:

FROM ubuntu:24.04

RUN apt-get update && apt-get install -y 
    python3 
    python3-pip 
    && rm -rf /var/lib/apt/lists/*

จะได้ Python เวอร์ชันเสถียรตามที่ระบบรองรับ และติดตั้ง pip สำหรับจัดการ package ของ Python

จัดการเวอร์ชัน Python ด้วย pyenv

ถ้าต้องการใช้ Python หลายเวอร์ชัน หรือควบคุมเวอร์ชันอย่างละเอียด สามารถใช้ pyenv

ตัวอย่าง Dockerfile ที่ติดตั้ง Python 3.11.6 ด้วย pyenv:

FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y 
    git 
    curl 
    make 
    build-essential 
    libssl-dev 
    zlib1g-dev 
    libbz2-dev 
    libreadline-dev 
    libsqlite3-dev 
    wget 
    llvm 
    libncurses5-dev 
    libncursesw5-dev 
    xz-utils 
    tk-dev 
    libffi-dev 
    liblzma-dev 
    && rm -rf /var/lib/apt/lists/*

# ติดตั้ง pyenv
RUN git clone https://github.com/pyenv/pyenv.git ~/.pyenv

ENV PYENV_ROOT="$HOME/.pyenv"
ENV PATH="$PYENV_ROOT/bin:$PATH"

RUN echo 'eval "$(pyenv init --path)"' >> ~/.bashrc

# ติดตั้ง Python เวอร์ชันที่ต้องการ
RUN pyenv install 3.11.6 && pyenv global 3.11.6

วิธีนี้สามารถจัดการหลายเวอร์ชัน Python ได้ง่าย

ใช้ requirements.txt จัดการ dependencies

ในโปรเจกต์จริง มักต้องติดตั้งไลบรารี Python หลายตัว จึงนิยมใช้ requirements.txt จัดการ

ตัวอย่างไฟล์ requirements.txt:

flask==2.3.2
requests>=2.25.1
pandas

และใน Dockerfile:

COPY requirements.txt /app/requirements.txt
WORKDIR /app

RUN pip install --no-cache-dir -r requirements.txt

จะช่วยให้ติดตั้งไลบรารีทั้งหมดในไฟล์เดียว เพิ่มความสะดวกและทำซ้ำได้ง่าย

Best Practices สำหรับ Python

  • แนะนำให้ใช้ virtualenv หรือ venv ป้องกัน dependency conflict
  • เพิ่ม --no-cache-dir ตอนติดตั้ง package เพื่อลดขนาด image
  • ควรอัปเดต pip ให้เป็นเวอร์ชันล่าสุดก่อนติดตั้ง package ต่าง ๆ

6. ปัญหาที่พบบ่อยและวิธีแก้ไข

Permission Error (สิทธิ์การเข้าถึง)

ตัวอย่าง:

Permission denied

ปัญหานี้เกิดเมื่อไฟล์ที่ copy เข้าไปไม่มีสิทธิ์รัน หรือ user ไม่ถูกต้อง

วิธีแก้:

  • ให้สิทธิ์รันไฟล์:
  RUN chmod +x script.sh
  • เปลี่ยน owner ตามต้องการ:
  RUN chown root:root /path/to/file

หา package ไม่เจอ หรือ install ไม่ได้

ตัวอย่าง:

E: Unable to locate package xxx

มักเกิดจากไม่ได้รัน apt-get update หรือพิมพ์ชื่อ package ผิด

วิธีแก้:

  • รัน apt-get update ก่อน install:
  RUN apt-get update && apt-get install -y curl
  • ตรวจสอบชื่อ package ให้ถูกต้อง

ปัญหา network (DNS resolution)

ตัวอย่าง:

Temporary failure resolving 'deb.debian.org'

ปัญหา DNS ระหว่าง build

วิธีแก้:

  • ลอง restart Docker daemon:
  sudo systemctl restart docker
  • ระบุ DNS ใน /etc/docker/daemon.json:
  {
    "dns": ["8.8.8.8", "8.8.4.4"]
  }

ปัญหา build ติดแคชเก่า

Docker ใช้ layer cache เพื่อความเร็ว บางทีแก้ Dockerfile แล้วยังไม่ build ใหม่

วิธีแก้:

  • build โดยไม่ใช้ cache:
  docker build --no-cache -t my-image .

container รันคำสั่งไม่สำเร็จ/หยุดทันที

สาเหตุ:

  • คำสั่งใน CMD หรือ ENTRYPOINT ผิด หรือขาด arguments
  • ถ้าระบุ CMD ["bin/bash"] แล้วไม่ได้ใช้ -it จะหยุดทันที

วิธีแก้:

  • debug โดยรันเข้า bash:
  docker run -it my-image /bin/bash
  • เข้าใจความแตกต่างระหว่าง CMD กับ ENTRYPOINT

หากเจอปัญหาเหล่านี้บ่อย ๆ จะทำให้เข้าใจการออกแบบ Dockerfile ได้ลึกขึ้น แนะนำให้อ่าน error message อย่างใจเย็นและไล่ดูว่ามีปัญหาที่ layer/command ใด

7. สรุป

ทบทวนประเด็นสำคัญของ Dockerfile ที่ใช้ Ubuntu

บทความนี้อธิบายขั้นตอนการสร้างสภาพแวดล้อม Ubuntu ด้วย Dockerfile ตั้งแต่พื้นฐานจนถึงขั้นสูง สรุปสาระสำคัญดังนี้:

  • ทำความเข้าใจ โครงสร้างพื้นฐานของ Dockerfile คำสั่งอย่าง FROM, RUN, CMD, ENV จะช่วยให้ automate การสร้างสภาพแวดล้อมได้
  • Ubuntu เป็น image พื้นฐานที่เสถียรและยืดหยุ่น มี package เยอะ ชุมชนใหญ่มาก เหมาะกับงาน dev ทุกรูปแบบ
  • บริหารจัดการ package อย่างเป็นระบบ ติดตั้ง-ลบ-อัปเดตได้สะดวก ลดปัญหา dependency
  • สามารถใช้ Dockerfile สร้าง environment สำหรับ Python ด้วยเครื่องมืออย่าง pyenv, pip, requirements.txt ได้
  • การรับมือปัญหา จะช่วยให้ใช้งาน Docker ได้อย่างมั่นใจ เช่น เรื่อง permission, network, cache ฯลฯ

ก้าวถัดไปของการเรียนรู้ Dockerfile

เมื่อใช้ Dockerfile คล่อง จะขยายสู่การ deploy, test หรือ production ได้ง่ายขึ้น แนะนำศึกษาหัวข้อเหล่านี้ต่อ:

  • Docker Compose การจัดการ container หลายตัว
  • CI/CD Tools (GitHub Actions, GitLab CI ฯลฯ)
  • การใช้ Kubernetes สำหรับ orchestrate container หลาย ๆ ตัว

เอกสารและแหล่งอ้างอิงทางการ

8. คำถามที่พบบ่อย (FAQ)

Q1. ควรเลือก Ubuntu เวอร์ชันไหนใน Dockerfile?

A1. ถ้าต้องการความเสถียรและระยะ support ยาว เลือก LTS (Long Term Support) เช่น ubuntu:22.04 หรือ ubuntu:20.04 เพราะมี support 5 ปี ใช้งานได้มั่นใจ ถ้าอยากลองใช้ฟีเจอร์ใหม่ ๆ ให้เลือก ubuntu:24.04 แต่ควรทดสอบก่อนนำไป production

Q2. ติดตั้ง package ด้วย apt-get install แล้วเจอ “package not found”?

A2. มักเกิดจากไม่ได้รัน apt-get update ล่วงหน้า หรือพิมพ์ชื่อ package ผิด วิธีที่ถูกต้อง:

RUN apt-get update && apt-get install -y curl

ระวังชื่อ package ว่าเป็นเวอร์ชันล่าสุด (เช่น ใช้ python3 ไม่ใช่ python)

Q3. ตั้งค่า Environment Variable ใน Dockerfile ยังไง?

A3. ใช้คำสั่ง ENV เช่นเดียวกับตัวอย่างข้างต้น เช่น:

ENV DEBIAN_FRONTEND=noninteractive

ใช้สำหรับ suppress prompt ของ APT หรือตั้งค่าคอนฟิกต่าง ๆ ใน container

Q4. ความแตกต่างระหว่าง CMD กับ ENTRYPOINT?

A4. ทั้งคู่ใช้ระบุคำสั่งรันตอน container เริ่ม แต่ต่างกันที่ CMD สามารถ override ได้จากคำสั่ง docker run ส่วน ENTRYPOINT จะบังคับรันเสมอ

หัวข้อCMDENTRYPOINT
Override ได้หรือไม่Override ได้จาก docker runโดยปกติจะไม่ override
การใช้งานตั้งค่า command เริ่มต้นกำหนดให้รันเสมอ (แม้ส่ง argument มา)

ตัวอย่าง:

CMD ["python3", "app.py"]
# หรือ
ENTRYPOINT ["python3"]
CMD ["app.py"]

ในตัวอย่างหลัง สามารถส่ง argument เพิ่มจาก docker run ได้โดยไม่ต้องแก้ Dockerfile

Q5. แก้ไข Dockerfile แล้ว build ยังไม่เปลี่ยน?

A5. อาจเกิดจาก Docker ใช้ cache ของ layer เก่าอยู่ ให้ build แบบไม่ใช้ cache:

docker build --no-cache -t my-image .

จะช่วยให้ทุกการแก้ไขถูกนำไป build ใหม่ทั้งหมด