CI/CD là gì? Tự động deploy lên VPS với GitHub Actions

Chia sẻ bài viết

Mục lục
CI/CD là gì? Tự động deploy lên VPS với GitHub Actions

Trả lời nhanh: CI/CD là dây chuyền tự động giữa "viết xong code" và "khách dùng được": CI (Continuous Integration), mỗi lần push, hệ thống tự build và chạy test, hỏng là chặn ngay; CD (Continuous Deployment), qua được kiểm tra thì tự đưa lên server. Bộ đôi phổ biến nhất cho dự án cá nhân/đội nhỏ: GitHub Actions + VPS qua SSH, push lên nhánh main, hai phút sau bản mới đã sống trên server, không ai phải nhớ trình tự lệnh deploy nữa.

Deploy tay có hai vấn đề: phụ thuộc trí nhớ ("bước 3 là gì nhỉ?") và phụ thuộc con người ("đợi mình về nhà mở máy"). CI/CD biến trình tự đó thành văn bản chạy tự động, sai thì sửa văn bản, không sai vì quên. Bài này giải thích khái niệm rồi đi thẳng vào file workflow hoàn chỉnh deploy lên VPS, kèm các lỗi người mới hay vấp.

Tóm tắt nhanh
  • CI = gác cổng tự động: build + test mỗi push, hỏng là đỏ, không ai merge nhầm code gãy
  • CD = giao hàng tự động: qua cổng là lên server, quy trình nằm trong file YAML cạnh code
  • GitHub Actions + SSH + deploy script trên VPS: bộ ba đủ dùng cho 90% dự án
  • Secret (key SSH) cất trong GitHub Secrets, không bao giờ nằm trong code

CI/CD bằng một câu chuyện quen

Không CI/CD: sửa code → tự nhớ chạy test (hoặc quên) → SSH vào server → git pull, build, restart, sai một bước là site nằm, và cả quy trình sống trong đầu một người. Có CI/CD: sửa code → push → robot chạy test (đỏ thì dừng, báo ngay chỗ hỏng) → xanh thì robot tự deploy đúng trình tự, đúng từng lần như một. Giá trị không nằm ở "ngầu" mà ở loại con người khỏi khâu lặp lại, kể cả lúc 2h sáng, kể cả khi deploy là agent AI vừa xong việc tự bấm.

Chuẩn bị phía VPS: một script + một user

# tren VPS: script da co tu bai deploy Next.js
cat ~/deploy.sh   # git pull && npm ci && npm run build && pm2 restart app
# tao SSH key rieng cho CI (khong dung key ca nhan)
ssh-keygen -t ed25519 -f ~/.ssh/ci_deploy -N ""
cat ~/.ssh/ci_deploy.pub >> ~/.ssh/authorized_keys
cat ~/.ssh/ci_deploy      # private key, dan vao GitHub Secret o buoc sau

Vào repo GitHub → Settings → Secrets and variables → Actions, tạo 3 secret: VPS_HOST (IP), VPS_USER, VPS_SSH_KEY (nội dung private key). Nguyên tắc sắt: secret sống trong két của GitHub, không bao giờ trong code.

File workflow hoàn chỉnh

# .github/workflows/deploy.yml
name: CI-CD
on:
  push:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22, cache: npm }
      - run: npm ci
      - run: npm test --if-present
      - run: npm run build
  deploy:
    needs: test              # chi chay khi test xanh
    runs-on: ubuntu-latest
    steps:
      - name: Deploy len VPS qua SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USER }}
          key: ${{ secrets.VPS_SSH_KEY }}
          script: ~/deploy.sh

Đọc theo tiếng người: khi push vào main → job test dựng môi trường sạch, cài, test, build; job deploy chỉ chạy khi test xanh, SSH vào VPS gọi đúng script bạn vẫn chạy tay. Từ nay "deploy" nghĩa là "push", lịch sử ai deploy gì lúc nào nằm sẵn trong tab Actions.

Lỗi người mới hay vấp - và nâng cấp khi lớn

  • Permission denied: dán nhầm public key vào secret (cần private), hoặc quyền file authorized_keys sai (600).
  • Test xanh trên CI, chạy sai trên server: lệch phiên bản Node/env, ghim node-version trong workflow khớp VPS, env đặt trên server chứ không hardcode.
  • Deploy giữa giờ đông làm khựng site: pm2 reload (bài PM2) thay restart; nặng hơn thì build trên CI rồi rsync sản phẩm sang, server chỉ restart.
  • Build chậm/ngốn phút miễn phí: cache npm đã bật ở trên; đội build dày cân nhắc runner tự host trên VPS, nhanh hơn hẳn và không đếm phút.

Bảo mật trước khi tiện lợi

