Hướng dẫn viết Dockerfile chuẩn cho Node.js, Next.js và React
Hướng dẫn Dockerfile chuẩn cho Node.js, Next.js và React: multi-stage build, npm ci, Next.js standalone, Nginx, BuildKit cache, bảo mật và tối ưu Image.
ShanverseCập nhật 7 phút đọc— lượt xemĐang tải lượt xem
Docker
Next.js
React
Node.js
Chọn đúng mô hình trước khi viết
Đừng dùng một Dockerfile giống hệt cho cả ba. React SPA không cần mang Node.js và node_modules vào Image cuối; Next.js cần xử lý server output; Node.js API cần production dependencies hoặc bundle.
Cấu trúc nền tảng của Dockerfile tốt
Mermaid
Loading diagram…
Multi-stage build tách:
Dependencies: cài đúng theo lockfile.
Builder: compile TypeScript, Next.js hoặc React.
Runtime: chỉ copy artifact và dependency cần chạy.
Bình luận
.dockerignore bắt buộc
Kiểm tra project trước khi ignore public, migration hoặc file config cần cho build.
Dockerfile production cho Node.js API
Ví dụ Node.js + TypeScript, output ở dist/:
Build và chạy:
Vì sao cấu trúc này tốt?
npm ci cài đúng package-lock.json và fail nếu lockfile lệch.
Production dependencies tách khỏi dev dependencies.
Source không được copy trước bước cài dependency nên cache tốt hơn.
Image cuối không chứa compiler, TypeScript source hoặc npm cache.
USER node tránh chạy process dưới root.
CMD dạng JSON/exec giúp Node nhận signal trực tiếp.
Nếu ứng dụng được bundle thành một artifact không cần node_modules, bỏ stage prod-deps. Nếu package native cần compile/runtime library, kiểm tra kỹ trước khi chuyển base Image.
Alpine hay Debian Slim?
node:22-alpine nhỏ hơn, nhưng dùng musl libc và có thể gây vấn đề với native modules, browser binaries hoặc thư viện mong đợi glibc. bookworm-slim lớn hơn nhưng thường tương thích dễ hơn.
Chọn theo kết quả test, không chỉ nhìn kích thước. Pin major/minor hoặc digest theo quy trình cập nhật bảo mật; không dùng latest cho build cần tái hiện.
Dockerfile production cho Next.js
Bật standalone output trong next.config.js:
Dockerfile:
Build:
Nếu project không có public/, điều chỉnh dòng COPY. Với monorepo, standalone output và build context có thể cần cấu hình tracing root.
Biến môi trường Next.js
Biến server-side có thể được cấp lúc runtime nếu code đọc khi request/startup.
Biến NEXT_PUBLIC_* thường được nhúng vào JavaScript client lúc build và không thể đổi chỉ bằng runtime environment.
Không dùng ARG/ENV để đưa secret vào layer.
Secret cần cho bước build có thể dùng BuildKit secret mount:
Đảm bảo build tool không ghi secret vào artifact hoặc log.
Dockerfile production cho React SPA
Vite/React build ra dist/; Create React App thường dùng build/. Stage cuối chỉ cần web server:
nginx.conf cho client-side routing:
Build và chạy:
Không chạy npm run dev hoặc Vite dev server ở production. Chúng phục vụ trải nghiệm development, không phải web server production đã harden.
Tối ưu Build Cache
Thứ tự nên là:
Nếu COPY . . đứng trước npm ci, một thay đổi source nhỏ có thể làm mất cache cài dependency.
BuildKit cache mount tăng tốc download nhưng không được copy vào Image cuối:
Trong CI phân tán, cấu hình cache export/import nếu cần; cache chỉ là tối ưu, build vẫn phải đúng khi cache rỗng.
Chọn một package manager
npm: copy package-lock.json, dùng npm ci.
pnpm: copy pnpm-lock.yaml, pin/enable Corepack và dùng pnpm install --frozen-lockfile.
Yarn: copy lockfile tương ứng và dùng immutable install phù hợp phiên bản.
Không copy nhiều lockfile rồi đoán package manager. CI nên fail khi lockfile không đồng bộ.
CMD, signal và PID 1
Tốt:
Tránh:
Exec form giảm shell trung gian và giúp process nhận SIGTERM. Application vẫn phải xử lý graceful shutdown. Có thể chạy với docker run --init hoặc init process phù hợp khi workload sinh child process.
HEALTHCHECK có nên đặt trong Dockerfile?
Có thể:
Nhưng orchestrator thường quản lý readiness/liveness riêng. Health check phải nhẹ, có timeout và kiểm tra đúng khả năng phục vụ, không chỉ process tồn tại.
Security checklist
Base Image từ nguồn tin cậy và được cập nhật.
Lockfile được commit và install ở chế độ frozen.
Runtime chạy non-root.
Không có .env, token hoặc private key trong layers.
Final stage không chứa build tools không cần thiết.
Image được scan và tạo SBOM theo pipeline.
Runtime filesystem/read-only mount được dùng khi ứng dụng hỗ trợ.
CPU/memory limits được đặt ngoài Dockerfile.
Port được document bằng EXPOSE, nhưng publish bằng -p/orchestrator.
Log ghi ra STDOUT/STDERR.
Anti-patterns phổ biến
Một stage duy nhất
Image chứa dev dependencies, compiler, source và cache. Dùng multi-stage build.
COPY . . trước khi cài dependency
Cache bị vô hiệu thường xuyên.
Dùng npm install khi có lockfile
Production build khó tái hiện hơn; dùng npm ci.
Chạy root
Tăng mức ảnh hưởng khi application bị khai thác.
Copy .env rồi xóa ở layer sau
Secret vẫn có thể tồn tại trong layer cũ.
Dùng cùng runtime cho React và Node API
React SPA build xong chỉ cần static server/CDN; Node.js runtime là thừa.
Kiểm tra Image trước khi phát hành
Tùy application, --read-only có thể yêu cầu thêm writable mount. Test startup, graceful shutdown, health endpoint, log, permission và architecture mục tiêu.
Tổng kết
Node.js API: tách dev dependencies, build artifact và production dependencies.
Next.js: dùng output: 'standalone' để tạo runtime Image gọn.
React SPA: build bằng Node.js, serve static files bằng Nginx/CDN.
Copy lockfile trước source để tận dụng cache.
Final stage phải nhỏ, non-root và không chứa secret.
Mục lục(23)
Codedocker
1# syntax=docker/dockerfile:123FROM node:22-bookworm-slim AS base4WORKDIR /app5ENV NODE_ENV=production67FROM base AS prod-deps8COPY package.json package-lock.json ./9RUN --mount=type=cache,target=/root/.npm \10 npm ci --omit=dev && npm cache clean --force1112FROM base AS builder13ENV NODE_ENV=development14COPY package.json package-lock.json ./15RUN --mount=type=cache,target=/root/.npm npm ci16COPY tsconfig.json ./17COPY src ./src18RUN npm run build1920FROM base AS runner21COPY --from=prod-deps --chown=node:node /app/node_modules ./node_modules22COPY --from=builder --chown=node:node /app/dist ./dist23COPY --chown=node:node package.json ./24USER node25EXPOSE 300026CMD ["node", "dist/server.js"]
Hướng dẫn Docker Compose cho Node.js với hai cấu hình docker-compose.yml hoàn chỉnh: PostgreSQL và MongoDB, kèm healthcheck, service discovery, volume, bảo mật và debug.
Hướng dẫn Docker Hardening thực tế với non-root user, multi-stage builds, minimal image, read-only filesystem, Linux capabilities, seccomp, scanning và supply-chain security.
Docker Compose khi nào không còn đủ? So sánh Kubernetes và Docker Swarm về multi-host, self-healing, scaling, rolling update, networking, secrets và lộ trình migration production.