티스토리 뷰
Oracle Cloud + Tailscale + Kubernetes 완벽 가이드(4)
pak2251 2025. 10. 26. 19:263단계: Kubernetes + Cilium 클러스터 구축
시리즈: Oracle Cloud + Tailscale + Kubernetes 완벽 가이드
← 이전: 2단계: Tailscale 메시 네트워크 구성 | 다음: 4단계: 네트워킹 심화 이해 →
Tailscale 메시 네트워크 위에 Kubernetes 클러스터와 Cilium CNI 설치
📋 이 단계에서 할 일
- Container Runtime (containerd) 설치
- Kubernetes 패키지 설치
- 마스터 노드 초기화
- Cilium CNI 설치 (VXLAN 모드)
- 워커 노드 추가
- 클러스터 검증
🐳 Phase 1: Container Runtime 설치
모든 노드에서 실행
1. Containerd 설치
# Docker 저장소 추가 (containerd 포함)
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# Containerd 설치
sudo dnf install -y containerd.io
# 설정 파일 생성
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
# SystemdCgroup 활성화 (중요!)
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
# 서비스 시작
sudo systemctl restart containerd
sudo systemctl enable containerd
# 확인
sudo systemctl status containerd2. crictl 설치 (디버깅 도구)
# crictl 다운로드
VERSION="v1.34.0"
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-arm64.tar.gz
sudo tar zxvf crictl-$VERSION-linux-arm64.tar.gz -C /usr/local/bin
rm -f crictl-$VERSION-linux-arm64.tar.gz
# crictl 설정
cat <<EOF | sudo tee /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 2
EOF
# 확인
sudo crictl version☸️ Phase 2: Kubernetes 설치
모든 노드에서 실행
1. Kubernetes 저장소 추가
# Kubernetes 공식 저장소
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.34/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.34/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl
arch=aarch64
EOF2. Kubernetes 패키지 설치
# 버전 고정 설치 (1.34.1)
sudo dnf install -y \
kubelet-1.34.1 \
kubeadm-1.34.1 \
kubectl-1.34.1 \
--disableexcludes=kubernetes
# kubelet 서비스 활성화
sudo systemctl enable --now kubelet🎮 Phase 3: 마스터 노드 초기화
마스터 노드에서만 실행
1. kubelet node-ip 설정
# Tailscale IP 확인
TAILSCALE_IP=$(tailscale ip -4)
echo "Control Plane Tailscale IP: $TAILSCALE_IP"
# kubelet이 Tailscale IP 사용하도록 설정
echo "KUBELET_EXTRA_ARGS=--node-ip=$TAILSCALE_IP" | sudo tee /etc/sysconfig/kubelet2. kubeadm 초기화
# 클러스터 초기화 (kube-proxy 없이)
sudo kubeadm init \
--apiserver-advertise-address=$TAILSCALE_IP \
--apiserver-cert-extra-sans=$TAILSCALE_IP \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/12 \
--skip-phases=addon/kube-proxy
# 출력되는 join 명령어를 안전한 곳에 저장!
# kubeadm join 100.64.0.1:6443 --token ... --discovery-token-ca-cert-hash ...3. kubectl 설정
# kubeconfig 설정
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 자동완성 설정
echo 'source <(kubectl completion bash)' >> ~/.bashrc
echo 'alias k=kubectl' >> ~/.bashrc
echo 'complete -o default -F __start_kubectl k' >> ~/.bashrc
source ~/.bashrc
# 노드 확인 (NotReady 상태가 정상 - CNI 설치 전)
kubectl get nodes4. Control Plane Taint 제거 (선택)
단일 노드 또는 테스트 환경에서 마스터에도 Pod 스케줄링:
kubectl taint nodes --all node-role.kubernetes.io/control-plane-🌐 Phase 4: Cilium CNI 설치
마스터 노드에서 실행
1. Helm 설치
# Helm 설치 스크립트
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
# 확인
helm version2. Cilium 설치 준비
# Cilium Helm 차트 추가
helm repo add cilium https://helm.cilium.io/
helm repo update
# Tailscale IP 확인
TAILSCALE_IP=$(tailscale ip -4)
echo "API Server IP: $TAILSCALE_IP"3. VXLAN vs Native Routing 선택
왜 VXLAN 터널링을 사용하나요?
Tailscale 환경의 제약:
# Tailscale은 노드 간 터널만 제공
# Pod 네트워크 라우팅은 자동으로 설정되지 않음!
# ❌ Native Routing 시도 시:
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
# → 노드 추가 시마다 모든 노드에서 수동 설정 필요!운영 복잡도 비교:
| 항목 | Native Routing | VXLAN Tunneling |
|---|---|---|
| 라우팅 관리 | 수동 (ip route) | 자동 (Cilium) |
| 노드 추가 | 모든 노드 업데이트 | 자동 감지 |
| 성능 | ~5% 빠름 | VXLAN 오버헤드 |
| 운영 난이도 | 높음 | 낮음 |
| 추천 | 고성능 필수 시 | 일반적인 경우 ✅ |
결론: 실무에서는 VXLAN의 운영 편의성이 미세한 성능 차이보다 훨씬 중요합니다.
4. Cilium 설치 실행
Tailscale 메시 네트워크에 최적화된 설정:
helm install cilium cilium/cilium \
--version 1.18.2 \
--namespace kube-system \
--set operator.replicas=1 \
--set operator.resources.limits.cpu="200m" \
--set operator.resources.limits.memory="256Mi" \
--set ipam.mode=kubernetes \
--set routingMode=tunnel \
--set tunnelProtocol=vxlan \
--set kubeProxyReplacement=true \
--set k8sServiceHost=$TAILSCALE_IP \
--set k8sServicePort=6443 \
--set autoDirectNodeRoutes=false \
--set bpf.masquerade=true \
--set loadBalancer.mode=snat \
--set bpf.lbExternalClusterIP=true \
--set enableIPv4Masquerade=true \
--set hostPort.enabled=true \
--set nodePort.enabled=true \
--set mtu=1200 \
--set ipv4.enabled=true \
--set ipv6.enabled=false \
--set image.pullPolicy=IfNotPresent \
--set hubble.relay.enabled=false \
--set hubble.ui.enabled=false \
--set prometheus.enabled=false주요 설정 설명
| 옵션 | 값 | 이유 |
|---|---|---|
routingMode=tunnel |
VXLAN 터널 | Tailscale과 호환 |
kubeProxyReplacement=true |
eBPF 사용 | kube-proxy 대체 |
mtu=1200 |
1200 bytes | Tailscale(1280) - VXLAN 헤더(50) |
loadBalancer.mode=snat |
SNAT | 리턴 패킷 라우팅 |
5. Cilium CLI 설치 및 확인
# Cilium CLI 설치
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=arm64
curl -L --fail --remote-name-all \
https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz
# 상태 확인
cilium status --wait
# 노드 Ready 확인
kubectl get nodes6. Cilium 동작 확인
# Cilium Pod 상태
kubectl -n kube-system get pods -l k8s-app=cilium
# Cilium 노드 목록 (Tailscale IP 확인)
kubectl -n kube-system exec ds/cilium -- cilium node list
# Masquerade 인터페이스 확인
kubectl -n kube-system exec ds/cilium -- cilium status --verbose | grep Masq
# 예상: Masquerading: BPF [enp0s6, tailscale0]
# CoreDNS 정상 동작 확인
kubectl get pods -n kube-system -l k8s-app=kube-dns👥 Phase 5: 워커 노드 추가
1. Join Token 생성 (마스터에서)
# 새로운 join 명령 생성
kubeadm token create --print-join-command
# 출력 예시:
# kubeadm join 100.64.0.1:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxx2. 워커 노드 Join (워커에서)
# Tailscale IP 설정
TAILSCALE_IP=$(tailscale ip -4)
echo "Worker Tailscale IP: $TAILSCALE_IP"
# kubelet node-ip 설정
echo "KUBELET_EXTRA_ARGS=--node-ip=$TAILSCALE_IP" | sudo tee /etc/sysconfig/kubelet
# Join 실행 (마스터에서 받은 명령 사용)
sudo kubeadm join 100.64.0.1:6443 \
--token <TOKEN> \
--discovery-token-ca-cert-hash sha256:<HASH>3. 노드 확인 (마스터에서)
# 노드 상태 확인
kubectl get nodes -o wide
# 노드 레이블 추가
kubectl label node <worker-name> node-role.kubernetes.io/worker=true✅ Phase 6: 클러스터 검증
1. 기본 통신 테스트
# 테스트 Pod 생성
kubectl run test-pod --image=nginx:alpine --restart=Never
# Pod 상태 확인
kubectl get pods -o wide
# Pod 로그 확인
kubectl logs test-pod
# Pod 삭제
kubectl delete pod test-pod2. 크로스 노드 통신 테스트
# 각 노드에 Pod 배포 (nicolaka/netshoot: 네트워크 디버깅 도구 포함)
kubectl run test-master --image=nicolaka/netshoot --restart=Never \
--overrides='{"spec":{"nodeSelector":{"node-role.kubernetes.io/control-plane":""}}}' \
-- sleep 3600
kubectl run test-worker --image=nicolaka/netshoot --restart=Never \
--overrides='{"spec":{"nodeSelector":{"node-role.kubernetes.io/worker":"true"}}}' \
-- sleep 3600
# Pod IP 확인
kubectl get pods -o wide
# 크로스 노드 ping 테스트
kubectl exec test-master -- ping -c 3 <worker-pod-ip>
kubectl exec test-worker -- ping -c 3 <master-pod-ip>
# DNS 테스트 (추가)
kubectl exec test-master -- nslookup kubernetes.default
kubectl exec test-worker -- nslookup kubernetes.default
# 테스트 정리
kubectl delete pod test-master test-worker왜 nicolaka/netshoot을 사용하나요?
- ✅ ping, curl, wget, dig, nslookup, traceroute, tcpdump 등 포함
- ✅ busybox보다 네트워크 디버깅에 최적화
- ✅ 실제 운영 환경 트러블슈팅에도 유용
3. Service 통신 테스트
# Deployment 생성
kubectl create deployment nginx --image=nginx:alpine --replicas=2
# Service 노출
kubectl expose deployment nginx --port=80 --type=ClusterIP
# Service 확인
kubectl get svc nginx
# 테스트 Pod에서 Service 접근 (curl 사용)
kubectl run test --rm -it --image=nicolaka/netshoot --restart=Never -- curl -s nginx
# 또는 간단한 HTTP 테스트
kubectl run test --rm -it --image=curlimages/curl --restart=Never -- curl -s nginx
# 정리
kubectl delete deployment nginx
kubectl delete svc nginx4. Cilium Health 확인
# Cilium 연결성 테스트 (시간이 걸림)
cilium connectivity test
# Health 상태
kubectl -n kube-system exec ds/cilium -- cilium-health status🔧 Phase 7: 마스터 노드 워크로드 스케줄링 설정 (옵셔널)
기본 동작: kubeadm은 마스터 노드에
node-role.kubernetes.io/control-plane:NoScheduletaint를 자동으로 추가하여 일반 워크로드가 스케줄되지 않도록 합니다.
언제 이 설정을 변경하나요?
graph TD
Start[마스터 노드 설정 결정] --> Q1{클러스터 규모?}
Q1 -->|1-2개 노드<br/>리소스 부족| SmallCluster[소규모 클러스터]
Q1 -->|3개 이상 노드<br/>워커 충분| LargeCluster[표준 클러스터]
SmallCluster --> Q2{개발/테스트?}
Q2 -->|예| RemoveTaint[옵션 A: Taint 제거<br/>마스터에 워크로드 허용]
Q2 -->|아니오<br/>프로덕션| KeepTaint1[Taint 유지 권장]
LargeCluster --> KeepTaint2[✅ Taint 유지<br/>컨트롤플레인 전용]
RemoveTaint --> Warning[⚠️ 주의: 게이트웨이 등<br/>고부하 워크로드는<br/>마스터 제외 권장]
style KeepTaint2 stroke:#4ecdc4,stroke-width:3px
style Warning stroke:#ff6b6b,stroke-width:2px옵션 A: Taint 제거 (마스터에 워크로드 허용)
사용 사례: 워커 노드가 1-2개뿐인 소규모 개발/테스트 환경
# 현재 taint 확인
kubectl describe node <master-node-name> | grep Taints
# Taint 제거 (마스터에 Pod 스케줄 허용)
kubectl taint nodes <master-node-name> node-role.kubernetes.io/control-plane:NoSchedule-
# ↑
# 마지막 '-' 주의!
# 제거 확인
kubectl describe node <master-node-name> | grep Taints
# 출력 예상: Taints: <none>주의사항:
# 게이트웨이 등 고부하 워크로드는 nodeSelector로 마스터 제외
apiVersion: apps/v1
kind: Deployment
metadata:
name: gateway
spec:
template:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: DoesNotExist # 마스터 노드 제외옵션 B: Taint 복구 (컨트롤플레인 전용으로 전환)
사용 사례: 워커 노드 확장 후 마스터를 컨트롤플레인 전용으로 격리
# 1. Taint 추가 (새 워크로드 스케줄링 금지)
kubectl taint nodes <master-node-name> node-role.kubernetes.io/control-plane:NoSchedule
# 2. 마스터에서 실행 중인 워크로드 확인
kubectl get pods -A -o wide --field-selector spec.nodeName=<master-node-name>
# 3. kube-system 외 네임스페이스의 Pod가 있다면 삭제 (자동으로 워커에 재배치)
kubectl delete pod <pod-name> -n <namespace>
# 4. 최종 확인 (시스템 Pod만 남아야 함)
kubectl get pods -A -o wide | grep <master-node-name>예상 결과 (정상):
# 마스터 노드에는 시스템 Pod만 실행
NAMESPACE NAME
kube-system cilium-xxxxx
kube-system cilium-envoy-xxxxx
kube-system cilium-operator-xxxxx
kube-system coredns-xxxxx
kube-system etcd-<master-name>
kube-system kube-apiserver-<master-name>
kube-system kube-controller-manager-<master-name>
kube-system kube-scheduler-<master-name>옵션 C: 권장 아키텍처 (워커 4개 이상)
graph TB
subgraph Architecture["권장 구성: 마스터 1 + 워커 3+"]
subgraph Master["🖥️ Master (Taint: NoSchedule)"]
CP[컨트롤플레인 전용<br/>etcd, apiserver, etc]
end
subgraph Worker1["🖥️ Worker 1"]
GW[게이트웨이 전용<br/>nodeSelector 고정]
end
subgraph Worker2["🖥️ Worker 2"]
App1[애플리케이션]
end
subgraph Worker3["🖥️ Worker 3+"]
App2[애플리케이션]
end
end
Internet[인터넷 트래픽] --> GW
GW --> App1
GW --> App2
style Master stroke:#4ecdc4,stroke-width:3px
style Worker1 stroke:#ffa500,stroke-width:2px설정 예시:
# 1. 마스터 taint 유지 (기본 상태)
kubectl describe node <master-name> | grep Taints
# Taints: node-role.kubernetes.io/control-plane:NoSchedule
# 2. Worker 1을 게이트웨이 전용으로 라벨링
kubectl label nodes <worker1-name> node-role=gateway
# 3. 게이트웨이 배포 시 nodeSelector 사용
apiVersion: apps/v1
kind: Deployment
metadata:
name: gateway
spec:
template:
spec:
nodeSelector:
node-role: gateway # Worker 1에만 배치검증: 새 Pod가 어디에 배치되는지 확인
# 테스트 Pod 생성
kubectl run nginx-test --image=nginx:alpine
# Pod가 배치된 노드 확인
kubectl get pod nginx-test -o wide
# 예상 결과:
# - Taint 제거한 경우: 마스터 또는 워커에 배치
# - Taint 유지한 경우: 워커에만 배치 (마스터 제외)
# 테스트 정리
kubectl delete pod nginx-test트레이드오프 요약
| 구성 | 장점 | 단점 | 권장 환경 |
|---|---|---|---|
| Taint 제거 | 리소스 효율 | 컨트롤플레인 위험 | 개발/테스트, 노드 1-2개 |
| Taint 유지 | 안정성 최우선 | 리소스 제약 | 프로덕션, 노드 3개 이상 |
핵심 원칙: "컨트롤플레인은 성역이다. 워크로드와 분리하라."
📋 체크리스트
필수 작업
- Containerd 설치 및 실행
- Kubernetes 패키지 설치
- 마스터 노드 초기화 성공
- kubectl 설정 완료
- Cilium CNI 설치
- 노드 Ready 상태 확인
- CoreDNS 정상 동작
- 워커 노드 Join (있는 경우)
- Pod 간 통신 성공
- Service 통신 성공
옵셔널 (Phase 7)
- 마스터 노드 taint 설정 결정 (유지 또는 제거)
- 워커 노드 역할 라벨링 (게이트웨이 전용 등)
- 테스트 Pod로 스케줄링 동작 검증
⚠️ 트러블슈팅
노드가 NotReady 상태
# kubelet 로그 확인
sudo journalctl -u kubelet -f
# CNI 플러그인 확인
ls -la /opt/cni/bin/Pod 간 통신 불가
# Cilium 상태 확인
cilium status
# VXLAN 인터페이스 확인
ip link show | grep vxlan
# iptables 규칙 확인
sudo iptables -L -n -t nat🔄 다음 단계
클러스터가 정상 동작하면:
→ 04-deep-dive-networking.md - 네트워킹 심화 이해
💡 추가 팁
리소스 최적화
Control Plane (2 OCPU, 12GB):
# kubelet 리소스 예약
sudo tee -a /var/lib/kubelet/config.yaml <<EOF
systemReserved:
cpu: "200m"
memory: "512Mi"
kubeReserved:
cpu: "200m"
memory: "512Mi"
EOFWorker Node (4 OCPU, 24GB):
# 더 많은 Pod 허용
sudo tee -a /var/lib/kubelet/config.yaml <<EOF
maxPods: 110
systemReserved:
cpu: "300m"
memory: "1Gi"
EOF모니터링 추가
# Metrics Server 설치
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# ARM64 호환성 패치
kubectl patch deployment metrics-server -n kube-system --type='json' \
-p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--kubelet-insecure-tls"}]'
# 확인
kubectl top nodes
kubectl top pods축하합니다! Kubernetes 클러스터가 성공적으로 구축되었습니다.
'실제 경험과 인사이트를 AI와 함께 정리한 글' 카테고리의 다른 글
| Oracle Cloud + Tailscale + Kubernetes 완벽 가이드(6) (0) | 2025.10.26 |
|---|---|
| Oracle Cloud + Tailscale + Kubernetes 완벽 가이드(5) (0) | 2025.10.26 |
| Oracle Cloud + Tailscale + Kubernetes 완벽 가이드(3) (0) | 2025.10.26 |
| Oracle Cloud + Tailscale + Kubernetes 완벽 가이드(2) (0) | 2025.10.26 |
| Oracle Cloud + Tailscale + Kubernetes 완벽 가이드(1) (0) | 2025.10.26 |
- Total
- Today
- Yesterday
- Claude
- AI agent
- Tailwind CSS
- LangChain
- Developer Tools
- Ontology
- SHACL
- Tax Analysis
- frontend
- claude code
- PYTHON
- architecture
- Go
- Rag
- react
- authentication
- api gateway
- AI
- 개발 도구
- knowledge graph
- security
- backend
- Kubernetes
- troubleshooting
- authorization
- LLM
- workflow
- AI Development
- Next.js
- ai 개발 도구
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
