Chuyển đến nội dung chính (Skip to content)
Mục lục bài viết
Docker

Viết Dockerfile với BuildKit, cache và secrets

Viết Dockerfile với BuildKit, cache và secrets

Sắp xếp layer, chọn exec form, quản lý dependency và đưa bí mật vào build đúng cách; kèm mẫu Node.js để điều chỉnh theo ứng dụng thực tế.

Đối chiếu ngày 24/10/2026. Các nguồn ở cuối bài dùng để kiểm tra phiên bản và giới hạn. Ví dụ phải điều chỉnh theo hệ điều hành và ứng dụng; không phải báo cáo thử nghiệm trên mọi nền tảng.

1. Các chỉ thị Dockerfile cốt lõi

Dockerfile là một tập tin văn bản chứa các chỉ thị từng bước để tự động hóa quá trình đóng gói mã nguồn và môi trường thực thi thành một Docker Image hoàn chỉnh. Các chỉ thị phổ biến nhất gồm:

  • FROM: Khởi tạo giai đoạn build và định nghĩa Base Image ban đầu.
  • WORKDIR: Thiết lập thư mục làm việc hiện tại cho mọi chỉ thị RUN, CMD, COPY tiếp theo.
  • COPY: Sao chép các tệp tin từ máy chủ Host vào hệ thống file của image (luôn ưu tiên hơn ADD trừ khi cần giải nén file tar tự động).
  • RUN: Thực thi các lệnh cài đặt gói phần mềm trong quá trình build và tạo ra layer mới.
  • USER: Chỉ định người dùng (UID/GID) thực thi các tiến trình bên trong container.
  • EXPOSE: Khai báo cổng mạng logic mà container sẽ lắng nghe (mang tính chất tài liệu hóa).
  • ENTRYPOINT & CMD: Xác định câu lệnh mặc định sẽ được thực thi khi container được khởi chạy.
Sơ đồ Build context → BuildKit và cache → Runtime image
Sơ đồ Build context → BuildKit và cache → Runtime image. Chạm vào sơ đồ để mở bản lớn.

2. Cache layer và BuildKit

Docker xây dựng image theo cơ chế tuần tự từng layer từ trên xuống dưới. Nếu một dòng lệnh trong Dockerfile không thay đổi và các file liên quan không đổi, Docker sẽ tái sử dụng lại layer đã có sẵn trong bộ nhớ đệm (Cache Hit).

Nguyên tắc sắp xếp vàng: Đặt những lệnh ít thay đổi lên trên cùng (cài đặt hệ điều hành, runtime), và đặt những lệnh thường xuyên thay đổi (mã nguồn ứng dụng) xuống dưới cùng.

# SAI LẦM: Copy toàn bộ code trước khi cài dependency -> Mất cache mỗi khi sửa 1 dòng code
COPY . .
RUN npm install

# ĐÚNG CHUẨN: Tách riêng file mô tả dependency để tận dụng cache theo dependency
COPY package.json package-lock.json ./
RUN npm ci
COPY . .

BuildKit/Buildx là công cụ build hiện đại. Kiểm tra docker buildx version và driver builder trước cache mount, secret mount hoặc đa nền tảng; không suy ra mọi Docker cũ đều có hành vi mặc định giống nhau.

# Su dung BuildKit cache mount de tang toc tai goi goi thu vien giua cac lan build
RUN --mount=type=cache,target=/root/.npm \
    npm ci --prefer-offline

3. ENTRYPOINT, CMD và tín hiệu dừng

Rất nhiều kỹ sư nhầm lẫn giữa hai chỉ thị này:

  • ENTRYPOINT: Khai báo tiến trình cốt lõi cố định không thể bị ghi đè ngẫu nhiên khi người dùng gõ lệnh docker run (trừ khi cố tình dùng cờ --entrypoint).
  • CMD: Cung cấp các tham số đối số mặc định cho ENTRYPOINT. Tham số này có thể dễ dàng bị thay thế bằng các tham số truyền vào đuôi lệnh docker run.

Exec Form (thường nên dùng): Sử dụng mảng JSON để tiến trình nhận trực tiếp PID 1 và xử lý được tín hiệu Unix (SIGTERM, SIGINT) để shutdown an toàn (Graceful Shutdown):

