- 1 1. บทนำ
- 2 2. โครงสร้างพื้นฐานของ Dockerfile
- 3 3. ปฏิบัติจริง: การสร้าง Dockerfile ที่ใช้ Ubuntu เป็นฐาน
- 4 4. การ build และตรวจสอบ Docker image
- 5 5. ขั้นสูง: การติดตั้ง Python environment
- 6 6. ปัญหาที่พบบ่อยและวิธีแก้ไข
- 7 7. สรุป
- 8 8. คำถามที่พบบ่อย (FAQ)
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
: สำหรับดาวน์โหลดไฟล์และตรวจสอบ APIvim
: โปรแกรมแก้ไขข้อความ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
จะบังคับรันเสมอ
หัวข้อ | CMD | ENTRYPOINT |
---|---|---|
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 ใหม่ทั้งหมด