K8S/🔥 network study🔥

[네떡스터디🔥kans] Cilium Gateway API

아야는 못말려 2024. 10. 12. 01:19
CloudNet@ 가시다님이 진행하는 쿠버네티스 네트워크 스터디 KANS 3기 내용을 정리한 글입니다.

 

이전 글에서 Istio의 Gateway API를 다뤘다면, 이번에는 Cilium의 Gateway API에 대해 살펴보려 합니다. Gateway API에 대해 더 알고 싶으신 분들은 이전 글을 참고해 주세요.

 

Cilium의 Gateway API

Cilium의 Gateway API는 다른 Ingress 컨트롤러들과는 크게 다른 부분이 Cilium에서는 네트워크 스택과 깊이 통합된다는 것입니다. 무슨말이냐면 보통의 Gateway API는 gateway 생성시 Deployment 형태로 설치되고 LoadBalancer를 통해 트래픽을 처리하지만, Cilium가 네트워크 관리 도구(CNI)이기 때문에 Gateway API는 CNI의 일부로 동작하게 됩니다. 이 방식 덕분에 Cilium의 Gateway API는 eBPF 기술을 활용해 트래픽을 가로채고 Envoy로 전달하여 클러스터 내부 트래픽을 더욱 빠르고 효율적으로 처리할 수 있습니다. 특히, X-Forwarded-For 헤더를 사용해 클라이언트의 IP를 정확하게 추적할 수 있다는 점에서 독특한 강점을 가지고 있습니다.

 

또한, Cilium CiliumNetworkPolicy 통해 트래픽을 세밀하게 제어할 있습니다. 이를 통해 보안을 강화하면서도 네트워크 흐름을 더욱 효과적으로 관리할 있습니다.  Cilium Gateway API 이용하는 것은 네트워크 보안과 성능 최적화가 중요한 환경에서 매우 유리한 선택이 있습니다.

 

 

직접 테스트해보기

cilium 클러스터를 생성하고 LB구성하는 환경을 만들기 위한 가이드는 2024.10.13 - [K8S/cilium] - Kind에서 Cilium으로 외부 접근 LoadBalancer 설정하기 에 작성해두었습니다.  자세한 내용은 해당 글에서 확인부탁드립니다.

 

클러스터 만들기

cilium에서는 kind로 cilium을 구성할 수 있도록 가이드를 주고 있습니다.

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

networking:
  disableDefaultCNI: true
  kubeProxyMode: "none"

 

cilium의 자체 ipam으로 구성해보았습니다. cidr은 사용하고 있는 도커 네트워크의 대역중 일부를 가져왔습니다.

apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
  name: ipam
spec:
  blocks:
    - cidr: 172.17.0.64/26

 

Gateway API CRD 설치하기

기본적으로 쿠버네티스에는 gateway api를 지원하기 위한 crd가 설치 안되어있을 수 있기 때문에 먼저 설치를 하도록 하겠습니다. 

아래의 명령어를 이용하면 기본적인 crd들이 설치가 됩니다.

kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v1.2.0" | kubectl apply -f -

 

 

 

기본적으로 설치된 routes에는 httprourtes, grpcroutes가 있는데 이 외에도 실험적인 route들이 있으며 cilium 에서는 tlsroute를 지원하고 있습니다. 

kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.0/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml

 

실험적인 기능에 대한 crd들은 다음의 명령어를 이용하여 한번에 설치할 수 있습니다.  하지만 이렇게 설치하게 되면 기존의 grproutes, httproutes에도 수정이 생길 수 있으니 조심해야합니다. (🚨 1.16.0 버전에서는 실험적인 기능과  cilium이 잘 연동되지 않아 TLSRoute를 제외하고는 stable 설치를 권장합니다.)

kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd/experimental?ref=v1.2.0" | kubectl apply -f -

 

Cilium 설치하기

istio와는 다르게 cilium에서는 설치시에 gateway API의 사용을 명시적으로 활성화 해주어야 합니다.

간단하게 설치하기 위해 cilium 명령어를 이용하여 설치해보도록 하겠습니다. API_SERVER_IP, API_SERVER_PORT에는 control plane은 1개로 구성했기 때문에 control plane의 아이피와 6443을 넣으면 됩니다. 

cilium install --version 1.16.2 \
    --set kubeProxyReplacement=true \
    --set gatewayAPI.enabled=true
    
# hubble까지 설치할 거라면
cilium install --version 1.16.2 \
    --set kubeProxyReplacement=true \
    --set gatewayAPI.enabled=true \
    --set hubble.enabled=true \
    --set hubble.relay.enabled=true \
    --set hubble.ui.enabled=true \
    --set l2announcements.enabled=true \
    --set k8sServiceHost=$API_SERVER_IP \
    --set k8sServicePort=$API_SERVER_PORT \
    --set externalIPs.enabled=true

 

cilium이 잘 설치 되었는지 확인해 봅니다.

 

상태 뿐만 아니라 실제로 gateway api가 활성화가 되었는지 확인해보겠습니다.

cilium config view | grep -w "enable-gateway-api"

 

이렇게 설치를 하고 나면 cilium도 기본적으로 default gatewayclass가 생성이됩니다. ACCEPTED가 True인 상태이면 성공입니다. 

 

 

테스트용 샘플 파드 생성하기

테스트 샘플 파드 생성이 필요하신분들은 아래의 더보기를 눌러 구성하시면 됩니다.

더보기

테스트용 샘플 파드 생성하기

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.23/samples/httpbin/httpbin.yaml

 

이상하게 mac에서 에러가 발생해서

에러가 발생해서 안뜨시는 분들은 이미지 태그를 0.1.0으로 변경하시면 됩니다.

 

Gateway 생성하기

