Giới thiệu
Trong thời đại DevOps và tự động hóa, CI/CD giúp đảm bảo code được kiểm tra, build và deploy liên tục, nâng cao chất lượng phần mềm. Với các dự án cá nhân hoặc nội bộ không sử dụng Jenkins, GitHub Actions, bạn vẫn có thể tự tạo hệ thống CI/CD đơn giản chạy trên máy local hoặc server riêng với những công cụ cơ bản như:
- Shell Script để tự động hóa các bước
- Crontab để lên lịch chạy script định kỳ
- msmtp để gửi email thông báo kết quả
Bài viết này hướng dẫn chi tiết cách làm, đồng thời chỉ chạy pipeline khi có code mới trên nhánh develop để tiết kiệm tài nguyên.
1. Mục tiêu
- Tự động pull code từ nhánh develop của Git
- Kiểm tra có commit mới trước khi chạy pipeline
- Cài đặt dependency (yarn install)
- Chạy lint kiểm tra code
- Chạy test tự động
- Build project
- Ghi log chi tiết theo từng lần chạy
- Gửi email thông báo kết quả, kèm file log đính kèm
- Tự động chạy định kỳ bằng crontab
2. Công cụ sử dụng
Shell Script
Tập hợp các lệnh shell được viết trong file .sh giúp tự động hóa quy trình CI/CD.
Crontab
Trình lập lịch có sẵn trên Linux/macOS để chạy script định kỳ theo lịch cài đặt.
msmtp
Công cụ dòng lệnh gửi email qua SMTP, dễ cấu hình với Gmail hoặc các dịch vụ khác.
3. Ví dụ dự án Node.js minh họa
Giả sử bạn có một project Node.js với cấu trúc:
my-node-project/
├── package.json
├── src/
├── tests/
└── …
Trong package.json bạn đã khai báo các script sau:
{
“scripts“: {
“lint“: “eslint .”,
“test“: “jest”,
“build“: “tsc -p tsconfig.json”
}
}
- lint: kiểm tra chuẩn code bằng ESLint
- test: chạy test với Jest
- build: build TypeScript thành JavaScript
4. Thiết lập CI/CD local chi tiết
Bước 1: Viết shell script ci_cd.sh
Tạo file script tại home folder:
touch ~/ci_cd.sh
chmod +x ~/ci_cd.sh
nano ~/ci_cd.sh
Dán đoạn code dưới đây vào, chỉnh sửa PROJECT_DIR và TO_EMAIL phù hợp:
#!/bin/bash
PROJECT_DIR=“/home/user/my-node-project”
DATE_FILE=$(date ‘+%Y-%m-%d_%H-%M-%S’)
LOGFILE=“$HOME/cicd_$DATE_FILE.log”
TO_EMAIL=“your.email@gmail.com”
ATTACH_NAME=“log_$DATE_FILE.txt”
cd “$PROJECT_DIR“ || { echo “Không vào được thư mục project”; exit 1; }
log() {
echo “[$(date ‘+%Y-%m-%d %H:%M:%S’)] $1“ | tee -a “$LOGFILE“
}
log “=== Bắt đầu CI/CD ===”
OLD_COMMIT=$(git rev-parse HEAD)
log “1. Pull code từ nhánh develop”
git pull origin develop >> “$LOGFILE“ 2>&1
NEW_COMMIT=$(git rev-parse HEAD)
if [ “$OLD_COMMIT“ == “$NEW_COMMIT“ ]; then
log “Không có thay đổi mới trên develop, pipeline dừng.”
exit 0
else
log “Phát hiện thay đổi mới trên develop, tiếp tục pipeline.”
fi
log “2. Cài đặt dependencies”
yarn install >> “$LOGFILE“ 2>&1
log “3. Chạy lint kiểm tra code”
yarn lint >> “$LOGFILE“ 2>&1
LINT_EXIT_CODE=$?
if [ $LINT_EXIT_CODE -ne 0 ]; then
log “Lint lỗi, pipeline dừng.”
EXIT_CODE=$LINT_EXIT_CODE
else
log “Lint thành công, chạy test tự động.”
log “4. Chạy test tự động”
yarn test >> “$LOGFILE“ 2>&1
TEST_EXIT_CODE=$?
if [ $TEST_EXIT_CODE -ne 0 ]; then
log “Test thất bại, pipeline dừng.”
EXIT_CODE=$TEST_EXIT_CODE
else
log “Test thành công, bắt đầu build.”
log “5. Build project”
yarn build >> “$LOGFILE“ 2>&1
EXIT_CODE=$?
fi
fi
if [ $EXIT_CODE -eq 0 ]; then
SUBJECT=“CI/CD: Build Thành Công”
STATUS=“<strong style=’color:green’>Thành công</strong>”
else
SUBJECT=“CI/CD: Build Thất Bại”
STATUS=“<strong style=’color:red’>Thất bại</strong>”
fi
BODY_HTML=“<html><body><h2>CI/CD Build Report</h2><p><b>Trạng thái:</b> $STATUS</p><p>Chi tiết log đính kèm.</p></body></html>”
(
echo “Subject: $SUBJECT“
echo “To: $TO_EMAIL“
echo “MIME-Version: 1.0”
echo “Content-Type: multipart/mixed; boundary=BOUNDARY”
echo
echo “–BOUNDARY”
echo “Content-Type: text/html; charset=UTF-8”
echo
echo “$BODY_HTML“
echo “–BOUNDARY”
echo “Content-Type: text/plain; name=\”$ATTACH_NAME\””
echo “Content-Disposition: attachment; filename=\”$ATTACH_NAME\””
echo
cat “$LOGFILE“
echo “–BOUNDARY–“
) | msmtp “$TO_EMAIL“
log “Đã gửi email tới $TO_EMAIL“
Lưu ý:
- Thay /home/user/my-node-project bằng đường dẫn thật của dự án.
- Đảm bảo đã cài đặt các package như eslint, jest, typescript trong project và có các script lint, test, build trong package.json.
- yarn install sẽ cài dependencies theo package.json và yarn.lock.
Bước 2: Thiết lập crontab chạy định kỳ
Mở terminal và chạy:
crontab -e
Thêm dòng sau để chạy script mỗi 10 phút:
*/10 * * * * /bin/bash ~/ci_cd.sh >> ~/cicd_cron.log 2>&1
- Log tổng hợp sẽ lưu tại ~/cicd_cron.log.
Bước 3: Cấu hình gửi email với msmtp
- Cài đặt msmtp:
- Trên macOS: brew install msmtp
- Trên Ubuntu/Debian: sudo apt install msmtp
- Tạo file cấu hình ~/.msmtprc:
defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
account gmail
host smtp.gmail.com
port 587
from your.email@gmail.com
user your.email@gmail.com
password YOUR_APP_PASSWORD
account default : gmail
- YOUR_APP_PASSWORD là mật khẩu ứng dụng Gmail (bật xác minh 2 bước và tạo app password).
- Đặt quyền bảo mật:
chmod 600 ~/.msmtprc
5. Kiểm tra và vận hành
- Script sẽ kiểm tra commit mới trên nhánh develop, nếu không có thay đổi sẽ dừng sớm.
- Khi có thay đổi, tự động cài dependencies, chạy lint, test, build.
- Kết quả chi tiết lưu log và gửi email thông báo.
- Log chi tiết theo timestamp ở file ~/cicd_YYYY-MM-DD_HH-MM-SS.log.
- Log tổng hợp crontab ở ~/cicd_cron.log.
6. Mở rộng
Tính năng | Gợi ý thực hiện |
Gửi log nén .gz | Thêm lệnh gzip “$LOGFILE” trước khi gửi |
Gửi thông báo qua Slack | Dùng curl gọi Slack Webhook API |
Auto deploy sau build | Thêm lệnh scp, rsync, hoặc pm2 deploy |
Gửi email nhiều người | Thêm nhiều trường To: hoặc dùng Cc: trong email |
7. Kết luận
Việc kiểm tra thay đổi commit giúp tối ưu tài nguyên, tránh chạy pipeline khi không cần thiết. Với shell script, crontab và msmtp, bạn có thể thiết lập CI/CD local đơn giản, hiệu quả, phù hợp các dự án nhỏ hoặc môi trường nội bộ.