Giao diện
Thực hành: Viết Dockerfile
🎯 Mục tiêu
🎯 Sau bài thực hành này, bạn sẽ:
- Viết Dockerfile production-ready cho Node.js và Python
- Phân biệt COPY vs ADD, RUN chain vs RUN riêng lẻ
- Hiểu thứ tự instruction tối ưu để tận dụng build cache
- Sử dụng đúng EXPOSE, CMD, và ENTRYPOINT
Phần 1: Trắc nghiệm
🧠 Quiz
Câu 1: Instruction FROM trong Dockerfile có vai trò gì?
- [ ] A) Copy file từ host vào container
- [x] B) Chỉ định base image để build image mới
- [ ] C) Chạy lệnh bên trong container khi build
- [ ] D) Mở port cho container giao tiếp với bên ngoài
💡 Giải thích:
FROMluôn là instruction đầu tiên trong Dockerfile. Nó xác định base image (ví dụnode:20-alpine,python:3.12-slim) — nền tảng mà image của bạn được xây dựng lên.
🧠 Quiz
Câu 2: Sự khác biệt chính giữa COPY và ADD là gì?
- [ ] A) COPY nhanh hơn ADD trong mọi trường hợp
- [ ] B) ADD chỉ hoạt động với file local, COPY hỗ trợ URL
- [x] C) ADD hỗ trợ tự động giải nén tar và tải URL, COPY chỉ copy đơn thuần
- [ ] D) Không có khác biệt — hai instruction hoàn toàn giống nhau
💡 Giải thích:
COPYchỉ copy file/folder từ build context vào image.ADDcó thêm tính năng tự giải nén.tarvà tải file từ URL. Best practice: luôn dùng COPY trừ khi cần giải nén tar — vì COPY rõ ràng và dễ dự đoán hơn.
🧠 Quiz
Câu 3: Tại sao nên gộp nhiều lệnh RUN bằng &&?
- [ ] A) Vì Docker không cho phép nhiều instruction RUN
- [ ] B) Vì
&&giúp lệnh chạy song song, tăng tốc build - [x] C) Vì mỗi RUN tạo một layer mới — gộp lại giảm số layer và kích thước image
- [ ] D) Vì
&&bắt buộc khi dùng Alpine Linux
💡 Giải thích: Mỗi instruction RUN tạo một layer trong image. Gộp
apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*thành một RUN giúp giảm layer, giảm kích thước image, và tránh cache cũ của package manager.
Phần 2: Sắp xếp thứ tự Dockerfile
🧩 Parsons Problem
Bài 1: Dockerfile cho Node.js API
Sắp xếp các instruction theo thứ tự tối ưu cho build cache:
FROM node:20-alpineWORKDIR /appCOPY package.json package-lock.json ./RUN npm ci --only=productionCOPY . .EXPOSE 3000CMD ["node", "server.js"]
🧩 Parsons Problem
Bài 2: Dockerfile cho Python Flask App
Sắp xếp các instruction đúng thứ tự:
FROM python:3.12-slimWORKDIR /appCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txtCOPY . .EXPOSE 5000CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
Phần 3: Tìm lỗi trong Dockerfile
🐛 Spot-the-Bug
Dockerfile bị lỗi — Node.js App
dockerfile
FROM node:20-alpine
COPY . .
RUN npm install
EXPOSE 3000
CMD ["node", "server.js"]Câu hỏi: Dockerfile trên có 2 vấn đề. Bạn tìm được không?
Đáp án:
- Thiếu WORKDIR — file nằm ở root
/, gây xung đột. ThêmWORKDIR /appsau FROM. - COPY all trước install — mỗi thay đổi file buộc Docker chạy lại
npm install. Nên COPYpackage.jsontrước, install, rồi COPY source.
🐛 Spot-the-Bug
Dockerfile bị lỗi — Python App
dockerfile
FROM python:3.12
WORKDIR /app
COPY ../src ./src
COPY requirements.txt .
RUN pip install -r requirements.txt
CMD ["python", "src/main.py"]Câu hỏi: Tìm lỗi trong Dockerfile trên.
Đáp án: COPY ../src ./src — Docker không cho phép COPY file nằm ngoài build context. Path ../src sẽ gây lỗi build. Cần điều chỉnh build context hoặc đặt lại vị trí Dockerfile.