Cilium 을 활용한 Kubernetes ClusterMesh 환경 구성

Jaemyeong.Lee·2023년 9월 13일
1

Cilium 을 활용한 Kubernetes ClusterMesh 환경 구성

cilium 의 여러가지 기능중에 clustermesh 를 활용하여 multi kubernetes cluster 를 구성하는 방법을 설명합니다.

cilium 이 제공할 수 있는 것

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 구성이라면 아래 요건이 필요할텐데요.

  • multi cluster routing
  • application 배포시 pod 가 multi cluster 에 배포
  • cluster 가 추가되면 기존 pod 리벨런싱

cilium 의 기본 동작 원리가 k8s service 를 확장하는 개념이기 때문에 필요요건 중에 multi cluster 의 traffic 을 routing 해주는 기능을 제공해 줄 수 있습니다.

  • cilium 은 multi cluster routing 기능에 초점

cilium 이 multi cluster 의 전체 요건을 충족한다고 볼 수는 없으나 multi cluster routing 기능을 활용하여 아래 cluster 운영 요건을 해결하는데 도움을 줄 수 있을 것이라는 개인적인 생각입니다.

  • kubernetes migration
  • kubernetes version upgrade
  • kubernetes 이중화 구성
  • kubernetes 재해복구 구성

multi cluster routing 구성(L4 단순 연결)

아래 그림은 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

multi cluster routing 구성(cilium clusermesh 활용)

아래 그림은 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 구현

아래 Demo 절차는 직접 구현을 해볼 수 있도록 step-by-step 으로 모든 script 를 포함하고 있으니 순서대로 직접 구현을 해보셔도 좋습니다.

참고로 아래 환경에서 실행하였습니다. 다른 os 에서는 shell script 를 다르게 사용해야 합니다.

  • mac os
  • docker desktop
  • minikube

Demo 요약

minikube 로 2개의 cluster 를 생성하고 cilium clustermesh 설정을 한 후 각 cluster 에 application 을 배포하여 multi cluster 간 pod routing 이 되는지 확인하는 절차입니다.

중요 체크사항으로 아래 minikube 설정에는 service cidr, pod cidr 을 동일하게 구성했습니다. 실제로 multi cluster routing 구성시에는 각 cluster 마다 다른 cidr 을 가지도록 설정을 해야 합니다.

cilium cli 설치

아래 절차는 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 설치

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

mk-prd 구성

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

mk-mig 구성

설치 절차는 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 연결 및 확인

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

sample application service, pod ip 확인

각 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 확인

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)

minikube ingress service 터널링 설정

이제 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]

sample application api 호출 확인

curl 명령어로 각 cluster 에 ingress 호출과 cilium ingress 를 각각 호출하여 routing 결과를 확인합니다.

ingress 호출

각 클러스터에 있는 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 호출

각 클러스터에 있는 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.

0개의 댓글