0

[Java Backend Zero to Hello] BÀI 7.6: CI/CD VỚI GITHUB ACTIONS

Java Backend Zero to Hello

📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 7: Testing & DevOps Cơ Bản | Bài 76/86


BÀI 7.6: CI/CD VỚI GITHUB ACTIONS

Mục tiêu

  • Hiểu CI/CD
  • Tạo GitHub Actions workflow
  • Build, test, deploy tự động
  • Tích hợp Docker

1. CI/CD LÀ GÌ?

  • CI (Continuous Integration) - Tích hợp liên tục: tự động build, test khi push code
  • CD (Continuous Deployment/Delivery) - Triển khai liên tục: tự động deploy khi pass test

Lợi ích

  • Phát hiện lỗi sớm
  • Giảm thời gian deploy
  • Tăng chất lượng code
  • Tự động hóa quy trình

2. GITHUB ACTIONS

2.1 Khái niệm

  • Workflow - Quy trình CI/CD
  • Job - Tập các step
  • Step - Hành động đơn lẻ
  • Action - Đơn vị tái sử dụng
  • Runner - Máy chạy workflow

2.2 Cấu trúc file

.github/
└── workflows/
    ├── ci.yml
    └── deploy.yml

3. WORKFLOW CƠ BẢN

3.1 .github/workflows/ci.yml

name: CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Cache Maven dependencies
        uses: actions/cache@v3
        with:
          path: ~/.m2
          key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
          restore-keys: ${{ runner.os }}-m2-

      - name: Build with Maven
        run: mvn clean package -DskipTests

      - name: Run tests
        run: mvn test

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: app-jar
          path: target/*.jar

4. TRIGGERS

on:
  # Push
  push:
    branches: [ main ]
    paths: [ 'src/**' ]  # Chỉ khi thay đổi src

  # Pull Request
  pull_request:
    branches: [ main ]

  # Schedule (cron)
  schedule:
    - cron: '0 0 * * *'  # Mỗi ngày lúc 0h

  # Manual
  workflow_dispatch:

  # Khi release
  release:
    types: [ published ]

5. JOBS VÀ STEPS

5.1 Multiple jobs

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: mvn test

  build:
    needs: test  # Chờ test xong
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: mvn package

  deploy:
    needs: [test, build]
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - run: echo "Deploying..."

5.2 Matrix strategy

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        java-version: [17, 21]
    steps:
      - uses: actions/setup-java@v4
        with:
          java-version: ${{ matrix.java-version }}
      - run: mvn test

6. SERVICES (DATABASE TRONG CI)

jobs:
  test:
    runs-on: ubuntu-latest

    services:
      mysql:
        image: mysql:8
        env:
          MYSQL_ROOT_PASSWORD: password
          MYSQL_DATABASE: testdb
        ports:
          - 3306:3306
        options: >-
          --health-cmd="mysqladmin ping"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=5

    steps:
      - uses: actions/checkout@v4
      - run: mvn test
        env:
          SPRING_DATASOURCE_URL: jdbc:mysql://localhost:3306/testdb

7. SECRETS

7.1 Cấu hình

Vào Settings → Secrets and variables → Actions → New repository secret

7.2 Sử dụng

steps:
  - name: Deploy
    run: ./deploy.sh
    env:
      API_KEY: ${{ secrets.API_KEY }}
      DB_PASSWORD: ${{ secrets.DB_PASSWORD }}

8. BUILD VÀ PUSH DOCKER IMAGE

jobs:
  docker:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            username/myapp:latest
            username/myapp:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

9. DEPLOY LÊN SERVER

9.1 SSH Deploy

jobs:
  deploy:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - name: Deploy to server
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /app
            git pull
            docker-compose pull
            docker-compose up -d

9.2 Deploy lên Cloud

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to AWS
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }}
          aws-region: ap-southeast-1

      - name: Deploy to ECS
        run: |
          aws ecs update-service \
            --cluster my-cluster \
            --service my-service \
            --force-new-deployment

10. WORKFLOW HOÀN CHỈNH

name: CI/CD Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

env:
  REGISTRY: docker.io
  IMAGE_NAME: username/myapp

jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_PASSWORD: test
          POSTGRES_DB: testdb
        ports: ['5432:5432']
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Cache Maven
        uses: actions/cache@v3
        with:
          path: ~/.m2
          key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}

      - name: Run tests
        run: mvn test
        env:
          SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/testdb

      - name: Upload coverage
        uses: codecov/codecov-action@v3

  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.event_name == 'push'

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Build JAR
        run: mvn clean package -DskipTests

      - name: Build & Push Docker
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - name: Deploy
        run: echo "Deploying to production..."

11. BADGES

Thêm badge vào README:

![CI](https://github.com/user/repo/workflows/CI/badge.svg)

12. BÀI TẬP THỰC HÀNH

Bài 1: CI Workflow

Tạo workflow build và test cho Spring Boot project.

Bài 2: Docker Build

Thêm job build và push Docker image.

Bài 3: Auto Deploy

Setup auto deploy khi merge vào main.


13. TÓM TẮT

Khái niệm Mô tả
Workflow Quy trình CI/CD
Job Tập step
Step Hành động
Action Đơn vị tái sử dụng
Trigger Sự kiện kích hoạt
Secrets Biến bí mật
Matrix Chạy nhiều config

Bài tiếp theo: 7.7 Triển khai lên Cloud


🧭 Điều Hướng Series

⬅️ Bài trước: BÀI 7.5: DOCKER COMPOSE

📋 Lộ trình tổng quan: Xem Toàn Bộ Series

➡️ Bài tiếp theo: BÀI 7.7: TRIỂN KHAI LÊN CLOUD


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí