GitHub Actions를 이용하여 GitOps의 YAML 파일 동적 업데이트

GitHub Actions를 이용하여 GitOps의 YAML 파일 동적 업데이트

·

2 min read

배경

  • Jenkins & Spinnaker 기반의 CI/CD 환경에서 GitHub Action & Argo CD로 전환하게 되었습니다.

  • Spinnaker에서는 배포 시 동적 파라미터를 제공하여 yaml 을 수정하는 기능이 있었으나, Argo CD는 이러한 기능을 지원하지 않는걸로 파악했습니다.

해결 (PoC)

  • Argo CD가 GitOps 방식을 따르므로, 애플리케이션 배포 시 GitHub Actions를 활용하여 Deploy Repositoryyaml 파일을 워크플로우 디스패치 이벤트로부터 받은 파라미터로 동적으로 수정합니다. 이를 통해 최종 배포 단계에서 yaml 파일을 업데이트하여 파라미터를 주입합니다.

구현 예시.

Application Repository 설정

# GitHub Workflow

name: Update WORKER_COUNT in sample.yaml

on:
  workflow_dispatch:
    inputs:
      workerCount:
        description: 'New WORKER_COUNT value'
        required: true
        default: '99' 
      userName:
        description: 'New userName value'
        required: true
        default: 'root'
      versionName:
        description: 'New Version Value'
        required: true
        default: '2'

jobs:
  update-yaml:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout B Repository
      uses: actions/checkout@v2
      with:
        repository: 'author/repository'
        token: ${{ secrets.TEST_B_REPO_TOKEN }}
        ref: 'main'

    - name: Install yq (YAML Processor)
      run: sudo snap install yq

    - name: Update WORKER_COUNT in sample.yaml
      run: |
        yq eval '.version = ${{ github.event.inputs.versionName }}' -i sample.yaml
        yq eval '.services.worker.environment.WORKER_COUNT = "${{ github.event.inputs.workerCount }}"' -i sample.yaml
        yq eval '.databases.postgres.environment.POSTGRES_USER = "${{ github.event.inputs.userName }}"' -i sample.yaml

    - name: Commit and Push changes
      uses: EndBug/add-and-commit@v7
      with:
        author_name: authorName
        author_email: authorEmail
        message: 'Update WORKER_COUNT in sample.yaml to ${{ github.event.inputs.workerCount }}'
        add: 'sample.yaml'
        push: true
        token: ${{ secrets.B_REPO_TOKEN }}

Deploy Repository의 sample.yaml 예시

version: 1
services:
  web:
    image: "example/webapp:latest"
    ports:
      - "80:80"
    environment:
      DEBUG: "false"
      DATABASE_URL: "postgres://user:password@postgres:5432/dbname"
  worker:
    image: "example/worker:latest"
    environment:
      QUEUE: "tasks"
      WORKER_COUNT: "2"
databases:
  postgres:
    image: "postgres:13"
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: "sampe"
      POSTGRES_PASSWORD: "password"
      POSTGRES_DB: "dbname"
networks:
  default:
    external:
      name: "my-custom-network"

결론

  • 처음 기대한 대로 동작을 하지만 해당 방식이 올바른 방식인지는 잘 모르겠습니다. PAT 관리도 유지보수 포인트가 될 것 같고.. 더 효율적이거나 권장되는 방법이 있다면 조언을 구하고 싶습니다.