-
Oracle Cloud + Tailscale + Kubernetes 완벽 가이드(6)실제 경험과 인사이트를 AI와 함께 정리한 글 2025. 10. 26. 19:27
5단계: 실전 경험과 아키텍처 결정 배경
시리즈: Oracle Cloud + Tailscale + Kubernetes 완벽 가이드
← 이전: 4단계: 네트워킹 심화 이해 | 처음으로: README
며칠간의 삽질에서 얻은 교훈 - "다음에는 이렇게 하지 말자"
📋 이 문서의 목적
이 가이드의 최종 아키텍처는 처음부터 완벽하게 설계된 것이 아닙니다.
여러 번의 시도와 실패를 거쳐 현재의 구성에 도달했습니다.왜 이 문서가 필요한가?
- 실패한 방법을 기록하여 같은 함정에 빠지지 않도록
- 아키텍처 결정의 배경과 근거 공유
- "왜 이렇게 했나?"에 대한 솔직한 답변
전체 여정 타임라인
graph TD Start[목표: Tailscale + Kubernetes 클러스터] --> Attempt1{시도 1: Tailscale in K8s} Attempt1 -->|DaemonSet 배포| Problem1[❌ 문제 발생] Problem1 --> Issue1a[네트워크 네임스페이스 충돌] Problem1 --> Issue1b[Pod 재시작 시 터널 끊김] Problem1 --> Issue1c[hostNetwork 보안 문제] Issue1a --> Decision1[🔄 systemd 서비스로 변경] Issue1b --> Decision1 Issue1c --> Decision1 Decision1 --> Attempt2{시도 2: Cilium Native Routing} Attempt2 -->|성능 최적화 시도| Problem2[❌ 문제 발생] Problem2 --> Issue2a[Tailscale이 Pod 라우팅 안함] Problem2 --> Issue2b[수동 라우팅 관리 악몽] Problem2 --> Issue2c[자동화 실패] Issue2a --> Decision2[🔄 VXLAN으로 회귀] Issue2b --> Decision2 Issue2c --> Decision2 Decision2 --> Final[✅ 최종 아키텍처] Final --> Layer1[Tailscale: systemd 서비스] Final --> Layer2[Cilium: VXLAN 모드] Final --> Layer3[eBPF: kube-proxy 대체] Layer1 --> Result[안정적 운영 중] Layer2 --> Result Layer3 --> Result style Start stroke:#00bfff,stroke-width:3px style Problem1 stroke:#ff6b6b,stroke-width:3px style Problem2 stroke:#ff6b6b,stroke-width:3px style Decision1 stroke:#ffa500,stroke-width:3px style Decision2 stroke:#ffa500,stroke-width:3px style Final stroke:#4ecdc4,stroke-width:3px style Result stroke:#95e1d3,stroke-width:3px🚫 실패담 1: Tailscale을 Kubernetes 내부에서 실행
시도한 방법
Tailscale을 Kubernetes 방식으로 관리하려고 시도했습니다:
# 시도했던 방법 (실패) apiVersion: apps/v1 kind: DaemonSet metadata: name: tailscale namespace: kube-system spec: template: spec: hostNetwork: true # ← 이미 여기서 문제의 냄새 containers: - name: tailscale image: tailscale/tailscale:latest securityContext: privileged: true # ← 보안 문제왜 시도했나?
- Kubernetes 방식으로 통합 관리
kubectl명령어로 모든 것 제어- GitOps 워크플로우에 포함
겪은 문제
1. CNI와 네트워크 네임스페이스 충돌
# Pod 네트워크 네임스페이스 ip netns exec cni-xxx ip route # 10.244.0.0/16 via cilium_host # 호스트 네트워크 네임스페이스 ip route # 100.64.0.0/10 via tailscale0 # → 두 세계가 서로를 인식하지 못함!증상:
- Tailscale Pod 시작은 되지만 라우팅 작동 안 함
tailscale status는 정상, 실제 통신은 실패- 패킷 드롭 발생
2. Pod 재시작 시 터널 끊김
# Scenario 1. Tailscale Pod 정상 실행 → 터널 연결 OK 2. Pod 재시작 (업데이트, 노드 이동 등) 3. Tailscale 재연결 시도 4. 기존 세션 끊김, 새 IP 할당 가능 5. 클러스터 전체 통신 장애 발생!문제:
- Pod는 ephemeral (일시적)
- Tailscale 터널은 persistent (지속적) 필요
- 근본적인 불일치
3. hostNetwork 사용의 보안 문제
hostNetwork: true # Pod가 호스트 네트워크 직접 사용문제점:
- Pod가 호스트의 모든 네트워크 접근 가능
- Kubernetes 네트워크 격리 무력화
- 보안 감사 실패
기술적 배경: 왜 작동하지 않는가?
네트워크 네임스페이스의 한계
graph TB subgraph Host["🖥️ Host Network Namespace"] TS[Tailscale tailscale0] TSR[라우팅 테이블<br/>100.64.0.0/10] HostRoute[호스트 라우팅 테이블] TS --> TSR TSR --> HostRoute end subgraph PodNS["📦 Pod Network Namespace"] Veth[veth 인터페이스] PodRoute[독립 라우팅 테이블<br/>10.244.x.0/24] Veth --> PodRoute end Host -.->|❌ 접근 불가| PodNS PodNS -.->|❌ 접근 불가| Host style Host stroke:#00bfff,stroke-width:3px style PodNS stroke:#ff6b6b,stroke-width:3px style TS stroke:#4ecdc4,stroke-width:2px style Veth stroke:#ee5a6f,stroke-width:2px핵심 문제:
- Tailscale은 호스트 라우팅 테이블 수정
- Pod는 독립 네트워크 네임스페이스
- 두 레이어가 서로 통신 불가
결론: 노드 레벨 systemd 서비스
최종 선택:
# 각 노드에서 직접 설치 curl -fsSL https://tailscale.com/install.sh | sh sudo tailscale up --login-server=...장점:
- ✅ 안정적인 터널 (재부팅 시에도 유지)
- ✅ CNI와 충돌 없음
- ✅ 단순하고 명확한 관리
- ✅ Tailscale 공식 권장 방법
단점:
- ❌ 노드별 수동 설정 필요
- ❌ Kubernetes 방식 관리 불가
- ❌ GitOps에 포함 어려움
트레이드오프:
운영 안정성 > 관리 편의성
🚫 실패담 2: Cilium Native Routing 시도
시도한 방법
VXLAN 오버헤드를 제거하여 성능을 높이려고 시도:
# Native Routing 모드로 Cilium 설치 helm install cilium cilium/cilium \ --set routingMode=native \ # ← VXLAN 대신 Native --set autoDirectNodeRoutes=true \ # ← 자동 라우팅 기대 --set ipv4NativeRoutingCIDR=10.244.0.0/16왜 시도했나?
- VXLAN 캡슐화 오버헤드 제거 (5-10% 성능 향상)
- "더 빠른 네트워크"에 대한 욕심
- 기술 블로그에서 "Native Routing이 최고"라는 글 읽음
겪은 문제
1. Tailscale이 Pod 라우팅을 자동 설정하지 않음
# 기대했던 것: tailscale up --advertise-routes=10.244.0.0/16 # → 모든 노드에 자동으로 라우팅 설정될 줄 알았음 # 현실: ip route show # 100.64.0.2 via tailscale0 ← 노드 IP만 있음 # 10.244.1.0/24는 없음!깨달음:
- Tailscale은 노드 간 터널만 제공
- Pod 네트워크는 별도로 라우팅 설정 필요
advertise-routes는 광고만, 자동 설정 아님
2. 수동 라우팅 테이블 관리의 악몽
각 노드에서 수동 설정 필요:
# Master 노드 (100.64.0.1) sudo ip route add 10.244.1.0/24 via 100.64.0.2 # Worker 1 sudo ip route add 10.244.2.0/24 via 100.64.0.3 # Worker 2 # Worker 1 (100.64.0.2) sudo ip route add 10.244.0.0/24 via 100.64.0.1 # Master sudo ip route add 10.244.2.0/24 via 100.64.0.3 # Worker 2 # Worker 2 (100.64.0.3) sudo ip route add 10.244.0.0/24 via 100.64.0.1 # Master sudo ip route add 10.244.1.0/24 via 100.64.0.2 # Worker 1graph TB subgraph Master["🖥️ Master (100.64.0.1)"] M1[Pod CIDR: 10.244.0.0/24] M2[라우팅 테이블] M3["route add 10.244.1.0/24 via .2"] M4["route add 10.244.2.0/24 via .3"] end subgraph Worker1["🖥️ Worker 1 (100.64.0.2)"] W1[Pod CIDR: 10.244.1.0/24] W2[라우팅 테이블] W3["route add 10.244.0.0/24 via .1"] W4["route add 10.244.2.0/24 via .3"] end subgraph Worker2["🖥️ Worker 2 (100.64.0.3)"] WW1[Pod CIDR: 10.244.2.0/24] WW2[라우팅 테이블] WW3["route add 10.244.0.0/24 via .1"] WW4["route add 10.244.1.0/24 via .2"] end Master <-->|Tailscale 터널| Worker1 Worker1 <-->|Tailscale 터널| Worker2 Master <-->|Tailscale 터널| Worker2 Note1["😱 노드 추가 시<br/>모든 노드에서<br/>라우팅 업데이트 필요!"] style Note1 stroke:#ff6b6b,stroke-width:3px style Master stroke:#00bfff,stroke-width:2px style Worker1 stroke:#4ecdc4,stroke-width:2px style Worker2 stroke:#ffa500,stroke-width:2px문제점:
- 노드 추가 시마다 모든 노드에서 업데이트
- IP 변경 시 모든 라우팅 테이블 수정
- 재부팅 시 라우팅 유실 → 스크립트 작성 필요
- 운영 복잡도 기하급수적 증가
3. 자동화의 어려움
시도한 자동화 방법들:
# 1. systemd 서비스로 라우팅 추가 (실패) # - 노드 추가/제거 시 동기화 문제 # 2. Kubernetes Operator 작성 (너무 복잡) # - 라우팅 테이블 관리 Operator 필요 # - 오버엔지니어링 # 3. Ansible 플레이북 (관리 포인트 증가) # - Kubernetes 외부 도구 의존성 # - GitOps와 불일치결론: 모두 만족스럽지 않음
기술적 배경: Native Routing의 요구사항
Native Routing이 작동하는 환경
graph TB subgraph Ideal["✅ Native Routing 이상적 환경"] direction LR N1[Node 1] <--> Switch[L2 스위치 또는<br/>클라우드 라우팅] N2[Node 2] <--> Switch N3[Node 3] <--> Switch Switch --> Auto[자동 라우팅<br/>BGP / VPC Peering /<br/>물리 스위치] end subgraph Reality["❌ 우리 환경 (Tailscale)"] direction TB subgraph Acc1["Oracle Account 1"] Node1[Node 1<br/>10.244.0.0/24] end subgraph Acc2["Oracle Account 2"] Node2[Node 2<br/>10.244.1.0/24] end subgraph Acc3["Oracle Account 3"] Node3[Node 3<br/>10.244.2.0/24] end Node1 <-.->|WireGuard 터널| Node2 Node2 <-.->|WireGuard 터널| Node3 Node1 <-.->|WireGuard 터널| Node3 Manual[수동 라우팅만 가능<br/>자동화 없음!] end style Ideal stroke:#4ecdc4,stroke-width:3px style Reality stroke:#ff6b6b,stroke-width:3px style Auto stroke:#95e1d3,stroke-width:2px style Manual stroke:#ee5a6f,stroke-width:2px style Acc1 stroke:#00bfff,stroke-width:1px style Acc2 stroke:#00bfff,stroke-width:1px style Acc3 stroke:#00bfff,stroke-width:1px근본적인 불일치:
- Native Routing: Layer 2/3 라우팅 필요
- Tailscale: Layer 4 터널 (라우팅 제공 안 함)
결론: VXLAN 터널링으로 회귀
최종 선택:
helm install cilium cilium/cilium \ --set routingMode=tunnel \ --set tunnelProtocol=vxlan장점:
- ✅ 라우팅 자동 관리 (Cilium이 전담)
- ✅ 노드 추가/제거 시 설정 불필요
- ✅ 운영 복잡도 낮음
- ✅ 안정적이고 예측 가능
단점:
- ❌ VXLAN 캡슐화 오버헤드 (~5-10%)
- ❌ MTU 감소 (1500 → 1200)
성능 테스트 결과:
# iperf3 테스트 (Pod to Pod) Native Routing: ~9.2 Gbps VXLAN: ~8.7 Gbps 차이: ~5% # 실제 워크로드 영향: 거의 무시 가능 # CPU/메모리가 먼저 병목트레이드오프:
미세한 성능 차이 < 압도적인 운영 편의성
✅ 최종 아키텍처 결정
선택한 구성
graph TB subgraph Layer1["🌐 Layer 1: 노드 간 연결 (Tailscale)"] TS[Tailscale systemd 서비스] TSF[WireGuard 터널<br/>100.64.0.0/10] TSM[관리: systemd] TS --> TSF TSF --> TSM end subgraph Layer2["📦 Layer 2: Pod 네트워킹 (Cilium CNI)"] Cilium[Cilium VXLAN 모드] PodNet[Pod 네트워크<br/>10.244.0.0/16] AutoRoute[자동 라우팅 관리] CiliumM[관리: Helm Chart] Cilium --> PodNet PodNet --> AutoRoute AutoRoute --> CiliumM end subgraph Layer3["⚡ Layer 3: 서비스 로드밸런싱 (eBPF)"] eBPF[Cilium eBPF] KubeProxy[kube-proxy 대체] SvcLB[Service Load Balancing] eBPF --> KubeProxy KubeProxy --> SvcLB end Layer1 ==>|노드 터널 제공| Layer2 Layer2 ==>|Pod 네트워크 제공| Layer3 Responsibility["책임 분리<br/>---<br/>Tailscale: 노드만 연결<br/>Cilium: 나머지 전부"] style Layer1 stroke:#00bfff,stroke-width:3px style Layer2 stroke:#4ecdc4,stroke-width:3px style Layer3 stroke:#ffa500,stroke-width:3px style Responsibility stroke:#ee5a6f,stroke-width:2px각 계층의 책임
계층 역할 관리 방식 CIDR 대역 Tailscale 노드 간 터널 systemd 서비스 100.64.0.0/10 Cilium Pod 네트워킹 Helm Chart 10.244.0.0/16 eBPF Service LB Cilium 내장 - 명확한 책임 분리:
- Tailscale: "노드만 연결" (Layer 1)
- Cilium: "나머지 전부" (Layer 2 + 3)
의사결정 플로우차트
graph TD Start[Kubernetes 클러스터 구축 필요] --> Q1{노드들이<br/>동일 네트워크?} Q1 -->|예<br/>VPC/L2 동일| VPC[Native Routing 가능] Q1 -->|아니오<br/>서로 다른 네트워크| Overlay[Overlay 네트워크 필요] VPC --> Q2{BGP 또는<br/>클라우드 라우팅<br/>사용 가능?} Q2 -->|예| NativeOK[✅ Cilium Native Routing<br/>최고 성능] Q2 -->|아니오| ManualRoute{수동 라우팅<br/>관리 가능?} ManualRoute -->|가능<br/>노드 수 고정| NativeManual[⚠️ Native Routing<br/>+ 수동 설정<br/>5-10% 성능 향상] ManualRoute -->|불가능<br/>노드 수 가변| UseVXLAN[→ VXLAN 사용] Overlay --> Q3{Tailscale/WireGuard<br/>터널 사용?} Q3 -->|예| TailscaleQ{Tailscale을<br/>어디서 실행?} Q3 -->|아니오| OtherOverlay[다른 Overlay 검토<br/>Flannel, Calico 등] TailscaleQ -->|K8s 내부<br/>DaemonSet| TSFail[❌ 네임스페이스 충돌<br/>권장 안 함] TailscaleQ -->|노드 레벨<br/>systemd| TSOK[✅ Tailscale systemd] TSOK --> UseVXLAN TSFail -.->|실패 후| TSOK UseVXLAN --> Final[✅ 최종 구성<br/>Tailscale systemd<br/>+ Cilium VXLAN<br/>+ eBPF] NativeOK --> CNI[CNI 선택:<br/>Cilium, Calico, Flannel] UseVXLAN --> CNI2[CNI 선택:<br/>Cilium 권장] style Start stroke:#00bfff,stroke-width:3px style Final stroke:#4ecdc4,stroke-width:4px style NativeOK stroke:#95e1d3,stroke-width:3px style TSFail stroke:#ff6b6b,stroke-width:3px style TSOK stroke:#4ecdc4,stroke-width:3px트레이드오프 분석
성능 vs 운영성
구성 성능 운영 난이도 안정성 선택 Native + K8s Tailscale ⭐⭐⭐⭐⭐ ⭐ ⭐ ❌ Native + systemd Tailscale ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐ ❌ VXLAN + systemd Tailscale ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ✅ 우선순위:
- 안정성 (가장 중요)
- 운영 편의성 (두 번째)
- 성능 (세 번째)
실무 관점
"완벽한 설정"은 없습니다:
- 모든 것을 만족하는 구성은 존재하지 않음
- 상황과 우선순위에 따라 선택
- 우리의 선택: 안정성과 단순함
💡 배운 교훈
1. 단순함이 최고
복잡한 최적화 << 단순하고 안정적인 구성예시:
- ❌ Native Routing + 자동화 스크립트 + Operator
- ✅ VXLAN + 기본 설정
이유:
- 복잡한 시스템은 디버깅 어려움
- 운영 중 문제 발생 시 원인 파악 지연
- 팀원 온보딩 시간 증가
2. 운영 안정성 > 미세한 성능
5% 성능 향상 vs 50% 운영 부담 감소
- 대부분의 경우 성능은 충분함
- CPU/메모리/디스크가 먼저 병목
- 네트워크 5% 차이는 체감 불가
실제 경험:
# 성능 병목 분석 결과 1. 데이터베이스 쿼리 최적화: 50% 개선 2. 애플리케이션 코드 리팩토링: 30% 개선 3. 네트워크 최적화 (Native vs VXLAN): 5% 개선 → 우선순위가 명확함3. 공식 문서 권장사항에는 이유가 있다
Tailscale 공식 문서:
"Run Tailscale as a system service on each node"
Cilium 공식 문서:
"VXLAN is recommended for overlay networks"
왜 처음부터 안 따랐나?
- "내 상황은 다를 거야"
- "더 나은 방법이 있을 거야"
- "최신 기술을 써야 해"
깨달음:
- 공식 문서는 수많은 사례 기반
- 대부분의 엣지 케이스 고려됨
- 특별한 이유 없으면 권장사항 따르기
4. 완벽한 설정은 없다
모든 아키텍처는 트레이드오프:
- 성능 ↔ 안정성
- 복잡도 ↔ 유연성
- 자동화 ↔ 제어권
우선순위 명확히:
- 무엇이 가장 중요한가?
- 무엇을 포기할 수 있는가?
- 팀이 관리할 수 있는가?
5. 삽질은 배움의 과정
실패한 시도들이 가치 있는 이유:
- 기술의 한계 이해
- 트레이드오프 체감
- 더 나은 결정의 근거
이 문서의 목적:
- 같은 실수 반복 방지
- 결정의 배경 공유
- 다음 구축자를 위한 가이드
🔮 향후 개선 가능성
1. Tailscale in Kubernetes 재검토
언제 다시 시도할 가치가 있나?
- Tailscale Kubernetes Operator 안정화
- CNI와의 통합 개선
- 공식 지원 시작
현재 상태:
- Tailscale Operator: 베타
- 프로덕션 사용: 권장 안 됨
2. Native Routing 재검토
언제 시도할 가치가 있나?
- BGP 라우팅 가능한 환경
- 클라우드 VPC Peering 사용
- 초고성능 필요 (HPC, ML)
우리 환경에서는:
- 서로 다른 Oracle 계정 = VPC Peering 불가
- Native Routing 불가능
3. 모니터링 강화
추가할 만한 것:
- Cilium Hubble (네트워크 가시성)
- Prometheus + Grafana
- 성능 메트릭 수집
📚 추가 자료
참고한 문서들
비슷한 경험담
✍️ 추가 실패담 (향후 작성 예정)
이 문서는 계속 업데이트됩니다. 앞으로 추가할 내용:
- iptables vs eBPF 선택 과정
- MTU 설정 시행착오
- 블록볼륨 마운트 실수
- Headscale vs Tailscale 공식 서버
- Oracle Cloud 방화벽 설정 함정
- SELinux Permissive 모드의 이유
- 기타...
기여 환영:
비슷한 경험이 있다면 공유해주세요!
*"실패는 성공의 어머니" - 하지만 남의 실패로부터 배우면 더 빠릅니다.*
'실제 경험과 인사이트를 AI와 함께 정리한 글' 카테고리의 다른 글
Cilium devices 파라미터 완벽 가이드: Tailscale 환경에서의 핵심 (0) 2025.10.26 Kubernetes Pod Security Standards: nginx-unprivileged로 보안 강화하기 (0) 2025.10.26 Oracle Cloud + Tailscale + Kubernetes 완벽 가이드(5) (0) 2025.10.26 Oracle Cloud + Tailscale + Kubernetes 완벽 가이드(4) (0) 2025.10.26 Oracle Cloud + Tailscale + Kubernetes 완벽 가이드(3) (0) 2025.10.26