Sổ tay kỹ thuật

Dockerfile – best practices

cheatsheet#docker#dockerfile#security· cập nhật 2026-11-06

Tra nhanh cách viết Dockerfile build nhanh, image gọn và chạy an toàn với multi-stage, layer cache, non-root, .dockerignore và HEALTHCHECK.

Sửa trang này
Mục lục

Áp dụng cho BuildKit (mặc định từ Docker Engine 23). Lệnh CLI xem Docker – lệnh hay dùng, giảm dung lượng image xem Giảm dung lượng Docker image.

Layer cache

Mục đích Cách viết
Copy file khai báo dependency trước, code sau COPY requirements.txt . → RUN pip install -r requirements.txt → COPY . .
Gộp update + install + dọn cache trong một RUN RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/*
Cache thư mục download giữa các lần build (không vào image) RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
Lệnh hay đổi (COPY code, ARG version) đặt cuối Mọi layer sau layer thay đổi đều bị build lại
Dùng parser Dockerfile mới nhất Dòng đầu file: # syntax=docker/dockerfile:1
Kiểm tra lỗi Dockerfile mà không build docker build --check .

Multi-stage

Mục đích Cách viết
Đặt tên stage FROM golang:1.23 AS build
Copy artifact từ stage trước COPY --from=build /out/app /usr/local/bin/app
Copy từ image khác (không cần stage) COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
Chỉ build tới stage nào đó (test, dev) docker build --target test .
Stage không được tham chiếu sẽ bị BuildKit bỏ qua Đặt stage test, lint song song với build thoải mái
Dockerfile
# syntax=docker/dockerfile:1
FROM python:3.12-slim AS build
WORKDIR /app
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
 
FROM python:3.12-slim
RUN useradd --system --uid 10001 --no-create-home app
WORKDIR /app
COPY --from=build /opt/venv /opt/venv
COPY --chown=app:app . .
ENV PATH="/opt/venv/bin:$PATH" PYTHONUNBUFFERED=1
USER 10001
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/healthz')" || exit 1
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Bảo mật và runtime

Mục đích Cách viết
Chạy non-root (dùng UID số để Kubernetes runAsNonRoot kiểm tra được) USER 10001
File thuộc user app mà không thêm layer chown COPY --chown=app:app . .
Pin base image theo digest FROM python:3.12-slim@sha256:<digest>
Secret lúc build, không lưu vào layer RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci + docker build --secret id=npmrc,src=$HOME/.npmrc .
Exec form để app là PID 1 và nhận SIGTERM CMD ["app", "--flag"] (không dùng CMD app --flag)
App không tự reap zombie / xử lý signal docker run --init hoặc ENTRYPOINT ["tini", "--"]
Đổi signal dừng STOPSIGNAL SIGQUIT (vd nginx graceful)
Healthcheck cho Docker/Compose HEALTHCHECK CMD curl -fsS http://127.0.0.1:8000/healthz || exit 1 (image phải có curl)

Không COPY .env, không ARG TOKEN hay ENV PASSWORD=... cho secret: giá trị ARG/ENV nằm trong metadata, xem được bằng docker history/docker inspect. Xoá file ở layer sau cũng không xoá khỏi layer trước.

ARG và ENV

Mục đích Cách viết
Biến chỉ dùng lúc build ARG VERSION=dev → docker build --build-arg VERSION=1.2.0 .
Biến có ở cả build và runtime container ENV TZ=Asia/Ho_Chi_Minh
ARG trước FROM chỉ dùng được trong dòng FROM ARG PY=3.12 → FROM python:${PY}-slim
Dùng lại ARG đó trong stage: khai báo lại (không gán giá trị) FROM python:${PY}-slim → ARG PY
Truyền ARG sang ENV runtime ARG VERSION → ENV APP_VERSION=$VERSION
ARG có sẵn của BuildKit TARGETPLATFORM, TARGETOS, TARGETARCH (khai báo ARG TARGETARCH để dùng)
Gắn label OCI LABEL org.opencontainers.image.source="https://github.com/example/app"

.dockerignore

.dockerignore
.git
.venv
node_modules
__pycache__/
*.pyc
.env
*.pem
dist/
Dockerfile*
docker-compose*.yml
Mục đích Ghi chú
Context nhỏ, build nhanh Dòng transferring context: 500MB khi build là dấu hiệu thiếu .dockerignore
Tránh lọt secret vào image COPY . . copy mọi thứ không bị ignore, kể cả .env
Cache ổn định Đổi file trong .git cũng làm hỏng cache của COPY . . nếu không ignore
Ngoại lệ ! để giữ lại: *.md rồi !README.md

Kubernetes bỏ qua HEALTHCHECK trong image; ở đó dùng probe trong manifest, xem Resource và probe.