-
이코에코(Eco²) GitOps #03 네트워크 안정화이코에코(Eco²)/Kubernetes Cluster+GitOps+Service Mesh 2025. 11. 24. 17:05
🛎️ 본 포스팅은 구현이 완료된 사안만 다룹니다. 현재 이코에코 14-nodes cluster는 ap-northeast-2 리전에 배포돼 있습니다.
0.7.3에서 App-of-Apps / Sync Wave / Helm+Kustomize까지 한 번에 올렸더니, 해야할 작업이 산더미였다.
이번 편은 그 이후 버전들(0.7.4 ~ 0.7.5)에서 보안 그룹이랑 ArgoCD가 어떻게 엉켜 있었는지 정리해본다.
2편은 여기: 이코에코(Eco²) 인프라 구축 #02 - GitOps: Ansible 의존성 줄이기1. Security Group 정리 안 하고 GitOps만 본 게 화근이었다 (v0.7.4)
1.1 마스터/워커 SG 분리 구조의 한계
초기 SG 구조는 마스터 SG 하나, 워커 SG 하나에 서로를 참조하는 방식이었다.
- Master SG ↔ Worker SG 서로 인바운드 허용
- 각 SG 안에 etcd / API Server / NodePort / Calico / Typha 등 온갖 포트가 섞여 있음
- Terraform 기준 312줄짜리 SG 모듈이 됨
이 구조의 부작용은 명확했다.
- SG 간 순환 참조 때문에 `terraform destroy`가 깔끔하게 안 떨어짐
- Pod 레벨 통신까지 SG로 묶이니, NetworkPolicy랑 역할이 혼재
- 이건 SG에서 막히는 건지, NP에서 막히는 건지.. 디버깅 복잡도 증가
이때 정리한 문서가 이거다.
→ docs/architecture/SECURITY_GROUP_SIMPLIFICATION.md
여기 보면 이전 구조/개선 구조가 ASCII 그림으로 잘 나와 있다.
1.2 Cluster SG 하나로 통일
결국 SG 레벨에서는 “노드끼리는 서로 다 통신 가능해야 한다”는 쪽으로 결론을 냈다.
Pod 간 세밀한 통제는 K8s NetworkPolicy로 넘기고, SG는 노드 레벨 방화벽만 맡기자 쪽으로.
그래서 구조를 이렇게 갈아엎었다.
이전:
aws_security_group.master
aws_security_group.worker
+ 서로를 참조하는 rule들 (12개 정도)
이후:
aws_security_group.k8s_cluster # 단일 SG
- SSH (22)
- API Server (6443)
- NodePort (30000-32767)
- self 인그레스 (노드 간 모든 통신 허용)실제 Terraform 모듈은 여기서 볼 수 있다.
→ terraform/modules/security-groups/main.tf
→ 출력값/SSM 파라미터 정리는 여기:
1. terraform/modules/security-groups/outputs.tf
2. terraform/ssm-parameters.tf
문서에 있는 숫자를 그대로 가져오면:항목 이전 개선 후 SG 개수 2개 (Master/Worker) 1개 (Cluster) SG 모듈 줄 수 312줄 155줄 순환 참조 12개 0개 terraform destroy 15분+ 대기 후 실패 즉시 성공
실제로 이 작업은 commit 단위로 보면 아래와 같이 묶여 있다.
1. SG 범위 줄이기:
11f9f68: refactor: reduce the SG bound
2. Calico/네트워킹 쪽 정리와 같이 진행:
00d64e3: `refactor(calico): Ansible 단독 관리로 전환 (BGP off, VXLAN Always, Operator 미사용)`
b178427: fix: enable SSA for calico`
SG를 이렇게 정리해두니, Calico Typha 5473 포트 이슈 같은 경우도 SG 레벨에선 다시 다룰 일이 없어졌다.
그 얘기는 아래에 살짝 더 풀겠다.
2. Calico 리팩토링: Operator, Helm, 그리고 Typha(5473) (v0.7.4)
2.1 Operator + Helm 이중 배포
한동안 Calico는 “부트스트랩에서 raw manifest로 설치 + 나중에 Helm Operator로 관리”라는 오묘한 구조였다.
- Ansible 부트스트랩:
https://raw.githubusercontent.com/projectcalico/calico/v3.26.x/manifests/calico.yaml 적용
- ArgoCD Wave 5:
platform/helm/calico에서 Tigera Operator + Installation CR 배포
결과적으로 calico-node DaemonSet이 kube-system / calico-system 양쪽에 중복 생성되거나,
Helm Sync에서 AlreadyExists, Field is immutable 에러가 계속 터지고 Root App Wave 5(dev-calico, prod-calico)가 Progressing에서 넘어가지 않는 상황이 나왔다
이 부분은 트러블슈팅 문서로 따로 빼놨다.
v0.7.4 시점에는 부트스트랩과 Operator의 스펙을 일치시켜 덮어쓰자 쪽이었으나.. Calico는 한 번만 쓰는 걸로 변경했다.
결국에는 “Operator 덮어쓰기 시도 실패 → Helm 단일 방식” 쪽으로 선회했다.
그렇지만 이 경우 부트스트랩 시 클러스터 내부망이 구성되지 않는다.
슬프지만 Calico는 ArgoCD와 함께 부트스트랩 1회 배포로 픽스됐다.
관련 커밋들:
- 00d64e3: `refactor(calico): Ansible 단독 관리로 전환`
- a4a5925: `docs: add troubleshooting for calico`
트러블슈팅 문서도 Calico 파트에 슬슬 쌓이기 시작했다.
2.2 Calico Typha 5473 포트 이슈
https://docs.tigera.io/calico/latest/reference/typha/overview
Typha overview | Calico Documentation
Use the Calico Typha daemon to increase scale and reduce impact on the datastore.
docs.tigera.io

여기서 Felix는 각 노드에 붙어 있는 Calico 에이전트고
Typha는 이 Felix들이 직접 API 서버에 몰려들지 않도록 앞에서 받아주는 중간 허브/프록시 역할을 한다.
조금 더 나누어보면
Felix 입장에서의 Typha- 원래는 각 Felix가 직접 Kubernetes API(또는 etcd)에 붙어서 “정책이 뭐 바뀌었는지, 어떤 Pod/Endpoint가 생겼는지”를 계속 watch 해야 함.
- 노드가 수십, 수백 개로 늘어나면 API 서버 입장에서 watch 커넥션이 늘어나고, 업데이트를 똑같은 내용으로 N번 브로드캐스트해야 해서 부담이 커짐.
Typha를 가운데 두면:
- Felix는 더 이상 API 서버랑 직접 안 붙고, Typha 하나(또는 여러 개)에만 붙어서 업데이트를 받음.
- Felix ↔ Typha 연결만 잘 유지되면 되고, API 서버 부하는 Typha 쪽에서 한번 흡수.
Typha 내부에서 하는 일
- Kubernetes API(or 데이터스토어)를 watch하면서 클러스터 상태를 in-memory로 캐싱.
- 노드별 Felix 클라이언트들과 gRPC 같은 장기 커넥션을 유지하면서, 네트워크 정책/엔드포인트/노드 변화 같은 걸 “한 번 받아서 여러 Felix에게 팬아웃(fan-out)” 한다.
Felix 입장에서는 API 서버 대신 Typha만 보면 되는 구조가 된다.
API 서버 입장에서는 Typha 몇 대만 상대하면 된다
공식 문서 기준으로도 Typha는 작은 클러스터에선 필수가 아니다.
노드 수가 수백개를 넘어가면, Felix 수 × API 서버 연결 수가 감당 안 되니 Typha를 권장하는 편이다.
Calico Operator를 쓰면 클러스터 규모를 보고 Typha Deploy 개수도 자동으로 튜닝해 준다.
현 설정이 켜진 건 오작동에 가깝지만.. 이참에 써보는 것도 나쁘진 않으니 그냥 뒀다.
전직장에서도 개발용 클러스터는 non-HA 기준 3-nodes가 권장사항이어서 Typha를 다뤄본 적은 없었다.
아무튼 Calico Typha 5473 포트 문제는 “SG 정리 안 하면 이렇게 된다”의 교과서 같은 이슈였다.
증상은 이랬다.# calico-node (master)만 Ready가 안 됨 NAME READY STATUS RESTARTS AGE calico-node-nv4qn 0/1 Running 0 13m Failed to connect to typha endpoint 10.0.3.88:5473 (i/o timeout)
로그를 보면 Master ↔ Worker 사이에서 5473/TCP만 막혀 있었던 상황이라 해결은 간단했다.
AWS CLI로 Master/Worker SG 간 5473/TCP 인바운드 열어주고
재발하지 않도록 Terraform SG 모듈에 Typha 관련 rule을 영구 반영했다.
몇 초 후 calico-node 전부 1/1 Ready가 되며 문제는 해결됐다.
이 이슈가 SG 통합 작업(Cluster SG)과 시점이 겹쳐서 결국 Calico 필수 포트(179, 4789, 5473 등)를 SG 레벨에서 한 번 더 정리하고 넘어가게 됐다.
3. Helm/Kustomize 역할 분리 다시 잡기 (v0.7.4)
0.7.1에서 base/overlay 패턴을 도입하면서 Kustomize 기반은 잡아놨는데 0.7.4에서는 어디까지 Helm으로 보고, 어디부터 Kustomize로 볼지가 주안점이었다.
Changelog 한 줄로 정리하면 이렇다.
1. Platform 계층: Helm Chart 중심 (platform/helm/)
2. Workload 계층: Kustomize base/overlay (workloads/)
3. CRDs: platform/crds/로 완전 분리
4. patch 방식: JSON → YAML로 통일
실제 구조는 대략 이런 느낌이다.platform/ helm/ external-dns/ alb-controller/ kube-prometheus-stack/ ... crds/ external-secrets/ ot-redis/ rabbitmq-operator/ workloads/ base/ auth/ location/ ... overlays/ dev/ prod/
14nodes/이 구조는 GitOps 전용 문서에서 한 번 더 정리해뒀다.
GitOps 구조 문서가 있다면, 거기에 Helm/Kustomize 스택이 쭉 나와 있을 거다.
관련 커밋들은 이런 식으로 이어진다.
- CRD/Helm overlay 정리:
918d0bc: `refactor: split helm/crd env overlays`
cf72a26: `refactor/data-cr-structure`
d90b180: `fix: centralize crd management`
이 구간은 “코드 풀 리팩토링 + CRD/Helm 재배치” 느낌이라,
GitHub에서 diff를 쭉 훑어 보는 게 글로 설명하는 것보다 훨씬 직관적이다.4. ArgoCD CrashLoopBackOff & ERR_TOO_MANY_REDIRECTS (v0.7.5)
0.7.4까지는 네트워크/보안/구조 정리 느낌이었다면,
0.7.5는 거의 ArgoCD 삽질 특집에 가깝다.
4.1 command/args 패치하다 CrashLoopBackOff
어느 순간 ArgoCD Server Pod가 계속 CrashLoop를 도는 걸 확인했다.kubectl get pods -n argocd NAME READY STATUS RESTARTS AGE argocd-server-58d469d955-kmdd6 0/1 CrashLoopBackOff 4 2m
로그를 보면Error: unknown command "/usr/local/bin/argocd-server" for "argocd-server
원인은 아주 단순했다.
- Ansible에서 `kubectl patch`로 Deployment의 command만 이렇게 바꿔버렸고:
command: ["argocd-server", "--insecure"]
원래 있던 args는 그대로 남아 있었다.
args: ["/usr/local/bin/argocd-server"]
결국 실제로 실행된 건 이거였다.
argocd-server --insecure /usr/local/bin/argocd-server
→ "/usr/local/bin/argocd-server"를 또 서브커맨드로 본 것이 사건을 정리한 문서가 바로 이거다.
→ docs/troubleshooting/ARGOCD_DEPLOYMENT_ISSUES.md
여기 보면 “Before/After Ansible Task”가 그대로 들어가 있다.
- Before: Deployment command를 직접 패치
- After: argocd-cmd-params-cm ConfigMap 기반으로 server.insecure=true 설정 + rollout restart
관련 Ansible Role 변경은 여기서 확인할 수 있다.
→ ansible/roles/argocd/tasks/main.yml
이 Role을 손본 커밋 중 하나:
f90366f: fix: Enhance ArgoCD Ansible role for production readiness
요약하면
- ArgoCD는 ConfigMap(argocd-cmd-params-cm)으로 server 옵션을 받는 게 표준이고
- Deployment를 직접 패치하면 command/args 충돌로 CrashLoopBackOff를 자초하기 쉽다.
4.2 ERR_TOO_MANY_REDIRECTS: ALB HTTPS + ArgoCD HTTP두 번째 이슈는 브라우저에서 ArgoCD 접속할 때 ERR_TOO_MANY_REDIRECTS가 뜨는 문제였다.
구조는 이랬다.브라우저 (HTTPS) ↓ ALB (HTTPS 종료) ↓ ArgoCD (HTTP) ← "어? HTTPS 아니네? HTTPS로 리다이렉트해야지!" ↓ ALB (다시 HTTPS) ← 반복...결론적으로:
- ALB에서는 HTTPS 종료 후 ArgoCD로 HTTP로 트래픽을 넘겨야 하고
- ArgoCD는 `--insecure` 모드로 떠서 HTTP를 받아들여야 한다
- Ingress에는 `alb.ingress.kubernetes.io/backend-protocol: HTTP`가 필요하다
이 내용은 같은 트러블슈팅 문서 2번 섹션에 잘 정리돼 있다.
ARGOCD_DEPLOYMENT_ISSUES.md#2-err_too_many_redirects-alb-https-종료-문제
Ansible Role 쪽은 이제 다음을 보장한다.
- ConfigMap에 `server.insecure=true` 패치
- `rollout restart` + `rollout status`로 적용 확인
- Ingress annotation은 Kustomize/Helm overlay에서 관리5. GitOps 1.0 → 2.0
0.7.4 ~ 0.7.5 사이에 했던 작업을 정리하면 이런 흐름이다.
1. 보안 그룹 단순화
- Master/Worker SG 나눠서 꼬아 놨던 걸 Cluster SG 하나로 모으고
- “노드 레벨 방화벽은 SG, Pod 레벨은 NetworkPolicy”로 책임 분리
- SG 모듈 312줄 → 155줄, 순환 참조 제거
- 문서: SECURITY_GROUP_SIMPLIFICATION.md
2. Calico/Helm/Kustomize 스택 재정비
- Calico Operator + Helm 중복 설치 이슈 정리
- Typha 5473 포트 문제를 SG/문서 레벨에서 해결
- 문서:
- calico-operator-helm-conflict.md
- CALICO_TYPHA_PORT_5473_ISSUE.md
3. ArgoCD 안정화
- Deployment 직접 패치 대신 ConfigMap 기반 설정으로 전환
- ALB HTTPS 종료 환경에서의 리디렉션 루프 해결
- Ansible Role 멱등성/재시작/검증 단계 강화
- 문서: ARGOCD_DEPLOYMENT_ISSUES.md
토큰은 여전히 잘 타고 있고, 아직 더 다듬을 부분이 많지만 그래도 이제는 클러스터의 장애지점을 찾을 때,
SG/Calico/ArgoCD/Ansible 어느 층을 먼저 봐야 할지 감이 잡히는 구조가 된 듯 싶다.
다음 편에선 Sync Wave 자체 얘기랑 Helm+Kustomize overlay를
실제 예시(ArgoCD/ExternalSecrets/데이터 스택)로 풀어볼 생각이다.
CrashLoopBackOff 로그를 바탕으로 “Wave 숫자가 어떻게 바뀌었는지, 어떤 순으로 정렬됐는지”에 대해서도 써보겠다.'이코에코(Eco²) > Kubernetes Cluster+GitOps+Service Mesh' 카테고리의 다른 글
이코에코(Eco²) GitOps #06 - Namespace · RBAC · NetworkPolicy를 한 뿌리에서 (3) 2025.11.25 이코에코(Eco²) GitOps #05 Sync Wave (0) 2025.11.25 이코에코(Eco²) GitOps #04 Operator와 Helm-charts를 오가며 겪은 시행착오들 (0) 2025.11.24 이코에코(Eco²) GitOps #02 Ansible 의존성 감소, Kustomize Overlays 패턴 적용 (0) 2025.11.24 이코에코(Eco²) GitOps #01 AWS + IaC 기반 K8s 클러스터 구축기 (0) 2025.11.12