KUBERNETES

3. Argo-CD를 이용한 GitOps 시스템 구축

이번 장은 ArgoCD를 이용하여 GitOps(이하 깃옵스) 시스템을 구축하는 방법을 알아보겠습니다.

1. GitOps와 단일 진실 원천(SSOT) 정의

먼저, 깃옵스의 정의를 알아보겠습니다. 앞에서 코드로 선언하는 쿠버네티스의 특징과 설치 부분에서 알아보았듯이 쿠버네티스의 모든 리소스는 코드를 구현할 수 있습니다. 깃옵스는 이러한 코드를 깃(Git)에 보관하고 깃에 보관한 코드가 현재 운영 중인 상태(Ops)와 동일하게 맞추는 것을 의미합니다.

현업에서 현재 운영 상태를 깃에 Commit, Push하지 않고 임의로 자기 로컬 소스에서 변경하던지, 명령어를 변경하는 경우를 금지하기 위하여 많이 사용합니다. 임의로 변경된 상태는 변경 내역을 추적하기 어렵습니다. 전체 중 일부 클러스터만 장애가 발생하여 확인하면 임의로 변경된 부분만 발견하는 것은 비교적 흔한 경우 중 하나입니다. 그리고 새롭게 시스템을 구성하는 경우 일일이 찾아야 하는 등 추가 리소스가 많이 필요합니다.

깃옵스는 단일 진실 원천(Single Source of Truth, SSOT) 개념을 사용하고 있어 해당 정의를 알아보겠습니다. “단일 진실 원천”은 데이터 관리 원칙 중 하나로, 특정 데이터의 정확하고 신뢰할 수 있는 하나의 버전만 시스템 전체에 존재한다는 개념을 나타냅니다. 이 원칙은 일관성, 정확성, 효율성을 향상시키는 데 중요한 역할을 합니다.

일관성: 모든 시스템 구성 요소가 동일한 데이터 소스를 참조하므로 데이터의 일관성이 유지됩니다.
정확성: 중복이나 불일치의 가능성이 감소하므로 데이터의 정확성이 향상됩니다.
효율성: 데이터를 유지 관리할 단일 위치가 있으므로 업데이트와 관리가 훨씬 더 효율적입니다.


<From: Cloud Native Computing Foundation>

깃옵스에서는 Git 저장소가 시스템의 구성과 상태에 대한 단일 진실 원천 역할을 합니다. 코드와 인프라의 전체 상태를 Git 저장소에 버전화하고 저장함으로써, 선언적인 접근 방식을 통해 시스템을 관리하고 자동화합니다.  현업에서 현재의 운영 상태를 개별 사용자가 임의로 명령어로 변경하거나 커밋하지 않은 로컬 소스로 변경하지 않고 중앙화된 깃 소스에서만 변경하는 것을 의미합니다. 깃옵스로 시스템의 일관성이 유지되어 협업 생산성이  향상되는 것이 필자가 생각하는 가장 큰 이점입니다. 

모든 시스템과 사용자가 동일한 데이터 소스를 참조하므로 정보의 불일치가 발생할 확률이 줄어들고 중복된 데이터를 관리하고 동기화하는 데 필요한 노력과 비용을 줄일 수 있습니다. 이로 인해 전체 시스템의 운영 효율성이 향상됩니다. 검색 등을 통하여 이전 상태를 조회하는 기능도 자주 사용합니다.

그러나 이 원칙을 실현하는 것은 종종 어렵습니다. 바쁜 업무에 원칙을 따르지 않고 싶은 수많은 유혹이 있습니다. 깃옵스 관련 도구를 사용하여 정책을 강제하는 것이 필요하며 올바른 데이터 아키텍처, 프로세스, 관리 도구가 필요합니다. 깃옵스를 구현하기 위하여 여러 도구를 사용할 수 있는데 CD(연속 배포, Continuous Deployment)에 사용하는 도구는 ArgoCD를 가장 많이 사용하고 있습니다. 여러 CD 도구들 중에서 ArgoCD는 1) 사용하기 편리한 UI 제공 2) 다른 도구들과 통합이 쉽고 3) 사용자가 많아 사례가 풍부합니다.

