기존에 Https 라우팅을 위해 사용하던 Ingress 리소스를 Gateway-Api 의 리소스로 싹 고쳤다. 이 글은 마이그레이션 방법 및 Gateway-api 에 대한 기록이다.
Gateway-API 란?
Gateway api 는 k8s 새롭게 제공하는 네트워크 표준을 말한다. 이를 이용하면 Ingress 에서는 할 수 없었던 복잡한 규칙( 라우팅 규칙, 가중치 기반 트래픽 처리.. 등 )을 처리할 수 있다.
사실 기존에도 이 한계를 극복하기 위해 나온 다양한 솔루션들이 이미 존재한다. (ex, istio, Linkerd ) 하지만 이것들은 각자 독자적인 CRD를 사용했고, 그 벤더사에 lock-in 되는 문제도 있었다.
이에, gateway-api 를 이용해 공통된 표준을 만들고, 이를 istio 나 linkerd 같은 구현체들이 따를 수 있게 함으로써 이러한 문제들을 해결하려는 것이다. 더 다양한 내용은 k8s 공식 설명 을 참고하자.
Ingress Migration
본격적으로, Migration 해보자. k8s gateway api 를 지원하는 구현체를 골라야 하는데, 필자는 istio를 사용했다. istio docs 에 따르면, 계속해서 지원할 예정이고, 점차 표준으로 채택한다고 한다. 또한, 기존에 Service mesh 로 강력한 기능들을 많이 제공해 왔기 때문에 선택했다.
일단 istio 를 설치해보자. 스크립트는 여기서 참고했다. 작성일 기준으로 istio 버전은 1.27.1 이다.
#!/bin/bash
# repo 추가
helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo update
# Gateway-api CRDS 추가. experimental 버전을 써도 되긴 하나, 그냥 standard 를 사용했다.
wget https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/standard-install.yaml
kubectl apply -f standard-install.yaml
# istio-base 설치.
helm install istio-base istio/base -n istio-system --create-namespace
# istiod 설치. values.yaml 은 resource 부분만 변경했다. 필요하면 고치자.
helm install istiod istio/istiod -n istio-system -f ./istiod/values.yaml --wait
여기서 ingress-gateway 를 배포해야 하는데, 여기서 두가지 선택지가 있다.
- gateway.networking.k8s.io/v1
- networking.istio.io/v1
전자가 k8s gateway-api 표준으로 GatewayClass, HttpRoute, ReferenceGrant 등을 지원하는것이고, 후자는 기존에 사용하던 istio 의 custom crd 이다. Virtual Service, DestinationRule.. 등등이 있다.
Istio는 이제 양쪽 모두를 지원하기 때문에, 기왕이면 표준 API 를 이용해서 설치한다.
# gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: api-gateway
namespace: istio-system
spec:
gatewayClassName: istio
listeners:
- name: http #for aceme-challenge http.
hostname: "your-domain"
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
...
Gateway 에 보면, 아래쪽에 listeners 를 이용해서 규칙을 적용할 수 있는데, 여기서 cert-manager 를 사용하고 있다면( 필자도 마찬가지였다 ) http 로 라우팅되는 저 규칙을 반드시 추가해 주어야 한다. acme-challenge 를 받아줄 http 통신이기 때문에 없으면 갱신도, 인증서도 발급되지 않는다.
이 yaml 을 적용하면 gateway가 만들어진다. ( svc type 은 LoadBalancer 이다. )
추가적으로, cert-manager 의 경우도 Gateway Api 를 사용해야 하기 때문에 함께 업데이트 한다.
#!/bin/bash
helm install \
cert-manager oci://quay.io/jetstack/charts/cert-manager \
--version v1.18.2 \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true \
--set config.apiVersion="controller.config.cert-manager.io/v1alpha1" \
--set config.kind="ControllerConfiguration" \
--set config.enableGatewayAPI=true
기존에 사용하던 ClusterIssuer 를 다음과 같이 변경해야 한다.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-issuer
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: your-email
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-priv-key-name
# Enable gateway-api
solvers:
- http01:
gatewayHTTPRoute:
parentRefs:
- name: api-gateway
namespace: istio-system
kind: Gateway
solver 를 ingress 에서 http route 로 변경해주고, parentRefs 에 위쪽에 만든 Gateway-api 를 사용하는 게이트웨이를 추가한다.
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: letsencrypt-cert
namespace: istio-system
spec:
secretName: letsencrypt-priv-key-name
issuerRef:
name: letsencrypt-issuer
kind: ClusterIssuer
dnsNames:
- your.dns.here
commonName: your.dns.here
그리고 certificate 를 만들어서, 챌린지가 정상적으로 성공하는지 확인한다. 기본 Gateway 로 라우팅 된 후, certificate 까지 발급되었는지 확인하자.

여기까지 만들어졌으면 이제 Https 로 통신하기 위한 라우팅 규칙을 추가한다.
# gateway.yaml 에 https 라우팅 추가하고 rollout 한다.
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: api-gateway
namespace: istio-system
spec:
gatewayClassName: istio
listeners:
... # http 삭제하면 자동갱신 안됨.
- name: https-blog
hostname: "notypie.dev" # 위쪽에서 작성한 도메인을 쓰면 된다.
protocol: HTTPS
port: 443
allowedRoutes:
namespaces:
from: All
tls:
mode: Terminate
certificateRefs:
- name: notypie-dev-blog-tls # 위쪽에서 만든 tls 이름을 작성하면 된다.
kind: Secret
...
---
# blog_route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: blog-route
namespace: notypie-dev
spec:
parentRefs:
- name: api-gateway
namespace: istio-system
sectionName: https-blog # gateway listeners 이름을 맞춰준다.
hostnames:
- "notypie.dev"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: kubernetes.service.name
port: PORT
이 블로그 라우팅을 예로 들면, 위쪽에서 만든 tls 를 설정값으로 추가하고, Ingress 를 대체하기 위해 HTTP Route 리소스를 생성한다.
여기까지 작성해서, domain 을 이용해서 접근했을 때 정상적으로 https 로 페이지가 보인다면 성공한 것이다.
마치며
istio 를 구현체로 이용해서 Gateway api 를 사용해봤다. 변경해야 할 부분이 많아서, 고생을 좀 했다.
이번에 표준으로 다 맞춰두었으니 다음번엔 istio 리소스들을 활용해서 다양한 규칙, 서킷브레이커 등을 적용해보자.