LabHub
배우기 러닝패스 코스

GitOps and Argo CD

Building a Manifest Repository and Catching Drift

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

매니페스트를 담은 git 저장소를 만들어 클러스터에 적용하고, 손으로 만든 변경(드리프트)을 감지해 저장소 기준으로 되돌릴 수 있게 됩니다.

왜 중요한가

GitOps 의 규칙은 한 문장입니다 — 저장소가 옳고 클러스터가 따라온다. 이 문장을 지키는 순간 "지금 프로덕션에 뭐가 떠 있나"라는 질문이 git log 로 답할 수 있는 질문이 되고, 롤백은 git revert 라는 평범한 작업이 됩니다. 반대로 클러스터를 직접 고치는 습관이 하나라도 남아 있으면 저장소는 현실을 설명하지 못하는 문서가 되고, 그 순간부터 재현이 불가능해집니다. 이 실습에서 kubectl diff 를 반복해서 쓰는 이유가 여기 있습니다 — diff 는 "선언과 실제가 얼마나 벌어졌나"를 종료 코드로 답해 주는 드리프트 계측기이고, ArgoCD 가 화면에 OutOfSync 라고 띄우는 것과 정확히 같은 판단을 사람 손으로 하는 것입니다. 이 환경에는 ArgoCD 컨트롤러가 돌지 않으므로, 그 컨트롤러가 대신 해 주는 일을 마지막 단계에서 직접 스크립트로 작성해 봅니다.

단계

  1. /root/gitops/repo 디렉터리를 만들어 git init 하고, 그 저장소에 user.nameuser.email 을 설정하세요. 그다음 /root/gitops/repo/README.md 를 만들어 첫 커밋을 남기세요 (커밋이 최소 하나 있어야 합니다).
  2. /opt/lab/fixtures/gitops/seed/deployment.yamlservice.yaml/root/gitops/repo/apps/web/ 로 복사하세요. Deployment 는 metadata.labelsapp.kubernetes.io/managed-by: gitops 를 갖고, spec.selector.matchLabelsapp.kubernetes.io/nameweb 이어야 하며, spec.replicas기본값에 맡기지 말고 명시해야 합니다(여기서는 2 로 시작합니다). 컨테이너 이미지는 nginx:1.27 처럼 태그가 고정된 값이어야 합니다 (:latest 는 실패 처리됩니다). README.md 도 그대로 있어야 합니다.
  3. apps/web/deployment.yaml, apps/web/service.yaml, README.md 세 파일을 모두 git add 해 추적시키고, 10자 이상의 의미 있는 메시지로 커밋하세요. 마치면 git status --porcelain 출력이 비어 있어야 합니다.
  4. kubectl apply -n gitops-lab -f /root/gitops/repo/apps/web/ 로 적용하고, 그 출력 전체를 /root/gitops/out/apply.txt 에 저장하세요. 적용 후 gitops-lab 네임스페이스에 Deployment web 과 Service web 이 있어야 하고, Deployment 에 app.kubernetes.io/managed-by=gitops 라벨이 붙어 있어야 합니다.
  5. 저장소의 apps/web/deployment.yaml 에서 spec.replicas3 으로 고치고, 커밋 메시지에 replicas 라는 단어를 넣어 커밋한 뒤 클러스터에 다시 적용하세요. 끝나면 커밋이 2개 이상이고, 저장소와 클러스터의 replicas 가 둘 다 3 이며, 작업 트리가 깨끗해야 합니다.
  6. 이번에는 저장소를 건드리지 말고 kubectl scale deploy web -n gitops-lab --replicas=5 로 드리프트를 만드세요. 그 상태에서 kubectl diff -n gitops-lab -f /root/gitops/repo/apps/web/ 의 출력을 /root/gitops/out/drift-diff.txt 로, 그 명령의 종료 코드/root/gitops/out/drift-exit.txt 로 저장하세요. 그리고 /root/gitops/out/drift-note.txt 에 손으로 한 변경이 다음 적용에서 되돌려져 사라진다는 내용을 한국어로 두세 줄 적으세요.
  7. 저장소 기준으로 다시 적용해 드리프트를 없애세요. 그다음 kubectl diff -n gitops-lab -f /root/gitops/repo/apps/web/ 를 한 번 더 실행해 그때의 종료 코드/root/gitops/out/clean-exit.txt 에 저장하세요. 손으로 만든 5 를 저장소에 반영하면 안 됩니다 — 저장소의 replicas 는 3 이고 작업 트리는 깨끗해야 합니다.
  8. /root/gitops/sync.sh 를 만들고 실행 권한을 주세요. 이 스크립트는 (a) kubectl diff 로 적용 전 차이를 확인하고, (b) kubectl apply 로 적용하고, (c) git rev-parse HEAD 로 어떤 커밋을 적용했는지 기록해야 합니다. 실행 결과로 /root/gitops/out/sync-report.jsonrepo_commit(현재 HEAD 의 전체 해시), drift(불리언 false), applied(적용한 오브젝트 수, 2 이상) 세 키를 담으세요.

참고

선언을 담을 저장소 초기화하기

/root/gitops/repo 디렉터리를 만들어 git init 하고, 그 저장소에 user.nameuser.email 을 설정하세요. 그다음 /root/gitops/repo/README.md 를 만들어 첫 커밋을 남기세요 (커밋이 최소 하나 있어야 합니다).

