Thiết lập CI/CD Local với Shell Script, Crontab và msmtp

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_DIRTO_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.jsonyarn.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

  1. Cài đặt msmtp:
  • Trên macOS: brew install msmtp
  • Trên Ubuntu/Debian: sudo apt install msmtp
  1. 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ộ.

Top bài viết trong tháng

Scroll to Top

FORM ỨNG TUYỂN

Click or drag a file to this area to upload.
File đính kèm định dạng .docs/.pdf/ và nhỏ hơn 5MB