Ở bài viết trước, mình đã hướng dẫn cách tạo một EC2 instance bằng AWS CDK Python với Amazon Linux 2023, có cài sẵn Nginx, Node.js và mở port 80 để truy cập web.
Trong bài viết này, mình sẽ hướng dẫn cách deploy tự động một ứng dụng Express.js lên EC2 mỗi khi bạn push code lên GitHub, sử dụng AWS CodeBuild và SSH.
1. Kiến trúc tổng quan
- Mỗi khi push code lên GitHub
- AWS CodeBuild được kích hoạt và tự động build
- Nó sử dụng SSH key từ Secrets Manager để kết nối EC2
- Đóng gói source code, chuyển qua EC2, giải nén, cài dependencies và chạy app
Flow như sau:
GitHub Push → CodeBuild Run → SSH to EC2 → Deploy App
2. Chuẩn bị EC2
Ở bài viết này mình sẽ sử dụng lại EC2 đã được tạo ở bài viết trước đó. Nếu các bạn chưa tạo có thể tham khảo bài viết này của mình
Tạo SSH key
Trên máy local, bạn chạy lệnh sau để tạo key:
ssh-keygen -t rsa -b 4096 -m PEM -f ec2-codebuild-key
Kết quả sẽ có 2 file:
- ec2-codebuild-key: đây là private key sẽ lưu vào AWS Secrets Manager
- ec2-codebuild-key.pub: đây là public key sẽ copy vào EC2
Thêm public key vào EC2
Connect vào EC2 đã tạo trước đó và chạy câu lệnh bên dưới:
echo "<PUBLIC_KEY_CONTENT>" >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys
Các bạn nhớ thay <PUBLIC_KEY_CONTENT>
bằng nội dung file ec2-codebuild-key.pub
bạn vừa tạo nhé
Tạo Secrets Manager chứa private key
- Truy cập AWS Console → Secrets Manager
- Chọn
Store a new secret
- Secret type:
Other type of secret
- Phần Key/value pairs: Chọn Plaintext và copy toàn bộ nội dung file
ec2-codebuild-key
và paste vào - Đặt tên secret:
codebuild/ssh/ec2-private-key
Như vậy việc lưu private key trên Secrets Manager đã xong
3. Tạo ứng dụng Express.js đơn giản
Mình tạo sẵn file app.js
của ứng dụng như bên dưới. Ở đây mình sẽ tạo 1 server HTML đơn giản chạy ở port 80 và hiển thị 1 đoạn text
const express = require('express');
const app = express();
const port = 80; app.get('/', (req, res) => { res.send('<h1>Express.js auto-deployed from GitHub to EC2 via CodeBuild!</h1>');
}); app.listen(port, () => { console.log(`Server running at http://localhost:${port}`);
});
Tiếp theo mình sẽ tạo file package.json
để định nghĩa các dependencies cần thiết để chạy Express
{ "name": "express-auto-deploy", "version": "1.0.0", "description": "Express.js app auto-deployed to EC2 via CodeBuild and SSH", "main": "app.js", "scripts": { "start": "node app.js" }, "dependencies": { "express": "^4.18.2" }
}
4. Định nghĩa file cấu hình
Tiếp theo mình sẽ tạo ra file buildspec.yml
, file này giống như một bản hướng dẫn chi tiết mà CodeBuild sẽ làm theo. Cụ thể:
- Xác định môi trường cần thiết (version Node.js, biến môi trường, SSH key...)
- Chạy các lệnh build như npm install, zip source code...
- Thực hiện các bước deploy, ví dụ như: copy source lên EC2, giải nén, cài đặt và khởi chạy ứng dụng,...
Mỗi phần trong file sẽ tương ứng với một phase cụ thể (install, build, post_build...) giúp kiểm soát từng giai đoạn trong pipeline.
version: 0.2 env: variables: EC2_USER: ec2-user # Tên user của EC2 EC2_HOST: your-public-ip # Public IP của EC2 (bạn thay IP của bạn vào đây) DEPLOY_DIR: /home/ec2-user/app # Thư mục nơi source code sẽ được giải nén và chạy secrets-manager: EC2_PRIVATE_KEY: codebuild/ssh/ec2-private-key # Lấy private key từ Secrets Manager phases: install: runtime-versions: nodejs: 14 commands: - echo "$EC2_PRIVATE_KEY" > ec2-key.pem # Tạo file key từ biến môi trường - chmod 600 ec2-key.pem # Đảm bảo key có quyền truy cập đúng build: commands: - npm install - zip -r artifact.zip . post_build: commands: - echo "Deploying to EC2 via SSH..." - | # Copy mã nguồn đã zip sang EC2 qua scp scp -o StrictHostKeyChecking=no -i ec2-key.pem artifact.zip $EC2_USER@$EC2_HOST:/home/$EC2_USER/ # SSH vào EC2 để giải nén, cài npm và chạy app ssh -o StrictHostKeyChecking=no -i ec2-key.pem $EC2_USER@$EC2_HOST " sudo systemctl stop nginx || true && # Dừng nginx nếu đang chạy rm -rf $DEPLOY_DIR && # Xóa thư mục cũ và tạo lại unzip -o /home/$EC2_USER/artifact.zip -d $DEPLOY_DIR && # Giải nén mã nguồn cd $DEPLOY_DIR && npm install && sudo fuser -k 80/tcp || true && # Giải phóng port 80 nếu bị chiếm sudo nohup node app.js > out.log 2>&1 & # Chạy app và redirect log exit " artifacts: files: - artifact.zip
5. Tạo CodeBuild project và push GitHub
Sau khi đã chuẩn bị đầy đủ thì bây giờ chúng ta sẽ tạo CodeBuild
- Vào AWS Console → CodeBuild → Create project
- Project configuration:
- Project name: ExpressAppDemo
- Source:
- Source provider: GitHub → Kết nối GitHub repo của bạn
- Repository: Chọn option mà bạn bạn mong muốn, ở đây mình chọn
Repository in my Github account
- Github repository: paste link repo của các bạn vào đây
- Primary source webhook events:
- Để việc build lại mỗi khi có code mới được push lên Github thì bạn hãy check vào mục
Rebuild every time a code change is pushed to this repository
- Để việc build lại mỗi khi có code mới được push lên Github thì bạn hãy check vào mục
- Environment:
- Additional configuration: mục
Environment variables
, các bạn hãy thêm giá trị như bên dưới để Codebuild trỏ đến giá trị private key mà chúng ta đã thêm trước đó- Name: EC2_PRIVATE_KEY
- Value: codebuild/ssh/ec2-codebuild-key
- Type: Secrets Manager
- Additional configuration: mục
- Buildspec: chọn
Use a buildspec file
- Nhấn Create project
6. Kết quả
Như vậy mọi thứ đã xong, giờ mỗi khi bạn push code mới lên repository GitHub:
- CodeBuild sẽ tự động build và deploy lên EC2
- Truy cập
http://<EC2_PUBLIC_IP>
bạn sẽ thấy code mới được tự động được deploy
Trên đây mình đã giới thiệu về cách tự động deploy ứng dụng Express.js lên EC2 thông qua AWS CodeBuild. Bài viết có thể còn nhiều hạn chế, rất mong nhận được góp ý từ mọi người để mình cải thiện trong những bài sau. Cảm ơn các bạn đã theo dõi và ủng hộ!