Thực hành: đóng gói ứng dụng Node.js vào Docker container từ A đến Z

  • author-image

    Nguyễn Đình Cường

  • blog-tag
  • blog-comment 0 comment
  • created-date 09 Nov, 2026
blog-thumbnail

"Chạy được trên máy tôi" là câu nói quen thuộc của lập trình viên. Docker giải quyết vấn đề này bằng cách đóng gói ứng dụng cùng môi trường của nó vào một container chạy giống nhau ở mọi nơi. Bài này hướng dẫn bạn viết Dockerfile đầu tiên cho một ứng dụng Node.js đơn giản.

Image và container khác nhau thế nào

Hãy hình dung image như bản thiết kế bất biến, gồm hệ điều hành thu gọn, Node.js, code và thư viện của bạn. Container là một thể hiện đang chạy của image đó. Từ một image, bạn có thể chạy nhiều container. Dockerfile là file văn bản mô tả từng bước để dựng image.

Chuẩn bị ứng dụng mẫu

Cài Docker Desktop (Windows, macOS) hoặc Docker Engine (Linux) và kiểm tra bằng docker --version. Tạo thư mục docker-demo với hai file. Đầu tiên là package.json:

{
  "name": "docker-demo",
  "version": "1.0.0",
  "main": "server.js",
  "scripts": { "start": "node server.js" },
  "dependencies": {}
}

Và server.js, dùng module HTTP có sẵn của Node để khỏi phải cài thêm thư viện:

const http = require('http');

const port = process.env.PORT || 3000;

http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
  res.end('Xin chào từ container!\n');
}).listen(port, () => {
  console.log('Đang chạy ở cổng ' + port);
});

Viết Dockerfile

Tạo file tên đúng là Dockerfile (không có phần mở rộng):

FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install --omit=dev

COPY . .

EXPOSE 3000

CMD ["npm", "start"]

Giải thích từng dòng:

  • FROM: chọn image nền. Phiên bản alpine nhỏ gọn, tải nhanh.
  • WORKDIR: thư mục làm việc bên trong container.
  • COPY package*.json ./ rồi RUN npm install: cài thư viện trước khi chép code. Docker lưu cache theo từng lớp, nên khi bạn chỉ sửa code mà không đổi thư viện, bước cài sẽ không phải chạy lại.
  • COPY . .: chép phần còn lại của mã nguồn.
  • EXPOSE: tài liệu hóa cổng ứng dụng lắng nghe.
  • CMD: lệnh chạy khi container khởi động.

Thêm .dockerignore

Giống .gitignore, file .dockerignore ngăn những thứ không cần thiết bị chép vào image, làm image nhẹ và an toàn hơn:

node_modules
npm-debug.log
.git
.env

Build và chạy

docker build -t docker-demo .
docker run --rm -p 3000:3000 docker-demo

Tùy chọn -t đặt tên cho image. Tùy chọn -p 3000:3000 ánh xạ cổng 3000 của máy bạn tới cổng 3000 trong container. Mở http://localhost:3000, bạn sẽ thấy dòng chào. Tùy chọn --rm tự xóa container sau khi dừng, bấm Ctrl + C để dừng.

Để chạy nền, dùng -d và đặt tên:

docker run -d --name demo -p 3000:3000 docker-demo
docker ps
docker logs demo
docker stop demo

Truyền cấu hình qua biến môi trường

Đừng viết cứng mật khẩu hay khóa API vào image. Hãy truyền khi chạy:

docker run --rm -e PORT=4000 -p 4000:4000 docker-demo

Lỗi thường gặp

  • Không truy cập được từ trình duyệt: quên tùy chọn -p, hoặc ứng dụng chỉ lắng nghe ở 127.0.0.1 bên trong container thay vì mọi địa chỉ. Với Node, listen(port) mặc định đã lắng nghe mọi địa chỉ.
  • Build chậm: sắp xếp lại thứ tự lệnh để tận dụng cache và thêm .dockerignore.
  • Sửa code nhưng container không đổi: cần build lại image, hoặc dùng bind mount khi phát triển.

Mẹo giữ image gọn và an toàn

Chọn image nền nhỏ như bản alpine hoặc slim, và ghim phiên bản cụ thể thay vì dùng nhãn latest để build luôn tái lập được. Không chạy ứng dụng bằng tài khoản root trong container nếu có thể: image Node chính thức có sẵn người dùng node, bạn chỉ cần thêm dòng USER node trước CMD. Với ứng dụng cần bước build như React hay TypeScript, hãy dùng multi-stage build: giai đoạn đầu cài đủ công cụ để build, giai đoạn sau chỉ chép kết quả build sang image nhỏ để chạy. Cách này giảm đáng kể dung lượng và bề mặt tấn công.

Kết luận

Bạn vừa đóng gói một ứng dụng Node.js thành image và chạy nó như container. Nắm được FROM, COPY, RUN, CMD là đủ để đóng gói phần lớn ứng dụng nhỏ. Bước tiếp theo nên là Docker Compose để chạy cùng lúc ứng dụng và cơ sở dữ liệu.

Để học Docker và quy trình triển khai một cách bài bản, bạn có thể xem các khóa học DevOps tại codebem.com.

author_photo
Nguyễn Đình Cường

0 comment