应用的值老是被还原——找出字段的主人
한국어 원문으로 표시합니다.
목표
kwok 클러스터에서 서버측 적용으로 관리자 둘을 만들고 managedFields 를 직접 읽는다. 충돌과 강제, 필드 놓아 주기, scale 하위 자원의 충돌까지 실물로 일으켜 보고, 마지막에 Argo CD 의 무시 규칙과 이어 붙인다.
왜 중요한가
GitOps 를 켜도 클러스터의 객체를 쓰는 주체는 하나가 아니다. Argo CD 가 쓰고, 오토스케일러가 replicas 를 쓰고, 웹훅이 컨테이너를 끼워 넣고, 사람이 급할 때 kubectl 로 쓴다. 서버측 적용은 '누가 이 필드의 주인인가' 를 API 서버가 기록으로 들고 있는 장치다. 이 기록을 읽을 줄 알아야 세 가지 질문에 답할 수 있다 — 왜 내 적용이 거절되는가, 왜 강제로 밀어 넣으면 다음에 상대가 거절당하는가, 왜 값을 놓아 줬는데 옛 값으로 돌아가지 않는가. 그리고 이 기록은 Argo CD 쪽으로 이어진다. 무시 규칙의 managedFieldsManagers 는 필드 경로가 아니라 이 소유 기록으로 비교 대상을 고르기 때문이다.
단계
- kwok 클러스터에 네임스페이스
ga-ssa를 만들고,/root/ga-ssa/deploy.yaml에 Deploymentweb을 쓰세요 —spec.replicas2, 셀렉터와 라벨은app: web, 컨테이너 하나(web, 이미지nginx:1.25) 입니다.kubectl apply --server-side --field-manager=gitops로 적용하세요. kubectl -n ga-ssa get deploy web -o json --show-managed-fields로 소유 기록을 읽어, 관리자마다 한 줄씩<관리자> | <연산>형식으로/root/ga-ssa/managers.txt에 저장하세요.gitops가Apply연산으로 들어 있어야 합니다./root/ga-ssa/hotfix.yaml에 같은 Deployment 를 쓰되spec.replicas는 5, 이미지는nginx:1.27로 하세요.--field-manager=hotfix로 서버측 적용을 시도하고, 실패 출력을 표준오류까지 합쳐/root/ga-ssa/conflict.txt에 저장하세요.--force-conflicts는 아직 쓰지 않습니다.- 같은 적용을
--force-conflicts와 함께 다시 하고, 성공 출력을/root/ga-ssa/force.txt에 저장하세요. 이제 클러스터의 이미지는nginx:1.27이고, 그 필드의 주인은hotfix입니다. /root/ga-ssa/hotfix-slim.yaml을 만드세요 —hotfix.yaml과 같지만spec.replicas줄이 없습니다.--field-manager=hotfix로 서버측 적용한 뒤,spec.replicas를 소유한 관리자 목록을/root/ga-ssa/release.txt에 저장하세요(아무도 없으면 빈 파일). 클러스터의 replicas 가 몇이 되는지 확인하세요./root/ga-ssa/web-csa.yaml에 Deploymentweb-csa를 쓰고(같은 네임스페이스, 라벨과 컨테이너 이름은web-csa, 이미지nginx:1.25)--server-side없이 평범한kubectl apply로 올리세요. 두 Deployment(web과web-csa)의metadata.annotations키 목록을/root/ga-ssa/csa.txt에 저장하세요./root/ga-ssa/scale-deploy.yaml에 Deploymentweb-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에 저장합니다./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/
이름을 밝히고 적용한다
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 로 적용하세요.
--field-manager 는 '이 변경을 누가 했는가' 를 API 서버에 알려 주는 이름입니다. 서버측 적용은 이 이름별로 어떤 필드를 소유하는지 기록해 둡니다 — 클라이언트측 적용에는 없는 개념입니다.
소유 기록을 읽는다
kubectl -n ga-ssa get deploy web -o json --show-managed-fields 로 소유 기록을 읽어, 관리자마다 한 줄씩 <관리자> | <연산> 형식으로 /root/ga-ssa/managers.txt 에 저장하세요. gitops 가 Apply 연산으로 들어 있어야 합니다.
이 옵션을 빼면 .metadata.managedFields 가 null 로 나옵니다 — kubectl 이 기본으로 감추기 때문입니다. jq 로 배열을 돌면서 manager 와 operation 을 뽑으세요.
두 번째 관리자가 같은 필드를 쓰려 하면
/root/ga-ssa/hotfix.yaml 에 같은 Deployment 를 쓰되 spec.replicas 는 5, 이미지는 nginx:1.27 로 하세요. --field-manager=hotfix 로 서버측 적용을 시도하고, 실패 출력을 표준오류까지 합쳐 /root/ga-ssa/conflict.txt 에 저장하세요. --force-conflicts 는 아직 쓰지 않습니다.
서버는 '이 필드는 다른 사람이 들고 있다' 며 거절하고, 어떤 필드인지 목록으로 알려 줍니다. 이 거절이 없으면 두 자동화가 서로의 값을 조용히 덮어쓰게 됩니다. 정답지에서 실패로 멈추지 않게 조심하세요.
소유권을 빼앗는다
같은 적용을 --force-conflicts 와 함께 다시 하고, 성공 출력을 /root/ga-ssa/force.txt 에 저장하세요. 이제 클러스터의 이미지는 nginx:1.27 이고, 그 필드의 주인은 hotfix 입니다.
강제는 충돌을 없애는 것이 아니라 소유권을 옮기는 것입니다. 옛 주인은 그 필드에서 빠지므로, 다음번에 옛 주인이 자기 값을 다시 적용하면 이번에는 그쪽이 충돌을 만납니다 — 자동화 둘이 강제를 번갈아 쓰면 끝나지 않는 싸움이 됩니다.
필드를 놓아 주면 값은 주인에게 돌아가지 않는다
/root/ga-ssa/hotfix-slim.yaml 을 만드세요 — hotfix.yaml 과 같지만 spec.replicas 줄이 없습니다. --field-manager=hotfix 로 서버측 적용한 뒤, spec.replicas 를 소유한 관리자 목록을 /root/ga-ssa/release.txt 에 저장하세요(아무도 없으면 빈 파일). 클러스터의 replicas 가 몇이 되는지 확인하세요.
매니페스트에서 필드를 빼면 그 관리자는 소유 목록에서 그 필드를 놓습니다. 그런데 값은 옛 주인의 값으로 돌아가지 않습니다 — 아무도 소유하지 않는 필드는 API 기본값이 됩니다. 소유자 목록은 jq 로 .fieldsV1."f:spec"."f:replicas" 가 null 이 아닌 항목을 고르면 됩니다.
클라이언트측 적용은 무엇을 남기나
/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 에 저장하세요.
클라이언트측 적용은 '내가 지난번에 보낸 매니페스트' 를 주석 하나에 통째로 넣어 두고 그것과 비교해 무엇을 지울지 정합니다. 그래서 소유자 개념이 없고, 두 도구가 같은 객체를 다루면 서로의 필드를 지웁니다. 서버측으로 올린 쪽에는 그 주석이 없습니다.
kubectl scale 은 다른 문으로 들어온다
/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 에 저장합니다.
kubectl scale 은 객체 전체가 아니라 scale 이라는 하위 자원에 씁니다. 그래서 소유 기록에 관리자 kubectl 과 하위 자원 scale 이 따로 남고, 충돌 메시지도 그 사실을 알려 줍니다. 오토스케일러가 만드는 충돌이 정확히 이 모양입니다.
소유자 이름으로 비교에서 빼기
/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 에 저장하세요.
Argo CD 에서 '오토스케일러가 쓴 필드는 비교하지 않는다' 를 표현하는 방법이 이 두 가지입니다 — 경로로 빼거나 관리자 이름으로 빼거나. 다만 미리보기 명령은 경로 규칙만 렌더하므로, 관리자 이름 규칙이 실제로 무엇을 거를지는 소유 기록을 사람이 읽어 판단해야 합니다.