# Exec Form (Dung): Nhap tien trinh truc tiep PID 1
ENTRYPOINT ["node", "server.js"]
CMD ["--port", "3000"]

# Shell Form (Tranh dung): Se tao them mot tien trinh /bin/sh -c boc ben ngoai, chan tin hieu tat container
CMD node server.js

4. ARG và ENV dùng cho việc gì?

  • ARG: Chỉ tồn tại trong quá trình xây dựng image (Build-time). Người dùng có thể truyền vào bằng cờ docker build --build-arg VERSION=1.2.0. Biến này không còn tồn tại khi container được chạy.
  • ENV: Tồn tại trong cả quá trình build và tiếp tục được lưu vào metadata của container khi chạy (Run-time). Dùng cho các cấu hình như NODE_ENV=production, PORT=8080.

5. Giới hạn build context bằng .dockerignore

Khi bạn gõ docker build, Docker daemon trước tiên phải gửi toàn bộ thư mục hiện tại (Build Context) sang daemon. Nếu bạn không có file .dockerignore, thư mục node_modules, file log và thư mục .git nặng hàng trăm MB sẽ bị gửi qua socket, làm chậm tốc độ build và tiềm ẩn rò rỉ mã bảo mật.

Tạo file .dockerignore ngay cạnh Dockerfile:

node_modules
.git
.github
*.log
.env*
coverage
dist
Dockerfile
README.md

6. Quyền runtime của ứng dụng

Root trong container làm tăng rủi ro khi kết hợp lỗ hổng hoặc quyền host sai, không có nghĩa mọi RCE tự động chiếm host. Ưu tiên USER không root, giảm capability, không mount socket hoặc thư mục nhạy cảm không cần thiết.

# Tao user he thong voi UID co dinh va khong co thu muc home nguy hiem
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# Chuyen quyen so huu thu muc ung dung
USER appuser

7. Mẫu Dockerfile và điều kiện áp dụng

Dưới đây là một mẫu Dockerfile chuẩn hóa cho ứng dụng Node.js sẵn sàng cho môi trường sản xuất:

# 1. Base Image gon nhe va on dinh
FROM node:24-alpine AS base
WORKDIR /usr/src/app

# 2. Thiet lap moi truong
ENV NODE_ENV=production

# 3. Tach lop dependency de tan dung BuildKit cache
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci --omit=dev

# 4. Sao chep ma nguon ung dung sau khi loai bo boi .dockerignore
COPY . .

# 5. Bao ve quyen han: Chuyen sang user khong co quyen root
RUN chown -R node:node /usr/src/app
USER node

# 6. Khai bao cong va lenh thuc thi exec form
EXPOSE 3000
CMD ["node", "bin/server.js"]

Build secret và kiểm thử runtime

ARG và ENV không phải nơi chứa token. BuildKit secret mount chỉ cấp secret cho RUN cần dùng; lệnh ghi secret vào output hoặc log vẫn có thể làm lộ. Ví dụ dùng npmrc riêng ngoài Git.

# syntax=docker/dockerfile:1
# Trong stage co lockfile:
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci
docker build --secret id=npmrc,src=/secure/path/npmrc -t app:review .

Mẫu chính dành cho JavaScript đã có bin/server.js. TypeScript cần stage build trước omit=dev. Không tắt lifecycle scripts nếu dependency cần build native module. EXPOSE không publish cổng; exec form không tự làm chương trình xử lý SIGTERM đúng.

Các nhánh kiểm tra dockerfile buildkit
Các nhánh kiểm tra dockerfile buildkit. Chạm vào sơ đồ để mở bản lớn.

Nguồn đối chiếu và xác nhận sau thay đổi

Đọc đúng tài liệu theo phiên bản. Địa chỉ, tên và đường dẫn trong ví dụ cần thay theo môi trường. Sơ đồ là khái niệm, không phải screenshot hay benchmark.

Lưu cấu hình và digest cũ, kiểm tra backup phục hồi được, xác nhận endpoint và log sau thay đổi. Rollback phải tính đến dữ liệu đã ghi mới; đổi image không tự phục hồi database.

Tìm hiểu thêm

Xem toàn bộ lộ trình Docker