본문 바로가기
K8s/Advanced Network

[KANS3] 6. Ingress + Gateway API

by okms1017 2024. 10. 13.
728x90

✍ Posted by Immersive Builder  Seong

 

1. Ingress 

Ingress 통신 흐름 

Nginx 인그레스 컨트롤러의 경우 외부에서 접속을 시도할 때 인그레스 컨트롤러 파드로 먼저 인입되고, 이후 어플리케이션 파드의 IP와 직접 통신합니다(Bypass). 인그레스 컨트롤러를 외부에 노출 시, 서비스 타입으로는 NodePort 보다 LoadBalancer 타입을 사용하기를 권장합니다. 

Ingress (CloudNet@)

 

* Service / Ingress 

Service Ingress
L4 L7
TCP/UDP/SCTP HTTP/HTTPS

 

Ingress 기능

  • 고급 라우팅 : 경로 기반(/*) 또는 호스트 기반(*.*) 라우팅을 지원합니다. 
  • 카나리 배포 : 신규 버전 배포 시, 어노테이션 설정을 통해 카나리 배포 전략을 지원합니다. 
  • SSL/TLS 종료 : 외부와 연결되는 구간은 보안통신, 내부와 연결되는 구간은 평문통신을 지원합니다. 
  • 인그레스는 더 이상 추가 기능을 지원하지 않습니다. 추가 기능은 앞으로 Gateway API 에서 지원합니다. 

 

Ingress-Nginx Controller 

ingress-nginx는 리버스 프록시와 로드밸런서 역할로서 Nginx를 사용하는 쿠버네티스 인그레스 컨트롤러입니다. 

컨피그맵 설정을 Nginx 설정파일에 적용하고, 변경 적용 시 다시 로드(reload)하는 방식으로 동작합니다. 

 

When a reload is required

 

  • New Ingress Resource Created.
  • TLS section is added to existing Ingress.
  • Change in Ingress annotations that impacts more than just upstream configuration. For instance load-balance annotation does not require a reload.
  • A path is added/removed from an Ingress.
  • An Ingress, Service, Secret is removed.
  • Some missing referenced object from the Ingress is available, like a Service or Secret.
  • A Secret is updated.

 

Ingress-Nginx Controller 설치 

하기 명령어를 따라서 ingress-nginx 컨트롤러를 설치합니다. 

 


  
$ cat <<EOT> ingress-nginx-values.yaml
controller:
service:
type: NodePort
nodePorts:
http: 30080
https: 30443
nodeSelector:
kubernetes.io/hostname: "k3s-s"
metrics:
enabled: true
serviceMonitor:
enabled: true
EOT
$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
$ helm repo update
$ kubectl create ns ingress
$ helm install ingress-nginx ingress-nginx/ingress-nginx -f ingress-nginx-values.yaml --namespace ingress --version 4.11.2
$ kubectl get all -n ingress
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-controller-979fc89cf-6fw7t 1/1 Running 0 33s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller NodePort 10.10.200.220 <none> 80:30080/TCP,443:30443/TCP 33s
service/ingress-nginx-controller-admission ClusterIP 10.10.200.181 <none> 443/TCP 33s
service/ingress-nginx-controller-metrics ClusterIP 10.10.200.234 <none> 10254/TCP 33s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ingress-nginx-controller 1/1 1 1 33s
NAME DESIRED CURRENT READY AGE
replicaset.apps/ingress-nginx-controller-979fc89cf 1 1 1 33s
$ kc describe svc -n ingress ingress-nginx-controller
Name: ingress-nginx-controller
Namespace: ingress
Labels: app.kubernetes.io/component=controller
app.kubernetes.io/instance=ingress-nginx
app.kubernetes.io/managed-by=Helm
app.kubernetes.io/name=ingress-nginx
app.kubernetes.io/part-of=ingress-nginx
app.kubernetes.io/version=1.11.2
helm.sh/chart=ingress-nginx-4.11.2
Annotations: meta.helm.sh/release-name: ingress-nginx
meta.helm.sh/release-namespace: ingress
Selector: app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.10.200.220
IPs: 10.10.200.220
Port: http 80/TCP
TargetPort: http/TCP
NodePort: http 30080/TCP
Endpoints: 172.16.0.5:80
Port: https 443/TCP
TargetPort: https/TCP
NodePort: https 30443/TCP
Endpoints: 172.16.0.5:443
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
$ kubectl patch svc -n ingress ingress-nginx-controller -p '{"spec":{"externalTrafficPolicy": "Local"}}'
service/ingress-nginx-controller patched
$ kc describe cm -n ingress ingress-nginx-controller
Name: ingress-nginx-controller
Namespace: ingress
Labels: app.kubernetes.io/component=controller
app.kubernetes.io/instance=ingress-nginx
app.kubernetes.io/managed-by=Helm
app.kubernetes.io/name=ingress-nginx
app.kubernetes.io/part-of=ingress-nginx
app.kubernetes.io/version=1.11.2
helm.sh/chart=ingress-nginx-4.11.2
Annotations: meta.helm.sh/release-name: ingress-nginx
meta.helm.sh/release-namespace: ingress
Data
====
allow-snippet-annotations:
----
false
BinaryData
====
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CREATE 14m nginx-ingress-controller ConfigMap ingress/ingress-nginx-controller
$ kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf
$ kubectl get all,sa,cm,secret,roles -n ingress
$ kc describe clusterroles ingress-nginx
$ kubectl get pod,svc,ep -n ingress -o wide -l app.kubernetes.io/component=controller

 

Ingress Hands-On 

 

[ 오브젝트 배포 : 디플로이먼트, 서비스 ]

 

  • svc1-web : ClusterIP, 9001:80/TCP, deploy1-websrv(1)
  • svc2-guest : NodePort, 9002:8080/TCP, deploy2-guestsrv(2)
  • svc3-admin : ClusterIP, 9003:8080/TCP, deploy3-adminsrv(3)

 

 

[ 인그레스 배포 ]

 

  • rule1 : */, svc1-web, 80/TCP
  • rule2 : */guest, svc2-guest, 8080/TCP
  • rule3 : */admin, svc3-admin, 8080/TCP

# ingress1.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-1
  annotations:
    #nginx.ingress.kubernetes.io/upstream-hash-by: "true"
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc1-web
            port:
              number: 80
      - path: /guest
        pathType: Prefix
        backend:
          service:
            name: svc2-guest
            port:
              number: 8080
      - path: /admin
        pathType: Prefix
        backend:
          service:
            name: svc3-admin
            port:
              number: 8080

 

 

 

인그레스 라우팅 정책 설정이 nginx.conf 설정 파일에 반영됩니다. 

 

※ X-Forwarded-* Header 

** X-Forwarded-For : Client IP 주소가 변환되는 환경에서 Client IP 주소를 저장 

** X-Forwarded-Proto : 변환되기 이전 프로토콜을 저장 

 

 

[ 인그레스 접속 테스트 ]

 

경로 기반 라우팅을 통해 모든 어플리케이션 파드로 요청이 분기됨을 확인할 수 있습니다. 

 

client_address는 ingress-nginx 컨트롤러 파드의 IP 주소이고, x-forwarded-for는 실제 접속을 요청한 Client IP 주소를 의미합니다. 

 

svc2-guest와 svc3-admin으로 각각 접속을 반복 시도하면 라운드로빈으로 부하가 분산됩니다. (분산 알고리즘 변경 가능)

 

그리고 패킷을 분석해보면 오버레이 통신을 하며, ingress-nginx 컨트롤러에서 목적지 파드의 IP로 직접 통신을 하고 있음을 알 수 있습니다. 

 

* ingress-nginx 컨트롤러 파드가 목적지 파드로 바로 통신이 가능한 이유가 무엇일까 ? 

- endpoints 정보에 대한 조회(list,watch) 권한이 있는 ClusterRole과 Role이 바인딩된 ServiceAccount를 ingress-nginx 컨트롤러 파드가 사용하기 때문입니다. 

 

 

[ 분산 알고리즘 변경 : RR ▶ IP-Hash ]

 

아래와 같이 어노테이션 설정을 통해 분산 알고리즘을 라운드 로빈에서 IP Hash로 변경합니다. 

 

이후 반복 접속을 시도하였을 때 처음 접속한 목적지 파드로 세션이 고정됩니다. 

 

Host Based Routing

  • HOST1 : okms1017.name/, svc3-admin, 8080/TCP
  • HOST2 : *.okms1017.name/echo, svc3-admin, 8080/TCP

# ingress2.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-2
spec:
  ingressClassName: nginx
  rules:
  - host: okms1017.name
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc3-admin
            port:
              number: 8080
  - host: "*.okms1017.name"
    http:
      paths:
      - path: /echo
        pathType: Prefix
        backend:
          service:
            name: svc3-admin
            port:
              number: 8080

 

 

 

[ 인그레스 접속 테스트 ]

 

아래와 같이 접속을 시도하면 HTTP Header의 Host Field가 호스트가 아닌 IP로 지정되므로 404 에러가 발생합니다. 

 

이번에는 "okms1017.name" 도메인 기반으로 요청합니다. 호스트가 일치할 경우, 모든 경로에 대한 요청이 성공합니다. 

 

반면, "blog.okms1017.name" 서브 도메인으로 접속을 요청할 경우 호스트와 경로가 모두 일치하여야 요청이 성공합니다. 

 

Canary Deployment  

[ 오브젝트 배포 : 디플로이먼트, 서비스 ]

 

 

 

[ 인그레스 배포 ]

 

Annotation 설정의 canary 옵션 가중치를 점진적으로 조정하여 서비스 영향도를 최소화합니다. 

 

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-canary-v1
spec:
  ingressClassName: nginx
  rules:
  - host: okms1017.name
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc-v1
            port:
              number: 8080

---

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-canary-v2
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  ingressClassName: nginx
  rules:
  - host: okms1017.name
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc-v2
            port:
              number: 8080

 

 

  • nginx.ingress.kubernetes.io/canary-weight: "10"  ( 90:10 )

 

  • nginx.ingress.kubernetes.io/canary-weight: "50"  ( 50:50 )

 

  • nginx.ingress.kubernetes.io/canary-weight: "50"  ( 0:100 )

 

TLS Termination 

[ 인그레스 배포 ]

 

# tls-termination-ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: https
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - okms1017.name
    secretName: secret-https
  rules:
  - host: okms1017.name
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc-https
            port:
              number: 8080

 

 

 

[ 인증서 및 Secret 생성 ]

 


  
# 인증서 생성
$ MYDOMAIN1=okms1017.name
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=$MYDOMAIN1/O=$MYDOMAIN1"
# Secret 생성
$ kubectl create secret tls secret-https --key tls.key --cert tls.crt
# Secret 확인
$ kubectl get secrets secret-https
$ kubectl get secrets secret-https -o yaml
# 접속 확인
curl -Lk https://$MYDOMAIN1:30443

 

 

[ HTTPS 접속 테스트 ]

 

 


2. Gateway API

Gateway API 란?

Gateway API는 쿠버네티스에서 트래픽 관리와 네트워크 정책을 보다 효율적으로 처리하기 위해 만들어진 추상화 계층입니다. 기존의 Ingress API 보다 더 확장성 있고 유연한 방식으로 트래픽을 제어할 수 있습니다. Gateway API는 쿠버네티스 클러스터 내에서 외부 트래픽을 관리하고, 트래픽의 흐름을 구성하고 제어하는 여러 구성 요소를 제공합니다. 

 

* 요청 흐름 

 

구성 요소

Gateway API 구성 요소로 GatewayClass, Gateway, HTTPRoute, TLSRoute, TCPRoute, Service 등이 있습니다. 

 

  • GatewayClass : Gateway API의 최상위 구성 요소로, CSP가 제공하는 트래픽 처리 방식을 정의하는 리소스입니다.
  • Gateway : GatewayClass에 의해 정의된 실제 트래픽을 처리하는 리소스입니다. 클러스터 운영자가 게이트웨이를 구성하고 관리하며, 트래픽이 클러스터 내부로 들어오는 진입점을 담당합니다.
  • HTTPRoute: HTTP 기반의 트래픽을 관리하는 리소스입니다. HTTPRoute는 트래픽을 어떤 서비스나 파드로 라우팅할지 정의하며, 호스트 이름/경로/헤더 기반의 필터링이 가능합니다. 
  • TCPRoute/TLSRoute : TCP 또는 TLS 기반 트래픽을 처리하는 리소스입니다. TCPRoute는 TCP 프로토콜로 들어오는 트래픽을 어떻게 처리할지 정의하며, 주로 비 HTTP 트래픽(예: 데이터베이스 연결)을 위한 라우팅에 사용됩니다. TLSRoute는 TLS 프로토콜로 보호된 트래픽을 처리하고, SNI(Server Name Indication)를 사용하여 트래픽을 특정 백엔드로 라우팅할 수 있습니다.
  • Service : Gateway API에서 최종적으로 트래픽을 전달받는 백엔드 서비스입니다. HTTPRoute, TCPRoute, TLSRoute 등은 트래픽을 특정 Service로 전달합니다. 해당 Service는 내부 Pod로 트래픽을 분배합니다.

 

주요 기능  

  1. 개선된 리소스 모델 : API는 GatewayClass, Gateway 및 Route(HTTPRoute, TCPRoute 등)와 같은 새로운 사용자 정의 리소스를 도입하여 라우팅 규칙을 정의하는 보다 세부적이고 표현력 있는 방법을 제공합니다.
  2. 프로토콜 독립적 : 주로 HTTP용으로 설계된 Ingress와 달리, Gateway API는 TCP/UDP/TLS를 포함한 여러 프로토콜을 지원합니다.
  3. 강화된 보안 : TLS 구성 및 보다 세부적인 액세스 제어를 지원합니다.
  4. 교차 네임스페이스 지원 : 서로 다른 네임스페이스의 서비스로 트래픽을 라우팅하여 보다 유연한 아키텍처를 구축할 수 있는 기능을 제공합니다.
  5. 확장성 : API는 사용자 정의 리소스 및 정책으로 쉽게 확장할 수 있도록 설계되었습니다.
  6. 역할 지향 : 클러스터 운영자, 애플리케이션 개발자, 보안 팀 간의 우려를 명확하게 분리합니다.

 

종류 

Gloo Gateway, Cilium Gateway API, Istio Gateway API, Kong API Gateway, Envoy Gateway 등이 있습니다. 

 

Gloo Gateway Architecture

Gloo Gateway Architecture

 

Gloo Gateway Hands-On

이번 핸즈온은 Kind 환경에 적합한 Gloo Gateway를 사용합니다. 

 

  • Install Kind Cluster (Single Node)

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
  - containerPort: 30002
    hostPort: 30002

 

  • Install Gateway API CRDs

$ kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml

 

  • Install Glooctl Utility

$ docker exec -it myk8s-control-plane bash

$ curl -sL https://run.solo.io/gloo/install | GLOO_VERSION=v1.17.7 sh

$ export PATH=$HOME/.gloo/bin:$PATH

$ glooctl version

 

  • Install Gloo Gateway (OpenSource Version)

$ helm repo add gloo https://storage.googleapis.com/solo-public-helm

$ helm repo update

$ helm install -n gloo-system gloo-gateway gloo/gloo \

--create-namespace --version 1.17.7 --set kubeGateway.enabled=true \

--set gloo.disableLeaderElection=true --set discovery.enabled=false

 

  • Install Httpbin Application

$ kubectl apply -f https://raw.githubusercontent.com/solo-io/solo-blog/main/gateway-api-tutorial/01-httpbin-svc.yaml

 

  • Httpbin NodePort Setting

apiVersion: v1
kind: Service
metadata:
  labels:
    app: httpbin
    service: httpbin
  name: httpbin
  namespace: httpbin
spec:
  type: NodePort
  ports:
  - name: http
    port: 8000
    targetPort: 80
    nodePort: 30000
  selector:
    app: httpbin

 

  • Configure a Gateway Listener

kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
  name: http
spec:
  gatewayClassName: gloo-gateway
  listeners:
  - protocol: HTTP
    port: 8080
    name: http
    allowedRoutes:
      namespaces:
        from: All

 

  • gloo-proxy-http NodePort Setting (Port 30001)

apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/instance: http
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: gloo-proxy-http
    app.kubernetes.io/version: 1.17.7
    gateway.networking.k8s.io/gateway-name: http
    gloo: kube-gateway
    helm.sh/chart: gloo-gateway-1.17.7
  name: gloo-proxy-http
  namespace: gloo-system
spec:
  ports:
  - name: http
    nodePort: 30001
    port: 8080
  selector:
    app.kubernetes.io/instance: http
    app.kubernetes.io/name: gloo-proxy-http
    gateway.networking.k8s.io/gateway-name: http
  type: LoadBalancer

 

  • Establish External Access to Proxy

$ kubectl port-forward deployment/gloo-proxy-http -n gloo-system 8080:8080 &

 

  • Configure Simple Routing with an HTTPRoute

apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: httpbin
  namespace: httpbin
  labels:
    example: httpbin-route
spec:
  parentRefs:
    - name: http
      namespace: gloo-system
  hostnames:
    - "api.example.com"
  rules:
  - matches:
    - path:
        type: Exact
        value: /get
    backendRefs:
      - name: httpbin
        port: 8000

 

  • Test the Simple Route with Curl

 

  • Explore Routing with Regex Matching Patterns

    - matches:
        - path:
            type: PathPrefix
            value: /api/httpbin/
      filters:
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /

 

  • Test Routing with Regex Matching Patterns

 

  • Test Transformations with Upstream Bearer Tokens

      filters:
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /
              
        # Add a Bearer token to supply a static API key when routing to backend system
        - type: RequestHeaderModifier
          requestHeaderModifier:
            add:
              - name: Authorization
                value: Bearer my-api-key

 

  • Configure Two Workloads for Migration Routing

 

  • Test Simple V1 Routing

apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: my-workload
  namespace: my-workload
  labels:
    example: my-workload-route
spec:
  parentRefs:
    - name: http
      namespace: gloo-system
  hostnames:
    - "api.example.com"
  rules:
    - matches:
      - path:
          type: PathPrefix
          value: /api/my-workload
      backendRefs:
        - name: my-workload-v1
          namespace: my-workload
          port: 8080

 

  • Simulate a v2 Dark Launch with Header-Based Routing

  rules:
    - matches:
      - path:
          type: PathPrefix
          value: /api/my-workload
        headers:
        - name: version
          value: v2
      backendRefs:
        - name: my-workload-v2
          namespace: my-workload
          port: 8080      
    - matches:
      - path:
          type: PathPrefix
          value: /api/my-workload
      backendRefs:
        - name: my-workload-v1
          namespace: my-workload
          port: 8080

 

  • Expand V2 Testing with Percentage-Based Routing

rules:
    - matches:
      - path:
          type: PathPrefix
          value: /api/my-workload
      # Configure a 50-50 traffic split across v1 and v2 : 버전 1,2 50:50 비율
      backendRefs:
        - name: my-workload-v1
          namespace: my-workload
          port: 8080
          weight: 50
        - name: my-workload-v2
          namespace: my-workload
          port: 8080
          weight: 50

 

  • Explore Envoy Metrics

 

 


[출처]

1) CloudNet@, KANS 실습 스터디

