Á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 |
# 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
.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.