Docker image production: nhỏ hơn, an toàn hơn, build nhanh hơn
Docker

Docker image production: nhỏ hơn, an toàn hơn, build nhanh hơn

Nam Nguyen
4 phút đọc
0 lượt xem
#docker
#image
#security
#build

Image production cần được thiết kế#

Nhiều Dockerfile chạy được ở local nhưng chưa đủ tốt cho production: image quá nặng, chứa dev dependency, copy cả file env, chạy bằng root, không có tag rõ ràng hoặc build chậm vì cache bị phá liên tục. Docker image production cần được xem như artifact phát hành, không phải bản chụp tạm của thư mục dự án.

Một image tốt có ba đặc điểm: chỉ chứa thứ cần để chạy, build có thể lặp lại và giảm quyền runtime. Điều này giúp deploy nhanh hơn, giảm bề mặt tấn công và dễ debug version đang chạy.

Multi-stage build giúp tách build-time và runtime#

Build app thường cần nhiều công cụ hơn runtime. Ví dụ frontend cần TypeScript, bundler và dev dependency để build, nhưng container runtime chỉ cần output build và package cần thiết để chạy. Multi-stage build cho phép dùng một stage để build, sau đó copy kết quả sang stage runtime nhỏ hơn.

Dockerfile
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:22-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=build /app/.next ./.next
COPY --from=build /app/public ./public
EXPOSE 3000
CMD ["npm", "run", "start"]

Ví dụ này vẫn cần điều chỉnh theo framework, nhưng nguyên tắc chính là tách dependency build và dependency runtime. Với Next.js, nếu dùng output standalone, image có thể còn nhỏ hơn nữa.

Cache layer quyết định tốc độ build#

Docker cache theo layer. Nếu bạn copy toàn bộ source trước khi chạy npm ci, chỉ cần sửa một file UI cũng khiến layer install dependency bị rebuild. Cách tốt hơn là copy package manifest trước, install dependency, rồi mới copy source. Khi dependency không đổi, build dùng lại cache.

.dockerignore cũng ảnh hưởng trực tiếp tới cache và tốc độ. Build context càng nhỏ, Docker gửi dữ liệu càng nhanh và ít khả năng cache bị invalid bởi file không liên quan.

Không đưa secret vào image#

Secret trong image là lỗi nghiêm trọng vì image có thể được push lên registry, cache ở CI hoặc chia sẻ cho môi trường khác. Biến như database password, service role key, JWT secret và private API key phải được inject ở runtime qua secret manager hoặc environment của nền tảng deploy.

Nếu build cần token private để tải package, hãy dùng cơ chế secret mount của build system khi có thể, hoặc đảm bảo token không nằm trong layer cuối. Sau build, kiểm tra history và scan image để giảm rủi ro rò rỉ.

Chạy non-root khi có thể#

Container không phải sandbox tuyệt đối. Chạy process bằng user root làm tăng tác động nếu app bị khai thác. Nhiều base image cung cấp user non-root sẵn, hoặc bạn có thể tạo user riêng. Đồng thời, filesystem runtime nên ghi càng ít càng tốt; log nên ra stdout/stderr để platform thu thập.

Checklist Docker image production#

  • Base image có version rõ, được cập nhật định kỳ.
  • Dockerfile dùng multi-stage nếu build cần nhiều tool hơn runtime.
  • .dockerignore loại node_modules, cache, .env, .git, log và output build local.
  • Dependency production được tách khỏi dev dependency khi phù hợp.
  • Image không chứa secret, token, file local hoặc credential.
  • Process runtime không chạy root nếu framework cho phép.
  • Image được tag bằng commit SHA hoặc version release.
  • CI scan dependency/image và lưu kết quả theo release.

Nguồn tham khảo chính#

Chia sẻ bài viết

Giúp người khác tìm thấy bài viết này

Bình luận

Đang tải bình luận...

Đang tải bình luận...

Để lại bình luận

Email của bạn sẽ không được công khai

Tối thiểu 10 ký tự

0 / 5000