Kind로 Cilium 설치하기

Kind로 Cilium 설치하기

이 가이드는 kind를 사용해 Docker 위에서 로컬로 실행되는 멀티노드 Kubernetes 클러스터에 Cilium을 배포하고 운영하는 방법을 보여줘요.

출처: Installation Using Kind

본문

이 가이드는 kind를 사용해 Docker 위에서 로컬로 실행되는 멀티노드 Kubernetes 클러스터에서 Cilium의 배포와 운영을 시연해요.

의존성 설치하기

  1. Install Docker Engine에 설명된 대로 docker stable을 설치해요.
  2. Kubernetes Docs에 설명된 대로 kubectl 버전 >= v1.14.0을 설치해요.
  3. Helm 문서 Installing Helm에 따라 helm >= v3.13.0을 설치해요.
  4. kind 문서 Installation and Usage에 따라 kind >= v0.7.0을 설치해요.

kind 구성하기

kind 클러스터 생성은 YAML 구성 파일로 해요. 기본 CNI를 비활성화하고 Cilium으로 교체하려면 이 단계가 필요해요.

다음 템플릿을 바탕으로 kind-config.yaml 파일을 만들어요. 이 파일은 워커 노드 3개와 컨트롤 플레인 노드 1개로 구성된 클러스터를 생성해요.

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
- role: worker
networking:
  disableDefaultCNI: true

기본적으로 kind 릴리스가 만들어질 당시의 최신 Kubernetes 버전이 사용돼요.

실행 중인 Kubernetes 버전을 바꾸려면 각 노드에 image를 정의해야 해요. 자세한 내용은 Node Configuration 문서를 참고하세요.

팁

기본적으로 kind는 다음 pod와 service 서브넷을 사용해요.

Networking.PodSubnet     = "10.244.0.0/16"
Networking.ServiceSubnet = "10.96.0.0/12"

이 서브넷 중 하나라도 로컬 네트워크 주소 범위와 충돌한다면, kind 구성 파일의 networking 섹션을 업데이트해 충돌하지 않는 다른 서브넷을 지정하세요. 그렇지 않으면 Cilium 배포 시 연결 문제가 생길 수 있어요. 예를 들면:

networking:
  disableDefaultCNI: true
  podSubnet: "10.10.0.0/16"
  serviceSubnet: "10.11.0.0/16"

클러스터 생성하기

위에서 정의한 구성으로 클러스터를 만들려면 만든 kind-config.yaml을 kind의 --config 플래그로 전달해요.

kind create cluster --config=kind-config.yaml

몇 초 또는 몇 분 후 4개 노드 클러스터가 생성돼요.

새 kubectl 컨텍스트(kind-kind)가 KUBECONFIG에 추가되거나, 설정되지 않았다면 ${HOME}/.kube/config에 추가돼요.

kubectl cluster-info --context kind-kind

참고

Cilium을 배포하기 전까지 클러스터 노드는 NotReady 상태로 남아요. 이 동작은 정상이에요.

Cilium 설치하기

Helm 저장소를 설정해요.

helm repo add cilium https://helm.cilium.io/

Cilium 차트는 OCI 레지스트리(Quay.io와 Docker Hub)에서도 사용할 수 있어요. 별도 설정 없이 oci:// URL로 바로 설치하면 됩니다.

차트 서명 검증과 digest 기반 설치는 OCI Registry 섹션을 참고하세요.

kind 클러스터의 각 워커 노드에 cilium 이미지를 미리 로드해요.

docker pull quay.io/cilium/cilium:v1.20.2
kind load docker-image quay.io/cilium/cilium:v1.20.2

그런 다음 Helm으로 Cilium 릴리스를 설치해요.

helm install cilium cilium/cilium --version 1.20.2 \
   --namespace kube-system \
   --set image.pullPolicy=IfNotPresent \
   --set ipam.mode=kubernetes
