What is GitOps?
개발자의 코드가 실제 서비스로 반영되기까지 많은 과정을 거쳐야 한다. Repository에 Push 후 CI를 통해 Docker Image로 빌드되고, Container Registry(ex: DockerHub)로 업로드하면 CI 과정은 끝나며 이후부턴 Kubernetes에 어떻게 배포할지 고민이 필요하다.
처음엔 Manifest 파일을 작성하고 이를 kubectl 명령어를 통해 서비스를 배포하다가, 서비스마다 일일이 Manifest 파일을 작성하기 번거롭기 때문에 Helm, kustomize 등을 활용하고, 이후 자동화를 위해 Jenkins나 Ansible 등의 툴이나 API 호출같은 방식을 택하게 된다.
문제는 사람마다 선호하는 배포 방식이 제각각이고 여러 소스(원천)로부터 Manifest가 변경된다는 점이다. 분명히 1시간 전에 이미지 태그를 1.1로 업데이트하여 배포했는데, 다시 와서 보니 누군가가 1.0으로 돌려놨다던가 하는 시나리오를 생각해볼 수 있다. 이런 경우 어디서 누가 Manifest를 변경했는지 추적하기 쉽지 않고, 다시 Manifest 파일을 원복해야 하는 수고로움이 발생한다.
GitOps는 이러한 문제를 해결하기 위해, Manifest를 가져오는 소스를 Git Repository 한 곳으로 통일하는 방식으로 문제에 접근한다. 해당 repo에 존재하는 Manifest파일과 k8s에 존재하는 리소스의 현재 상태를 계속 비교하며 Sync 작업을 수행, 만약 현재 Manifest에 정의한 리소스가 생성되지 않았으면 이를 생성하고, 일치하지 않는 경우 Spec에 맞도록 복구 작업을 수행한다. 이 모든 과정은 자동으로 진행되기 때문에 사람이 배포 과정에 개입할 여지를 최소한으로 줄인다. 더 이상 배포를 Imperative 방식이 아닌 Declarative 방식으로 수행할 수 있다는 얘기다.
GitOps 방식의 이점
Manifest가 위치한 Repository만 신경쓰면 되므로, 배포 과정을 매우 단순화시킬 수 있으며 사람의 부주의로 발생할 수 있는 Human Error을 줄인다. 그리고 터미널에서 'kubectl' 명령어를 실행하거나, 스크립트를 수정하는 등의 작업이 없어지기 때문에 더욱 빠르고 자주 배포할 수 있다.
서비스 업데이트는 해당 Manifest파일을 수정해서 Repository에 Push하는 것이 전부이며, 만약 새 버전에 문제가 있는 경우, 'git revert'를 해서 이전으로 쉽게 돌아갈 수 있다.
또한 Manifest Repository에 권한이 있는 인원만 배포 과정에 참여할 수 있으며, Manifest 파일 변경 이력이 Git에 그대로 남기 때문에 추적이 용이하다.
Argo CD
GitOps를 구현한 솔루션은 Jenkins X, Flux CD, Tekton 등 다양하지만, 이번엔 가장 많이 사용하는 Argo CD에 대해서 알아보자.
설치에 앞서 Argo CD의 Architecture와 각 Component를 이해할 필요가 있다.
Components
API Server
Argo CD의 Web UI, CLI 및 다른 CI/CD 시스템으로부터 request를 받는 API 서버이며 gRPC와 REST 방식 모두 지원한다. application 관리 및 상태 보고, sync/rollback 등의 작업 요청, repository 및 클러스터의 credential 관리, Git 웹훅 이벤트 리스너 및 포워딩 등의 기능을 담당한다.
Repository Server
application manifest가 위치한 Git Repository의 Local cache 역할을 담당하며, 아래 input 들을 통해 k8s manifest 파일을 가져올 수 있다.
- Repository URL
- Revision(commmt sha, tag, branch)
- Application(어플리케이션 구성에 필요한 manifest 파일들) Path
- 템플릿 관련 설정(Helm의 values.yaml, ksonnet environments 등)
Application Controller
application을 계속 모니터링하면서 클러스터 위의 current state와 Repository에 정의한 Manifest에 정의한 desired state를 비교, sync 작업을 수행하는 k8s controller이다. 사용자가 정의한 lifecycle event hook(PreSync, Sync, PostSync)을 호출하는 기능도 갖고 있다.
설치(Non-HA)
가장 먼저 Argo CD를 배포할 Namespace 먼저 생성하자
kubectl create namespace argocd
'argocd'가 아닌 다른 namespace를 생성할 수도 있으나, 이 경우 Argo CD Manifest 파일의 namespace 필드를 모두 수정해야함에 유의한다.
Argo CD Manifest 파일을 다운로드한다.
curl https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml -o argo-cd.yaml
공식 홈페이지는 웹에 있는 파일을 바로 apply 하도록 가이드하고 있으나, 이는 상당히 위험한 방식이다. 해당 파일에 어떤 내용이 있는지 확인하고, 환경에 맞게 수정할 필요가 있다.
우선 Manifest 파일의 'argocd-server' Service를 아래와 같이 변경한다.
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: server
app.kubernetes.io/name: argocd-server
app.kubernetes.io/part-of: argocd
name: argocd-server
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
- name: https
port: 443
protocol: TCP
targetPort: 8080
selector:
app.kubernetes.io/name: argocd-server
웹콘솔 접근을 위해 argocd-server의 Service 타입을 ClusterIP에서 NodePort로 변경하여 클러스터 외부에서 접근할 수 있게 한다. 현재 테스트 환경의 k8s는 Desktop의 VM 위에 구축되었기 때문에, Load Balancer 대신 NodePort를 사용한다.
이번엔 Argo CD CLI 툴을 다운로드하고, PATH 경로에 추가한다.
VERSION=$(curl --silent "https://api.github.com/repos/argoproj/argo-cd/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/$VERSION/argocd-linux-amd64
chmod +x /usr/local/bin/argocd
이제 모든 준비가 됐으니, k8s에 Argo CD를 배포한다.
kubectl apply -n argocd -f argo-cd.yaml
배포와 더불어 application, appproject 와 같은 Argo CD에서 정의한 CRD도 같이 생성되며 앞으로 만들 관련 리소스는 Kubernetes의 backing store인 etcd에 저장된다.
다음은 웹 콘솔 접근을 위해 NodePort를 확인한다.
kubectl get svc -n argocd argocd-server
HTTP는 32127, HTTPS는 32722번 포트로 mapping되었으며, 우리는 HTTP로 접근한다.
argocd-server의 경우, Self Signed Certificate을 사용하므로 브라우저에서 경고를 내보내는 것에 유의한다.
경고를 스킵한 후, 위 화면을 확인할 수 있다. 그런데 Username과 Password는 우리가 따로 설정한 적이 없는데 어떻게 로그인을 해야할까?
최초 생성시 Username은 admin이고, Password는 아래 명령어로 확인할 수 있다.
kubectl get pods -n argocd -l app.kubernetes.io/name=argocd-server -o name | cut -d'/' -f 2
본격적인 Argo CD 사용에 앞서, admin 계정의 비밀번호를 변경한다. 웹에선 변경할 수 없지만 CLI를 통해 가능하다. 우선 아래 명령어로 로그인부터 하자.
argocd login <ARGOCD_SERVER> #ex) localhost:32127 or myargocd.example.com, ...
다음 명령어로 현재 계정의 비밀번호를 변경할 수 있다.
argocd account update-password
이제 변경 완료한 admin 계정으로 로그인하여 Argo CD 웹 메인 화면에 접근해보자.
아직은 Application을 만들지 않았기 때문에 위와 같이 텅빈 화면만 나온다.
Argo CD Application 생성
Argo CD는 Example Apps를 통해 다양한 방식(helm, kustomize 등)으로 구성한 Application 샘플을 제공한다. 이번엔 가장 간단한 'guestbook' 예제를 통해 Application 생성을 실습해보자.
'guestbook' Application은 아래와 같이 Deployment와 Service 두 개의 리소스로 구성된다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: guestbook-ui
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app: guestbook-ui
template:
metadata:
labels:
app: guestbook-ui
spec:
containers:
- image: gcr.io/heptio-images/ks-guestbook-demo:0.2
name: guestbook-ui
ports:
- containerPort: 80
apiVersion: v1
kind: Service
metadata:
name: guestbook-ui
spec:
ports:
- port: 80
targetPort: 80
selector:
app: guestbook-ui
그리고 guestbook-ui를 브라우저로 접근할 경우, 아래와 같은 화면을 확인할 수 있다.
ArgoCD 웹콘솔 > Applications > '+NEW APP' 메뉴를 통해 새로운 Application을 생성할 수 있다.
Application Name은 'guestbook', Project는 따로 추가하지 않았으므로 'default'를 선택한다. SYNC POLICY는 'Manual'로 설정한다. 'Automatic'으로 바꿀 경우, 일정시간마다 해당 Repo를 확인하면서 자동으로 동기화 작업을 수행한다.
Repository URL은 Example Apps가 위치한 Git URL을 입력한다. Public Repo이기 때문에 별다른 인증과정은 요구하지 않지만 만약 Private Repo 또는 따로 Hosting 중인 Git Server(ex: Github Enterprise, gitlab 등)인 경우 사전에 추가 설정이 필요하다.
Revision은 HEAD를 기본으로 사용하나, 다른 브랜치 또는 태그 등을 선택할 수 있다. 이번엔 master를 지정하겠다.
Path는 해당 repo 및 revision에서 Application 생성에 사용할 Manifest가 있는 디렉토리를 의미한다. Example Apps repo는 다양한 Application 디렉토리가 존재하지만 우리는 'guestbook' app을 선택한다.
Application이 배포될 곳으로 현재 ArgoCD가 배포된 k8s Cluster를 선택한다. 'default' Namespace에 배포하되 다른Namespace를 사용하고 싶은 경우 미리 생성하거나, 'AUTO-CREATE NAMESPACE' 옵션을 활성화하자.
마지막으로 디렉토리 관련 설정이다. DIRECTORY RECURSE의 경우, Path로 지정한 디렉토리의 하위 경로까지 모두 확인하여 Manifest 파일을 생성하는 옵션으로 복잡한 Application 배포에 적합하다.
이제 모든 정보를 입력하였으니 상단의 CREATE 버튼을 눌러서 생성을 하자.
우리가 방금 만든 guest App이 OutOfSync 상태인 것을 확인할 수 있다. 참고로 웹 콘솔이 아닌 CLI에서도 App 정보를 확인할 수 있다.
SYNC 버튼을 눌러서 동기화 작업을 수행할 수 있으며, 어떤 Resource가 동기화될지 선택 가능하다.
SYNCHRONIZE 버튼을 눌러서 확인을 완료하면 실제 동기화 작업이 이루어지며, 웹 상에서 아래와 같이 현재 App 상태를 보여준다.
guestbook App을 선택하면, Application Details 메뉴로 이동할 수 있다.
해당 메뉴에선 Application이 어떤 리소스로 구성되어 있는지 확인이 가능하며, 각 리소스를 선택하여 상태와 이벤트 로그 등을 볼 수 있다.
이번엔 리소스가 k8s 클러스터에 실제로 생성되었는지 확인해보자.
Deployment(guestbook-ui), Service(guestbook-ui)가 모두 정상적으로 생성되었음을 알 수 있다.
마치며...
이번 페이지에선 GitOps의 개념과 ArgoCD 설치 및 기본 사용법에 대해 알아보았다. 필자도 처음 ArgoCD를 접했을 땐 그 필요성에 많은 의구심을 품었으나, 일부 서비스에 대해 시범적으로 적용해보고 익숙해지면서 지금은 맡고 있는 프로젝트에 요긴하게 사용하고 있다. 한번 세팅하고 나면 배포 과정에 사람이 개입할 일이 크게 줄기 때문이다.
다음엔 Jenkins와 연동하여 CI/CD 파이프라인을 구성하는 방법에 대해서 작성할 예정이다.
참고
GitOps - gitops.tech
Architectural Overview
Getting Started
'CI-CD' 카테고리의 다른 글
Jenkins Pipeline (0) | 2021.03.01 |
---|---|
kustomize를 활용한 Manifest 관리 (0) | 2021.02.24 |
CD를 위한 Jenkins, Argo CD 연계 (0) | 2021.02.21 |
CI를 위한 Jenkins, GitHub, Docker Hub 연계 (0) | 2021.02.20 |
Kubernetes 위에 Jenkins 설치하기 (0) | 2021.02.19 |