Kubernetes Gateway API에서의 traffic 전달 논리 구조
Introduction
Ingress + API Gateway = Kubernetes Gateway API 에서의 논의에 따라 기존 Ingress를 Kubernetes Gateway API로 교체하는 방법을 요약한다. Kubernetes Gateway API 설치는 다음의 문서에 근거한다.
Prerequisite
•
Istio : 현재 Kubernetes Gateway API를 API Gateway 및 Service Mesh 부문까지 포함하여 지원한다(나아가 앞으로 default API로 사용할 것이라고). Istio Ingress Gateway는 설치할 필요 없이 istiod 만 설치하면 된다.
•
교체 절차
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
복사
2. Load Balancer (KinD: multi node 지원 개발용 Kubernetes 전용)
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
복사