cilium 선택적 서비스 노드 노출하기

Selective Service Node Exposure는 서비스를 생성하고 그 서비스를 통해 트래픽을 받을 수 있는 노드를 설정 할 수 있는 기능입니다. 1.17버전 부터 사용이 가능합니다. 

 

아래의 그림에서 처럼 서비스의 annotations에 정의되어있는 service.cilium.io/node의 값과 같은 값을 갖고 있는 노드에서만 해당 서비스로 호출이 가능합니다. 서비스가 아닌 파드아이피로 직접 호출할 때에는 어디에서든지 통신이 가능합니다.

 

직접 테스트 해보기

노드에 라벨을 붙이고 나면 cilium과 오퍼레이터를 재시작 해야하기 때문에 이번엔 클러스터 생성할 때 부터 라벨을 붙여보겠습니다.

cat > labeled-cilium.yaml << EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  labels:
    service.cilium.io/node: control-plane
- role: worker
  labels:
    service.cilium.io/node: worker-a
- role: worker
  labels:
    service.cilium.io/node: worker-b

networking:
  disableDefaultCNI: true
  kubeProxyMode: "none"

EOF

kind create cluster --name aya --config labeled-cilium.yaml

 

라벨이 잘 들어가져있나 확인해봅니다. 

 

 cilium을 설치합니다.

API_SERVER=$( kubectl get nodes -l node-role.kubernetes.io/control-plane -o yaml | yq '.items[0].status.addresses[] | select(.type=="InternalIP").address' )


helm install cilium cilium/cilium --version 1.17.1 \
   --namespace kube-system \
   --set k8sServiceHost=${API_SERVER} \
   --set k8sServicePort=6443 \
   --set bpf.masquerade=true \
   --set kubeProxyReplacement=true

 

테스트 용 nginx 서비스 생성

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        imagePullPolicy: Always
        name: nginx

 

kubectl expose deployment nginx --port 80 --name nginx

 

아직 아무것도 설정하지 않은 상태에서 확인해보겠습니다.

❯ kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   5m10s
nginx        ClusterIP   10.96.83.188   <none>        80/TCP    75s

# 전부 aya-worker 노드에 떠있음 
❯ kubectl get pods -o custom-columns="NAME:.metadata.name,NODE:.spec.nodeName"
NAME                     NODE
nginx-5869d7778c-7hhkj   aya-worker
nginx-5869d7778c-hq5qz   aya-worker

# aya-worker2에서 보면 nginx의 서비스 아이피가 잘 보임
root@aya-worker2:/home/cilium# cilium service list
ID   Frontend               Service Type   Backend
1    10.96.0.1:443/TCP      ClusterIP      1 => 172.17.0.3:6443/TCP (active)
2    10.96.50.179:443/TCP   ClusterIP      1 => 172.17.0.2:4244/TCP (active)
3    10.96.0.10:53/TCP      ClusterIP      1 => 10.0.1.97:53/TCP (active)
                                           2 => 10.0.1.43:53/TCP (active)
4    10.96.0.10:9153/TCP    ClusterIP      1 => 10.0.1.97:9153/TCP (active)
                                           2 => 10.0.1.43:9153/TCP (active)
5    10.96.0.10:53/UDP      ClusterIP      1 => 10.0.1.97:53/UDP (active)
                                           2 => 10.0.1.43:53/UDP (active)
6    10.96.83.188:80/TCP    ClusterIP      1 => 10.0.0.41:80/TCP (active)
                                           2 => 10.0.0.114:80/TCP (active)

 

이제 이 상태에서 서비스에 annotations를 추가해보겠습니다.

apiVersion: v1
kind: Service
metadata:
  annotations:
    service.cilium.io/node: worker-a
  labels:
    app: nginx
  name: nginx
  namespace: default
  
 ...

 

worker-a의 라벨이 달려있는 worker에는 보여야하고 그 외의 노드에서는 서비스의 클러스터 아이피가 보이지 않아야 합니다.

# 같은 라벨을 갖고있는 노드에서는 서비스의 아이피와 백엔드가 잘 보입니다. 
root@aya-worker:/home/cilium# cilium service list
ID   Frontend               Service Type   Backend
1    10.96.0.1:443/TCP      ClusterIP      1 => 172.17.0.3:6443/TCP (active)
2    10.96.50.179:443/TCP   ClusterIP      1 => 172.17.0.4:4244/TCP (active)
3    10.96.0.10:53/UDP      ClusterIP      1 => 10.0.1.97:53/UDP (active)
                                           2 => 10.0.1.43:53/UDP (active)
4    10.96.0.10:53/TCP      ClusterIP      1 => 10.0.1.97:53/TCP (active)
                                           2 => 10.0.1.43:53/TCP (active)
5    10.96.0.10:9153/TCP    ClusterIP      1 => 10.0.1.97:9153/TCP (active)
                                           2 => 10.0.1.43:9153/TCP (active)
7    10.96.83.188:80/TCP    ClusterIP      1 => 10.0.0.41:80/TCP (active) # <--요기
                                           2 => 10.0.0.114:80/TCP (active)

---
# 라벨이 같지 않은 노드에서는 클러스터가 보이지 않게 되었습니다.
root@aya-worker2:/home/cilium# cilium service list
ID   Frontend               Service Type   Backend
1    10.96.0.1:443/TCP      ClusterIP      1 => 172.17.0.3:6443/TCP (active)
2    10.96.50.179:443/TCP   ClusterIP      1 => 172.17.0.2:4244/TCP (active)
3    10.96.0.10:53/TCP      ClusterIP      1 => 10.0.1.97:53/TCP (active)
                                           2 => 10.0.1.43:53/TCP (active)
4    10.96.0.10:9153/TCP    ClusterIP      1 => 10.0.1.97:9153/TCP (active)
                                           2 => 10.0.1.43:9153/TCP (active)
5    10.96.0.10:53/UDP      ClusterIP      1 => 10.0.1.97:53/UDP (active)
                                           2 => 10.0.1.43:53/UDP (active)