helm install cilium oci://quay.io/cilium/charts/cilium 1.20.2 \
   --namespace kube-system \
   --set image.pullPolicy=IfNotPresent \
   --set ipam.mode=kubernetes

참고

Cilium의 Socket LB (Kubernetes Without kube-proxy)를 활성화하려면 cgroup v2가 활성화되고, Kind 노드가 별도의 cgroup namespaces에서 실행되어야 하며, 이 네임스페이스들이 Cilium이 올바른 cgroup 계층에 BPF 프로그램을 attach할 수 있도록 기본 호스트의 cgroup 네임스페이스와 달라야 해요. 확인하려면 다음 명령을 실행하고 cgroup 값이 서로 다른지 확인하세요.

$ docker exec kind-control-plane ls -al /proc/self/ns/cgroup
lrwxrwxrwx 1 root root 0 Jul 20 19:20 /proc/self/ns/cgroup -> 'cgroup:[4026532461]'

$ docker exec kind-worker ls -al /proc/self/ns/cgroup
lrwxrwxrwx 1 root root 0 Jul 20 19:20 /proc/self/ns/cgroup -> 'cgroup:[4026532543]'

$ ls -al /proc/self/ns/cgroup
lrwxrwxrwx 1 root root 0 Jul 19 09:38 /proc/self/ns/cgroup -> 'cgroup:[4026531835]'

cgroup v2를 활성화하는 한 가지 방법은 커널 파라미터 systemd.unified_cgroup_hierarchy=1을 설정하는 거예요. cgroup 네임스페이스를 활성화하려면 컨테이너 런타임을 그에 맞게 구성해야 해요. 예를 들어 Docker에서는 dockerd의 --default-cgroupns-mode를 private으로 설정해야 해요.

Kind에서 Socket LB가 제대로 동작하게 하는 또 다른 요구사항은 cgroup v1 컨트롤러 net_cls와 net_prio를 비활성화하거나(또는 커널 파라미터 cgroup_no_v1="all"로 cgroup v1을 아예 비활성화하거나), 호스트 커널이 이 fix를 포함하도록 5.14 이상이어야 한다는 거예요.

자세한 내용은 Pull Request를 참고하세요.

설치 검증하기

최신 버전의 Cilium CLI를 설치해요. Cilium CLI는 Cilium 설치, 설치 상태 점검, 다양한 기능(예: clustermesh, Hubble) 활성화/비활성화에 사용할 수 있어요.

CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/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}

전체 releases 페이지를 참고하세요.

Cilium이 제대로 설치됐는지 확인하려면 다음을 실행해요.

$ cilium status --wait
   /¯\
/¯\__/¯\    Cilium:         OK
\__/¯\__/    Operator:       OK
/¯\__/¯\    Hubble:         disabled
\__/¯\__/    ClusterMesh:    disabled
   \__/

DaemonSet         cilium             Desired: 2, Ready: 2/2, Available: 2/2
Deployment        cilium-operator    Desired: 2, Ready: 2/2, Available: 2/2
Containers:       cilium-operator    Running: 2
                  cilium             Running: 2
Image versions    cilium             quay.io/cilium/cilium:v1.9.5: 2
                  cilium-operator    quay.io/cilium/operator-generic:v1.9.5: 2

클러스터가 올바른 네트워크 연결을 갖췄는지 확인하려면 다음 명령을 실행해요.

$ cilium connectivity test
ℹ️  Monitor aggregation detected, will skip some flow validation steps
✨ [k8s-cluster] Creating namespace for connectivity check...
(...)
---------------------------------------------------------------------------------------------------------------------
📋 Test Report
---------------------------------------------------------------------------------------------------------------------
✅ 69/69 tests successful (0 warnings)

참고

연결성 테스트는 Pod 중 하나에 열린 파일이 너무 많아 배포에 실패할 수 있어요. 이런 오류가 보이면 호스트 머신의 inotify 리소스 한도를 늘리세요 (Pod errors due to "too many open files").

