cilium 의 여러가지 기능중에 clustermesh 를 활용하여 multi kubernetes cluster 를 구성하는 방법을 설명합니다.
cilium 의 기본 동작은 multi cluster 에 배포된 Application 의 k8s service 에 cilium service annotation 을 추가하는 것으로 동작합니다.
# k8s service object 에 annotaion 추가
apiVersion: v1
kind: Service
metadata:
name: echoserver
namespace: echoserver
annotations:
service.cilium.io/global: "true"
진정한 multi cluster 구성이라면 아래 요건이 필요할텐데요.
cilium 의 기본 동작 원리가 k8s service 를 확장하는 개념이기 때문에 필요요건 중에 multi cluster 의 traffic 을 routing 해주는 기능을 제공해 줄 수 있습니다.
cilium 이 multi cluster 의 전체 요건을 충족한다고 볼 수는 없으나 multi cluster routing 기능을 활용하여 아래 cluster 운영 요건을 해결하는데 도움을 줄 수 있을 것이라는 개인적인 생각입니다.
아래 그림은 kubernetes cluster 2개를 를 단순히 L4 에 연결하여 ingress 로 접속되게 한 이중화 구성입니다.
flowchart TB
subgraph minikube-prd
direction TB
A1[Ingress] --> B1[Service] --> C10[Pod]
B1[Service] --> C11[Pod]
end
subgraph minikube-mig
direction TB
A2[Ingress] --> B2[Service] --> C21[Pod]
B2[Service] --> C22[Pod]
end
LB[L4] --> A1
LB[L4] --> A2
이런 구성에서 아래 그림처럼 1개 cluster 내 pod 가 전체적으로 장애가 발생할 경우에 L4 에서는 인지를 할 수 없으니 traffic 을 계속해서 cluster 로 routing 을 하게 되서 일부 traffic 에 대한 장애가 발생하게 됩니다.
flowchart TB
subgraph minikube-prd
direction TB
A1[Cilium Ingress] --> B1[Service]
B1[Service] -.X.- C11[Pod X]
B1[Service] -.X.- C12[Pod X]
end
subgraph minikube-mig
direction TB
A2[Cilium Ingress] --> B2[Service]
B2[Service] --> C21[Pod]
B2[Service] --> C22[Pod]
end
LB[L4] --traffic--> A1
LB[L4] --> A2
아래 그림은 cilium clusermesh 기능을 활용하여 multi cluster routing 기능을 구성한 모습니다.
flowchart TB
subgraph minikube-prd
direction TB
A1[Cilium Ingress] --> B1[Service]
B1[Service] --> C11[Pod]
B1[Service] --> C12[Pod]
end
subgraph minikube-mig
direction TB
A2[Cilium Ingress] --> B2[Service]
B2[Service] --> C21[Pod]
B2[Service] --> C22[Pod]
end
B1 --> C21
B1 --> C22
B2 --> C11
B2 --> C12
LB[L4] --> A1
LB[L4] --> A2
아래 그림에서 보듯이 1개 cluster 내에 pod 가 전체 장애가 발생하더라도 다른 cluster 의 pod 로 routing 을 해주게 됩니다.
flowchart TB
subgraph minikube-prd
direction TB
A1[Cilium Ingress] --> B1[Service]
B1[Service] -.X.- C11[Pod X]
B1[Service] -.X.- C12[Pod X]
end
subgraph minikube-mig
direction TB
A2[Cilium Ingress] --> B2[Service]
B2[Service] --> C21[Pod]
B2[Service] --> C22[Pod]
end
B1 --> C21
B1 --> C22
B2 -.X.- C11
B2 -.X.- C12
LB[L4] --> A1
LB[L4] --> A2
아래 Demo 절차는 직접 구현을 해볼 수 있도록 step-by-step 으로 모든 script 를 포함하고 있으니 순서대로 직접 구현을 해보셔도 좋습니다.
참고로 아래 환경에서 실행하였습니다. 다른 os 에서는 shell script 를 다르게 사용해야 합니다.
minikube 로 2개의 cluster 를 생성하고 cilium clustermesh 설정을 한 후 각 cluster 에 application 을 배포하여 multi cluster 간 pod routing 이 되는지 확인하는 절차입니다.
중요 체크사항으로 아래 minikube 설정에는 service cidr, pod cidr 을 동일하게 구성했습니다. 실제로 multi cluster routing 구성시에는 각 cluster 마다 다른 cidr 을 가지도록 설정을 해야 합니다.
아래 절차는 cilium cli 로 명령어를 실행하지만 실제로 cilium 은 CRD(custom resource definition)을 생성하게 됩니다. 생성되는 CRD 는 cluster 내에서 조회하거나 cilium document 를 참고하세요.
os 환경에 맞게 script 를 사용해야 합니다. cilium document 를 참고하세요.
# local 에서 실행
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/master/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "arm64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-darwin-${CLI_ARCH}.tar.gz{,.sha256sum}
shasum -a 256 -c cilium-darwin-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-darwin-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-darwin-${CLI_ARCH}.tar.gz{,.sha256sum}
cilium
minikube 가 설치나 addon 을 사용하는데 편리하여 단순 클러스터 구성시 자주 사용합니다. os 환경에 맞게 script 를 사용해야 합니다. minikube document 를 참고하세요.
# local 에서 실행
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64
sudo install minikube-darwin-amd64 /usr/local/bin/minikube
minikube version
# 설치된 minikube 확인
minikube profile list
# 삭제시 사용
minikube delete --all
# 다운로드 한 docker image 까지 삭제할때 사용
minikube delete --all --purge
Demo 에는 2개의 cluster 가 필요합니다. prd 클러스터를 먼저 생성합니다.
각 단계는 이전 단계에서 생성되는 pod 가 정상적으로 실행이 되어야 다음 단계가 실행될 수 있으니 pod 실행 상태를 모니터링 하면서 진행하세요.
# local 에서 실행
# minikube 설치
# --insecure-registry : docker image pull 시 403 에러 발생해서 추가
# --static-ip : node ip 를 다르게 하려고 추가
minikube start -p mk-prd \
--driver=docker \
--insecure-registry="quay.io" \
--insecure-registry="registry.k8s.io" \
--network=minikube \
--static-ip=192.168.0.100 \
--container-runtime=containerd \
--network-plugin=cni \
--cni=true
# metal lb 설치
# minikube 에 addon 인 ingress 가 loadbalacer type 으로 실행되므로 추가
kubectl --context=mk-prd apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.10/config/manifests/metallb-native.yaml
# metal lb IPAddressPool 설치
kubectl --context=mk-prd apply -f - <<EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.100.0/24
EOF
# minikube ingress enable
minikube addons enable ingress -p mk-prd
# cilium install with ingressController enable
cilium install --context mk-prd \
--cluster-id=1 \
--kube-proxy-replacement=strict \
--helm-set ingressController.enabled=true \
--helm-set ingressController.loadbalancerMode=shared
# cilium hubble enable
cilium hubble enable --context mk-prd \
--ui \
--helm-set hubble.relay.service.type=ClusterIP
# cilium clustermesh enable
cilium clustermesh enable --context mk-prd --service-type=NodePort
# cilium 상태 확인
cilium status --context mk-prd
# sample app 배포
kubectl --context=mk-prd apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
name: echoserver
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserver
namespace: echoserver
spec:
replicas: 1
selector:
matchLabels:
app: echoserver
template:
metadata:
labels:
app: echoserver
spec:
containers:
- image: ealen/echo-server:latest
imagePullPolicy: IfNotPresent
name: echoserver
ports:
- containerPort: 80
env:
- name: PORT
value: "80"
---
apiVersion: v1
kind: Service
metadata:
name: echoserver
namespace: echoserver
annotations:
service.cilium.io/global: "true"
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
type: ClusterIP
selector:
app: echoserver
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echoserver
namespace: echoserver
spec:
ingressClassName: nginx
rules:
- host: echoserver.localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: echoserver
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echoserver-cilium
namespace: echoserver
spec:
ingressClassName: cilium
rules:
- host: echoserver.cilium.localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: echoserver
port:
number: 80
EOF
설치 절차는 prd cluster 와 동일합니다.
# local 에서 실행
# minikube 설치
minikube start -p mk-mig \
--driver=docker \
--insecure-registry="quay.io" \
--insecure-registry="registry.k8s.io" \
--network=minikube \
--static-ip=192.168.0.200 \
--container-runtime=containerd \
--network-plugin=cni \
--cni=true
# metal lb 설치
kubectl --context=mk-mig apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.10/config/manifests/metallb-native.yaml
# IPAddressPool 설치
kubectl --context=mk-mig apply -f - <<EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: first-pool
namespace: metallb-system
spec:
addresses:
- 192.168.200.0/24
EOF
# minikube ingress enable
minikube addons enable ingress -p mk-mig
# cilium install with ingressController enable
cilium install --context mk-mig \
--cluster-id=2 \
--kube-proxy-replacement=strict \
--helm-set ingressController.enabled=true \
--helm-set ingressController.loadbalancerMode=shared
# cilium hubble enable
cilium hubble enable --context mk-mig \
--ui \
--helm-set hubble.relay.service.type=ClusterIP
# cilium clustermesh enable
cilium clustermesh enable --context mk-mig --service-type=NodePort
# cilium 상태 확인
cilium status --context mk-mig
# sample app 배포
kubectl --context=mk-mig apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
name: echoserver
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserver
namespace: echoserver
spec:
replicas: 1
selector:
matchLabels:
app: echoserver
template:
metadata:
labels:
app: echoserver
spec:
containers:
- image: ealen/echo-server:latest
imagePullPolicy: IfNotPresent
name: echoserver
ports:
- containerPort: 80
env:
- name: PORT
value: "80"
---
apiVersion: v1
kind: Service
metadata:
name: echoserver
namespace: echoserver
annotations:
service.cilium.io/global: "true"
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
type: ClusterIP
selector:
app: echoserver
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echoserver
namespace: echoserver
spec:
ingressClassName: nginx
rules:
- host: echoserver.localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: echoserver
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echoserver-cilium
namespace: echoserver
spec:
ingressClassName: cilium
rules:
- host: echoserver.cilium.localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: echoserver
port:
number: 80
EOF
cilium clustermesh 기능을 활성화해서 2개 cluster 간 routing 이 되도록 설정합니다.
# clustermesh connect 설정
cilium clustermesh connect --context mk-prd --destination-context mk-mig
# clustermesh 설정 상태 확인, 완료될때까지
cilium clustermesh status --context mk-prd --wait
각 cluster 에 배포된 sample application echoserver 의 service, pod ip 를 확인해봅니다. 이때 ip 가 중복되지 않아야 합니다.
위에서 cluster cidr 설정 필요에 대해 언급했습니다.
kubectl --context=mk-prd get -n echoserver svc -o wide
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
# echoserver ClusterIP 10.110.200.29 <none> 80/TCP 24m app=echoserver
kubectl --context=mk-mig get -n echoserver svc -o wide
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
# echoserver ClusterIP 10.107.10.189 <none> 80/TCP 15m app=echoserver
kubectl --context=mk-prd get -n echoserver pod -o wide
# NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
# echoserver-75b74d967-z2k6f 1/1 Running 0 24m 10.0.0.124 mk-prd <none> <none>
kubectl --context=mk-mig get -n echoserver pod -o wide
# NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
# echoserver-75b74d967-58gmq 1/1 Running 0 16m 10.0.0.76 mk-mig <none> <none>
cilium service routing 을 확인해보면 아래 결과처럼 echoserver service clusterIP 에 각 cluster 의 2개의 pod ip 가 할당되고 active 상태인 것을 확인할 수 있습니다.
cluster 내 service clusterIP 로 들어오는 traffic 을 각 cluster 의 pod 로 routing 을 해준다는 의미입니다.
cluster 가 3개 이상으로 늘어난다면 아래 숫자도 해당 cluster 수 만큼 늘어나게 됩니다.
kubectl --context=mk-prd exec -n kube-system -ti ds/cilium -- cilium service list --clustermesh-affinity
# 30 10.110.200.29:80 ClusterIP 1 => 10.0.0.124:80 (active)
# 2 => 10.0.0.76:80 (active)
kubectl --context=mk-mig exec -n kube-system -ti ds/cilium -- cilium service list --clustermesh-affinity
# 30 10.107.10.189:80 ClusterIP 1 => 10.0.0.76:80 (active)
# 2 => 10.0.0.124:80 (active)
이제 traffic 을 확인해보기 위해 minikube 의 ingress service 를 local 에서 호출할 수 있도록 minikube service 터널링을 실행합니다.
실행상태로 유지되어야 하니 별도의 터미널에서 실행하세요.
# service 목록을 확인합니다.
minikube service list -p mk-prd
minikube service list -p mk-mig
# minikube ingress service 를 터널링
minikube service -n ingress-nginx ingress-nginx-controller -p mk-prd
minikube service -n ingress-nginx ingress-nginx-controller -p mk-mig
# cilium ingress service 를 터널링
minikube service -n kube-system cilium-ingress -p mk-prd
minikube service -n kube-system cilium-ingress -p mk-mig
# 각 실행 결과는 아래 형태로 표시됩니다. http/80 에 해당하는 port 를 확인합니다.
# 아래 실행결과에서는 http://127.0.0.1:60011 를 사용해서 cilium-ingress 를 호출하면 됩니다.
# 각 실행결과를 참고하세요.
# |-------------|----------------|-------------|----------------------------|
# | NAMESPACE | NAME | TARGET PORT | URL |
# |-------------|----------------|-------------|----------------------------|
# | kube-system | cilium-ingress | http/80 | http://192.168.0.100:30880 |
# | | | https/443 | http://192.168.0.100:32224 |
# |-------------|----------------|-------------|----------------------------|
# 🏃 Starting tunnel for service cilium-ingress.
# |-------------|----------------|-------------|------------------------|
# | NAMESPACE | NAME | TARGET PORT | URL |
# |-------------|----------------|-------------|------------------------|
# | kube-system | cilium-ingress | | http://127.0.0.1:60011 |
# | | | | http://127.0.0.1:60012 |
# |-------------|----------------|-------------|------------------------|
# [kube-system cilium-ingress http://127.0.0.1:60011 http://127.0.0.1:60012]
curl 명령어로 각 cluster 에 ingress 호출과 cilium ingress 를 각각 호출하여 routing 결과를 확인합니다.
각 클러스터에 있는 ingress 호출하면 해당 서버에 있는 pod 만 호출됨
# 각 클러스터에 있는 ingress 호출하면 해당 서버에 있는 pod 만 호출됨
# port 를 위에 조회된 걸로 변경해야 함
for i in {1..10}
do
curl -H "Host: echoserver.localhost" http://127.0.0.1:63599/?echo_env_body=HOSTNAME
sleep 1
echo ""
done
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
for i in {1..10}
do
curl -H "Host: echoserver.localhost" http://127.0.0.1:63847/?echo_env_body=HOSTNAME
sleep 1
echo ""
done
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
각 클러스터에 있는 cilium ingress 호출하면 2개 서버에 있는 pod 에 호출됨
# port 를 위에 조회된 걸로 변경해야 함
for i in {1..10}
do
curl -H "Host: echoserver.cilium.localhost" http://127.0.0.1:63869/?echo_env_body=HOSTNAME
sleep 1
echo ""
done
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
for i in {1..10}
do
curl -H "Host: echoserver.cilium.localhost" http://127.0.0.1:63987/?echo_env_body=HOSTNAME
sleep 1
echo ""
done
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-58gmq"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-z2k6f"
# "echoserver-75b74d967-58gmq"
이상으로 cilium clustermesh 를 활용하여 multi cluster routing 을 구성해 봤습니다.
cilium 은 network 관련해서 종합선물셋트와 같은 open source 입니다.
추가로 cilium 의 기능을 테스트하고 공유하도록 하겠습니다.
.End.