<From: ArgoCD>

ArgoCD는 지정된 Git 저장소와 쿠버네티스 클러스터를 지속적으로 모니터링합니다. 저장소의 변경사항이 감지되면, ArgoCD는 자동으로 클러스터의 상태를 저장소의 상태와 동기화합니다. 물론 상황에 따라 수동 동기화 옵션도 제공됩니다. 그리고 문제가 발생하면 이전 상태로 쉽게 롤백할 수 있습니다. Git의 버전 관리 덕분에 모든 변경 내역이 추적되므로 안정적인 상태로 복원하기 쉽습니다.

그리고 ArgoCD 대시보드를 통해 애플리케이션의 실시간 상태, 동기화 상태, Health를 시각적으로 확인할 수 있습니다. 헬름으로 애플리케이션을 배포하면 전체 리소스를 파악하기가 어려운데 ArgoCD 대시보드를 통하여 편리하게 파악할 수 있어 많은 사용자들이 선호하는 기능입니다. 사용자 별로 Project 별로 접근 제어 권한을 설정하여 팀원들이 적절한 액세스 수준을 갖게 할 수 있습니다.

 Argo CD는 Git 저장소를 단일 진실 원천으로 사용하여 쿠버네티스 클러스터의 상태를 지속적으로 동기화하고 모니터링합니다. 이를 통해 개발자와 운영팀이 협업을 강화하고, 안정적이고 신속한 배포를 실현할 수 있습니다.

그럼 실습을 통하여 자세하게 알아보겠습니다.

실습 내역
1. ArgoCD 설치
2. ArgoCD를 이용하여 NGINX 헬름 차트 배포
3. 깃옵스 실습 – 로컬 환경 임의 수정 검증

2. Argo-CD 설치

쿠버네티스 환경에서 애플리케이션은 주로 헬름을 이용하여 설치합니다. 헬름(Helm)은 쿠버네티스 패키지 관리자로, 흔히 알고 있는 운영 체제의 apt, yum과 유사합니다. 헬름을 사용하면 여러 쿠버네티스 리소스를 묶어 하나의 패키지로 관리할 수 있으며, 이를 통해 애플리케이션의 설치, 업그레이드, 제거가 간소화됩니다. 헬름에 관한 자세한 내용은 11장에서 다룹니다.

그럼, 헬름으로 ArgoCD를 설치합니다. 윈도우 WSL의 Homebrew 설치 사용자와 MAC 사용자는 brew를 사용하여 로컬 PC에 헬름을 설치합니다.

brew install helm

다음으로 ArgoCD 공식 홈페이지를 이용하여 ArgoCD 헬름 차트를 내려받습니다.

helm repo add argo https://argoproj.github.io/argo-helm
helm pull argo/argo-cd --version v5.14.1
tar xvfz argo-cd-5.14.1.tgz
mv argo-cd argo-cd-v5.14.1
rm -rf argo-cd-5.14.1.tgz
cd argo-cd-v5.14.1
mkdir ci && cp values.yaml ci/jerry-test-values.yaml

원격의 ArgoCD의 헬름 리포지토리를 등록(helm repo add)하고 로컬에 헬름 차트를 다운(helm pull)받습니다. 이 후 기본 헬름 Value 파일을 각 환경에 맞게 수정하기 위하여 기존 Values.yaml 파일을 복사하여 임의의 이름 (jerry-test-values.yaml)으로 변경합니다. 헬름 명령어에 대한 자세한 설명은 11장에서 다룹니다.

기본 공식 헬름 Value을 아래와 같이 수정합니다. (필자 깃허브 참조)

configs:
  credentialTemplates:
    ssh-creds:
      url: git@github.com:junghoon2
      sshPrivateKey: |
        -----BEGIN OPENSSH PRIVATE KEY-----
        xxxxxxxxxxx
        -----END OPENSSH PRIVATE KEY-----
  repositories:
    k8s-class:
      name: k8s-class
      url: git@github.com:junghoon2/k8s-class.git

. configs.credentialTemplates.ssh-creds

ArgoCD에서 등록할 깃허브 레포지토리 정보를 등록합니다. 각자 사용하는 깃허브의 등록한 ssh 키정보(~/.ssh/id_rsa)를 입력합니다. 개인 키 정보라 보안상 해당 정보를 마스킹 처리(xxxxx) 하였습니다.

리포지토리 정보는 ArgoCD 설치를 완료하고 GUI로도 가능합니다. 하지만 가능하면 GitOps 철학에 맞게 깃레포 정보도 소스 코드에 입력하는 것을 권고합니다. 처음에는 번거롭지만 GUI를 이용한 작업은 하지 않는 것이 향후 재사용성 측면에서 낫습니다.

.repositories.k8s-class.name/url

각자 깃 레포의 이름과 URL을 등록합니다.

지금은 아직 인그레스 설정을 하기 전이라 인그레스 관련 헬름 Values 설정이 빠져있습니다. 5장의 인그레스 설정이 완료되면 인그레스 설정을 추가하여 편리하게 인그레스 주소로 접속할 수 있습니다.

해당 헬름 Value 파일(jerry-test-values.yaml)을 이용하여 ArgoCD를 설치합니다.

$ helm install argocd -n argocd --create-namespace -f ci/jerry-test-values.yaml .
NAME: argocd
LAST DEPLOYED: Sun Jun 25 02:18:51 2023
NAMESPACE: argocd
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
In order to access the server UI you have the following options:

1. kubectl port-forward service/argocd-server -n argocd 8080:443

    and then open the browser on http://localhost:8080 and accept the certificate

2. enable ingress in the values file `server.ingress.enabled` and either
      - Add the annotation for ssl passthrough: https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/#option-1-ssl-passthrough
      - Set the `configs.params."server.insecure"` in the values file and terminate SSL at your ingress: https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/#option-2-multiple-ingress-objects-and-hosts


After reaching the UI the first time you can login with username: admin and the random password generated during the installation. You can find the password by running:

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

