graph LR traffic((traffic)) --> LB[Load Balancer] --> Gateway[Gateway] --> HTTPRoute --> Service
Mermaid
복사
Kubernetes Gateway API에서의 traffic 전달 논리 구조
Introduction
My Cluster 프로젝트의 일환으로, Ingress + API Gateway = Kuberneters 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 삭제와 Gateway API 설치, 그리고 (KinD 환경의 경우) host 443 포트 포워딩 설정으로 나뉜다.
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 전용)
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: anyflow-gateway
namespace: istio-system
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: anyflow-tls
namespace: istio-system
allowedRoutes:
namespaces: # 모든 namespace의 HTTPRoute를 수용
from: All
YAML
복사
위를 설치하면 아래와 같이 gateway resource가 설치되었음을 확인할 수 있다.
kubectl get gateway -n istio-system
# NAME CLASS ADDRESS PROGRAMMED AGE
# anyflow-gateway istio 172.18.255.200 True 2d19h
Bash
복사
또한 아래와 같이 gateway의 LoadBalancer type의 서비스가 생성된 것을 볼 수 있다.
kubectl get svc -n istio-system
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# anyflow-gateway-istio LoadBalancer 10.103.138.151 172.18.255.200 15021:30209/TCP,443:31781/TCP 2d20h
# ....
YAML
복사
4. HTTPRoute 생성
당연한 이야기이지만 routing 대상 service가 미리 설치되어 있어야 한다. 이미 ingress가 있었을 경우 routing 대상 service가 있었을 것이다. 아래에서는 krakend 란 service가 있음을 가정한다. 아래 설정은 다음의 규칙을 설정한다.
•
api.anyflow.net domain으로의 traffic에 대해서 설정
•
/ path로 들어오는 traffic을 /__apispec/ path로 redirect
•
/ prefix인 모든 traffic을 krakend service로의 routing
•
HTTP에서 HTTPS로 영구 redirection
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: krakend
namespace: cluster # 앞선 gateway의 allowedRoutes 설정에 따라 다른 namespace의 service라도 무방
spec:
parentRefs:
- name: anyflow-gateway # 앞서 생성한 gateway의 이름을 지정
namespace: istio-system # 앞서 생성한 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: krakend
port: 80
- filters:
- type: RequestRedirect
requestRedirect: # HTTP에서 HTTPS로 영구 redirection
scheme: https
statusCode: 301
YAML
복사
위까지 완료하면 해당 host에서 위에서 설정한 api.anyflow.net 도메인으로 정상 서비스되는지 확인 가능하다. 이 경우 host의 hosts 파일에 api.anyflow.net 도메인에 대해 routing을 localhost로 설정해야 한다.
Gateway로 traffic을 보내기 위한 port forwarding 설정
본 섹션의 내용은 KinD 환경에서 host machine으로 들어온 traffic을 gateway로 보내기 위한 설정이다. 앞서 논했듯이, Linux와는 달리 Mac이나 Windows의 Docker는 host에서 아래에서 설정하는 주소에 접근이 불가능하기에, Linux 환경에서만 동작한다.
iptables 명령을 통해 port forwarding을 설정한다. host로 들어오 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
복사