DevOps/Study

Istio Hands-on Study [1기] [1주차 연습과제] Kubernetes Gateway API

juyeon22 2025. 4. 16. 22:37

Getting Stared With the Kubernetes Gateway API

Gateway API 란 ?

  • 기존 HTTP, HTTPS만 지원하는 Ingress와 다르게, 다양한 프로토콜(L4/L7) 및 고급 네트워크 관리 기능을 지원하는 네트워크 트래픽 관리 API입니다.
  • 기존 Ingress는 구현한 벤더별 설정 들에 의존 했지만, Gateway API는 벤더별 의존을 없에고 k8s 내부 표준으로 사용하기 위해 만들었다고 생각합니다.
  • Ingress와 다르게 역할 분리가 명확하게 되어있으며, 고급 라우팅을 적용할 수 있습니다.

Gateway API의 역할 구조

alt text

Figure 1 Gateway API 의 역할 사진 출처

  • Infrastructure Provider
    • Cloud 서비스를 사용하는 경우 CSP 제공자, On-premise 환경인 경우에는 System Engineer Role 역할입니다.

클러스터가 사용할 수 있는 기본 네트워킹 인프라(예: 클라우드 로드밸런서, 온프레미스 하드웨어 로드밸런서, 클러스터 내 프록시 소프트웨어)를 관리하고 제공합니다.

  • Cluster Operator
    • Kubernetes의 Resource를 관리하는 (DevOps Engineer, SRE) 역할입니다.
    • Kubernetes 클러스터의 전반적인 관리, 정책 적용, 네트워크 접근 제어, 애플리케이션 권한 등을 책임지며, 클러스터가 여러 사용자나 팀의 요구사항을 충족하도록 관리합니다.
  • Application Developer
    • 애플리케이션의 비즈니스 로직에 집중하며, 애플리케이션 노출 및 라우팅 설정에 집중합니다.

Gateway API의 통신 방식

alt text

Figure 2 Ingress의 통신 방식 사진 출처

sequenceDiagram
    participant User as 외부 사용자
    participant GatewayClass as GatewayClass (Gateway API)
    participant Gateway as Gateway (Gateway API)
    participant HTTPRoute as HTTPRoute
    participant Service as Kubernetes Service
    participant Pod as Pod (애플리케이션)

    Note over GatewayClass,Gateway: 클러스터 관리자가 GatewayClass를 생성 및 관리
    Note over Gateway,HTTPRoute: 개발자가 Gateway와 HTTPRoute를 생성 및 연결

    User->>Gateway: HTTP/HTTPS 요청 (예: example.com)
    Gateway->>GatewayClass: GatewayClass에 따라 트래픽 처리 방식 결정
    Gateway->>HTTPRoute: 요청 정보 전달 (호스트/경로 매칭)
    HTTPRoute->>Service: 라우팅 규칙에 따라 서비스로 전달
    Service->>Pod: 요청 전달 (ClusterIP/Pod IP)
    Pod-->>Service: 응답 반환
    Service-->>HTTPRoute: 응답 반환
    HTTPRoute-->>Gateway: 응답 반환
    Gateway-->>User: 응답 반환

Figure 3 Gateway API의 통신 방식

Gateway API의 주요 구성요소

  • Gateway Class
    • Ingress와 비교 시 IngressClass 객체와 매핑되는 객체입니다.
    • Gateway가 트래픽 처리할 컨트롤러를 정하고 어떻게 작동할지 참고하는 객체입니다.
  • Gateway
    • Ingress와 비교 시 Ingress 객체와 매핑되는 객체입니다.
    • 트래픽의 진입점 역할을 하며, Kubernetes 클러스터 내부로 어떤 트래픽을 인입을 허용할 것 인지 규정하는 객체입니다.
    • TLS 종료와 인증서 지정 기능 또한 제공하는 객체입니다.
  • HTTP/gRPC/TCP/UDP/TLS(L4/L7) Route
    • Ingress와 비교 시 Ingress 객체의 .spec.rules. 항목에 매핑되는 객체입니다.
    • 트래픽 Route 규칙지정하는 역할을 하며, Kubernetes 클러스터 내부의 어떤 서비스로 라우팅을 할지 규정하는 객체입니다.

Istio 와 Gateway API 비교

  • Gateway API는 Istio Ingress/Egress Gateway와 다르게 North-South 지점에 위치해서 작동합니다.
  • Istio Service Mesh에서는 North-South지점 뿐만 아니라, East-South 환경에서도 작동이 필요하기 때문에, GAMMA (Gateway API for Mesh Management and Administration)가 생성되어 East-West 트래픽 관리 방법이 정의됐습니다.

Istio Virtual Service

apiVersion: networking.istio.io/v1
kind: VirtualService
...
spec:
  hosts:
  - details
  http:
  - route:
    - destination:
        host: details
        subset: v1

HTTP Route

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: reviews
spec:
  parentRefs:
  - group: ""
    kind: Service
    name: reviews
    port: 9080
  rules:
  - backendRefs:
    - name: reviews-v1
      port: 9080

Gateway API를 적용한 Istio 예제 실습

실습환경 구성

# Cluster 생성
kind create cluster --name myk8s --image kindest/node:v1.32.2 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000 # Sample Application
    hostPort: 30000
  - containerPort: 30001 # Prometheus
    hostPort: 30001
  - containerPort: 30002 # Grafana
    hostPort: 30002
  - containerPort: 30003 # Kiali
    hostPort: 30003
  - containerPort: 30004 # Tracing
    hostPort: 30004
  - containerPort: 30005 # kube-ops-view
    hostPort: 30005
networking:
  podSubnet: 10.10.0.0/16
  serviceSubnet: 10.200.1.0/24
EOF

# 클러스터 접속
docker exec -it myk8s-control-plane /bin/bash 

# 기본 툴 설치
apt update && apt install tree psmisc lsof wget bridge-utils net-tools dnsutils tcpdump ngrep iputils-ping git vim -y



# Gateway CRD 설치
kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
  { kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v1.2.1" | kubectl apply -f -; }


# Istio 설치
export ISTIOV=1.25.1
curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV sh -
cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl
istioctl install --set profile=minimal -y

# 샘플코드 경로 이동
cd istio-$ISTIOV

# 설치 결과 확인
kubectl get crd | grep .istio.io

# Result (Do Not Copy This!)
authorizationpolicies.security.istio.io         
destinationrules.networking.istio.io            
envoyfilters.networking.istio.io                
gateways.networking.istio.io                    
peerauthentications.security.istio.io           
proxyconfigs.networking.istio.io                
requestauthentications.security.istio.io        
serviceentries.networking.istio.io              
sidecars.networking.istio.io                    
telemetries.telemetry.istio.io                  
virtualservices.networking.istio.io             
wasmplugins.extensions.istio.io                 
workloadentries.networking.istio.io             
workloadgroups.networking.istio.io       


# Prometheus, Kiali, Grafana, jaeger 설치
kubectl apply -f samples/addons

# NodePort 변경 및 nodeport 30001~30003으로 변경 : prometheus(30001), grafana(30002), kiali(30003), jaeger(30004)
kubectl patch svc -n istio-system prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}'
kubectl patch svc -n istio-system grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}'
kubectl patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort", "ports": [{"port": 20001, "targetPort": 20001, "nodePort": 30003}]}}'
kubectl patch svc -n istio-system tracing -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 16686, "nodePort": 30004}]}}'

# default 네임스페이스에 istio-proxy sidecar 주입
kubectl label namespace default istio-injection=enabled

# 샘플 애플리케이션 배포
kubectl apply -f samples/httpbin/httpbin.yaml

Gateway API를 적용한 Istio 구성

# 테스트를 위한 namespace 생성
kubectl create namespace istio-ingress


kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway
  namespace: istio-ingress
spec:
  gatewayClassName: istio
  listeners:
  - name: default
    hostname: "*.example.com"
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: All
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http
  namespace: default
spec:
  parentRefs:
  - name: gateway
    namespace: istio-ingress
  hostnames: ["httpbin.example.com"]
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /get
    backendRefs:
    - name: httpbin
      port: 8000
EOF


kubectl get gateway -n istio-ingress
# Result (Do Not Copy This!)
NAME      CLASS   ADDRESS   PROGRAMMED   AGE
gateway   istio             False        13s


# NodePort 로 변경
kubectl annotate gateway -n istio-ingress gateway networking.istio.io/service-type=NodePort --overwrite


# Gateway 설정 확인
kubectl get svc -n istio-ingress gateway-istio


# Result ((Do Not Copy This!)
NAME            TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)                        AGE
gateway-istio   NodePort   10.200.1.158   <none>        15021:32525/TCP,80:31697/TCP   2m24s

# NodePort 를 30000번으로 변경
kubectl patch svc -n istio-ingress gateway-istio -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 80, "nodePort": 30000}]}}'

# HTTP Routie 객체 생성

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http
  namespace: default
spec:
  parentRefs:
  - name: gateway
    namespace: istio-ingress
  hostnames: ["httpbin.example.com"]
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /get
    - path:
        type: PathPrefix
        value: /headers
    filters:
    - type: RequestHeaderModifier
      requestHeaderModifier:
        add:
        - name: my-added-header
          value: added-value
    backendRefs:
    - name: httpbin
      port: 8000
EOF

# 테스트를 위해 curl 수행

while true; do curl -s -HHost:httpbin.example.com "http://127.0.0.1:30000/headers" | jq '.headers["My-Added-Header"][0]' ; sleep 0.5; echo; done

Figure 4 Kiali로 확인 결과