kube-controller-manager : 다양한 컨트롤러들을 하나의 프로세스로 묶어 실행하는 컴포넌트 입니다.
Node Controller (노드 장애 감지), Replicaset Controller(Pod 수 유지) 등 수십 개의 컨트롤러가 동작
위 내용들을 가지고 도식화를 해보자면 그림과 같습니다 (apiserver 중심)
vanilla k8s는 이런 컨트롤 플레인의 구성들을 직접 관리해야 합니다.
추가적으로 위 구성들을 어떤 노드에 올릴지, HA구성을 어떻게 할지, 인증서 갱신은 어떻게 처리할지,
버전 업그레이드는 어떻게 할지 전부 사용자 책임입니다.
EKS는 스터디 하면서 잘 아시다 싶이 컨트롤 플레인 전체가 AWS Managed VPC 관리 영역으로 빠집니다.
사용자는 Control Plane 노드 자체를 볼 수도 없고, etcd backup이나 apiserver HA 구성에
신경 쓸 필요도 없습니다. (AWS가 알아서 Multi-AZ에 Control Plane을 배치하고, 장애 시 자동 복구)
위의 내용을 도식화 해보았을 때 확실히 사용자가 까다롭게 관리해야 할 것 같습니다만,
커스터마이징이 자유로워 사내 보안 규정에 맞게 잘 관리가 될 것 같기도 합니다.
데이터플레인 비교
vanilla k8s는 data plane 까지도 직접 구성한 EC2(또는 베어메탈, VM) 위에 올리고
kubelet, kube-proxy, CNI 플러그인도 직접 설치 및 관리를 해야 합니다.
반면에 EKS는 add-on 기능을 사용하여 쉽게 구성이 가능하며, 관리도 용이합니다 !
EKS에 대해서 학습할 때 데이터플레인은 많이 뜯어봤기 때문에 자세한 설명은 생략하고,
EKS에서 add-on으로 vpc-cni를 사용했었는데 여기에선 Calico, Cilium, Flannel에 대해서
간단하게 나마 알아보는 시간을 갖도록 하겠습니다.
📌 CNI (Container Network Interface) Plugin
k8s는 네트워킹 구현을 직접 제공하지 않습니다.
"Pod끼리 통신할 수 있어야 한다", "Pod에 IP가 할당되어야 한다"는 스펙만 정의하고, 구현은 CNI에 위임.
vanilla k8s를 설치하면 CNI가 없는 상태로 시작하기 때문에 클러스터 관리자가 직접 골라서 설치해야함.
1)Flaneel : 가장 단순한 오버레이 네트워크 방식
노드 간 트래픽을 VXLAN으로 캡슐화해서 전달합니다.
설정이 거의 없어서 학습용이나 간단한 스테이징, 개발 환경에 적합하지만 Network Policy를 미지원.
2) Calico : BGP 라우팅 기반으로 동작합니다.
오버레이 없이 실제 라우팅 테이블을 조작하기 때문에 성능이 좋고, Network Policy를 지원함.
대규모 프로덕션 환경에서 가장 많이 선택되는 CNI 중 하나입니다.
3) Cilium : eBPF를 기반으로 동작합니다.
커널 레벨에서 패킷을 처리하기 때문에 성능이 뛰어나고, L7 수준의 네트워크 정책, Service Mesh 기능 제공
복잡하지만 현재 가장 활발하게 발전중인 CNI라고 합니다.
각 CNI마다 특징이 다르지만, 핵심은 명확합니다. "다른 노드에 있는 Pod끼리 어떻게 통신하게 만들 것인가?"
이걸 해결하는 방식이 크게 오버레이(VXLAN) vs 언더레이(BGP / Calico)로 나뉩니다.
이 내용은 2주차의 EKS 네트워킹 중, CNI 동작 과정에서 딥하게 다뤄볼 예정입니다.
간단하게 말씀드리자면, 인캡슐레이션 디캡슐레이션 시 사용되는 리소스에 대한 오버헤드 차이 입니다.
03. sample application 배포
📌 kube-ops-view install
클러스터의 노드와 파드 상태를 실시간으로 시각화 해주는 대쉬보드를 설치해 볼 예정입니다.
# kube-ops-view
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view \
--version 1.2.2 \
--set service.main.type=NodePort \
--set service.main.ports.http.nodePort=30000 \
--set env.TZ="Asia/Seoul" \
--namespace kube-system
# 확인
kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view
# kube-ops-view 접속
open "http://$NODE1:30000/#scale=1.5"
open "http://$NODE1:30000/#scale=1.3"
위 helm 차트에서 kube-ops-view를 가져올 때 명령어를 잠깐 살펴보도록 하겠습니다.
service.main.type=NodePort : 외부에서 노드IP로 직접 접근할 수 있게 NodePort 방식으로 서비스를 연다. service.main.ports.http.nodeport=30000 : NodePort 번호를 30000으로 고정한다. (지정을 안하게 되면 30000~32767 사이에서 랜덤으로 배정됨) --namespace kube-system : kube-ops-view가 클러스터 전체 상태를 읽어야 하기 때문에 kube-system에 설치.
위 명령으로 서비스를 띄운 후 pod, service, endpoint 까지 확인할 수 있습니다.
실제로 데쉬보드 형태로 보았을 때 아래와 같이 테스트 환경에서 파드 상태를 확인하기 좋습니다.
📌 게임 파드 배포 by nodePort 30001
# 샘플 애플리케이션 배포
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: mario
labels:
app: mario
spec:
replicas: 1
selector:
matchLabels:
app: mario
template:
metadata:
labels:
app: mario
spec:
containers:
- name: mario
image: pengbai/docker-supermario
---
apiVersion: v1
kind: Service
metadata:
name: mario
spec:
selector:
app: mario
ports:
- port: 80
protocol: TCP
targetPort: 8080
nodePort: 30001
type: NodePort
EOF
# 확인
kubectl get deploy,pod,svc,ep
# 접속
curl http://$NODE1:30001 -I
open http://$NODE1:30001
위 yaml 파일을 배포하였을 때 아래와 같이 서비스들을 확인할 수 있습니다.
서비스에 대해서 아래와 같이 간단하게 설명하도록 하겠습니다.
service/mario -> 80:30001/TCP - 80은 서비스 내부 포트, 30001은 외부에서 접근하는 NodePort 이므로 http://$NODE1:30001로 접근 - 서비스가 192.168.1.230:8080 (mario Pod)으로 트래픽을 전달합니다.