축하해요! 이제 Cilium이 동작하는 완전한 Kubernetes 클러스터가 갖춰졌어요. 🎉

Cilium과 필요한 컴포넌트들이 설치되는 과정을 다음과 같이 모니터링할 수 있어요.

$ kubectl -n kube-system get pods --watch
NAME                                    READY   STATUS              RESTARTS   AGE
cilium-operator-cb4578bc5-q52qk         0/1     Pending             0          8s
cilium-s8w5m                            0/1     PodInitializing     0          7s
coredns-86c58d9df4-4g7dd                0/1     ContainerCreating   0          8m57s
coredns-86c58d9df4-4l6b2                0/1     ContainerCreating   0          8m57s

모든 컴포넌트가 뜨기까지 몇 분이 걸릴 수 있어요.

cilium-operator-cb4578bc5-q52qk         1/1     Running   0          4m13s
cilium-s8w5m                            1/1     Running   0          4m12s
coredns-86c58d9df4-4g7dd                1/1     Running   0          13m
coredns-86c58d9df4-4l6b2                1/1     Running   0          13m

Pod 사이의 연결을 테스트하려면 "connectivity-check"를 배포할 수 있어요. 이를 위해 별도 네임스페이스를 만드는 것을 권장해요.

kubectl create ns cilium-test

다음 명령으로 체크를 배포해요.

kubectl apply -n cilium-test -f https://raw.githubusercontent.com/cilium/cilium/1.20.2/examples/kubernetes/connectivity-check/connectivity-check.yaml

이 단계는 다양한 연결 경로를 사용해 서로 연결되는 일련의 deployment들을 배포해요. 연결 경로에는 서비스 로드밸런싱 유무와 다양한 네트워크 정책 조합이 포함돼요. Pod 이름은 연결 변형(variant)을 나타내고, readiness와 liveness 게이트는 테스트의 성공 여부를 나타내요.

$ kubectl get pods -n cilium-test
NAME                                                     READY   STATUS    RESTARTS   AGE
echo-a-76c5d9bd76-q8d99                                  1/1     Running   0          66s
echo-b-795c4b4f76-9wrrx                                  1/1     Running   0          66s
echo-b-host-6b7fc94b7c-xtsff                             1/1     Running   0          66s
host-to-b-multi-node-clusterip-85476cd779-bpg4b          1/1     Running   0          66s
host-to-b-multi-node-headless-dc6c44cb5-8jdz8            1/1     Running   0          65s
pod-to-a-79546bc469-rl2qq                                1/1     Running   0          66s
pod-to-a-allowed-cnp-58b7f7fb8f-lkq7p                    1/1     Running   0          66s
pod-to-a-denied-cnp-6967cb6f7f-7h9fn                     1/1     Running   0          66s
pod-to-b-intra-node-nodeport-9b487cf89-6ptrt             1/1     Running   0          65s
pod-to-b-multi-node-clusterip-7db5dfdcf7-jkjpw           1/1     Running   0          66s
pod-to-b-multi-node-headless-7d44b85d69-mtscc            1/1     Running   0          66s
pod-to-b-multi-node-nodeport-7ffc76db7c-rrw82            1/1     Running   0          65s
pod-to-external-1111-d56f47579-d79dz                     1/1     Running   0          66s
pod-to-external-fqdn-allow-google-cnp-78986f4bcf-btjn7   1/1     Running   0          66s

참고

단일 노드 클러스터에 연결성 체크를 배포하면 멀티노드 기능을 확인하는 Pod들은 Pending 상태로 남아요. 이는 해당 Pod들이 성공적으로 스케줄되려면 노드가 최소 2개 필요하기 때문이에요. 정상적인 현상이에요.

테스트가 끝나면 cilium-test 네임스페이스를 삭제해요.

kubectl delete ns cilium-test

