Dockerfile cơ bản: Tạo Image của riêng bạn

Photo of author

Văn Ngọc Tân

Dockerfile cơ bản: Tạo Image của riêng bạn

Bạn có biết?

Bạn có bao giờ nấu ăn theo công thức chưa? Công thức ghi rõ: nguyên liệu gì, bao nhiêu gam, bước nào trước bước nào sau. Cuối cùng bạn có một món ăn hoàn chỉnh.

Dockerfile cũng giống vậy — nó là “công thức nấu ăn” để tạo ra Docker Image. Bạn viết các bước trong Dockerfile, Docker “nấu” (build) ra Image, rồi từ Image đó chạy Container. Hôm nay chúng ta sẽ học cách viết công thức này!

Dockerfile là gì?

Dockerfile là một file text chứa danh sách các instructions (lệnh hướng dẫn) để build Docker Image. Mỗi dòng trong Dockerfile là một bước trong quá trình tạo Image.

Bạn có thể hình dung:

  • Dockerfile = Công thức nấu ăn (blueprint)
  • Image = Món ăn hoàn chỉnh (bản sao sẵn sàng dùng)
  • Container = Bữa ăn được phục vụ (instance đang chạy)

Cấu trúc Dockerfile cơ bản

Mỗi Dockerfile gồm các instruction chính sau:

FROM — Chọn base image

Đây luôn là dòng đầu tiên. Chọn “nền tảng” để build lên:

FROM node:18-alpine
FROM python:3.11-slim
FROM ubuntu:22.04

Bạn có 3 lựa chọn phổ biến:

  • Alpine — nhỏ nhất (~5MB base), bảo mật tốt, phù hợp production
  • Slim — nhỏ hơn full, bỏ bớt package không cần thiết
  • Full — đầy đủ tool, nhưng nặng hơn nhiều

💡 Mẹo: Ưu tiên dùng Alpine trừ khi cần package đặc biệt.

WORKDIR — Đặt working directory

Giống như cd vào thư mục làm việc. Các lệnh COPY, RUN, CMD sẽ thực thi trong thư mục này:

WORKDIR /app

COPY — Copy files vào Image

Copy file từ máy host vào trong Image:

COPY package.json ./
COPY . .

Dòng đầu copy riêng package.json, dòng thứ hai copy toàn bộ source code.

RUN — Chạy lệnh khi build

Thực thi lệnh trong quá trình build Image. Dùng để cài đặt package, compile code:

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

EXPOSE — Khai báo port

Thông báo Container sẽ listen port nào. Đây chỉ là “khai báo”, không tự động mở port:

EXPOSE 3000

ENV — Đặt biến môi trường

Set environment variable cho Container:

ENV NODE_ENV=production
ENV APP_PORT=3000

CMD — Lệnh chạy khi start Container

Lệnh mặc định khi Container khởi động. Mỗi Dockerfile chỉ có một CMD:

CMD ["node", "server.js"]

ARG — Build-time variables

Biến chỉ có giá trị khi build, không tồn tại trong Container đang chạy:

ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine

Ví dụ hoàn chỉnh

Dockerfile cho Node.js app

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Giải thích từng dòng

  • FROM node:18-alpine — dùng Node.js 18 trên Alpine Linux
  • WORKDIR /app — mọi thứ sẽ nằm trong thư mục /app
  • COPY package*.json ./ — copy package.json trước (tận dụng Docker cache)
  • RUN npm ci — cài đặt dependencies
  • COPY . . — copy source code sau cùng
  • EXPOSE 3000 — app chạy trên port 3000
  • CMD ["node", "server.js"] — lệnh khởi động

Build và chạy

# Build Image từ Dockerfile trong thư mục hiện tại
docker build -t myapp:1.0 .

# Chạy Container từ Image vừa build
docker run -d -p 3000:3000 myapp:1.0

# Kiểm tra Container đang chạy
docker ps
Developer viết code trên laptop với terminal mở
Viết Dockerfile cũng giống như viết công thức — từng bước một, theo đúng thứ tự. Ảnh: Unsplash

Bảng so sánh: COPY vs ADD

Tiêu chí COPY ADD
Chức năng Copy files từ host vào Image Copy files + tự động extract tar, download từ URL
Đơn giản ✅ Đơn giản, dễ hiểu ❌ Có hành vi ẩn, khó predict
Khuyến nghị ✅ Luôn ưu tiên dùng ❌ Chỉ dùng khi cần extract tar
Ví dụ COPY app.js ./ ADD archive.tar.gz ./

💡 Quy tắc: Luôn dùng COPY trừ khi bạn cần chức năng đặc biệt của ADD.

Bảng so sánh: CMD vs ENTRYPOINT

Tiêu chí CMD ENTRYPOINT
Mục đích Tham số mặc định cho Container Định nghĩa lệnh chính, cố định
Override ✅ Dễ override khi docker run ❌ Khó override, cần --entrypoint
Kết hợp Có thể dùng với ENTRYPOINT Có thể dùng với CMD
Ví dụ CMD ["node", "app.js"] ENTRYPOINT ["python"]

Ví dụ kết hợp ENTRYPOINT + CMD:

ENTRYPOINT ["python"]
CMD ["app.py"]

# Chạy mặc định: python app.py
# Override CMD: docker run myimage script.py  → python script.py

Best Practices

6 nguyên tắc quan trọng khi viết Dockerfile:

1. Dùng .dockerignore — Loại trừ files không cần thiết, giảm kích thước Image:

# .dockerignore
node_modules
.git
.env
*.log

2. Sắp xếp Dockerfile đúng thứ tự — Ít thay đổi ở trên, nhiều thay đổi ở dưới. Docker cache layer theo thứ tự, nếu một layer thay đổi thì tất cả layer bên dưới đều build lại.

3. Dùng Alpine images — Nhỏ gọn, bảo mật tốt hơn. Image node:18 full ~900MB, node:18-alpine chỉ ~170MB.

4. Gộp RUN commands — Giảm số layers, giảm kích thước Image:

# ❌ Tạo 2 layers riêng biệt
RUN apt-get update
RUN apt-get install -y curl

# ✅ Gộp thành 1 layer
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*

5. Không dùng root user — Tăng bảo mật bằng cách chạy Container với user thường:

# Cho Node.js
USER node

# Tạo user mới
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

6. Multi-line commands — Dùng \&& để viết lệnh dài dễ đọc:

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

Bước tiếp theo

Bạn đã biết cách viết Dockerfile cơ bản! Nhưng Dockerfile còn có nhiều kỹ thuật nâng cao giúp Image nhỏ hơn, build nhanh hơn và bảo mật tốt hơn.

👉 Bài tiếp theo: Dockerfile nâng cao: Multi-stage Build và tối ưu

0 0 đánh giá
Đánh giá bài viết
Theo dõi
Thông báo của
guest
0 Góp ý
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất
Phản hồi nội tuyến
Xem tất cả bình luận