(You should delete the initial secret afterwards as suggested by the Getting Started Guide: https://argo-cd.readthedocs.io/en/stable/getting_started/#4-login-using-the-cli)

설치가 완료되면 ArgoCD 관련 파드를 확인할 수 있습니다.

# argocd 네임스페이스로 변경합니다.
$ k ns argocd

$ (jerry-test:argocd) k get pod
NAME                                               READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                    1/1     Running   0          69s
argocd-applicationset-controller-fc4dbb87c-bpf6f   1/1     Running   0          70s
argocd-dex-server-fd7d54c-crcr9                    1/1     Running   0          69s
argocd-notifications-controller-7f66dc5c75-xvsz7   1/1     Running   0          70s
argocd-redis-79c77796b7-x6kl6                      1/1     Running   0          70s
argocd-repo-server-6c9c4978b8-4btch                1/1     Running   0          70s
argocd-server-b694d4bc6-br6lt                      1/1     Running   0          70s

3. Port-forward를 이용한 Argo-CD 파드 접속

그럼, 설치한 ArgoCD 파드를 Port-forward를 이용하여 접속하겠습니다. 클러스터 외부에서 클러스터 내부에서 실행하고 있는 파드로 접속하기 위하여 주로 쿠버네티스의 인그레스 리소스를 사용합니다. 해당 내용은 5장에서 자세하게 설명하겠습니다. 지금은 추가 인그레스 설정 작업없이 관리자가 편하게 사용할 수 있는 Port-forward를 이용하여 파드에 접속합니다. 현업에서도 보안 상의 이유로 인그레스 설정을 하지 않은 파드는 Port-forward를 이용하여 접속합니다.

Port-forward는 ‘kubectl port-forward’ 명령을 사용합니다. port-forward 명령어가 길지만 명령어 자동 완성이 가능하여 어렵지 않습니다. port-forward 명령은 클러스터 내의 특정 Pod에 대한 트래픽을 로컬 시스템의 특정 포트로 전달(port-forward)하는 기능을 제공합니다. 이를 통해 로컬 개발 환경에서 직접 클러스터의 내부 리소스에 접근할 수 있습니다. 이미 kubectl 명령어를 실행하기 위하여 API 서버 포트가 연결되어 있으므로 간단한 설정만으로 클러스터 내부 포트에 연결할 수 있습니다. 로컬 시스템의 지정된 포트로 들어오는 트래픽은 API 서버를 통해 선택한 Pod의 특정 포트로 전달됩니다.

쿠버네티스 API 서버는 이 과정에서 중개자 역할을 하며, 실제 트래픽의 전달은 kubelet이 담당합니다. 그럼 아래 명령어를 사용하여 ArgoCD 파드로 접속합니다.

[jerry:~ (jerry:argocd)]$ k get service argocd-server
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
argocd-server   ClusterIP   10.233.37.108   <none>        80/TCP,443/TCP   43d

[jerry:~ (jerry:argocd)]$ k port-forward svc/argocd-server 8080:80
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

쿠버네티스는 서비스(service) 객체로 파드 트래픽을 제어합니다. port-forward 역시 파드 대신 서비스를 이용하면 편리합니다. 서비스에 대한 자세한 설명은 이어지는 장에서 다룹니다.

‘8080:80’ 명령어의 앞 8080 포트는 로컬호스트의 포트를 의미하고 뒤 80 포트는 클러스터 서비스가 사용하는 80 포트를 의미합니다. 즉 내 로컬호스트의 8080 포트를 클러스터 서비스의 80 포트로 연결하라는 의미입니다. 이제 아래와 같이 브라우저에 ‘localhost:8080’를 입력하면 ArgoCD 화면을 확인할 수 있습니다.

초기 ‘admin’ 사용자의 패스워드는 Secret로 확인할 수 있습니다. Secret은 패스워드 등과 민감한 정보를 저장하는 쿠버네티스 객체입니다. 자세한 설명은 앞으로 이어지는 글에서 다루며 지금은 아래와 같이 디코딩하여 평문으로 패스워드를 확인합니다.

[(jerry-test:argocd) ~]$ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
RNTP10IXD2P3uSWg

로그인 창에 Username admin을 입력하고 Password에 위 명령어 출력 결과를 입력합니다. 로그인 후 화면 왼편 메뉴의 ‘Settings’-’Repositories’를 선택하면 헬름 Values 파일에 설정한 깃허브 레포지토리가 정상으로 등록된 것을 확인할 수 있습니다.

ArgoCD를 정상으로 설치하였습니다.

4. Argo-CD를 이용하여 NGINX 헬름 배포

이제 설치한  ArgoCD를 이용하여 애플리케이션을 배포합니다. 애플리케이션은 웹서버 용도로 많이 사용하는 Nginx입니다. 

Nginx 역시 헬름 차트를 이용하여 배포합니다.

[jerry:k8s-class (jerry:argocd)]$ mkdir nginx-webserver && cd nginx-webserver
[jerry:nginx-webserver (jerry:argocd)]$ helm pull oci://registry-1.docker.io/bitnamicharts/nginx --version 15.1.0
[jerry:nginx-webserver (jerry:argocd)]$ tar xvfz nginx-15.1.0.tgz
[jerry:nginx-webserver (jerry:argocd)]$ rm -rf nginx-15.1.0.tgz
[jerry:nginx-webserver (jerry:argocd)]$ mv nginx nginx-web15.1.0
[jerry:nginx-webserver (jerry:argocd)]$ mkdir ci && cp values.yaml ci/my-values.yaml

이전과 동일하게 헬름을 설치하는 과정입니다. Nginx 웹서버 버전은 최신 버전을 사용해도 괜찮지만 필자와 동일한 구성을 원하면 버전 정보(15.1.0)을 지정합니다.

헬름 Values.yaml 파일을 간단히 아래와 같이 수정합니다. 해당 파일은 필자의 깃헙에서 확인할 수 있습니다.

replicaCount: 2
service:
  type: ClusterIP
metrics:
  enabled: true

기본 설정에서 Nginx 웹서버의 파드 수량을 2개로 변경하는 등 간단한 변경입니다. 해당 헬름 Values 파일을 기준으로 Nginx 웹서버를 배포합니다. ArgoCD는 애플리케이션을 쿠버네티스 환경에 배포하기 위하여 GUI 웹에서 작업이 가능합니다. 하지만 다시 사용하기 용이하고 GitOps에 적합하게 애플리케이션 배포 설정도 코드로 하는 것을 추천합니다.

ArgoCD는 코드로 배포할 수 있도록 ‘Application’이라는 CRD(Custom Resource Definition)를 사용합니다. CRD는 쿠버네티스에서 사용자 정의 리소스를 정의하기 위한 기능입니다. 쿠버네티스는 기본적으로 파드, 서비스, 디플로이먼트 등과 같은 핵심 리소스를 제공하지만, 사용자는 이 외에도 독자적인 리소스 유형을 정의하고 사용할 수 있습니다. 

CRD를 사용하면 사용자는 자신만의 리소스 유형을 정의하고, 이를 클러스터에서 마치 내장된 리소스처럼 사용할 수 있습니다. ArgoCD에서도 애플리케이션 배포를 용이하게 ‘Application’이라는 자체 리소스를 제공합니다.

그럼 Nginx 웹서버를 배포하기 위한 ArgoCD Application를 만들겠습니다. (필자 깃헙)

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx
  namespace: argocd
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  destination:
    namespace: nginx
    server: https://kubernetes.default.svc
  project: default
  source:
    helm:
      valueFiles:
      - ci/my-values.yaml
    path: nginx-webserver/nginx-15.1.0
    repoURL: https://github.com/junghoon2/k8s-class.git
    targetRevision: HEAD
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true

. metadata.finalizers

‘Application’ 리소스를 삭제하면 관련된 쿠버네티스 리소스(파드 등)까지 같이 삭제하는 옵션니다. 

. spec.destination.server

 ArgoCD가 애플리케이션을 배포하는 목적지를 지정합니다. 원격 쿠버네티스 클러스터도 지정할 수 있고 ArgoCD가 설치된 쿠버네티스도 지정할 수 있습니다.  주소를 ‘https://kubernetes.default.svc’ 지정하면 ArgoCD가 설치된 쿠버네티스로 지정합니다.

. spec.source.helm

ArgoCD는 애플리케이션 설치 형태를 헬름, 매니페스트 등을 지원합니다. 이번 실습에서 Nginx를 헬름으로 설치하므로 ‘helm’으로 지정하였습니다.

. spec.source.path, repoURL

헬름 차트가 위치한 깃허브 레포지토리 URL과 해당 헬름 차트 경로를 지정합니다.

.spec.syncPolicy.automated.prune/selfHeal

ArgoCD에서 자동으로 애플리케이션을 배포할지 지정하는 옵션입니다. 깃에 소스가 올라가면 자동으로 쿠버네티스에 헬름을 배포하고 싶으면 ‘automated’ 옵션을 지정합니다. 

실제 현업에서 Dev, Stage 환경에서는 automated 옵션을 사용하고 운영 환경에서는 수동으로 변화(‘Diff’) 내역을 확인하고 배포하기 위하여 automated 옵션을 사용하지 않는 경우도 많습니다.

prune은 깃에서 코드를 삭제하면 실제 리소스도 같이 삭제하는 옵션이며 selfHeal 옵션은 실패한 작업을 자동으로 복구합니다.

. spec.syncOptions.CreateNamespace

네임스페이스를 자동으로 생성하는 옵션입니다.

Application CRD도 같은 쿠버네티스 리소스이므로 ‘k apply’ 명령어로 리소스를 생성할 수 있습니다.

$ k apply -f nginx-webserver/nginx-15.1.0/cd/my-application.yaml 
application.argoproj.io/nginx created

Argocd ‘Application’ 이라는 별도의 쿠버네티스 객체가 생성되었습니다. ArgoCD의 Application이란 일반적으로 프로그램 Application이 아니라 ArgoCD에서 자체 생성한 쿠버네티스 객체의 한 종류입니다.

[(jerry-test:argocd) cd]$ k get applications -n argocd nginx
NAME    SYNC STATUS   HEALTH STATUS
nginx   Synced        Healthy

ArgoCD 웹에서 화면 왼편 메뉴의 ‘Applications’를 확인하면 새롭게 argocd/nginx가 생성된 것을 확인할 수 있습니다.

해당 메뉴를 클릭하면 NGINX 헬름 차트로 설치한 쿠버네티스 리소스를 확인할 수 있습니다. Service, Deploy가 설치되었습니다.

설치된 Nginx 웹서버 파드는 명령어로도 확인할 수 있습니다.

[jerry:~ (jerry:nginx)]$ k get pod -n nginx
NAME                     READY   STATUS    RESTARTS      AGE
nginx-7979bfc556-4twdt   2/2     Running   2 (35d ago)   35d
nginx-7979bfc556-cvg5w   2/2     Running   1 (35d ago)   35d

위와 같이 ArgoCD를 이용하여 애플리케이션 파드를 배포할 수 있습니다. 

최초 ArgoCD 배포 시 로컬 PC에서 ‘helm install’ 명령어를 사용하여 애플리케이션을 배포하였습니다. 이 후 ArgoCD를 배포한 후 NGINX는 ‘helm install’ 명령어가 아니라 ArgoCD를 이용하여 NGINX 애플리케이션을 배포하였습니다. 

로컬 PC에서 명령어로 설치한 애플리케이션은 Git에 저장하지 않을 수 있어 향후 관리가 어렵습니다. 하지만 ArgoCD를 이용하면 깃에 소스를 올리고 배포하는 것을 강제할 수 있어 깃옵스 정책을 적용하기가 용이합니다. 쿠버네티스에서 설치하는 모든 애플리케이션은 ArgoCD를 이용하여 배포하는 것을 권고합니다. 

ArgoCD는 UI를 지원하여 Helm으로 어떤 리소스를 설치하였는지 확인할 수 있어 편리합니다.

5. GitOps 실습

그럼 실제 운영(Ops) 중인 상태와 깃(Git) 상태를 다르게 하여 ArgoCD가 어떻게 GitOps를 구현하는지 알아보겠습니다.

소스가 아니라 명령어를 사용하여 NGINX 파드의 숫자를 2개에서 5개로 변경합니다. 로컬의 콘솔 창을 2개로 나누고 위에서는 파드의 숫자를 변경하고 아래에서는 변경 사항을 실시간으로 확인하겠습니다.

아래 창은 아래와 같이 ‘k get pod -w(watch)’ 명령어로 파드의 변경 사항을 실시간으로 확인합니다.

# nginx 네임스페이스로 변경합니다.
$ (⎈ |switch-singapore-test:echoserver) k ns nginx
Context "switch-singapore-test" modified.
Active namespace is "nginx".

$ (⎈ |switch-singapore-test:nginx) k get pod -w
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7979bfc556-7bz89   2/2     Running   0          6m30s
nginx-7979bfc556-gb7t2   2/2     Running   0          6m30s

위 창에서 파드 숫자를 변경합니다. 파드 숫자 변경은 명령어로 scale을 사용합니다.

$ (⎈ |switch-singapore-test:nginx) k scale deployment nginx --replicas 5
deployment.apps/nginx scaled

명령어로 파드의 숫자를 5개로 지정하였으나 파드는 증가하지 않습니다.  ‘ContainerCreating’과 동시에 ‘Terminating ‘ 되었습니다.

$ (⎈ |switch-singapore-test:nginx) k get pod -w
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7979bfc556-7bz89   2/2     Running   0          6m30s
nginx-7979bfc556-gb7t2   2/2     Running   0          6m30s

nginx-7979bfc556-8btj2   0/2     Pending   0          0s
nginx-7979bfc556-8btj2   0/2     Pending   0          0s
nginx-7979bfc556-85x5c   0/2     Pending   0          0s
nginx-7979bfc556-sqd4j   0/2     Pending   0          0s
nginx-7979bfc556-85x5c   0/2     Pending   0          0s
nginx-7979bfc556-8btj2   0/2     ContainerCreating   0          0s
nginx-7979bfc556-sqd4j   0/2     Pending             0          0s
nginx-7979bfc556-85x5c   0/2     ContainerCreating   0          0s
nginx-7979bfc556-sqd4j   0/2     ContainerCreating   0          0s
nginx-7979bfc556-sqd4j   0/2     Terminating         0          1s
nginx-7979bfc556-85x5c   0/2     Terminating         0          1s
nginx-7979bfc556-8btj2   0/2     Terminating         0          1s

파드의 숫자는 여전히 2개입니다. 왜 그럴까요?

$ (⎈ |switch-singapore-test:nginx) k get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7979bfc556-7bz89   2/2     Running   0          8m46s
nginx-7979bfc556-gb7t2   2/2     Running   0          8m46s

왜냐하면 깃소스에서 파드의 수량을 수정하지 않아서 ArgoCD가 자동으로 현재의 클러스터 상태를 깃에 동기화된 소스의 상태와 자동으로 맞추기 위하여 항상 2개로 유지하기 때문입니다. 

그럼, 차이를 확인하기 위하여 ArgoCD에서 ‘automated’ 옵션을 제거하겠습니다. ‘automated’ 옵션은 자동으로 현재의 상태와 깃의 상태를 맞추는 옵션입니다. 해당 옵션을 제거하면 ArgoCD가 현재의 상태를 자동으로 수정하지 않습니다. 

다시 ‘k scale deployment nginx –replicas 5’ 명령어를 실행하고 ArgoCD 웹으로 확인하면 ‘OutOfSync’입니다. 문구에서 확인할 수 있듯이 현재 깃에 저장된 소스의 상태가 운영중인 클러스터의 현재 상태와 서로 Sync 상태가 아닌 것을 확인할 수 있습니다.

<OutOfSync>

메뉴의 ‘APP DIFF’를 확인하면 자세한 메시지를 확인할 수 있습니다.

‘replicas’, 파드의 레플리카 숫자가 5개와 2개로 서로 차이나는 것을 알 수 있습니다. 

실무 운영 환경에서는 위와 같이 ‘automated’ 옵션을 비활성화하고 사용하기도 합니다. 항상 ‘Diff’를 수동으로 확인하여 작업 이상 유무를 체크하고 실제 클러스터에 반영하는 과정을 거칩니다. 

정리하면 작업자가 깃소스가 아닌 임의로 명령어로 파드의 수량을 변경하여도 ‘Automated’ 옵션이 활성화되어 있으면 ArgoCD가 자동으로 현재의 상태를 깃 소스와 동기화하여 파드의 숫자를 2개로 유지합니다.

그럼 이제 반대로 깃 소스에서 파드의 숫자를 2개에서 1개로 변경하겠습니다. NGINX 헬름 value 파일의 ‘replicaCount’ 옵션을 변경합니다.

replicaCount: 1 # 2 to 1개로 변경

Git commit 후 push 하여 Git main으로 merge 합니다. 아래는 필자가 사용하는 VSCode Git Commit 화면 예시입니다.

ArgoCD 메뉴에서 ‘REFRESH’하면 파드의 숫자가 자동으로 1개로 줄어들었습니다.

kubectl 명령어로 확인해도 파드의 숫자가 1개로 줄었습니다.

$ (⎈ |switch-singapore-test:nginx) k get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7979bfc556-gb7t2   2/2     Running   0          25m

이처럼 ArgoCD는 깃소스에 반영된 상태를 실제 운영 쿠버네티스 상태와 서로 동기화합니다. 모든 변경 작업을 명령어 혹은 로컬의 소스에서 임의로 하지 않고 중앙화된 깃저장소에서만 작업이 이루어지게 할 수 있습니다. 

이와 유사하게 테라폼을 사용하는 인프라 작업도 Git PR Review 거쳐서 실제 상태에 반영합니다.

위 스크린샷은 EKS 업그레이드 작업 시 실제로 사용한 필자의 PR Review 메시지입니다. EKS 업그레이드를 위한 테라폼 코드 작업을 리뷰를 통하여 동료에게 검증한 사례입니다. 미리 작업 관련 코드를 검증하여 작업 중 발생할 수 있는 장애를 줄일 수 있었습니다. 검증된 코드를 main으로 merge하여 실제 상태에 반영하게 하였습니다.

테라폼 코드 이 외 작업을 위한 파이썬 코드도 동일하게 깃에 저장하여 리뷰를 받습니다.

import boto3

regions = ["ap-northeast-2", "us-west-2", "ap-northeast-1", "us-east-1"]

for region in regions:
    session = boto3.Session(region_name=region)
    client = session.client("kafka")

    # to print region name
    print(f"{region}")

    # Get a list of all clusters
    response = client.list_clusters()

    # Loop through the instances and print out their details
    for instance in response["ClusterInfoList"]:
        # Get the type, state, and launch time
        ClusterName = instance["ClusterName"]
        InstanceType = instance["BrokerNodeGroupInfo"]["InstanceType"]
        NumberOfBrokerNodes = instance["NumberOfBrokerNodes"]
        CreationTime = instance["CreationTime"].strftime("%Y-%m-%d %H:%M:%S")
        State = instance["State"]

        # Print out the instance information in a formatted string
        print(
            f"{ClusterName}, {InstanceType}, {NumberOfBrokerNodes}ea brokers, {CreationTime}, {State}"
        )

위 예제는 각 리전 별 전체 AWS MSK Cluster 리스트를 출력하는 파이썬 코드입니다.

물론 실제 운영을 하면 모든 작업에 대하여 코드 리뷰를 받기는 시간 제약 상 어렵습니다. 하지만 모든 작업은 사전에 코드를 작성하고 해당 코드를 기반으로 문서를 작성해서 동료에게 사전 리뷰를 받는 프로세스를 정착하는 것이 시스템을 안정적으로 운영하는데 효과적입니다. 그리고 적어도 모든 작업 내역은 코드로 남겨두는 것이 향후 동일한 작업을 수행할 때 큰 도움이 되므로 꼭 남겨두는 것을 권고합니다. 

지금까지 ArgoCD 깃옵스 사례를 공유하였습니다. 깃옵스는 정책이므로 이를 지키는 의지가 중요합니다. 코드 리뷰를 충실하게 하고 번거로워도 작업 절차를 지키는 매일의 노력이 필요합니다.

해당 기술 블로그에 질문이 있으시면 언제든지 문의해 주세요. 직접 답변해 드립니다.
k8sqna@jennifersoft.com

1. CI/CD 도구로 CI는 Github Actions, CD는 ArgoCD가 가장 많이 사용하는 추세입니다.
2. 윈도우 Ubuntu 사용자도 homebrew를 사용할 수 있습니다. homebrew를 사용하지 않는 사용자는 apt, yum 등으로 헬름을 설치할 수 있습니다. 헬름 설치 참조 : https://helm.sh/docs/intro/install/#from-apt-debianubuntu 

Next

Contact Us

안녕하세요? 제니퍼소프트입니다.
기술 문의의 경우 질문자의 회사/이름/연락처를 본문에 기술해 주셔야만 원할한 지원이 가능합니다.
보내주신 문의 사항을 검토하여 빠른 시일 내에 답변해 드리겠습니다.

  • Chris
  • Irene

메일을 보냈습니다.

메일 전송이 완료되었습니다.
빠른 시일 내에 답변드리겠습니다.
감사합니다.
제니퍼소프트 웹사이트는 쿠키를 사용합니다. 쿠키에 대한 자세한 정보 및 삭제 방법은 제니퍼소프트의 개인정보처리방침을 참고하시기 바라며 본 사이트를 계속해서 이용하는 것은 제니퍼소프트의 쿠키 사용에 동의함을 의미합니다.