GitOps 와 ArgoCD · 필드의 주인은 누구인가 · 실습
내가 적용한 값이 자꾸 되돌아간다 — 필드의 주인 찾기
목표
kwok 클러스터에서 서버측 적용으로 관리자 둘을 만들고 managedFields 를 직접 읽는다. 충돌과 강제, 필드 놓아 주기, scale 하위 자원의 충돌까지 실물로 일으켜 보고, 마지막에 Argo CD 의 무시 규칙과 이어 붙인다.
왜 중요한가
GitOps 를 켜도 클러스터의 객체를 쓰는 주체는 하나가 아니다. Argo CD 가 쓰고, 오토스케일러가 replicas 를 쓰고, 웹훅이 컨테이너를 끼워 넣고, 사람이 급할 때 kubectl 로 쓴다. 서버측 적용은 '누가 이 필드의 주인인가' 를 API 서버가 기록으로 들고 있는 장치다. 이 기록을 읽을 줄 알아야 세 가지 질문에 답할 수 있다 — 왜 내 적용이 거절되는가, 왜 강제로 밀어 넣으면 다음에 상대가 거절당하는가, 왜 값을 놓아 줬는데 옛 값으로 돌아가지 않는가. 그리고 이 기록은 Argo CD 쪽으로 이어진다. 무시 규칙의 managedFieldsManagers 는 필드 경로가 아니라 이 소유 기록으로 비교 대상을 고르기 때문이다.
단계
1. kwok 클러스터에 네임스페이스 ga-ssa 를 만들고, /root/ga-ssa/deploy.yaml 에 Deployment web 을 쓰세요 — spec.replicas 2, 셀렉터와 라벨은 app: web, 컨테이너 하나(web, 이미지 nginx:1.25) 입니다. kubectl apply --server-side --field-manager=gitops 로 적용하세요.
2. kubectl -n ga-ssa get deploy web -o json --show-managed-fields 로 소유 기록을 읽어, 관리자마다 한 줄씩 <관리자> | <연산> 형식으로 /root/ga-ssa/managers.txt 에 저장하세요. gitops 가 Apply 연산으로 들어 있어야 합니다.
3. /root/ga-ssa/hotfix.yaml 에 같은 Deployment 를 쓰되 spec.replicas 는 5, 이미지는 nginx:1.27 로 하세요. --field-manager=hotfix 로 서버측 적용을 시도하고, 실패 출력을 표준오류까지 합쳐 /root/ga-ssa/conflict.txt 에 저장하세요. --force-conflicts 는 아직 쓰지 않습니다.
4. 같은 적용을 --force-conflicts 와 함께 다시 하고, 성공 출력을 /root/ga-ssa/force.txt 에 저장하세요. 이제 클러스터의 이미지는 nginx:1.27 이고, 그 필드의 주인은 hotfix 입니다.
5. /root/ga-ssa/hotfix-slim.yaml 을 만드세요 — hotfix.yaml 과 같지만 spec.replicas 줄이 없습니다. --field-manager=hotfix 로 서버측 적용한 뒤, spec.replicas 를 소유한 관리자 목록을 /root/ga-ssa/release.txt 에 저장하세요(아무도 없으면 빈 파일). 클러스터의 replicas 가 몇이 되는지 확인하세요.
6. /root/ga-ssa/web-csa.yaml 에 Deployment web-csa 를 쓰고(같은 네임스페이스, 라벨과 컨테이너 이름은 web-csa, 이미지 nginx:1.25) --server-side 없이 평범한 kubectl apply 로 올리세요. 두 Deployment(web 과 web-csa)의 metadata.annotations 키 목록을 /root/ga-ssa/csa.txt 에 저장하세요.
7. /root/ga-ssa/scale-deploy.yaml 에 Deployment web-scale(레플리카 2, 라벨과 컨테이너 이름 web-scale, 이미지 nginx:1.25)을 쓰고 --field-manager=gitops 로 서버측 적용하세요. 그다음 kubectl -n ga-ssa scale deploy web-scale --replicas=4 로 늘리고, 같은 파일을 같은 관리자 이름으로 다시 적용해 보세요. 실패 출력을 /root/ga-ssa/scale-conflict.txt 에 저장합니다.
8. /root/ga-ssa/live.yaml 에 클러스터의 web 을 소유 기록까지 포함해 YAML 로 저장하세요(-o yaml --show-managed-fields). /root/ga-ssa/argocd-cm.yaml 에 키 resource.customizations.ignoreDifferences.apps_Deployment 를 두고 managedFieldsManagers 에 hotfix, jsonPointers 에 /spec/replicas 를 적으세요. argocd admin settings resource-overrides ignore-differences /root/ga-ssa/live.yaml --argocd-cm-path /root/ga-ssa/argocd-cm.yaml 의 출력을 /root/ga-ssa/ignore.txt 에 저장하세요.
참고
kubectl get ... -o json은 managedFields 를 숨깁니다 —--show-managed-fields를 붙이세요.--field-manager로 관리자 이름을 정합니다. 기본값은 명령마다 다릅니다.- 충돌 메시지는 어떤 필드가 누구 것인지 알려 줍니다. 그 목록을 먼저 읽으세요.
- 흔한 실수:
--force-conflicts를 습관처럼 붙인다 — 소유권이 옮겨 가 다음번에 상대가 막힙니다. - 흔한 실수: 매니페스트에서 필드를 빼면 옛 값으로 돌아갈 거라 기대한다. API 기본값이 됩니다.
- 참고: https://kubernetes.io/docs/reference/using-api/server-side-apply/
단계 8개
- 이름을 밝히고 적용한다
- 소유 기록을 읽는다
- 두 번째 관리자가 같은 필드를 쓰려 하면
- 소유권을 빼앗는다
- 필드를 놓아 주면 값은 주인에게 돌아가지 않는다
- 클라이언트측 적용은 무엇을 남기나
- kubectl scale 은 다른 문으로 들어온다
- 소유자 이름으로 비교에서 빼기