Bỏ qua đến nội dung chính
DockerfileDockersecurityDevOpsbest practices

Dockerfile Best Practices: Security, Size, Cache

Dockerfile best practices đầy đủ: multi-stage build, layer cache, non-root user, scan vulnerability, distroless. Code production-ready cho Node.js.

Xuất bản 8 phút đọc

Dockerfile best practices chuẩn 2026 quyết định 80% chất lượng image production. Bài này đi qua 10 quy tắc + Dockerfile mẫu cho Node.js, Python, Go ở cuối.

1. Luôn dùng multi-stage build

Tách build dependencies khỏi runtime. Image final chỉ chứa app + runtime deps:

FROM node:22-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-slim
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
RUN npm ci --omit=dev
USER node
CMD ["node", "dist/server.js"]

Stage builder có TypeScript, dev deps, source. Stage cuối chỉ có dist + production deps. Image cuối ~200MB thay vì 800MB.

2. Pin version base image

# ❌ Sai — không reproducible
FROM node:latest
FROM node:22

# ✓ Đúng — cụ thể
FROM node:22.5.1-slim
# Tốt hơn — pin digest
FROM node:22.5.1-slim@sha256:abc123...

Renovate/Dependabot tự bump version có PR — anh review từng update.

3. Tận dụng layer cache

Đặt instruction ít thay đổi trước:

# ❌ Sai — sửa code = re-run npm ci
COPY . .
RUN npm ci

# ✓ Đúng — sửa code không invalidate npm ci
COPY package*.json ./
RUN npm ci
COPY . .

4. .dockerignore đầy đủ

node_modules
npm-debug.log
.git
.gitignore
.env*
.next
.cache
*.md
.vscode
.idea
__tests__
coverage
.DS_Store

Không chỉ vì size — .env không được vào image. Secret leak vào registry là incident phổ biến.

5. Chạy non-root user

FROM node:22-slim
RUN groupadd -r app && useradd -r -g app -u 1001 app
WORKDIR /app
COPY --chown=app:app . .
USER app
CMD ["node", "server.js"]

Image official Node có user node sẵn (UID 1000). Dùng USER node là đủ.

6. Handle signal đúng — dùng exec form

# ❌ Sai — shell form, không nhận SIGTERM
CMD node server.js

# ✓ Đúng — exec form, app trực tiếp PID 1
CMD ["node", "server.js"]

Khi shell form, node là child của shell — SIGTERM gửi shell, không tới app. App không graceful shutdown được.

7. Combine RUN để giảm layer

# ❌ Tạo 3 layer
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean

# ✓ 1 layer + dọn cache trong cùng layer
RUN apt-get update \
  && apt-get install -y curl \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/*

8. HEALTHCHECK cho orchestrator

HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:3000/healthz || exit 1

K8s/ECS dùng để restart container khi unhealthy. Endpoint /healthz nên kiểm DB connection, không chỉ "200 OK".

9. KHÔNG bao giờ ARG/ENV cho secret

# ❌ Secret leak vào image layer
ARG DATABASE_PASSWORD
ENV DB_PASS=$DATABASE_PASSWORD

# ✓ Dùng BuildKit secret mount
# syntax=docker/dockerfile:1.4
RUN --mount=type=secret,id=db_pass \
  cat /run/secrets/db_pass | npm run migrate

Build với:

DOCKER_BUILDKIT=1 docker build --secret id=db_pass,src=./db_pass.txt .

10. Scan image trước khi push

# Trivy
trivy image alodev-api:latest

# Snyk
snyk container test alodev-api:latest

# Docker Scout (built-in)
docker scout cves alodev-api:latest

Tích hợp CI: fail build nếu có CRITICAL vuln chưa patch.

Full example: Node.js production

# syntax=docker/dockerfile:1.6
FROM node:22.5.1-slim AS deps
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
  npm ci --omit=dev

FROM node:22.5.1-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .
RUN npm run build

FROM gcr.io/distroless/nodejs22-debian12
WORKDIR /app
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY package.json ./
EXPOSE 3000
USER nonroot
CMD ["dist/server.js"]

Distroless: không có shell, không apt, gần như không attack surface. Image ~120MB.

Kết luận

10 quy tắc Dockerfile best practices: multi-stage, pin version, layer cache, non-root, exec form, combine RUN, healthcheck, secret mount, scan. Áp dụng đầy đủ, image anh sẽ nhỏ hơn 3x và an toàn hơn nhiều. Đọc thêm Docker cơ bản nếu mới bắt đầu, và CI/CD GitHub Actions để tự động build + scan.

Zalo