October 12, 2025

[Home-K8S] #18 Cilium Gateway API 사용하기 (from nginx-ingress)

[Home-K8S] #18 Cilium Gateway API 사용하기 (from nginx-ingress)

Cilium Gateway API

기존에는 flannel CNI를 사용하면서 nginx-ingress 를 사용해 왔지만, cilium 로 변경하면서 Cilium Gateway 로 전환했습니다.

Gateway API 는 k8s 의 Ingress, Load Balancing, Service Mesh APIs 의 차세대 프로젝트로 더 확장 가능한 구조를 가지고 있습니다.
(nginx는 권장하지도 않으면서 annotation 으로 다 해야하는게 별로이긴 합니다.)

  1. Gateway
    1. Infra 레이어 (IP, 포트, TLS 인증서)
  2. HTTPRoute
    1. 라우팅 규칙 (도메인별, 경로별 라우팅)
  3. GatewayClass
    1. Gateway 구현체 (Cilium, nginx, Istio 등)

구성 방안

  1. ciliumCNI 로 구성
  2. Gateway API CRD 설치
    1. 처음 구성할 때부터 crd를 같이 설치하는 옵션을 주고 gateway api를 활성화하면 같이 설치가 되는 것으로 알고 있지만, 설치가 안될 시 다음 명령어를 사용합니다.
      kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v1.3.0" | kubectl apply -f -
  3. Cilium Gateway API 활성화
    1. helm 이면 helm upgrade 를 실행하면 되고, cilium cli 도 그냥 실행하면 기존 옵션은 유지된 채로 진행됩니다.
cilium install \
    --set gatewayAPI.enabled=true \
    --set installCRDs=true
  1. ClusterIssuer 설정
    1. cert manager 의 solvers를 수정해 줍니다.
      기존 ingress 는 꼭 지워줍니다.
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: 
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
      # - http01:
      #     ingress:
      #       ingressClassName: nginx
      - http01:
          gatewayHTTPRoute:
            parentRefs:
            - name: cilium-gateway
              namespace: cilium
              kind: Gateway
  1. Certificate 생성
    1. 와일드 카드 설정은 DNS-01 challenge 를 사용해야 합니다. 그냥 하나하나 다 적어 줍니다.
      (CloudFlare API 를 사용한 설정이 필요합니다. )
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: dogring-kr-tls
  namespace: cilium
spec:
  secretName: dogring-kr-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - dogring.kr
  - www.dogring.kr
  # 필요한 서브도메인 추가
  usages:
  - digital signature
  - key encipherment
  1. Gateway 생성
    1. hostname 을 지정하지 않으면 모든 도메인을 처리합니다.
    2. allowedRoutes 설정은 해당 namespace 의 HTTPRoute 를 사용할 수 있게 합니다.
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: cilium-gateway
  namespace: cilium
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  gatewayClassName: cilium
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
  - name: https
    port: 443
    protocol: HTTPS
    allowedRoutes:
      namespaces:
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: dogring-kr-tls
        namespace: cilium
  1. HTTP -> HTTPS 리다이렉트
    1. http 로 들어오는 모든 요청을 https 로 리다이렉트 합니다.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-to-https-redirect
  namespace: cilium
spec:
  parentRefs:
  - name: cilium-gateway
    namespace: cilium
    sectionName: http
  rules:
  - filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        statusCode: 301
  1. HTTPRoute 설정
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app-dogring-kr
  namespace: app                    # App Service 의 namespace
spec:
  parentRefs:
  - name: cilium-gateway
    namespace: cilium               # Gateway 의 namespace
    sectionName: https              # Gateway Listenser name 설정
  hostnames:
  - dogring.kr                      # 도메인 설정
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: app-service
      port: 80
      namespace: app

트러블 슈팅

  1. cilium-secrets
    1. 해당 과정 전에 연습하다가 cilium-secrets 를 제가 만든 줄 알고 지웠었는데, 해당 cilium 에 tls secret 을 위한 secret 을 구성합니다.
  2. body-size
    1. 블로그의 경우 큰 이미지를 올려야 할 때가 있습니다. 이를 위해 nginx 의 proxy-body-size 를 설정해 줬었는데, cilium 의 백엔드 정책으로 설정할 수 있습니다.
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
  name: body-size-limit
  namespace: cilium
spec:
  services:
  - name: app-service
    namespace: app
  resources:
  - "@type": type.googleapis.com/envoy.config.route.v3.RouteConfiguration
    name: ghost-route
    virtual_hosts:
    - name: ghost
      domains:
      - "dogring.kr"
      routes:
      - match:
          prefix: "/"
        route:
          cluster: app-service
        per_filter_config:
          envoy.filters.http.buffer:
            "@type": type.googleapis.com/envoy.extensions.filters.http.buffer.v3.BufferPerRoute
            buffer:
              max_request_bytes: 104857600  # 100MB

Comments