ArgoCD를 활용한 k8 CI/CD pipeline 구축 #2
최다찬업데이트:
이야기에 앞서
이번 글에서 다룰 CICD 전체 구성도 입니다.
특이한 점은 git repo를 두가지를 사용한다는점 입니다.
- 어플리케이션 코드가 올라가 있는 App repository
- Github Actions CI workflow 있음
- 어플리케이션 코드
- 빌드를 위한 DockerFile
- 코드를 컨테이너로 빌드하여 ECR로 PUSH
- 어플리케이션 Manifest(k8 POD를 만들기 위한)가 존재하는 Config repository
- 어플리케이션 Manifest : k8 Resource 배포를 위한 Kustomize 형식의 yaml 파일들입니다.
- app-of-apps
- argo-declarartive-setup-yaml (배포랑은 상관 없음)
사용 기술
이 글에서 다루게 될 기술과 주제에요.
Container OrchestrationWhy EKS ?Terraform을 활용한 EKS 구축EKS 주요 addOn 설치 자동화 및 서비스 통합
- 어플리케이션 배포 자동화와 GitOps (CI/CD pipeline)
- What’s GitOps
- GitHub Actions (CI)
- ArgoCD (CD)
What’s GitOps
GitOps란 무엇일까요 ? 다들 DevOps는 많이 들어보셨을거에요. DevOps는 개발자와
운영자의 협업, 통합, 자동화를 강조하는 개념입니다. GitOps는 DevOps를
실천하기 위한 방법 중 하나 입니다.
간단하게 설명 드리면 모든 선언적 코드로 되어 있는 파일을 git 으로 관리하고 이것을 pipeline을 통해 IT 운영에 활용하는 것을 의미 합니다.
여기서 핵심은 선언적 코드 입니다. 선언적 코드로 되어 있어야 자동화가 가능하기 때문이에요. GitOps의 목적에서 자동화는
빠질수 없는 요소 입니다.
오늘 다룰 ArgoCD는 이 GitOps와 아주 밀접한 관계가 있어요.
GitHub Actions (CI)
GitHub Actions는 GitHub에서 제공하는 CI(Continuous Integration, 지속 통합)와 CD(Continuous Deployment, 지속 배포) 서비스입니다.
아래는 구성도와 사용 방법입니다.
Github Secret 등록
AWS ECR을 사용할거라 AWS ACCESS KEY가 필요해요. 실습 예제 링크
name: CI/CD
on:
push:
branches: [ master ]
paths-ignore:
- '.gitignore'
- '.dockerignore'
- 'README.md'
pull_request:
branches: [ master ]
jobs:
ci:
runs-on: ubuntu-latest
outputs:
IMAGE_TAG: $
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: $
aws-secret-access-key: $
aws-region: ap-northeast-2
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Set var
id: set-var
run: |
echo ::set-output name=ECR_REGISTRY::$
echo ::set-output name=ECR_REPOSITORY::demo
echo ::set-output name=IMAGE_TAG::$(cat VERSION)
- name: Docker image Build
id: build-image
run: |
docker build \
-f Dockerfile \
-t $/$:$ .
- name: Docker image Push
id: push-image
run: |
docker push $/$:$
CI Workflow
- 개발자가 수정된 앱 git push
- Github Action (CI)
- Configure AWS credentials (Secret에 미리 등록 된 AWS KEY 사용)
- ECR Login
- Set Value : ECR_REGISTRY, ECR_REPOSITORY, IMAGE_TAG(cat VERSION file)
- docker image build & push
검증
ArgoCD (CD)
ArgoCD는 k8 전용 Continuous Deployment/Delivery Tool 입니다. ArgoCD는
k8 Resource 상태를 정의하기 위한 정보를 Git 저장소로 사용 하는 GitOps 패턴을
따르고 있어요. ArgoCD 공식 문서에도 나와 있듯이 GitOps 패턴을 사용하는 ArgoCD
역시 반드시 선언적 언어를 사용하도록 되어 있습니다.
k8에서 매니페스트를 관리하는 방법은 여러 가지가 있는데 띵스플로우에서는 Kustomize를 사용 하고 있어요. 물론 ArgoCD에서 Kustomize를 지원합니다. 지금부터는 어플리케이션 배포 자동화를 위한 ArgoCD 구축 및 CD pipeline 구현 방법을 알아 보겠습니다.
ArgoCD Architecture
- User Interface : Web, Command
- Server
- argocd-server : 메인 API 서버
- repo-server : git repo 관리 (로컬 캐시, connection 등)
- app-controller : 배포된 APP 모니터링 및 Sync 확인
- redis
- dex-server : 보안, SSO등 Argo 설정 관리
- ArgoCD Managed App
ArgoCD 설치
ArgoCD는 Helm Chart를 사용해 설치할거에요. 편의상 MakeFile을 만들어 놨는데 Helm 실행 명령어가 들어 있습니다. local과 eks의 차이는 Ingress 생성 유무 입니다.
git clone https://github.com/iamchoiz/k8-cicd-argocd.git
cd k8-cicd-argocd/argo-cd
make template-eks
make upgrade-eks
# URL : alb-endpoint
# ID : admin
# Pwd: kubectl get secret -n argocd argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
로그인
values-eks.yaml에서 Ingress 설치를 True로 하고, EKS를 구축 할때 aws_loadbalancer_controller를 설치 했기 때문에 자동으로 ALB가 생성됩니다. 이제 ALB의 엔드포인트 URL로 ArgoCD에 접속 할 수 있어요.
SSO 설정 (GithHub)
dev-server를 활용해서 SSO 설정을 할 수도 있어요.
- 먼저 Github OAuth Application을 생성 합니다.
- Client Secrets 생성
- helm chart value-eks.yaml 수정
Client Secrets 같은 경우 민감한 정보이기 때문에 실제 적용시에는 Secret으로 생성하는 것을 권장해요. ex) clientSecret:$생성한_SECRET_NAME:DATA_NAME
helm upgrade argocd -n argocd -f values-eks.yaml .
정상적으로 적용되면 사진과 같이 ‘LOG IN VIA GITHUB’이라는 버튼이 활성화
됩니다. 추가로 Argocd 같은 경우 RBAC을 지원하기 때문 rbacConfig 설정을 통해 모든 계정에 대한 세부적인 권한 관리를 할 수 있어요.
ArgoCD Declarative-Setup
ArgoCD에서는 Web U/I와 CLI를 지원하고 있지만 이외에 Declarative-Setup를 통해서 리소스를 생성 할 수 있도록 지원하고 있어요. 아래 예제를 보시면 금방 이해가 될거에요.
- git repository 등록 방법
- Web UI
로그인 -> 설정 -> Repositories - Helm Chart (values-eks.yaml)
helm upgrade argocd -n argocd -f values-eks.yaml .
- Web UI
- Project 생성
cd argo-declarartive-setup-yaml # AppProject.yaml 수정 (Default : dev Project) kubectl apply -f AppProject.yaml
- Application 생성(argo-declarartive-setup-yaml/Application-helm.yaml)
Application은 실제 배포 자동화 대상 Application입니다. 이부분은 조금 자세하게
설명하고 넘어갈게요. 아래 사진은 Application 생성을 위한 코드 Manifest 입니다.
핵심은 repoURL과 path인데, repoURL의 path에 있는 app Manifest를 읽어 ArgoCD Application을 생성한다 라고 이해하시면 좋을 것 같아요.- metadata.name : argocd의 Application Display name
- metadata.namespace : argocd가 설치된 Namespace 이름
- spec.destination.namespace : app이 배포될 Namespace 이름
- spec.destination.server : app이 배포될 k8 context URL
- spec.project : argocd project (이전에 생성한 Project 이름)
- spec.source.repoURL : app이 있는 git repo URL
- spec.source.path : app이 있는 git repo path
- spec.source.helm : Manifest가 Helm일 경우 values 이름 지정
- spec.syncPolicy.automated : Auto Sync 여부
💡 Continuous Delivery vs Continuous Deployment
갑자기 둘의 차이를 언급한 것은 둘의 차이가 Auto Sync와 관계가 있기 때문이에요. CI/CD에서 CD는 Continuous Delivery 또는 Continuous Deployment를 의미 합니다. 둘의 차이는 사실 간단해요. 모든 배포 과정을 자동으로 하면 Continuous Deployment이고 마지막 배포 과정만 수동으로 하게 되면 Continuous Delivery라고 합니다.
아래 사진이 이를 잘 설명해 줍니다. Image source
ArgoCD Application Controller는 git repo에 있는 Manifest 상태와 실제 k8에서 실행 중인 리소스 상태를 지속적으로 Sync가맞는지
비교 확인합니다. 이때 Auto Sync가
활성화 되어 있으면 변화가 생겼을때 바로 Sync를 맞추는 작업을 진행하고 비활성화 되어
있으면 OutOfSync 상태가 되고 수동으로 Sync를 맞출수 있게 해줍니다.
Auto Sync
Manual Sync
띵스플로우 같은 경우 현재 대부분의 서비스가 Continuous Delivery(Maunal Sync) 배포 전략을 사용하고 있고 일부 서비스만 Continuous Deployment(Auto Sync)를 사용하고 있어요.
Declarative-Setup을 사용해서 간단하게 Application을 배포 했습니다. 만약에 수동으로 설정한다면 ArgoCD Web UI에서 한땀한땀 모든 항목을 입력해야 할 겁니다.
그런데 요즘 MSA 아키택처가 유행하면서 굉장히 많은 서비스가 존재 할 수 있고 서비스 수가 계속 늘어날수가 있습니다. 그때마다 각각의 서비스들의 Manifest 파일을 관리하는 것도
쉽지 않을거에요.
그래서 ArgoCD에서는 App of Apps pattern을 통한 서비스 그룹 통합 관리 기능을 지원 합니다.
App Of Apps
말그대로 App들의 App입니다. App 하나를 생성해서 전체 App들을 관리 할 수 있게 해주는 기능입니다. 실습 예제로 확인 해볼게요.
먼저 App of Apps Mainfest 부터 볼게요. app-of-apps.yaml 파일은 특별할게 없습니다.
방금전에 사용한 Application-helm.yaml 파일과 동일한 형식으로 되어 있어요.
path가 app-of-apps 폴더로 되어 있는데 app-of-apps 폴더가 핵심입니다.
app-of-apps 폴더는 helm chart로 되어 있는데 단순히 repoURL과 app의 path만
넣어주면 됩니다. helm template은 단순하게 입력된 value에 대한 loop에요. 궁금하신
분들은 한번 보시면 좋을것 같습니다. 아까 실행했던 kustomize-app을 삭제하고 app-of-apps로 다시 배포 해보겠습니다.
# app-of-apps/values-eks.yaml
repoURL: 'https://github.com/iamchoiz/k8-cicd-argocd.git'
apps:
- name: kustomize-app
project: default
namespace: default
source:
path: kustomize_app
# customValues: true
# values:
# - values-eks.yaml
$ k delete -f argo-declarartive-setup-yaml/Application-helm.yaml
$ k apply -f argo-declarartive-setup-yaml/app-of-apps.yaml
검증
app-of-apps 아래 kustomize-app이 생성된 걸 확인 할 수 있어요.
아직 감이 안오시나요 ? 아래 영상을 보시면 이해가 쉬울거에요. 영상 시나리오는
app-of-apps 최초 배포 이후에 서비스를 추가 배포하는 시나리오에요.
자 .. 이제 준비가 끝났습니다. 현재 두개의 git repo가 준비되었어요.
- 어플리케이션 코드가 올라가 있는 App repository
- Github Actions CI workflow 있음
- 어플리케이션 코드
- 빌드를 위한 DockerFile
- 코드를 컨테이너로 빌드하여 ECR로 PUSH
- 어플리케이션 Manifest(k8 POD를 만들기 위한)가 존재하는 Config repository
- 어플리케이션 Manifest : k8 Resource 배포를 위한 Kustomize 형식의 yaml 파일들입니다.
- app-of-apps
- argo-declarartive-setup-yaml (배포랑은 상관 없음)
이제 git repo A의 GitHub Actions에서 빌드 후 git repo B의 컨테이너 이미지 버전을
변경 해주는 로직이 들어가면 CI/CD pipeline 완성 됩니다.
아래와 같은 구성도가 완성 됩니다.
CI/CD Workflow
- 개발자가 수정된 앱을 App repo에 push
- Github Action (CI)
- Configure AWS credentials
- ECR Login
- docker image build & ECR push
- app-of-apps가 바라보고 있는 Config repo의 k8 Manifest 수정
- ECR PUSH
- Config repo의 k8 Manifest (Image Tag) 수정
- ArgoCD가 변경 사항 확인
- 변경 사항 업데이트
- 최신 이미지 PULL
GitHub Actions 추가 사항
마지막으로 구성도에 있는 4번 항목인 Config repository 수정을 위한 GitHub Actions
수정이 필요해요. 간단하게 설명 드리면 Config repo를 clon해서 이미지 태그를 수정하고 수정된 사항을 Commit 하는 흐름 입니다.
cd:
needs: [ci]
runs-on: ubuntu-latest
steps:
- name: Checkout Target Repository
uses: actions/checkout@v2
with:
repository: iamchoiz/k8-cicd-argocd
path: deploy-k8s
- name: Replace image tag in helm values (LOCAL)
uses: mikefarah/yq@master
env:
IMAGE_TAG: $
with:
cmd: yq eval -i '.image.tag = env(IMAGE_TAG)' 'deploy-k8s/demo/values.yaml'
- name: Replace image tag in helm values (EKS)
uses: mikefarah/yq@master
env:
IMAGE_TAG: $
with:
cmd: yq eval -i '.image.tag = env(IMAGE_TAG)' 'deploy-k8s/demo/values-eks.yaml'
- name: Push helm repo
env:
token: $
IMAGE_TAG: $
run: |
cd deploy-k8s
git config --global user.email "dachan1207@gmail.com"
git config --global user.name "iamchoiz"
git add demo/values.yaml demo/values-eks.yaml;
git commit --message "Update demo image tag to $IMAGE_TAG";
git config -l | grep 'http\..*\.extraheader' | cut -d= -f1 | xargs -L1 git config --unset-all
git push --prune https://token:$token@github.com/iamchoiz/k8-cicd-argocd.git
마치며
요즘은 고객 요구사항을 신속하게 파악해 서비스에 반영하거나 버그가 발견되면 해결 후 신속하게 서비스에 배포 하는 것이 굉장히 중요해졌는데요. 오늘 설명한 CI/CD 개념이 이에 대한 솔루션이라고 생각합니다. CI/CD pipeline을 통해서 운영 중 무중단 배포가 가능해지면서
정기점검 이라는 문구를 보기 힘들어진 것 같아요.
저희가 EKS 마이그레이션 이후 우여곡절이 있었지만 현재는 안정화가 진행 되어서 좋은 효과를 보고 있고 신규로 오픈하는 서비스는 모두 EKS 환경에서 동작하도록 구현하고 있습니다. 사실 문제가 있는 서비스든 잘 동작하는 서비스든 인프라 환경 자체를 변경하는 것은 쉽지
않는 결정이긴 하지만 제대로 검토해서 서비스에 득이 있다고 판단하면 도전 해보는 것이
미래를 위한 좋은 방향이라고 생각합니다.
댓글남기기