[cilium] Service Mesh 구성하기 (shared 모드)

cilium에서는 ingress/gateway api 등으로 service mesh 구성을 지원합니다. 

다양한 모드가 존재하는데 shared는 1개의 ingress를 구성한뒤 클러스터에서 다 공통으로 사용하는 모드입니다. 이외에는 dedicated 모드는 Ingress 컨트롤러가 해당 Ingress 전용 로드밸런서를 생성하게 됩니다. 

 

shared 모드 service mesh 구성하기 

cilium 서비스메쉬를 구성하는걸 진행해보겠습니다. 

helm install cilium cilium/cilium --namespace kube-system \
  --set k8sServiceHost=auto --set ipam.mode="cluster-pool" \
  --set k8s.requireIPv4PodCIDR=true --set ipv4NativeRoutingCIDR=10.244.0.0/16 \
  --set routingMode=native --set autoDirectNodeRoutes=true --set endpointRoutes.enabled=true \
  --set kubeProxyReplacement=true --set bpf.masquerade=true --set installNoConntrackIptablesRules=true \
  --set endpointHealthChecking.enabled=false --set healthChecking=false \
  --set hubble.enabled=true --set hubble.relay.enabled=true --set hubble.ui.enabled=true \
  --set hubble.ui.service.type=NodePort --set hubble.ui.service.nodePort=30003 \
  --set prometheus.enabled=true --set operator.prometheus.enabled=true --set hubble.metrics.enableOpenMetrics=true \
  --set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,httpV2:exemplars=true;labelsContext=source_ip\,source_namespace\,source_workload\,destination_ip\,destination_namespace\,destination_workload\,traffic_direction}" \
  --set ingressController.enabled=true --set ingressController.loadbalancerMode=shared --set loadBalancer.l7.backend=envoy \
  --set localRedirectPolicy=true --set l2announcements.enabled=true \
  --set operator.replicas=1 --set debug.enabled=true

 

l7 설정이 활성화 되어있는걸 확인합니다. 

cilium config view | grep -E '^loadbalancer|l7'

 

cilium-agent에 들어가보면 노드별로 예약된 IP리스트도 확인할 수 있습니다. 

kubectl exec -it -n kube-system ds/cilium -- cilium ip list | grep ingress

 

확인해보면 cilium-envoy 가 구성되어있는것도 확인할 수 있습니다.

kubectl get pod -n kube-system -l k8s-app=cilium-envoy -owide

 

LB IP 설정하기

cat << EOF | kubectl apply -f -
apiVersion: "cilium.io/v2" 
kind: CiliumLoadBalancerIPPool
metadata:
  name: "cilium-lb-ippool"
spec:
  blocks:
  - start: "172.17.0.211"
    stop:  "172.17.0.215"
EOF

 

L2 announcement 설정하기

# L2 Announcement 정책 설정
cat << EOF | kubectl apply -f -
apiVersion: "cilium.io/v2alpha1"
kind: CiliumL2AnnouncementPolicy
metadata:
  name: policy1
spec:
  interfaces:
  - eth0
  externalIPs: true
  loadBalancerIPs: true
EOF

 

현재 리더 역할을 누가 하는지도 확인해보겠습니다.

# 현재 리더 역할 노드 확인
kubectl -n kube-system get lease | grep "cilium-l2announce"

 

 

# K8S 클러스터 내부 LB EX-IP로 호출 가능
LBIP=$(kubectl get svc -n kube-system cilium-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $LBIP
docker exec -it kind-worker apt update
docker exec -it kind-worker apt install iputils-arping -y 
docker exec -it kind-worker arping -c 2 -I eth0 $LBIP

 

외부 노드에서도 통신되는지 확인해보기 위해 하나의 컨테이너를 띄우고 그 안에서 확인해보겠습니다. 

docker run -d --rm --name client --cap-add=NET_ADMIN --network kind nicolaka/netshoot tail -f /dev/null

 

외부 컨테이너에서 호출도 해봅니다.

# k8s 외부 노드(router)에서 LB EX-IP로 호출 가능 확인
LBIP=$(kubectl get svc -n kube-system cilium-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $LBIP
docker exec -it client arping -c 2 -I eth0 $LBIP

 

샘플 애플리케이션 배포하기

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.26/samples/bookinfo/platform/kube/bookinfo.yaml

 

구성후 확인해보면 sidecar가 없는것을 알 수 있다 .

 

인그레스 클래스도 확인해보면 cilium으로 구성이 되어있습니다. 

kubectl get ingressclasses.networking.k8s.io

 

이제 ingress 배포해보겠습니다.

cat << EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: basic-ingress
  namespace: default
spec:
  ingressClassName: cilium
  rules:
  - http:
      paths:
      - backend:
          service:
            name: details
            port:
              number: 9080
        path: /details
        pathType: Prefix
      - backend:
          service:
            name: productpage
            port:
              number: 9080
        path: /
        pathType: Prefix
EOF

 

인그레스에 잘 아이피가 서비스에 설정되었는지도 확인해봅니다. 

kubectl get svc -n kube-system cilium-ingress

 

동일한 아이피가 ingress에도 설정되었는지 확인해보겠습니다.

kubectl get ingress

 

 

위에서 생성한 외부 컨테이너에서 호출이 잘 되는지 확인해보겠습니다. 

LBIP=$(kubectl get svc -n kube-system cilium-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $LBIP

# 실패하는 호출이 있는가?
docker exec -it client curl -so /dev/null -w "%{http_code}\n" http://$LBIP/
docker exec -it client curl -so /dev/null -w "%{http_code}\n" http://$LBIP/details/1
docker exec -it client curl -so /dev/null -w "%{http_code}\n" http://$LBIP/ratings

# Access the Bookinfo application
docker exec -it client curl -I "http://$LBIP/productpage?u=normal"

 

세번째 설정이 404로 에러발생하고 나머지는 다 잘 동작합니다. 

 

3번째에서는 /ratings로 호출을 보내는데  ingress설정을 보면 product page로 보내게 되어있습니다. ratings로 보내야하는데 그렇지 못해서 발생한 에러입니다. 

 

hubble에서 확인하면 다음과 같습니다.