2) https://kubernetes.io/docs/concepts/services-networking/ingress/

 

Ingress

Make your HTTP (or HTTPS) network service available using a protocol-aware configuration mechanism, that understands web concepts like URIs, hostnames, paths, and more. The Ingress concept lets you map traffic to different backends based on rules you defin

kubernetes.io

3) https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/

 

Ingress Controllers

In order for an [Ingress](/docs/concepts/services-networking/ingress/) to work in your cluster, there must be an _ingress controller_ running. You need to select at least one ingress controller and make sure it is set up in your cluster. This page lists co

kubernetes.io

4) https://kubernetes.github.io/ingress-nginx/

 

Welcome - Ingress-Nginx Controller

Overview This is the documentation for the Ingress NGINX Controller. It is built around the Kubernetes Ingress resource, using a ConfigMap to store the controller configuration. You can learn more about using Ingress in the official Kubernetes documentatio

kubernetes.github.io

5) https://kubernetes.io/docs/concepts/services-networking/gateway/

 

Gateway API

Gateway API is a family of API kinds that provide dynamic infrastructure provisioning and advanced traffic routing.

kubernetes.io

6) https://gateway-api.sigs.k8s.io/

 

Introduction - Kubernetes Gateway API

Introduction Gateway API is an official Kubernetes project focused on L4 and L7 routing in Kubernetes. This project represents the next generation of Kubernetes Ingress, Load Balancing, and Service Mesh APIs. From the outset, it has been designed to be gen

gateway-api.sigs.k8s.io

7) https://docs.solo.io/gateway/latest/about/architecture/

 

Architecture | Solo.io documentation

Learn more about the components that make up Gloo Gateway. These components work together to provide traffic management, security, and resiliency. Component architecture link The following image shows the different components that make up the Gloo Gateway

docs.solo.io

728x90

'K8s > Advanced Network' 카테고리의 다른 글

[KANS3] 8. Cilium CNI  (0) 2024.10.27
[KANS3] 7. Service Mesh: Istio  (0) 2024.10.20
[KANS3] 5. MetalLB + IPVS  (0) 2024.10.06
[KANS3] 4. Service ClusterIP + NodePort  (3) 2024.09.29
[KANS3] 3. Calico CNI + Mode  (0) 2024.09.22