Search
Duplicate
🛼

Kubernetes Gateway API로 Ingress 교체하기

Category
as S/W 엔지니어
Tags
Gateway API
Kubernetes Gateway API
HTTPRoute
kind
Kubernetes
ingress
Created time
2023/10/29
Kubernetes Gateway API에서의 traffic 전달 논리 구조

Introduction

Prerequisite

Istio : 현재 Kubernetes Gateway API를 API Gateway 및 Service Mesh 부문까지 포함하여 지원한다(나아가 앞으로 default API로 사용할 것이라고). Istio Ingress Gateway는 설치할 필요 없이 istiod 만 설치하면 된다.
KinD : local의 KinD 환경이라 하더라도 Load Balancer 및 GatewayClass, Gateway 리소스 설치 부분을 제외하고는 클라우드 환경과 동일하다.

교체 절차

Ingress 삭제

port 충돌을 막기 위하여 기 설치된 ingress controller를 삭제한다. 한편 ingress resource는 그대로 두어도 무방하다.

Gateway API 설치

1. Kubernetes Gateway API CRD 설치

kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \ { kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.8.0" | kubectl apply -f -; }
Bash
복사
위를 실행하면 아래와 같이 gatewayclass resources가 설치되었음을 확인할 수 있다.
kubectl get gatewayclass # NAME CONTROLLER ACCEPTED AGE # istio istio.io/gateway-controller True 33d # istio-remote istio.io/unmanaged-gateway True 33d
Bash
복사
Gateway API는 Load Balancer를 필요로 한다(참조). 이는 사실 ‘필요’라기보다는 Kubernetes Gateway API 요구사항 중 하나가 역할에 따른 resource 분리임을 고려했을 때, L7 Load Balancer(ingress)가 갖던 역할 통합에서, 역할 분리개선 사항으로 이해할 수 있을 듯 하다. 다음은 KinD 공식 문서에서 소개하는 metalLB 설치 절차이다(참조).
1.
metalLB 설치
# metalLB CRD 설치하기 kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml # 완료 기다리기 kubectl wait --namespace metallb-system \ --for=condition=ready pod \ --selector=app=metallb \ --timeout=90s
Bash
복사
2.
loadbalancer가 사용하는 주소 pool 설정
a.
kind가 docker에서 사용하는주소 pool 얻기
docker network inspect -f '{{.IPAM.Config}}' kind # 실행 결과 # [{172.18.0.0/16 172.18.0.1 map[]} {fc00:f853:ccd:e793::/64 fc00:f853:ccd:e793::1 map[]}]
Bash
복사
b.
앞서 얻은 주소 범위로 IPAddressPool 설정 및 L2Advertisement resource 설정하기
Linux와는 달리 Mac이나 Windows의 Docker는 host에서 아래에서 설정하는 주소에 접근이 불가능하다. 이로 인해 아래에서 논할 Gateway로 traffic을 보내기 위한 port forwarding 설정 역시 Linux 환경에서만 동작한다.
apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: example namespace: metallb-system spec: addresses: - 172.18.255.200-172.18.255.250 # 앞서 얻은 CIDR을 참조하여 설정 --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: empty namespace: metallb-system
YAML
복사

3. Gateway resource 생성

apiVersion: gateway.networking.k8s.io/v1beta1 kind: Gateway metadata: name: default-gateway namespace: cluster spec: gatewayClassName: istio addresses: - type: IPAddress value: 172.18.255.200 # 사용할 Load Balancer의 External IP를 지정 listeners: - name: https-anyflow-net # 443 port에 대한 설정 hostname: "*.anyflow.net" # subdomain에 대해 wildcard 사용 port: 443 protocol: HTTPS tls: mode: Terminate certificateRefs: - kind: Secret # 기존과 동일하게 Secret으로 인증서 지정 name: default-tls namespace: istio-system allowedRoutes: namespaces: # 모든 namespace의 HTTPRoute를 수용 from: All
YAML
복사
위를 설치하면 아래와 같이 Gateway resource가 설치되었음을 확인할 수 있다.
kubectl get gateway -n cluster # NAME CLASS ADDRESS PROGRAMMED AGE # default-gateway istio 172.18.255.200 True 2d19h
Bash
복사
또한 아래와 같이 gateway의 LoadBalancer type의 서비스가 생성된 것을 볼 수 있다.
kubectl get svc -n cluster # NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE # default-gateway-istio LoadBalancer 10.103.138.151 172.18.255.200 15021:30209/TCP,443:31781/TCP 2d20h # ....
YAML
복사

4. HTTPRoute 생성

당연한(?) 이야기이지만 routing 대상 service가 미리 설치되어 있어야 한다. 아래에서는 docserver란 service를 가정한다. 아래 설정은 다음의 규칙을 설정한다.
api.anyflow.net domain으로의 traffic에 대해서 설정
/ path로 들어오는 traffic을 /__apispec/ path로 redirect
/ prefix인 모든 traffic을 docserver service로의 routing
HTTP에서 HTTPS로 영구 redirection
apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: docserver namespace: cluster2 # 앞선 gateway의 allowedRoutes 설정에 따라 다른 namespace의 service라도 무방 spec: parentRefs: - name: default-gateway # 앞서 생성한 gateway의 이름을 지정 namespace: cluster # 앞서 생성한 gateway의 namespace를 지정 hostnames: - api.anyflow.net # routing 대상 domain rules: - matches: - path: type: Exact #Implementation-specific, PathPrefix, Exact value: / filters: - type: RequestRedirect requestRedirect: path: type: ReplaceFullPath replaceFullPath: /__apispec/ # / path로 들어오는 traffic을 /__apispec/ path로 redirect statusCode: 302 - matches: - path: type: PathPrefix #Implementation-specific, PathPrefix, Exact value: / # / prefix인 모든 traffic을 krakend service로의 routing backendRefs: - name: docserver port: 80 - filters: - type: RequestRedirect requestRedirect: # HTTP에서 HTTPS로 영구 redirection scheme: https statusCode: 301
YAML
복사
이제 해당 호스트에서 curl 등을 사용하여 위 설정의 정상 동작 여부를 테스트해본다. 아래는 이 테스트를 위한 /etc/hosts 파일 예이다.
... 172.18.255.200 api.anyflow.net # 172.18.255.200은 위에서 설정한 Load Balancer IP ...
Shell
복사

Appendix: Gateway로 traffic을 보내기 위한 port forwarding 설정

본 섹션은 위와 같은 /etc/hosts 파일 수정 없이도, kind 환경에서 host machine으로 들어온 traffic을 Gateway로 보내기 위한 설정을 다룬다. 참고로 Linux와는 달리 Mac이나 Windows의 Docker는 host에서 아래에서 설정하는 주소에 접근이 불가능하기에, 아래는 Linux 환경에서만 동작한다.
핵심은 iptables 명령을 통한 port forwarding 규칙 설정으로, 앞서와 마찬가지로 172.18.255.200 은 위에서 설정한 Load Balancer IP이다. 아래 예제는 443 port만 다루고 있다.
$ sudo iptables -A DOCKER -p tcp -s 0.0.0.0/0 -d 172.18.255.200 --dport 443 -j ACCEPT $ sudo iptables -t nat -A DOCKER -p tcp --dport 443 -j DNAT --to-destination 172.18.255.200:443 $ sudo iptables -t nat -A POSTROUTING -s 172.18.255.200 -d 172.18.255.200 -p tcp --dport 443 -j MASQUERADE
Bash
복사