앞서 Github Actions를 통한 Application CI/CD와 ArgoCD를 통한 클러스터 CD 파이프라인에 대한 글을 작성했다.
다만, Github Actions CI/CD에서 CD 부분은 CI에서 빌드한 내용을 Artifact로써 CD Job에서 사용하고, SSH 연결을 통해서 직접 운영 서버에 Deploy해주는 방식으로 구성했기에 아래와 같은 문제점이 거론될 수 있었다.
기존 Github Actions CI/CD의 이슈
- 특정 서버에 강하게 의존
- 이 배포는 SCP로 파일을 전송하고 SSH 연결을 거쳐 배포 스크립트를 실행하는 방식으로 되어있음
- 따라서 특정 원격 서버와 배포 스크립트에 강하게 의존하고 있어서 확장성과 서버 장애나 IP 변경에 배포 실패 가능성을 가짐
- 상태 관리 불가
- Workflow가 동작해서 배포가 이루어지면 Application의 상태를 모니터링하거나 관리할 방법이 없음 (단방향 배포)
- 예를 들어, 배포 스크립트가 실패하거나 배포 파일이 손상되어도, 워크플로우가 확인할 방법이 없음
- 쿠버네티스 클러스터와 호환 불가
- 단일 서버에 JAR파일을 배포하는 방식으로 설계되었기에, 쿠버네티스 클러스터와 같은 컨테이너 오케스트레이션 환경에 부적합
- 다중 환경이나 여러 Application에 대해서는 Workflow를 재작성해야함
- 아티펙트 관리의 비효율성
- CI를 통해 빌드된 JAR 파일을 Github Actions의 아티펙트로써 관리하는 구조는 단순히 임시 저장소로써 활용하는 방법
- docker hub와 같은 컨테이너 이미지 레지스트리를 통해 관리하는 것이 장기적으로 관리에 유리
이러한 단점들을 극복하기 위한 Github Actions와 ArgoCD를 통해 CICD 파이프라인을 구축해보도록 한다.
CI/CD 아키텍처
하나의 repo로 Application과 Manifest를 디렉토리를 분리해서 CICD 파이프라인을 작성하는 방법도 존재하지만, 이번 실습에서는 각각 Repo를 분리해서 관리하는 상황을 기반으로 진행해본다.
CI 파트
Application 코드 repo에 대해 Github Actions의 Workflow를 작성해서 push가 발생하면 이미지를 빌드하고, 컨테이너 이미지 레지스트리(docker hub)에 push하는 과정까지의 CI 파트를 구성해보도록 한다.
CI 파트는 이전 글과 빌드 Job과 비슷한 내용으로 구성하되, 이미지로써 빌드한 뒤 docker hub에 push하는 방식으로 변경해준다.
name: simple-web-pipeline
on:
push:
branches: [main]
paths:
- 'simple_flask/**'
jobs:
build:
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.docker_build.outputs.image_tag }}
env:
TAG: ${{ github.run_id }}
steps:
# Repo checkout
- name: Repo download
uses: actions/checkout@v4
# docker hub 로그인
- name: Login Docker hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# 빌드
- name: Build Project
run: |
cd simple_flask
docker build -t ${{ secrets.DOCKER_USERNAME }}/simple_web:${{ env.TAG }} .
# docker 이미지 push
- name: Push Docker Image
id: docker_build
run: |
docker push ${{ secrets.DOCKER_USERNAME }}/simple_web:${{ env.TAG }}
echo "image_tag=${{ env.TAG }}" >> $GITHUB_OUTPUT
이렇게 workflow를 구성하면 Application의 CI 파이프라인이 구성된 것을 확인할 수 있다.
CD 파트
앞서 Application repo에 push함으로써 새로운 Application 이미지 버전이 생기게 되는데, 이미지 버전 변경을 위해 태그값을 바꿔주는 작업이 필요하게 된다.
CD에서는 manifest repo의 이미지 태그를 CI 이후 새롭게 생성된 이미지 태그로 바꿔서 code push해주는 작업을 수행한다.
자동 커밋을 생성하는 대상이 다르기 때문에 Personal Acces Token을 발급받아 연결해주어야한다. (application repo에서 manifest repo로 생성)
manifest repo를 대상으로 Contents - Read and Write 권한을 주는 Token을 발급하고 application repo에 Secret으로 추가한다.
Token을 Secret으로 추가한 뒤, 아래와 같이 cd 작업을 Application repo의 workflow에 추가해준다.
deploy:
needs: build
runs-on: ubuntu-latest
steps:
# checkout manifest repo
- name: Checkout
uses: actions/checkout@v4
with:
repository: omoknooni/argocd-test
token: ${{ secrets.PAT_TOKEN }}
# Update kubernetes manifest image tag
- name: Update manifest
working-directory: ./kubernetes
run: |
sed -i "s|image: ${{ secrets.DOCKER_USERNAME }}/simple_web:.*|image: ${{ secrets.DOCKER_USERNAME }}/simple_web:${{ needs.build.outputs.image_tag }}|" deployment.yml
# Commit & Push manifest
- name: Commit N Push manifest
env:
PAT_TOKEN: ${{ secrets.PAT_TOKEN }}
run: |
git config --global user.email "hihm0609@gmail.com"
git config --global user.name "omoknooni"
git remote set-url origin https://x-access-token:${PAT_TOKEN}@github.com/omoknooni/argocd-test.git
git add .
git commit -m "Update image tag to ${{ needs.build.outputs.image_tag }}"
git push origin main
CI/CD 연동
CI/CD 파이프라인의 연동 과정을 보기에 앞서, 쿠버네티스 클러스터에 argoCD를 구축하고 manifest repo를 연동한 Application을 설정한다.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: simple-web
namespace: argo
spec:
project: default
source:
# manifest repo를 추가
repoURL: https://github.com/omoknooni/argocd-test.git
targetRevision: main
path: kubernetes
destination:
# 현재 argoCD가 구축된 클러스터를 destination으로 지정
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
# 자동 Sync 정책으로 설정
automated:
prune: true
selfHeal: true
그리고 Application 코드를 수정해서 push하면 Github Actions workflow가 동작하고, hub에 새 이미지를 push함과 동시에 manifest repo로 자동 커밋을 생성하게 된다. (이미지 태그 변경용)
manifest repo에 변경점이 추가되었으므로, ArgoCD가 repo를 polling해서 Sync하게되면서 배포가 마무리된다.
이렇게 Github Actions와 ArgoCD를 통해 비교적 현대적인 Application과 클러스터 manifest의 배포 파이프라인을 구성해봤다.
이 파이프라인을 통해 기존 Github Actions로만 구성된 파이프라인에서의 문제점들을 아래와 같이 해결할 수 있게된다.
문제점 | 기존 파이프라인 (Only Github Actions) | 통합 CI/CD 파이프라인 |
서버 의존성 | SCP나 SSH를 이용해 특정 서버에 크게 의존 | 쿠버네티스 API를 통해서 유연한 배포 |
상태 관리 | 없음 | ArgoCD를 통해 상태 모니터링과 롤백 |
쿠버네티스 호환 | 불가 | manifest repo와 함께 쿠버네티스 클러스터에도 적용 가능 |
GitOps 적용여부 | X | Git repo를 Single source of Truth로 사용 |