ViệcVì sao bắt buộc
Tạo một tài khoản riêng để triển khai, không dùng tài khoản quản trịKhóa bị lộ thì thiệt hại giới hạn ở thư mục ứng dụng
Dùng khóa riêng chỉ cho việc triển khai, không dùng lại khóa cá nhânThu hồi được riêng khi cần
Giới hạn lệnh khóa đó chạy đượcKhóa bị lộ cũng không mở được phiên đăng nhập tùy ý
Lưu khóa trong kho bí mật của kho mã, không để trong tệp cấu hìnhTệp cấu hình nằm trong lịch sử phiên bản, xóa sau vẫn còn
Bật xác thực hai lớp cho tài khoản kho mãKho mã có quyền đẩy lên máy chủ của bạn

Chuẩn bị phía máy chủ

# 1. Tao nguoi dung rieng cho viec trien khai
adduser --disabled-password --gecos "" trienkhai
mkdir -p /home/trienkhai/.ssh && chmod 700 /home/trienkhai/.ssh

# 2. Dat khoa cong khai vao, kem gioi han lenh chay duoc
echo 'command="/opt/trien-khai.sh",no-port-forwarding,no-pty ssh-ed25519 AAAA...'   > /home/trienkhai/.ssh/authorized_keys
chmod 600 /home/trienkhai/.ssh/authorized_keys
chown -R trienkhai:trienkhai /home/trienkhai/.ssh

# 3. Script trien khai, viet cho no dung mot viec
cat > /opt/trien-khai.sh <<'SH'
#!/bin/bash
set -euo pipefail
cd /var/www/ungdung
git pull --ff-only
docker compose pull
docker compose up -d
docker compose ps
SH
chmod +x /opt/trien-khai.sh

Dòng giới hạn lệnh trong tệp khóa công khai là dòng đáng chú ý nhất: nó biến khóa triển khai thành khóa chỉ chạy được đúng một tập lệnh, thay vì mở phiên đăng nhập đầy đủ vào máy chủ.

Ba lỗi người mới hay vấp

  • Không có bước quay lui. Triển khai hỏng lúc 5 giờ chiều thứ sáu mà không quay lại được là tình huống nên tránh bằng cách giữ bản trước và một lệnh quay lui.
  • Không kiểm sau khi triển khai. Thêm một bước gọi thử địa chỉ kiểm tra sức khỏe và báo lỗi nếu không phản hồi, thay vì coi triển khai xong là xong.
  • Đặt khóa và mật khẩu trong tệp cấu hình đẩy lên kho mã. Xóa ở lần đẩy sau vẫn còn trong lịch sử, và phải coi khóa đó là đã lộ.

Với dự án nhỏ, quy trình này chạy trên một máy chủ là đủ. Khi lớn hơn, bước tiếp theo là tách môi trường thử và môi trường thật, mỗi nơi một máy, và chỉ triển khai lên môi trường thật sau khi bản thử chạy ổn.

Câu hỏi thường gặp

Dự án một mình có cần CI/CD không?

Càng một mình càng cần, không có đồng đội review thì bộ test tự động là người gác cổng duy nhất, và deploy một-push tiết kiệm đúng thứ bạn thiếu nhất: sự tập trung.

GitHub Actions miễn phí được bao nhiêu?

Repo public: không giới hạn phút. Private: có hạn mức phút/tháng khá rộng cho dự án nhỏ, vượt thì trả thêm hoặc chuyển runner tự host (không đếm phút).

CI/CD với Docker thì khác gì?

Trình tự thành: build image trên CI → đẩy registry → server pull + up. Cùng triết lý, thêm tính nhất quán môi trường, bài Docker build chậm có mẹo cache cho khúc CI này.

Rollback thế nào khi bản mới lỗi?

Cách gọn: git revert commit lỗi rồi push, dây chuyền tự deploy bản lành. Cách nhanh: giữ bản build trước đó trên server (thư mục releases + symlink) để trỏ ngược tức thì, nâng cấp đáng làm khi site có khách thật.

Hạ tầng NVMe Enterprise của TND
VPS ổ Enterprise U.2 NVMe, CPU xung cao, đặt tại Việt Nam
Đầu nhận của dây chuyền là chiếc VPS: TND VPS NVMe cho khâu npm ci + build trong deploy.sh chạy vèo trên Enterprise U.2 NVMe RAID 10, pm2 reload mượt nhờ Xeon Platinum xung cao. Muốn cả dây chuyền nhanh gấp bội: đặt luôn runner tự host lên cùng máy, bài 18073 chờ sẵn trong mục liên quan.
Dùng thử VPS NVMe, bàn giao trong 5 phút

Bài viết liên quan