다음 단계

디버거 연결하기

Cilium의 Kind 구성은 기본적으로 에이전트와 Operator Pod에서 실행 중인 Delve 디버그 서버 인스턴스에 접근할 수 있게 해요. 사용법은 Debugging을 참고하세요.

문제 해결

k8s api-server에 연결할 수 없음

Cilium 에이전트 로그에서 다음을 볼 수 있어요.

level=info msg="Establishing connection to apiserver" host="https://10.96.0.1:443" subsys=k8s
level=error msg="Unable to contact k8s api-server" error="Get https://10.96.0.1:443/api/v1/namespaces/kube-system: dial tcp 10.96.0.1:443: connect: no route to host" ipAddr="https://10.96.0.1:443" subsys=k8s
level=fatal msg="Unable to initialize Kubernetes subsystem" error="unable to create k8s client: unable to create k8s client: Get https://10.96.0.1:443/api/v1/namespaces/kube-system: dial tcp 10.96.0.1:443: connect: no route to host" subsys=daemon

Kind는 노드를 Docker의 컨테이너로 실행하므로 호스트 머신의 커널을 공유해요. Socket LB를 비활성화하지 않았다면 Cilium이 attach한 eBPF 프로그램이 오래되어 더 이상 api-server 요청을 현재 kind-control-plane 컨테이너로 라우팅하지 못할 수 있어요.

kind 클러스터를 다시 만들고 helm 명령 Install Cilium을 사용하면 부정확한 eBPF 프로그램이 분리(detach)돼요.

Cilium 에이전트 Pod 크래시

다음 로그로 Cilium 에이전트 pod가 크래시하는지 확인해요. 이는 Cilium이 이미 실행 중인 환경(예: Cilium 개발 VM)에 kind 클러스터를 배포하고 있다는 것을 의미할 수 있어요. kind 컨테이너 노드의 부모 cgroup 계층에 겹치는 BPF cgroup 유형 프로그램이 attach되어 있는 경우에도 발생할 수 있어요. 이런 경우 Cilium을 내리거나 bpftool 문서를 따라 부모 cgroup 계층에서 실행 중인 겹치는 BPF cgroup 프로그램을 수동으로 분리하세요. 자세한 내용은 Pull Request를 참고하세요.

level=warning msg="+ bpftool cgroup attach /var/run/cilium/cgroupv2 connect6 pinned /sys/fs/bpf/tc/globals/cilium_cgroups_connect6" subsys=datapath-loader
level=warning msg="Error: failed to attach program" subsys=datapath-loader
level=warning msg="+ RETCODE=255" subsys=datapath-loader

Cluster Mesh

Kind로 샌드박스에서 Cluster Mesh를 시뮬레이션할 수도 있어요.

Kind 구성

이번에는 각 kubernetes 클러스터마다 하나씩 (2)개의 config.yaml을 만들어야 해요. pod-network-cidr과 service-cidr이 겹치지 않도록 명시적으로 구성할게요.

kind-cluster1.yaml 예시:

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
- role: worker
networking:
  disableDefaultCNI: true
  podSubnet: "10.0.0.0/16"
  serviceSubnet: "10.1.0.0/16"

kind-cluster2.yaml 예시:

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
- role: worker
networking:
  disableDefaultCNI: true
  podSubnet: "10.2.0.0/16"
  serviceSubnet: "10.3.0.0/16"

Kind 클러스터 생성하기

각 클러스터를 생성해요.

kind create cluster --name=cluster1 --config=kind-cluster1.yaml
kind create cluster --name=cluster2 --config=kind-cluster2.yaml

Cluster Mesh 설정하기

Cilium을 배포하고 Setting up Cluster Mesh 가이드에 따라 설정을 완료할 수 있어요. Kind에서는 NodePort 서비스를 kube-system 네임스페이스에 배포하고 싶을 거예요.

더 알아보기 (Learn more)