Từ Manual đến DevOps: Hướng dẫn CI/CD tự động Deploy với GitHub Actions & Docker
Bạn có đang deploy website của mình theo cách "truyền thống" này không? Ở bài hướng dẫn này tôi sẽ lấy ví dụ thực tới với website Java của tôi.
-
Build file
.jartrên máy tính cá nhân. -
Dùng
FileZillahoặcrsyncđể copy file nặng vài chục MB lên VPS. -
SSH vào VPS, gõ lệnh stop, xóa file cũ, chạy file mới...
Tôi cũng từng như vậy. Quy trình này không chỉ tốn thời gian mà còn rất dễ gây lỗi (quên config, sai phiên bản, rớt mạng giữa chừng).
Hôm nay, tôi sẽ chia sẻ cách tôi đã tự động hóa 100% quy trình này cho blog cá nhân của mình bằng GitHub Actions và Docker. Chỉ cần git push, pha một tách cà phê để quá trình CI/CD tự thực hiện, và website tự động cập nhật.
Mô hình hoạt động (Architecture)
Thay vì mang nguyên liệu lên VPS để nấu (build code trên VPS), chúng ta sẽ nấu chín ở nhà, đóng hộp và chỉ mang lên VPS để dùng.
-
Code (Local): Push code lên GitHub.
-
CI (GitHub Actions): Tự động build Java (Maven), đóng gói vào Docker Image.
-
Registry (Docker Hub): Lưu trữ Docker Image đã đóng gói.
-
CD (VPS): Tự động kéo Image mới về và khởi động lại container.
Phần 1: Dockerize ứng dụng Spring Boot
Để deploy tự động, ứng dụng của bạn phải chạy trong Docker. Tạo file Dockerfile ngay tại thư mục gốc dự án (ngang hàng với pom.xml).
# 1. Sử dụng Base Image nhẹ (Alpine)
FROM eclipse-temurin:17-jdk-alpine
# 2. Thiết lập thư mục làm việc
WORKDIR /app
# 3. Copy file .jar đã build vào container
# Lưu ý: Chúng ta sẽ build bằng Maven ở bước CI, nên file sẽ nằm trong target/
COPY target/*.jar app.jar
# 4. Chạy ứng dụng
ENTRYPOINT ["java", "-jar", "app.jar"]
Phần 2: Thiết lập Workflow với GitHub Actions
Đây là "trái tim" của hệ thống. Tạo file .github/workflows/deploy.yml.
File này định nghĩa quy trình: Build Maven -> Push Docker Hub -> Deploy VPS.
name: Deploy Java App
on:
push:
branches: [ "main" ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# 1. Lấy Source Code
- name: Checkout code
uses: actions/checkout@v4
# 2. Cài đặt Java 17
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: 'maven'
# 3. Build file .jar (Tạo ra thư mục target/)
- name: Build with Maven
run: mvn clean package -DskipTests
# 4. Đăng nhập Docker Hub
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# 5. Build & Push Docker Image
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/my-webapp:latest
# 6. Deploy lên VPS qua SSH
- name: Deploy to VPS
uses: appleboy/[email protected]
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USERNAME }}
key: ${{ secrets.VPS_KEY }}
port: 22 # Thay đổi nếu VPS bạn dùng port khác
script: |
cd ~/my-project-folder
docker compose pull webapp
docker compose up -d webapp
docker image prune -f
Phần 3: Cấu hình GitHub Actions & Docker
Bước 1: Chuẩn bị kho chứa Image (Docker Hub)
GitHub Actions sẽ build ra một cục Image, chúng ta cần chỗ để lưu nó trước khi VPS tải về.
1.Đăng nhập vào Docker Hub.
2.Tạo một Repository mới (Create Repository)

3.Đặt tên (ví dụ): com.quyenlt-webapp (tên này theo đúng ý định đổi tên miền của bạn).

Để chế độ Public (cho dễ cấu hình lúc đầu) hoặc Private (bảo mật hơn nhưng cần cấu hình thêm 1 chút, mình khuyên dùng Public nếu không có gì quá bí mật trong code, hoặc Private thì GitHub Actions vẫn login được).
Bước 2: Tạo chìa khóa để GitHub vào được VPS (SSH Key)
Đây là bước quan trọng nhất. Thay vì đưa mật khẩu VPS cho GitHub (rất nguy hiểm), ta sẽ tạo một cặp chìa khóa chuyên dụng.
Tạo cặp key mới (không trùng với key cá nhân của bạn): Copy và chạy lệnh sau trên Terminal của Mac:
ssh-keygen -t rsa -b 4096 -C "github-actions-deploy" -f ~/.ssh/github_actions_key
(Khi nó hỏi Passphrase, cứ nhấn Enter để bỏ qua, để trống).

Đưa "ổ khóa" (Public Key) lên VPS: Bạn cần copy nội dung file đuôi .pub lên VPS. Chạy lệnh này trên Mac để lấy nội dung:
cat ~/.ssh/github_actions_key.pub
-> Copy toàn bộ dòng kết quả hiện ra (bắt đầu bằng ssh-rsa ...).

Cài đặt vào VPS:
-
-
SSH vào VPS của bạn như mọi khi.
-
Gõ lệnh:
nano ~/.ssh/authorized_keys -
Dán đoạn mã vừa copy vào cuối file này (xuống dòng mới rồi dán).
-
Bấm
Ctrl+O->Enterđể lưu,Ctrl+Xđể thoát.
-
Bước 3: Cấu hình bí mật trên GitHub (GitHub Secrets)
Bây giờ ta nạp thông tin vào GitHub để nó biết đường truy cập.
1.Vào repo của bạn trên GitHub -> Settings.

2.Menu trái chọn Secrets and variables -> Actions.

3.Nhấn New repository secret và thêm lần lượt các mục sau:

Phần 5 : Kiểm Thử
Bước 1: Kích hoạt (Push code lên GitHub)
Hệ thống CI/CD chỉ chạy khi có code mới được đẩy lên. Tại thiết bị của bạn, hãy mở Terminal trong thư mục dự án và chạy các lệnh sau để đẩy file Dockerfile và deploy.yml mà bạn vừa tạo ở Phần 1 và Phần 2 lên:
git add .
git commit -m "Setup CI/CD pipeline"
git push origin main
(Nếu nhánh của bạn tên là master thì gõ git push origin master).
Bước 2: Theo dõi quá trình chạy (Monitor)
Ngay sau khi git push thành công, bạn làm như sau để xem "phim hành động":
-
Mở trình duyệt, vào trang GitHub Repository dự án của bạn.
-
Bấm vào tab Actions trên thanh menu phía trên.
-
Bạn sẽ thấy một dòng mới xuất hiện (có tên là "Setup CI/CD pipeline" hoặc "Deploy Java App").
-
🟡 Màu vàng xoay xoay: Đang chạy (đang build, đang đẩy docker...).
-
✅ Màu xanh lá: Thành công (Đã build xong và VPS đã cập nhật).
-
❌ Màu đỏ: Lỗi (Bạn bấm vào để xem lỗi ở bước nào: sai mật khẩu DockerHub, hay sai SSH Key...).
-

Bước 3: Kiểm tra kết quả (Verification)
Nếu bước 2 báo Màu xanh (Success), hãy kiểm tra xem VPS đã thực sự nhận hàng chưa bằng cách:
Cách 1: Kiểm tra "tuổi thọ" Container (Chính xác nhất) SSH vào VPS và gõ lệnh:
docker ps
Bạn nhìn vào cột STATUS:
-
Nếu thấy
webappghi làUp Less than a minute(hoặc vài phút). -
Trong khi
mysqldbghi làUp 2 weeks(hoặc thời gian dài). -
-> Chúc mừng bạn! Hệ thống đã tự động tắt web cũ và bật web mới lên thành công mà không làm sập Database.
Cách 2: Xem Logs thực tế Gõ lệnh xem log của app để chắc chắn nó khởi động Spring Boot thành công:
docker logs -f --tail 100 webapp
Nếu thấy logo Spring hiện ra và dòng Started Application in ... seconds thì là website đã sống lại.
Kết Luận
Quy trình sẽ tự động kích hoạt. GitHub Actions sẽ chuyển sang màu xanh ✅, và khi kiểm tra trên VPS bằng docker ps, container cũ đã được thay thế bằng container mới trong tích tắc mà không làm gián đoạn Database.
Tại sao bạn nên làm điều này ngay hôm nay?
-
Tiết kiệm thời gian: Không còn thao tác thủ công lặp đi lặp lại.
-
An toàn: Tránh việc lỡ tay xóa nhầm file trên production.
-
Lịch sử: Dễ dàng rollback về phiên bản cũ nếu bản mới bị lỗi (chỉ cần đổi tag image).
Nếu bạn đang làm dự án Java Spring Boot cá nhân hay đồ án, hãy thử setup CI/CD này nhé. Nó sẽ giúp ích cho bạn rất nhiều về thời gian và sự tiện lợi mà nó mang lại.
Chúc các bạn thành công!