이제 istio와 동일한 규칙으로 gateway를 생성해보도록 하겠습니다. 

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway
  namespace: cilium-ingress
spec:
  gatewayClassName: cilium
  listeners:
  - name: default
    hostname: "*.example.com"
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: All

 

이 파일을 배포했을 때 성공적으로 gateway가 생성된 것을 확인해볼 수 있습니다.

 

상태를 자세하게 보면 Accepted, Programmed, ResolvedRefs 상태가 있는데 각각은 다음의 의미를 갖습니다.

 

  • Accepted
    Gateway 설정이 클러스터에서 유효성 검사를 통과하고 성공적으로 적용됨. 설정이 올바르게 작성되었고, 클러스터에서 허용된 상태임.
  • Programmed
    설정한 Gateway가 Envoy와 같은 네트워크 프록시 시스템에 정상적으로 반영됨. 트래픽을 처리할 준비가 완료된 상태임.
  • ResolvedRefs
    설정에서 참조한 모든 시크릿(Secrets)이 발견되었고, 해당 시크릿들에 대한 사용 권한도 확인됨. 이는 인증서나 민감한 정보가 문제없이 적용되었음을 의미함.

 

 

서비스를 확인해봐도 동일하게 LoadBalancer로 잘생성이 되어있습니다.

 

하지만 신기하게도 pod는 생성되지 않습니다. 보통은 실제로 트래픽을 처리하기 위한 deployment가 뜹니다. ebpf 코드를 통해 다이렉트로 envoy 파드로 트래픽이 들어가게 되어있는 것 같습니다.

 

HTTPRoute 생성하기

이번에도 동일하게 istio와 동일한 룰을 생성해보도록 하겠습니다. gateway가 cilium-ingress 네임스페이스에 있던과는 다르게 httproute는 default 네임스페이스( 테스트 파드가 있는 네임스페이스)에 생성했습니다.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http
  namespace: default
spec:
  parentRefs:
  - name: gateway                    # 이 HTTPRoute가 연결될 Gateway 리소스의 이름
    namespace: cilium-ingress         # Gateway 리소스가 있는 네임스페이스
  hostnames: ["httpbin.example.com"] # 이 HTTPRoute가 처리할 호스트네임
  rules:
  - matches:
    - path:
        type: PathPrefix # 경로 매칭의 타입
        value: /get      # 매칭할 경로
    backendRefs:
    - name: httpbin
      port: 8000

 

 

별도의 컨테이너에서 호출해보기

따로 설정하지 않았다면 kind의 네트워크를 사용할 것이기 때문에 kind를 네트워크로 주어 컨테이너를 하나 생성합니다.

docker run -d --rm --name mypc --network kind  nicolaka/netshoot sleep infinity

 

이렇게 한뒤 테스트를 위한 아이피를 추출해보겠습니다.

export INGRESS_HOST=$(kubectl get gateways.gateway.networking.k8s.io gateway -n cilium-ingress -ojsonpath='{.status.addresses[0].value}')
echo $INGRESS_HOST

 

같은 네트워크 브릿지를 사용하여 컨테이너를 생성하고 거기서 호출해보면 신기하게도 호출이 잘 되는 것을 확인할 수 있습니다. 컨테이너 내부로 들어가기 전에 INGRESS_HOST의 값을 확인한 뒤 변경하여 테스트해보시길 바랍니다.

curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST/get"

 

 

하지만 신기하게도 cilium 파드에서 명령어로 엔드포인트의 리스트를 찾아보면 아무런 엔드포인트도 없는것을 확인할 수 있습니다.

 

그치만 이제 bpf의 lb 리스트를 조회해보니 보입니다.

Envoy 확인해보기

위에서 추가한 룰들은 Envoy에 추가되게 됩니다. envoy의 룰들은 다음의 명령어로 cilium의 파드내부에서 확인해볼 수 있습니다.

cilium-dbg envoy admin clusters

 

HTTPRoute를 넣기 전후를 비교해보면 새로 생성한 이후에 이러한 규칙들이 추가된 것을 확인해볼 수 있습니다. 

cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::canary::false
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::cx_active::0
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::cx_connect_fail::0
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::cx_total::0
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::health_flags::healthy
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::hostname::
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::local_origin_success_rate::-1
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::priority::0
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::region::
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::rq_active::0
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::rq_error::0
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::rq_success::0
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::rq_timeout::0
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::rq_total::0
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::sub_zone::
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::success_rate::-1
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::weight::1
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::10.244.1.46:8080::zone::
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::added_via_api::true
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::default_priority::max_connections::1024
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::default_priority::max_pending_requests::1024
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::default_priority::max_requests::1024
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::default_priority::max_retries::3
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::eds_service_name::default/httpbin:8000
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::high_priority::max_connections::1024
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::high_priority::max_pending_requests::1024
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::high_priority::max_requests::1024
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::high_priority::max_retries::3
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::observability_name::cilium-ingress/cilium-gateway-gateway/default:httpbin:8000
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::outlier::local_origin_success_rate_average::-1
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::outlier::local_origin_success_rate_ejection_threshold::-1
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::outlier::success_rate_average::-1
cilium-ingress/cilium-gateway-gateway/default:httpbin:8000::outlier::success_rate_ejection_threshold::-1

 

위에서 확인했을 때 bpf lb리스트에 12141로 보내도록 설정이 되어있는것을 확인했었습니다.

listeners의 리스트를 확인해보면 cilium-gateway-gateway 가 12141 포트를 받는것을 확인할 수 있습니다.

 

Hubble UI를 통한 확인

hubble을 통해서 확인해보면 Ingress에서 들어오고 있다는것이 잘 보이고 있습니다.  신기한건 cilium-ingress에서는 아무런 것도 보이지 않습니다.