+1

Blue-Green deployment với nginx và pm2

Trong bài viết này sẽ mô tả lại quá trình triển khai(deploy) ứng dụng node.js với nginx và pm2 sử dụng kĩ thuật Blue-Green deployment để giảm thiểu downtime tới mức thấp nhất.

Bài viết gốc được mình viết tại đây: Blue-Green deployment với nginx và pm2

Blue-Green deployment là gì?

Blue-Green deployment là một kỹ thuật triển khai phần mềm phổ biến nhằm mục đích giảm thiểu downtime của ứng dụng trong quá trình deploy, tăng tính ổn định của hệ thống.

Trong Blue-Green deployment, ứng dụng sẽ có hai môi trường (blue và green). Môi trường blue là môi trường ứng dụng đang hoạt động, và môi trường green dùng để deploy phiên bản mới.

Khi cần release, phiên bản mới sẽ được deploy lên môi trường green, sau khi test trên green thành công, traffict đến ứng dụng sẽ được chuyển sang môi trường green, biến môi trường green thành môi trường hoạt động của ứng dụng và môi trường blue hiện tại có thể được tắt đi.

Lưu ý: ở đây môi trường hiện tại không cố định phải là blue, môi trường mới cũng ko nhất thiết là green, chúng sẽ thay đổi vai trò cho nhau sau mỗi lần deploy thành công.

Áp dụng để deploy app node.js

Sau đây, mình sẽ áp dụng Blue-Green deployment để triển khai một web node.js (nest.js framework) trên VPS ubuntu sử dụng nginx và pm2

1. Chuẩn bị 2 môi trường Blue và Green

Chúng ta sẽ cần chuẩn bị 2 folder để chứa code của 2 môi trường blue và green, ví dụ:

  • /var/www/html/app/blue
  • /var/www/html/app/green

2. Sử dụng nginx làm reverse proxy

Tạo nginx config, sử dụng nginx làm reverse proxy cho ứng dụng node.js, ví dụ tạo file /etc/nginx/sites-available/main như bên dưới

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # url của ứng dụng nodejs ở đây
        proxy_pass http://127.0.0.1:3000;
        proxy_redirect off;
        proxy_read_timeout 240s;
    }
}

Và tạo symbolic link bằng cách chạy câu lệnh:

sudo ln -s /etc/nginx/sites-available/main /etc/nginx/sites-enabled/

3. Sử dụng pm2 làm process manager

Cài đặt và sử dụng pm2 làm process manager cho Node.js để quản lý cả 2 môi trường blue và green, mỗi môi trường sẽ chạy trên 1 port khác nhau, ví dụ 3000 và 3001

4. Tạo deploy script

Bước quan trọng nhất, chúng ta sẽ tạo một bash script để chạy mỗi khi cần deploy phiên bản mới, script sẽ tự động thực hiện tất cả các bước cần thiết. Script này sẽ thực hiện theo các bước sau:

  • Đọc file nginx config để xác định port và folder chứa code của môi trường đang hoạt động (ví dụ folder blue và port 3000)
  • Kéo code mới về folder còn lại (ví dụ folder green)
  • Build ứng dụng với code mới
  • Sử dụng pm2 và start ứng dụng trên port khác với port hiện tại (ví dụ 3001)
  • Health check ứng dụng trên port mới
  • Sau khi kiểm tra hoàn tất, update nginx config để proxy đến port mới
  • Reload nginx để chuyển traffict đến port mới, lúc này ứng dụng của bạn đã được cập nhật và gần như không có downtime
  • Cuối cùng, dùng pm2 stop ứng dụng trên port cũ
#!/bin/bash

# Một số biến cần thiết
# folder blue sẽ deploy lên port 3000
# folder green sẽ deploy lên port 3001
BLUE_DIR="/var/www/html/app/blue"
BLUE_PORT="3000"
GREEN_DIR="/var/www/html/app/green"
GREEN_PORT="3001"
NGINX_CONFIG="/etc/nginx/sites-available/main"

# Đọc thông tin từ file nginx config để
# kiểm tra app hiện đang chạy trên port nào
CURRENT_PORT=$(grep -oP 'proxy_pass 127.0.0.1:\K\d+' $NGINX_CONFIG)

# Biến để lưu tên folder chứa code đang chạy
# sử dụng để dừng app cũ sau khi deploy xong
OLD_NAME=""

# Biến để lưu path của thư mục chúng ta sẽ deploy code mới
NEW_DIR=""

# Nếu app đang chạy trên port 3000 (folder blue) 
# thì sẽ deploy code mới vào thư mục green (port 3001)
# và ngược lại
if [ "$CURRENT_PORT" == "$BLUE_PORT" ]; then
    NEW_DIR=$GREEN_DIR
    NEW_PORT=$GREEN_PORT
    OLD_NAME=$(basename $BLUE_DIR)
else
    NEW_DIR=$BLUE_DIR
    NEW_PORT=$BLUE_PORT
    OLD_NAME=$(basename $GREEN_DIR)
fi

# Kéo code mới nhất từ Github về thư mục chúng ta sẽ deploy
# và show thông tin commit mới nhất
echo "Pulling latest code into ($NEW_DIR)..."
cd $NEW_DIR
git pull
git show -s --format='%h %s'
echo ""

# Cài đặt các package cần thiết và build code
echo "Building application..."
rm -rf {dist,public}
yarn install
yarn build
echo ""

# Dùng pm2 start app trên port mới
echo "Starting new environment..."
NEW_NAME=$(basename $NEW_DIR)
PORT=$NEW_PORT pm2 start "dist/main.js" -i max --name "$NEW_NAME"
echo ""

# Chờ một chút để app mới start
echo "Waiting for new environment to start..."
echo ""
sleep 5

# Health check app mới để đảm bảo app đã start thành công trên port mới
echo "Health checking new environment..."
STATUS_CODE=$(curl -o /dev/null -s -w "%{http_code}" http://127.0.0.1:$NEW_PORT/health)

if [ "$STATUS_CODE" -ne 200 ]; then
    echo "New environment health check failed with status code: $STATUS_CODE"
    exit 1
fi
echo ""

# Update nginx config để thay đổi proxy_pass từ port cũ sang port mới
# Sau đó reload nginx để áp dụng thay đổi để chuyển traffic từ port cũ sang port mới
echo "Switching Nginx to new environment..."
sudo sed -i "s/proxy_pass 127.0.0.1:[0-9]*;/proxy_pass 127.0.0.1:$NEW_PORT;/" $NGINX_CONFIG
sudo nginx -s reload
echo ""

echo "Deployment complete. Environment ($NEW_NAME) is now live!"

# Stop và xóa app cũ sau khi deploy xong
echo "Stopping old environment ($OLD_NAME)..."
pm2 stop $OLD_NAME
pm2 delete $OLD_NAME
pm2 save

5. Tự động deploy

Sau khi hoàn thành deploy script bạn có thể lưu lại với tên như deploy.sh, mỗi lần cần release phiên bản mới, chỉ cần ssh vào VPS và chạy script để deploy.

Hoặc bạn cũng có thể sử dụng Github Action để tự động hóa việc deploy mỗi khi có code mới được đẩy lên branch production.

Tổng kết

Bài viết này triển khai Blue-Green deployment ở mức cơ bản, bạn có thể tùy ý tùy chỉnh các step để phù hợp với ứng dụng của mình

Việc test là rất quan trọng, bạn có thể test thật kỹ app trước khi switch traffict sang môi trường mới.

Mời xem thêm các bài viết khác tại series Xây dựng web với những công nghệ "cũ rích"

Chúc các bạn online vui vẻ!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí