Bài viết này sẽ hướng dẫn bạn cách đóng gói ứng dụng NestJS vào một container Docker, giúp ứng dụng chạy ổn định trên nhiều môi trường khác nhau. Cùng bắt đầu nào!
Bước 1: Thiết lập Dockerfile
Đầu tiên, chúng ta cần tạo một file Dockerfile
trong thư mục gốc của dự án NestJS. File này sẽ chứa các hướng dẫn để build Docker image.
Dưới đây là một Dockerfile
cơ bản:
# Use Node.js version 20 as the base image
FROM node:20 # Set the working directory in the container
WORKDIR /usr/src/app # Copy package.json and package-lock.json
COPY package*.json ./ # Install dependencies
RUN npm install # Copy the rest of the application code
COPY . . # Build the application
RUN npm run build # Run the application
CMD ["node", "dist/main.js"]
Dockerfile này thực hiện các tác vụ sau:
- Sử dụng Node.js phiên bản 20 làm base image.
- Thiết lập thư mục làm việc thành
/usr/src/app
. - Sao chép
package.json
vàpackage-lock.json
vào thư mục làm việc. - Cài đặt các dependencies bằng
npm install
. - Sao chép phần còn lại của mã ứng dụng vào container.
- Build ứng dụng bằng
npm run build
. - Chỉ định lệnh để chạy ứng dụng với
node dist/main.js
.
Tạo một file .dockerignore
để loại trừ các file không cần thiết khỏi Docker image.
node_modules
npm-debug.log
dist
.git
.env
*.md
.gitignore
Bước 2: Kiểm tra Docker Container cục bộ
Bây giờ, hãy kiểm tra Docker image cục bộ để đảm bảo mọi thứ hoạt động như mong đợi.
Build Docker Image: Mở terminal tại thư mục gốc của dự án và chạy lệnh:
docker build -t nest-app .
Lệnh này sẽ build Docker image và gắn tag nest-app
cho nó.
Chạy Docker Container: Sau khi build image, bạn có thể chạy nó bằng lệnh:
docker run -p 3000:3000 nest-app
Lệnh này sẽ khởi động một container mới từ image nest-app
và ánh xạ cổng 3000 của container với cổng 3000 trên máy cục bộ của bạn.
Kiểm tra ứng dụng: Mở trình duyệt web và truy cập http://localhost:3000. Nếu mọi thứ được thiết lập chính xác, bạn sẽ thấy ứng dụng NestJS của mình đang chạy.
Bước 3: Tối ưu hóa cho môi trường Production
Để tối ưu hóa Dockerfile cho môi trường production, chúng ta sẽ thực hiện một vài thay đổi để giảm kích thước image và cải thiện bảo mật.
Sử dụng Alpine Node Images: Các Alpine image nhỏ hơn và hiệu quả hơn. Cập nhật base image thành:
FROM node:20-alpine
Thiết lập biến môi trường NODE_ENV: Thiết lập NODE_ENV
thành production
để tối ưu hóa ứng dụng cho môi trường production:
ENV NODE_ENV production
Sử dụng npm
ci thay vì npm install
: npm ci
đáng tin cậy hơn cho các môi trường tự động như Docker builds. Thay thế RUN npm install
bằng:
RUN npm ci
Thêm hướng dẫn USER: Chạy ứng dụng với tư cách là người dùng không phải root để bảo mật tốt hơn. Thêm đoạn mã sau sau khi cài đặt dependencies:
USER node
Sử dụng Multistage Builds: Multistage builds cho phép bạn tạo image cuối cùng nhỏ hơn bằng cách tách biệt môi trường build và runtime. Dưới đây là ví dụ về một Multistage Dockerfile:
# Development stage FROM node:20-alpine AS development WORKDIR /usr/src/app COPY package*.json ./ RUN npm ci COPY . . USER node # Build stage FROM node:20-alpine AS build WORKDIR /usr/src/app COPY package*.json ./ COPY --from=development /usr/src/app/node_modules ./node_modules COPY . . RUN npm run build ENV NODE_ENV production RUN npm ci --only=production && npm cache clean --force USER node # Production stage FROM node:20-alpine AS production WORKDIR /usr/src/app COPY --from=build /usr/src/app/node_modules ./node_modules COPY --from=build /usr/src/app/dist ./dist CMD ["node", "dist/main.js"]
Thiết lập này sử dụng ba giai đoạn:
development
: Dành cho phát triển cục bộ với tất cả các dependencies.build
: Build ứng dụng cho production.production
: Giai đoạn cuối cùng chạy bản build production.
Bước 4: Xây dựng lại và chạy Image đã tối ưu hóa
Sau khi cập nhật Dockerfile
, hãy xây dựng lại image:
docker build -t nest-app .
Sau đó, chạy container đã được tối ưu hóa:
docker run -p 3000:3000 nest-app
Kiểm tra kích thước của image mới bằng lệnh:
docker images
Bạn sẽ thấy kích thước image giảm đáng kể, giúp nó hiệu quả hơn khi sử dụng trong môi trường production.
Khắc phục sự cố thường gặp
- Lỗi:
Cannot find module 'webpack'
: Đảm bảo bạn đang sử dụng đúng phiên bản Node.js trong base image. Ví dụ: sử dụngFROM node:20-alpine
thay vìFROM node:14-alpine
. - Lỗi:
nest command not found
: Điều này thường xảy ra nếu Nest CLI chưa được cài đặt. Trong multistage build, hãy đảm bảo bạn sao chép thư mụcnode_modules
từ giai đoạn development, nơi CLI được cài đặt.
Sử dụng các trình quản lý gói khác nhau
Nếu bạn đang sử dụng pnpm thay vì npm, Dockerfile
của bạn sẽ hơi khác một chút. Dưới đây là một ví dụ:
# Development stage
FROM node:20 AS development
RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
WORKDIR /usr/src/app
COPY pnpm-lock.yaml ./
RUN pnpm fetch --prod
COPY . .
RUN pnpm install
USER node # Build stage
FROM node:20 AS build
RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
WORKDIR /usr/src/app
COPY pnpm-lock.yaml ./
COPY --from=development /usr/src/app/node_modules ./node_modules
COPY . .
RUN pnpm build
ENV NODE_ENV production
RUN pnpm install --prod
USER node # Production stage
FROM node:20-alpine AS production
WORKDIR /usr/src/app
COPY --from=build /usr/src/app/node_modules ./node_modules
COPY --from=build /usr/src/app/dist ./dist
CMD ["node", "dist/main.js"]
Sử dụng Fastify với NestJS
Nếu bạn đang sử dụng Fastify thay vì Express, bạn sẽ cần sửa đổi file main.ts
để lắng nghe trên 0.0.0.0
:
import { NestFactory } from '@nestjs/core';
import { FastifyAdapter, NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create<NestFastifyApplication>( AppModule, new FastifyAdapter(), ); await app.listen(process.env.PORT || 3000, '0.0.0.0');
}
bootstrap();
Vậy là xong! Bây giờ bạn đã có một ứng dụng NestJS được docker hóa và tối ưu hóa cho môi trường production. Nếu bạn muốn triển khai ứng dụng NestJS của mình, hãy xem sliplane.io.