GitOps 에서 커밋 이력은 곧 감사 기록입니다. 저장소에 누가 바꿨는지가 남으려면 user.nameuser.email 이 그 저장소에 설정돼 있어야 하고, 커밋이 최소 하나 있어야 합니다.

앱별 매니페스트 디렉터리 만들기

/opt/lab/fixtures/gitops/seed/deployment.yamlservice.yaml/root/gitops/repo/apps/web/ 로 복사하세요. Deployment 는 metadata.labelsapp.kubernetes.io/managed-by: gitops 를 갖고, spec.selector.matchLabelsapp.kubernetes.io/nameweb 이어야 하며, spec.replicas기본값에 맡기지 말고 명시해야 합니다(여기서는 2 로 시작합니다). 컨테이너 이미지는 nginx:1.27 처럼 태그가 고정된 값이어야 합니다 (:latest 는 실패 처리됩니다). README.md 도 그대로 있어야 합니다.

픽스처를 복사해 쓰되, 저장소는 사람도 읽습니다. 그리고 기본값에 기대지 말고 개수와 이미지 태그를 명시하세요 — 같은 커밋이 다른 결과를 낳으면 그 저장소는 상태를 정의하지 못합니다. 셀렉터가 파드 라벨과 맞는지도 확인하세요.

선언을 커밋으로 못 박기

apps/web/deployment.yaml, apps/web/service.yaml, README.md 세 파일을 모두 git add 해 추적시키고, 10자 이상의 의미 있는 메시지로 커밋하세요. 마치면 git status --porcelain 출력이 비어 있어야 합니다.

추적되지 않은 파일이 남아 있으면 저장소는 클러스터를 정의하지 못합니다. 커밋 메시지는 몇 달 뒤 이 한 줄만 보고 되돌릴지 판단하게 되는 문장입니다.

저장소의 선언을 클러스터에 적용하기

kubectl apply -n gitops-lab -f /root/gitops/repo/apps/web/ 로 적용하고, 그 출력 전체를 /root/gitops/out/apply.txt 에 저장하세요. 적용 후 gitops-lab 네임스페이스에 Deployment web 과 Service web 이 있어야 하고, Deployment 에 app.kubernetes.io/managed-by=gitops 라벨이 붙어 있어야 합니다.

디렉터리 전체를 한 번에 적용할 수 있습니다. 매니페스트에 네임스페이스가 적혀 있지 않으니 명령에서 지정해야 하고, 적용 결과는 파일로 남겨야 합니다.

변경을 커밋을 거쳐 반영하기

저장소의 apps/web/deployment.yaml 에서 spec.replicas3 으로 고치고, 커밋 메시지에 replicas 라는 단어를 넣어 커밋한 뒤 클러스터에 다시 적용하세요. 끝나면 커밋이 2개 이상이고, 저장소와 클러스터의 replicas 가 둘 다 3 이며, 작업 트리가 깨끗해야 합니다.

순서가 핵심입니다. 저장소를 먼저 고치고 커밋한 다음 적용합니다. 클러스터를 먼저 고치면 그것은 변경이 아니라 드리프트입니다.

손으로 바꿔 드리프트 만들어 보기

이번에는 저장소를 건드리지 말고 kubectl scale deploy web -n gitops-lab --replicas=5 로 드리프트를 만드세요. 그 상태에서 kubectl diff -n gitops-lab -f /root/gitops/repo/apps/web/ 의 출력을 /root/gitops/out/drift-diff.txt 로, 그 명령의 종료 코드/root/gitops/out/drift-exit.txt 로 저장하세요. 그리고 /root/gitops/out/drift-note.txt 에 손으로 한 변경이 다음 적용에서 되돌려져 사라진다는 내용을 한국어로 두세 줄 적으세요.

이번엔 일부러 저장소를 건드리지 않고 클러스터만 바꿉니다. 차이를 보여 주는 명령의 종료 코드가 무엇인지가 이 단계의 핵심이고, 그 코드는 명령 바로 다음에 읽어야 합니다.

저장소 기준으로 되돌리기

저장소 기준으로 다시 적용해 드리프트를 없애세요. 그다음 kubectl diff -n gitops-lab -f /root/gitops/repo/apps/web/ 를 한 번 더 실행해 그때의 종료 코드/root/gitops/out/clean-exit.txt 에 저장하세요. 손으로 만든 5 를 저장소에 반영하면 안 됩니다 — 저장소의 replicas 는 3 이고 작업 트리는 깨끗해야 합니다.

손으로 만든 값을 저장소에 몰래 반영하면 사고를 코드로 승격시키는 것입니다. 저장소가 옳다고 가정하고 클러스터를 맞춘 뒤, 차이가 없을 때의 종료 코드를 확인하세요.

동기화 스크립트와 보고서 만들기

/root/gitops/sync.sh 를 만들고 실행 권한을 주세요. 이 스크립트는 (a) kubectl diff 로 적용 전 차이를 확인하고, (b) kubectl apply 로 적용하고, (c) git rev-parse HEAD 로 어떤 커밋을 적용했는지 기록해야 합니다. 실행 결과로 /root/gitops/out/sync-report.jsonrepo_commit(현재 HEAD 의 전체 해시), drift(불리언 false), applied(적용한 오브젝트 수, 2 이상) 세 키를 담으세요.

컨트롤러가 하는 일을 셸로 흉내 냅니다. 적용 전에 무엇이 바뀔지 보고, 적용하고, 어떤 커밋을 적용했는지 남깁니다. 스크립트를 저장소 안에 두면 보고서에 적은 해시가 어긋납니다.