Docker – Xây dựng môi trường Node.js đồng nhất từ máy phát triển đến máy chủ
Vì sao nên sử dụng Docker?
Trong quá trình phát triển ứng dụng Node.js, nhiều lập trình viên thường gặp tình trạng:
“Ứng dụng chạy được trên máy của mình nhưng khi đưa lên hosting hoặc máy chủ lại phát sinh lỗi.”
Nguyên nhân chủ yếu đến từ sự khác biệt về:
- Phiên bản Node.js
- Hệ điều hành
- Thư viện phụ thuộc
- Biến môi trường
- Công cụ build
Docker giúp đóng gói ứng dụng cùng toàn bộ môi trường chạy vào một container thống nhất. Nhờ đó, ứng dụng có thể hoạt động nhất quán trên máy phát triển, môi trường kiểm thử và máy chủ triển khai.
1. Cài đặt Docker
Windows và macOS
Tải và cài đặt Docker Desktop từ trang chủ Docker.
Ubuntu và Debian
sudo apt update
sudo apt install docker.io docker-compose-plugin
sudo usermod -aG docker "$USER"
Sau khi cài đặt, hãy đăng xuất rồi đăng nhập lại để áp dụng quyền sử dụng Docker.
Kiểm tra phiên bản
docker --version
docker compose version
2. Tạo Dockerfile để kiểm tra quá trình build
Trong thư mục gốc của dự án, cùng cấp với tệp package.json, hãy tạo một tệp có tên Dockerfile:
### Sử dụng Node.js LTS trên nền Alpine Linux
FROM node:20-alpine
#### Thiết lập thư mục làm việc
WORKDIR /app
#### Sao chép các tệp package trước để tận dụng bộ nhớ đệm
COPY package*.json ./
#### Cài đặt thư viện phụ thuộc
RUN npm install
#### Sao chép toàn bộ mã nguồn
COPY . .
#### Build dự án
RUN npm run build
#### Khai báo cổng ứng dụng
EXPOSE 3000
#### Lệnh chạy mặc định
CMD ["npm", "start"]
Lưu ý: Nếu dự án sử dụng Yarn hoặc pnpm, hãy thay
npm installvà các lệnh npm khác bằng lệnh tương ứng của trình quản lý gói đó.
3. Kiểm tra quá trình build bằng Docker
Cách 1: Build image và mở container
Build image
docker build -t my-app-test .
Mở terminal bên trong container
docker run -it --rm my-app-test sh
Bên trong container, bạn có thể kiểm tra các tệp hoặc chạy lại quá trình build:
ls -la
npm run build
Cách 2: Chỉ chạy quá trình build
Trên Linux hoặc macOS:
docker run --rm \
-v "$(pwd):/app" \
-w /app \
node:20-alpine \
sh -c "npm install && npm run build"
Lệnh trên sẽ:
- Gắn thư mục dự án vào container.
- Sử dụng image Node.js chính thức.
- Cài đặt các thư viện phụ thuộc.
- Thực hiện quá trình build.
Sau khi hoàn thành, thư mục đầu ra như dist, build hoặc .next sẽ được tạo ngay trong thư mục dự án trên máy tính.
4. Sử dụng Docker Compose
Docker Compose giúp đơn giản hóa việc cấu hình và chạy dự án.
Tạo tệp compose.yaml trong thư mục gốc của dự án:
services:
app:
image: node:20-alpine
working_dir: /app
volumes:
- .:/app
- /app/node_modules
ports:
- "3000:3000"
command: sh -c "npm install && npm run build && npm start"
Chạy ứng dụng
docker compose up
Chỉ chạy quá trình build
docker compose run --rm app sh -c "npm install && npm run build"
5. Multi-stage build dành cho môi trường production
Multi-stage build là phương pháp phổ biến khi triển khai ứng dụng lên máy chủ. Cách này giúp tách biệt môi trường build và môi trường chạy thực tế, từ đó giảm kích thước image cuối cùng.
#### Giai đoạn 1: Build ứng dụng
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
#### Giai đoạn 2: Chạy ứng dụng trong môi trường production
FROM node:20-alpine AS production
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["npm", "start"]
npm ciyêu cầu dự án có tệppackage-lock.json. Nếu chưa có tệp khóa này, hãy sử dụngnpm install.
Thư mục đầu ra phụ thuộc vào loại dự án:
| Công nghệ | Thư mục đầu ra thường gặp |
|---|---|
| React | build |
| Next.js | .next |
| Vite | dist |
Hãy thay đổi đường dẫn trong lệnh COPY --from=builder sao cho phù hợp với cấu trúc của dự án.
Build image production
docker build -t my-app-prod .
Chạy container production
docker run --rm -p 3000:3000 my-app-prod
6. Các lệnh Docker thường dùng
| Mục đích | Lệnh |
|---|---|
| Build image | docker build -t my-app . |
| Chạy quá trình build trong container | docker run --rm -v "$(pwd):/app" -w /app node:20-alpine sh -c "npm install && npm run build" |
| Mở terminal trong container | docker run -it --rm -v "$(pwd):/app" -w /app node:20-alpine sh |
| Xóa image | docker rmi my-app |
| Xem log của Docker Compose | docker compose logs -f |
| Dừng và xóa container do Docker Compose tạo | docker compose down |
7. Một số lưu ý quan trọng
Tạo tệp .dockerignore
Tệp .dockerignore giúp giảm thời gian build và tránh sao chép những dữ liệu không cần thiết vào image:
node_modules
.git
dist
build
.next
.env
.env.*
*.log
Không nên đưa các tệp chứa thông tin nhạy cảm như
.envvào Docker image.
Truyền biến môi trường
Nếu dự án sử dụng tệp .env, có thể truyền các biến môi trường khi chạy container:
docker run --rm \
-v "$(pwd):/app" \
-w /app \
--env-file .env \
node:20-alpine \
sh -c "npm install && npm run build"
Lưu ý khi sử dụng Windows PowerShell
Trong PowerShell, hãy thay:
$(pwd)
bằng:
${PWD}
Ví dụ:
docker run --rm `
-v "${PWD}:/app" `
-w /app `
node:20-alpine `
sh -c "npm install && npm run build"
Kết luận
Docker giúp tạo ra môi trường phát triển và triển khai đồng nhất, qua đó giảm thiểu lỗi phát sinh do sự khác biệt giữa máy lập trình và máy chủ.
Việc sử dụng Docker ngay từ giai đoạn phát triển mang lại nhiều lợi ích:
- Kiểm tra quá trình build trong môi trường độc lập.
- Quản lý thư viện phụ thuộc nhất quán.
- Hạn chế lỗi do khác biệt về hệ điều hành hoặc phiên bản Node.js.
- Đơn giản hóa quá trình kiểm thử và triển khai.
- Giúp ứng dụng Node.js vận hành ổn định và chuyên nghiệp hơn.

