GitHub Actions cơ bản: workflow, job và step
1. Tổng quan
GitHub Actions là công cụ CI/CD tích hợp sẵn trong GitHub, giúp bạn tự động hoá build, test, deploy mà không cần server CI riêng. Bài này giải thích ba khái niệm cốt lõi: workflow, job và step, kèm ví dụ cụ thể cho một project Spring Boot dùng Maven.
Đọc xong, bạn sẽ viết được một file workflow chạy test tự động mỗi khi push code, hiểu cách các job chạy song song hoặc tuần tự, và biết cách debug khi workflow fail.
2. Workflow là gì?
Workflow là một file YAML nằm trong thư mục .github/workflows/ của repository. Mỗi workflow định nghĩa khi nào chạy (trigger) và làm gì (jobs).
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: Build with Maven
run: mvn -B package
Giải thích:
nameở đầu file là tên hiển thị trên tab Actions của GitHub.onkhai báo trigger: ở đây workflow chạy khi cópushhoặcpull_requestvào branchmain.jobs.buildlà một job duy nhất tênbuild, chạy trên máy ảoubuntu-latest.
Lưu ý: File phải nằm đúng đường dẫn
.github/workflows/*.yml, sai thư mục GitHub sẽ không nhận diện workflow.
3. Job: đơn vị thực thi độc lập
Một workflow có thể có nhiều job. Mỗi job chạy trên một runner (máy ảo) riêng, mặc định các job chạy song song trừ khi bạn khai báo needs.
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: mvn -B test
deploy:
runs-on: ubuntu-latest
needs: test
steps:
- run: echo "Deploying application..."
Giải thích:
testvàdeploylà hai job riêng biệt, mỗi job có môi trường runner sạch, không chia sẻ file hệ thống với nhau.needs: testbuộcdeployphải chờtestthành công rồi mới chạy — tạo quan hệ tuần tự.- Nếu không có
needs, GitHub Actions sẽ chạytestvàdeploycùng lúc.
3.1. Chia sẻ dữ liệu giữa các job
Vì mỗi job có runner riêng, muốn truyền file giữa job này sang job khác bạn cần dùng artifacts.
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: mvn -B package
- uses: actions/upload-artifact@v4
with:
name: app-jar
path: target/*.jar
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/download-artifact@v4
with:
name: app-jar
Giải thích:
upload-artifactlưu file.jartừ jobbuildlên GitHub storage tạm thời.download-artifacttrong jobdeploylấy lại file đó về runner mới.- Đây là cách duy nhất để truyền dữ liệu giữa job (không dùng được biến môi trường thông thường).
4. Step: đơn vị thao tác nhỏ nhất
Step là một hành động cụ thể trong job, chạy tuần tự từ trên xuống. Step có hai loại chính: dùng uses (gọi action có sẵn) hoặc dùng run (chạy lệnh shell).
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- name: Run tests
run: mvn -B test
- name: Print result
run: echo "Test step finished with status ${{ job.status }}"
Giải thích:
- Step
Checkout codedùng action có sẵnactions/checkoutđể lấy source code vào runner. - Step
Cache Maven dependenciescache thư mục~/.m2/repository, giúp build sau nhanh hơn vì không phải tải lại dependency. keycủa cache dựa trên hash củapom.xml— khipom.xmlđổi, cache cũ bị bỏ, cache mới được tạo.- Step cuối dùng
runđể chạy lệnh shell thông thường, có thể tham chiếu context như${{ job.status }}.
5. Biến môi trường và secrets
Bạn thường cần truyền config nhạy cảm (API key, token) vào workflow mà không hard-code trong file YAML.
jobs:
deploy:
runs-on: ubuntu-latest
env:
SPRING_PROFILES_ACTIVE: prod
steps:
- uses: actions/checkout@v4
- name: Deploy to server
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
run: |
echo "Deploying with profile $SPRING_PROFILES_ACTIVE"
curl -H "Authorization: Bearer $DEPLOY_TOKEN" https://api.example.com/deploy
Giải thích:
envở cấp job áp dụng cho mọi step trong job đó (SPRING_PROFILES_ACTIVE).envở cấp step chỉ áp dụng riêng cho step đó (DEPLOY_TOKEN).secrets.DEPLOY_TOKENđược lấy từ Settings → Secrets and variables → Actions của repository, không bao giờ hiện giá trị thật trong log.
Lưu ý: Không bao giờ in trực tiếp giá trị secret bằng
echo $DEPLOY_TOKENra log — GitHub sẽ tự động mask nhưng tốt nhất vẫn tránh in secret.
6. Matrix: chạy nhiều phiên bản cùng lúc
Khi cần test trên nhiều phiên bản Java hoặc OS, matrix giúp bạn không phải viết lặp job.
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
java: [17, 21]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
- run: mvn -B test
Giải thích:
strategy.matrix.javakhai báo danh sách giá trị[17, 21].- GitHub Actions tự động tạo 2 job song song, mỗi job chạy với một phiên bản Java tương ứng.
- Cách này tiết kiệm công viết YAML lặp, phù hợp khi cần đảm bảo code chạy tốt trên nhiều môi trường.
7. Kiểm tra workflow bằng test đơn giản
Workflow không test trực tiếp bằng JUnit, nhưng bạn nên đảm bảo bước mvn test trong workflow thực sự chạy đúng test suite của project. Ví dụ một test đơn giản cho OrderService mà CI sẽ chạy:
class OrderServiceTest {
private final OrderService orderService = new OrderService();
@Test
void shouldCalculateTotalPriceCorrectly() {
Order order = new Order("ORD-001", List.of(
new OrderItem("Keyboard", 2, BigDecimal.valueOf(50)),
new OrderItem("Mouse", 1, BigDecimal.valueOf(20))
));
BigDecimal total = orderService.calculateTotal(order);
assertThat(total).isEqualByComparingTo(BigDecimal.valueOf(120));
}
}
Giải thích:
- Test này nằm trong
src/test/java, sẽ đượcmvn -B testtrong step của workflow chạy tự động. - Nếu test fail, step
Run testsbáo lỗi (exit code khác 0), job dừng lại và job phụ thuộc (needs) không chạy tiếp. - Đây là lý do CI hữu ích: code lỗi bị chặn trước khi merge vào
main.
Kết quả khi chạy trên GitHub Actions UI (tab Actions):
✓ Checkout code
✓ Set up JDK 21
✓ Build with Maven
✓ Run tests (shouldCalculateTotalPriceCorrectly PASSED)
8. Lỗi thường gặp
- Sai indent YAML: GitHub Actions dùng YAML, thụt lề sai 1 khoảng trắng khiến job hoặc step không được nhận diện, thường báo lỗi “Invalid workflow file”.
- Quên
runs-on: mỗi job bắt buộc phải córuns-on, thiếu sẽ khiến workflow fail ngay khi parse. - Dùng biến môi trường job này ở job khác:
envvà output biến thường không tự động truyền qua job, phải dùngoutputshoặcartifact. - Cache key không đổi khi dependency đổi: nếu
keycache quá chung (ví dụ chỉmaven-cache), bạn sẽ dùng nhầm cache cũ chứa dependency lỗi thời. - Chạy workflow nặng trên mọi push: nếu không giới hạn
pathshoặcbranches, mỗi commit nhỏ (sửa README) cũng trigger toàn bộ pipeline build + test, tốn phút chạy Actions (có giới hạn miễn phí).
Lưu ý: Nếu project chỉ cần build đơn giản và không có nhiều môi trường, không cần dùng
matrixhayartifact— thêm phức tạp không cần thiết sẽ làm workflow khó maintain.
9. Kết luận
Workflow là file YAML định nghĩa toàn bộ pipeline, job là các khối thực thi độc lập chạy trên runner riêng, và step là từng hành động cụ thể bên trong job. Hiểu rõ ba tầng này giúp bạn tổ chức pipeline CI/CD rõ ràng: job nào chạy song song, job nào phải chờ nhau qua needs, và dùng artifact khi cần chia sẻ dữ liệu.
Khi mới bắt đầu, bạn nên giữ workflow đơn giản (một job, vài step cơ bản: checkout, setup Java, test). Khi project lớn hơn, hãy thêm matrix, cache, và tách build/test/deploy thành các job riêng để dễ quản lý và debug.