Work/개발 노트
[KANS] 6주차 - Ingress, Gateway API
★용호★
2024. 10. 13. 01:24
Ingress 개요
- Ingress를 이해하기 위해서는 Service의 각 유형들에 대한 이해도가 있어야 함
- Ingress는 클러스터 외부에서 클러스터 내부 서비스로 트래픽을 전달할 수 있도록 제공하고, Service와 달리 HTTP 및 HTTPS를 사용할 수 있도록 하는 Kubernetes의 오브젝트
- Ingress는 다양한 환경과 요구사항에 맞춰 구현될 수 있어야 하고, SSL 인증서 관리, 고급 로드 밸런싱 알고리즘, 웹 애플리케이션 방화벽 등의 기능을 제공할 수 있어야 하기 때문에 Service 처럼 Built-in으로 제공되지 않고 별도로 설치해야함
- Ingress의 실제 동작 구현은 인그레스 컨트롤러가 처리함 (대표적으로 Nginx, Kong, AWS Loadbalancer Controller 등이 있음)
- 쿠버네티스는 Ingress API만 정의하고 실제 구현은 Add-on에게 맡김
Nginx Ingress
- ingress-nginx는 helm chart를 사용해서 설치하고, 이 글에서는 위 그림과 같이 Kubernetes에서 제공하는 ingress-nginx를 사용함.
- 아래 명령으로 설치
# Ingress-Nginx 컨트롤러 생성
cat <<EOT> ingress-nginx-values.yaml
controller:
service:
type: NodePort
nodePorts:
http: 30080
https: 30443
nodeSelector:
kubernetes.io/hostname: "k3s-s"
metrics:
enabled: true
serviceMonitor:
enabled: true
EOT
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
kubectl create ns ingress
helm install ingress-nginx ingress-nginx/ingress-nginx -f ingress-nginx-values.yaml --namespace ingress --version 4.11.2
- 설치가 완료되면 아래와 같이 nginx ingress controller가 실행되어 있는 것을 확인할 수 있음
- tcpdump 시 Source IP가 SNAT 되는 것 때문에 혼동되는 것을 방지하기 위해 externalTrafficPolicy는 Local로 변경 (Client의 IP 보존)
- kubectl patch svc -n ingress ingress-nginx-controller -p '{"spec":{"externalTrafficPolicy": "Local"}}'
- 이 후에는 실제로 트래픽을 수신할 Ingress를 생성해야함
- ingress-nginx를 사용할 때 Pod로 실행 중인 nginx의 설정은 configMap으로 관리되는데 해당 configMap이 수정되는 즉시 nginx Pod에 반영하고 실시간으로 reload 시켜주는 역할을 nginx ingress controller가 함.
- 아래의 작업이 수행 되면 nginx ingress controller가 config를 reload함
- New Ingress Resource Created.
- TLS section is added to existing Ingress.
- Change in Ingress annotations that impacts more than just upstream configuration. For instance load-balance annotation does not require a reload.
- A path is added/removed from an Ingress.
- An Ingress, Service, Secret is removed.
- Some missing referenced object from the Ingress is available, like a Service or Secret.
- A Secret is updated.
- 모든 트래픽은 ingress-nginx-controller로 유입되었다가 nginx에 의해 백엔드의 서비스로 트래픽이 밸런싱 됨
- Ingress 컨트롤러는 Service의 Endpoint 정보를 통해서 Pod의 IP를 알고 있기 때문에 Service의 대표 IP로 트래픽을 라우팅하는 것이 아니라 Pod의 IP로 Bypass함. 이런 이유로 Service를 NodePort로 만들 필요 없이 ClusterIP로만 만들어주면 Ingress 컨트롤러가 대상 pod로 트래픽을 전달함
- 이는 아래와 같이 ingress controller가 endpoints와 endpointslices 정보를 볼 수 있는 권한이 있기 때문
- Ingress의 엔드포인트로 트래픽을 다량으로 전송 시 Nginx ingress controller에 의해서 고르게 분산되어 Pod로 전달되는 것을 확인할 수 있음
- 패킷 헤더의 클라이언트 주소와 X-Forwared-for의 값이 다른 것을 볼 수 있는데 최종적으로 수신되었을 때의 클라이언트 IP는 SNAT되어 Ingress Controller의 IP 주소가 기록되는 것을 확인할 수 있음. X-forwarede-for에 기록된 IP 주소는 요청한 클라이언트의 소스 IP
Ingress를 활용하여 Carnary 배포하기
카나리는 광산에서 가스 유출이 있는지 확인하기 위해 냄새에 민감한 카나리라는 새를 보내보고 죽으면 위험, 살아있으면 가스가 없는 것으로 판단했다는데서 유래됨
1. 서로 다른 버전의 이미지를 사용하는 Deployment와 Service 배포
2. v1, v2에 해당하는 Ingress 생성. 이 떄 v2에 해당하는 Ingress는 weight 값을 지정하여 10%의 트래픽만 수신하도록 설정
cat <<EOT> canary-ingress1.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-canary-v1
spec:
ingressClassName: nginx
rules:
- host: kans.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-v1
port:
number: 8080
EOT
cat <<EOT> canary-ingress2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-canary-v2
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
ingressClassName: nginx
rules:
- host: kans.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc-v2
port:
number: 8080
EOT
kubectl apply -f canary-ingress1.yaml
kubectl apply -f canary-ingress2.yaml
3. 동작에 이상이 없을 경우 weight 값을 점차 늘려가는 방식으로 v2로 전환
kubectl annotate --overwrite ingress ingress-canary-v2 nginx.ingress.kubernetes.io/canary-weight=50
Gateway API 개요
Kuberentes의 공식 문서에 Ingress는 더이상 기능 추가를 하지 않을 예정이고 Gateway API가 새로운 기능으로 추가되었다는 코멘트가 있는 만큼 Gateway API의 중요성이 커질 것으로 예상됨
- Ingress에 비해 기능이 더 풍부하며 HTTP 뿐만 아니라 TCP, UDP에 대한 라우팅도 제공하고 있음
주요 기능들을 정리해보면 아래와 같음
- 확장된 기능: HTTP 헤더 기반 라우팅, 트래픽 가중치 설정, 카나리 배포, A/B 테스팅, 요청/응답 조작, 트래픽 미러링 등
-
- 역할 분리: 인프라 제공자, 클러스터 운영자, 애플리케이션 개발자의 세 가지 역할로 책임을 구분
- RBAC 기반의 책임 분리가 가능해져, 여러 팀이 Data Plane 인프라를 안전하게 공유할 수 있게됨
- 강력한 확장성 모델: CRD를 통한 사용자 정의 확장을 지원하여 API 자체에서 지원하지 않는 기능들도 제공 가능
- 표준화: 공급 업체별로 기능의 차이가 컸던 Ingress에 비해 Gateway API는 다양한 구현에서 지원되는 범용 사양을 제공
- 다양한 프로토콜 지원: Gateway API는 HTTP/HTTPS뿐만 아니라 TCP, gRPC 등 다양한 프로토콜을 지원
- 이식성: 적합성 테스트를 통해 API 기능의 일관성을 보장하기 때문에 손쉽게 다른 Gateway API 구현체로 변경 가능
Gloo Gateway로 Gateway API 학습해보기
Gloo Gateway가 kind 기반으로 따라해보기 쉽게 튜토리얼을 제공하고 있음 (참고)
- 위 구조에서 GatewayClass가 가장 최상위이며, Gateway API의 어떤 구현체를 사용할 것인지를 명시하게됨. Ingress로 비교하자면 IngressClass와 유사
- 트래픽을 어떻게 처리할지에 대한 프로토콜, 포트, 사용할 GatewayClass 등을 정의하는 것이 Gateway. AWS ALB의 리스너와 유사
- 라우팅 규칙을 정의해서 대상 Pod로 전달하기 위한 설정을 하는 것이 HTTPRoute
- Gloo가 컨트롤 플레인 역할을 수행하고, Envoy가 데이터 플레인 역할을 함
- 대부분의 Gateway API 구현체들은 Envoy를 사용함
- HTTPRoute 설정 후 HTTP 요청을 보내보면 결과가 반환되고, envoy가 처리해서 반환했다는 것을 확인할 수 있음