-
이코에코(Eco²) GitOps #03 네트워크 트러블슈팅이코에코(Eco²)/Kubernetes Cluster+GitOps+Service Mesh 2025. 11. 24. 17:05
🛎️ 본 포스팅은 구현이 완료된 사안만 다룹니다. 현재 이코에코 25-nodes cluster는 ap-northeast-2 리전에 배포되어 있습니다.
v0.7.3에서 App-of-Apps, Sync Wave, Helm+Kustomize를 한 번에 도입하면서 해야 할 작업이 산더미처럼 쌓였습니다.
이번 글에서는 그 이후 버전들(v0.7.4 ~ v0.7.5)에서 Security Group과 ArgoCD가 어떻게 얽혀 있었는지 정리합니다.이전 글: 이코에코(Eco²) 인프라 구축 #02 - GitOps: Ansible 의존성 줄이기
1. Security Group 정리 없이 GitOps만 본 것이 화근이었습니다 (v0.7.4)
1.1 Master/Worker SG 분리 구조의 한계
초기 Security Group 구조는 Master SG 하나, Worker SG 하나에 서로를 참조하는 방식이었습니다.
- Master SG ↔ Worker SG 상호 인바운드 허용
- 각 SG 안에 etcd, API Server, NodePort, Calico, Typha 등 다양한 포트가 혼재
- Terraform 기준 312줄짜리 SG 모듈
이 구조의 부작용은 명확했습니다.
문제점 설명 순환 참조 SG 간 상호 참조로 terraform destroy가 깔끔하게 완료되지 않음역할 혼재 Pod 레벨 통신까지 SG로 제어하여 NetworkPolicy와 책임이 중복 디버깅 복잡도 SG에서 막히는 것인지, NetworkPolicy에서 막히는 것인지 파악이 어려움 이 시점에 정리한 문서가 SECURITY_GROUP_SIMPLIFICATION.md입니다. 문서에는 이전 구조와 개선 구조가 ASCII 다이어그램으로 정리되어 있습니다.
1.2 Cluster SG 단일화
결론적으로 SG 레벨에서는 "노드끼리는 서로 모든 통신이 가능해야 한다"는 방향으로 결정했습니다. Pod 간 세밀한 제어는 Kubernetes 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
- terraform/modules/security-groups/outputs.tf
- terraform/ssm-parameters.tf
문서에 기록된 개선 수치는 다음과 같습니다.
항목 이전 개선 후 SG 개수 2개 (Master/Worker) 1개 (Cluster) SG 모듈 줄 수 312줄 155줄 순환 참조 12개 0개 terraform destroy 15분+ 대기 후 실패 즉시 성공 관련 커밋들은 다음과 같이 묶여 있습니다.
- SG 범위 축소:
- 11f9f68:
refactor: reduce the SG bound
- 11f9f68:
- 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-nodeDaemonSet이kube-system과calico-system양쪽에 중복 생성되거나, Helm Sync에서AlreadyExists,Field is immutable에러가 계속 발생했습니다. Root App Wave 5(dev-calico,prod-calico)가Progressing상태에서 넘어가지 않는 상황이 반복되었습니다.이 문제는 트러블슈팅 문서로 별도 정리했습니다.
v0.7.4 시점에는 부트스트랩과 Operator의 스펙을 일치시켜 덮어쓰는 방향을 시도했으나, 결국 "Operator 덮어쓰기 시도 실패 → Helm 단일 방식"으로 선회했습니다. 다만 이 경우 부트스트랩 시점에 클러스터 내부망이 구성되지 않는 문제가 있어서, Calico는 ArgoCD와 함께 부트스트랩 1회 배포로 고정되었습니다.
관련 커밋들:
트러블슈팅 문서도 Calico 파트에 축적되기 시작했습니다.
2.2 Calico Typha 5473 포트 이슈
Typha의 역할을 이해하려면 Calico의 구조를 알아야 합니다.
Felix와 Typha의 관계:
- Felix: 각 노드에 위치한 Calico 에이전트. 원래는 각 Felix가 직접 Kubernetes API(또는 etcd)에 연결하여 정책 변경, Pod/Endpoint 생성을 watch해야 합니다.
- Typha: Felix들이 직접 API 서버에 몰려들지 않도록 앞에서 받아주는 중간 허브/프록시 역할을 합니다.
Typha를 도입하면:
- Felix는 더 이상 API 서버와 직접 연결하지 않고, Typha 하나(또는 여러 개)에만 연결하여 업데이트를 수신합니다.
- API 서버 부하는 Typha에서 한 번 흡수됩니다.
Typha 내부 동작:
- Kubernetes API(또는 데이터스토어)를 watch하면서 클러스터 상태를 in-memory로 캐싱
- 노드별 Felix 클라이언트들과 gRPC 장기 연결을 유지하면서, 네트워크 정책/엔드포인트/노드 변화를 "한 번 받아서 여러 Felix에게 fan-out"
공식 문서 기준으로 Typha는 작은 클러스터에서는 필수가 아닙니다. 노드 수가 수백 개를 넘어가면 Felix 수 × API 서버 연결 수가 감당이 안 되어 Typha를 권장합니다. Calico Operator를 사용하면 클러스터 규모에 따라 Typha Deploy 개수를 자동으로 튜닝해 줍니다.
현재 설정에서 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)
v0.7.1에서 base/overlay 패턴을 도입하면서 Kustomize 기반은 잡아두었는데, v0.7.4에서는 어디까지 Helm으로 관리하고, 어디부터 Kustomize로 관리할지가 주요 관심사였습니다.
Changelog 기준으로 정리하면 다음과 같습니다.
- Platform 계층: Helm Chart 중심 (
platform/helm/) - Workload 계층: Kustomize base/overlay (
workloads/) - CRDs:
platform/crds/로 완전 분리 - 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/관련 커밋들은 다음과 같이 이어집니다.
- CRD/Helm overlay 정리:
이 구간은 "코드 전체 리팩토링 + CRD/Helm 재배치" 성격이라, GitHub에서 diff를 직접 확인하는 것이 글로 설명하는 것보다 직관적입니다.
4. ArgoCD CrashLoopBackOff & ERR_TOO_MANY_REDIRECTS (v0.7.5)
v0.7.4까지는 네트워크/보안/구조 정리 성격이었다면, v0.7.5는 거의 ArgoCD 트러블슈팅 특집에 가깝습니다.
4.1 command/args 패치로 인한 CrashLoopBackOff
어느 순간 ArgoCD Server Pod가 계속 CrashLoopBackOff 상태에 빠지는 것을 확인했습니다.
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를 서브커맨드로 인식하여 에러가 발생한 것입니다.이 사건을 정리한 문서가 ARGOCD_DEPLOYMENT_ISSUES.md입니다.
해결 방법:
- Before: Deployment command를 직접 패치
- After:
argocd-cmd-params-cmConfigMap 기반으로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에 접속할 때
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: HTTPannotation 설정
이 내용은 같은 트러블슈팅 문서의 2번 섹션에 정리되어 있습니다.
Ansible Role은 이제 다음을 보장합니다.
- ConfigMap에
server.insecure=true패치 rollout restart+rollout status로 적용 확인- Ingress annotation은 Kustomize/Helm overlay에서 관리
5. GitOps 1.0에서 2.0으로의 전환 정리
v0.7.4 ~ v0.7.5 사이에 수행한 작업을 정리하면 다음과 같습니다.
5.1 Security Group 단순화
- Master/Worker SG 분리로 꼬여 있던 구조를 Cluster SG 단일화
- "노드 레벨 방화벽은 SG, Pod 레벨은 NetworkPolicy"로 책임 분리
- SG 모듈 312줄 → 155줄, 순환 참조 제거
- 문서: SECURITY_GROUP_SIMPLIFICATION.md
5.2 Calico/Helm/Kustomize 스택 재정비
- Calico Operator + Helm 중복 설치 이슈 정리
- Typha 5473 포트 문제를 SG/문서 레벨에서 해결
- 문서:
5.3 ArgoCD 안정화
- Deployment 직접 패치 대신 ConfigMap 기반 설정으로 전환
- ALB HTTPS 종료 환경에서의 리디렉션 루프 해결
- Ansible Role 멱등성/재시작/검증 단계 강화
- 문서: ARGOCD_DEPLOYMENT_ISSUES.md
정리
아직 더 다듬을 부분이 많지만, 이제는 클러스터의 장애 지점을 찾을 때 SG, Calico, ArgoCD, Ansible 중 어느 계층을 먼저 확인해야 할지 감이 잡히는 구조가 되었습니다.
이 작업들을 통해 얻은 것은 단순한 트러블슈팅 경험을 넘어, 계층별 책임 분리의 중요성입니다.
계층 책임 도구 노드 레벨 방화벽 EC2 인스턴스 간 통신 제어 AWS Security Group Pod 레벨 격리 네임스페이스/서비스 간 트래픽 제어 Kubernetes NetworkPolicy 클러스터 네트워킹 CNI, 오버레이 네트워크 Calico (VXLAN) 애플리케이션 배포 선언적 상태 관리, 자동 동기화 ArgoCD 부트스트랩 초기 클러스터 구성 Ansible (최소화) 각 계층의 책임이 명확해지면서, 문제가 발생했을 때 어느 계층을 먼저 확인해야 하는지 판단하기 쉬워졌습니다. 이것이 GitOps 2.0으로 가는 과정에서 얻은 가장 큰 교훈입니다.
다음 글에서는 Sync Wave 자체에 대한 이야기와 Helm+Kustomize overlay를 실제 예시(ArgoCD, ExternalSecrets, 데이터 스택)로 풀어볼 예정입니다. CrashLoopBackOff 로그를 바탕으로 "Wave 숫자가 어떻게 바뀌었는지, 어떤 순서로 정렬되었는지"에 대해서도 다루겠습니다.
'이코에코(Eco²) > Kubernetes Cluster+GitOps+Service Mesh' 카테고리의 다른 글
이코에코(Eco²) Service Mesh #1: Istio Sidecar 마이그레이션 (0) 2025.12.08 이코에코(Eco²) GitOps #06 - Namespace · RBAC · NetworkPolicy를 한 뿌리에서 (3) 2025.11.25 이코에코(Eco²) GitOps #05 Sync Wave (0) 2025.11.25 이코에코(Eco²) GitOps #04: Operator(Controller) 기반 클러스터 인프라 구성 자동화 (0) 2025.11.24 이코에코(Eco²) GitOps #02: Ansible 의존성 감소, Kustomize Overlays 패턴 적용 (0) 2025.11.24