[KANS] 3기 6주 – Ingress & Gateway API

loudNet@팀에서 진행하는 쿠버네티스 네트워크 스터디 3기 참가글입니다.

‘쿠버네티스’ 네트워크에 대해서 직접 실습을 통해 장애 시 해결 능력을 갖추고, 학습 내용을 전파 및 공유합니다!


1. k3s

경량의 쿠버네티스. 간편한 설치와 절반의 메모리, 모든걸 100MB 미만의 바이너리로 제공합니다.

Lightweight Kubernetes. Easy to install, half the memory, all in a binary of less than 100 MB.

k3s docs

k3s는 쿠버네티스와 완벽히 호환되는 k8s의 배포판 중 하나이다. 기본 Kubernetes는 10글자로, 줄여서 k8s라고 표기할 수 있다. k3s는 (메모리 측면에서) 절반의 크기의 쿠버네티스를 구현하는것을 목표하였다. 따라서 10글자 > 5글자, k8s > k3s 를 프로젝트 이름으로 삼았다.

주요 기능)

  • 단일 바이너리로 패키지화.
  • 기본 스토리지 메커니즘으로 sqlite3를 기반으로 하는 경량 스토리지 백엔드. etcd3, MySQL, Postgres도 사용 가능.
  • 복잡한 TLS 및 옵션을 처리하는 간단한 런처에 포함.
  • 경량 환경을 위한 합리적인 기본값으로 기본적으로 보안을 유지함.
  • 다음과 같이 간단하지만 강력한 ‘batteries-included’ 기능 추가. 예를 들어:
    • local storage provider
    • service load balancer
    • Helm controller
    • Traefik ingress controller
  • 모든 쿠버네티스 컨트롤 플레인 구성 요소의 작동은 단일 바이너리 및 프로세스로 캡슐화. 이를 통해 K3s는 인증서 배포와 같은 복잡한 클러스터 작업을 자동화하고 관리.
  • 외부 종속성 최소화(최신 커널과 cgroup 마운트만 필요)


필수 종속성)

  • Containerd
  • Flannel (CNI)
  • CoreDNS
  • Traefik (인그레스)
  • Klipper-lb (서비스 로드밸런서)
  • 임베디드 네트워크 정책 컨트롤러
  • 임베디드 로컬 경로 프로비저너
  • 호스트 유틸리티(iptables, socat 등)


Architecture)

기존 쿠버네티스가 Controlplane과 Worker node들로 구성되었던 것처럼, k3s 또한 컨트롤플레인 역할의 k3s server와 워커노드 역할의 k3s agent 로 구성되어있다. 별다른 옵션을 설정하지않으면 CRI는 Containerd, CNI는 Flannel로 지정되고, etcd외의 다른 데이터베이스 옵션(SQLite, Postgres, MySQL/MariaDB 등) 과의 etcdAPI 호환을 위해 Kine라는 구성요소를 사용한다.


단일 서버노드로 구성하는 Single-server Setup with an Embedded DB으로 사용하거나, 고가용성을 위해 다수의 서버노드 또는 데이터베이스를 서버노드와 분리한 High-Availability K3s 구조를 사용할 수 있다. 각 구조의 장단점은 Stacked etcd topology 또는 External etcd topology 참조

Single-server
Embedded DB
External DB

AWS상에 EC2 기반 k3s 클러스터 배포

  • CloudFormation
# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/kans/kans-6w.yaml

# CloudFormation 스택 배포
# aws cloudformation deploy --template-file kans-1w.yaml --stack-name mylab --parameter-overrides KeyName=<My SSH Keyname> SgIngressSshCidr=<My Home Public IP Address>/32 --region ap-northeast-2
예시) aws cloudformation deploy --template-file kans-6w.yaml --stack-name mylab --parameter-overrides KeyName=kp-gasida SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2

## Tip. 인스턴스 타입 변경 : MyInstanceType=t3.xlarge (vCPU 4, Mem 16)
예시) aws cloudformation deploy --template-file kans-6w.yaml --stack-name mylab --parameter-overrides MyInstanceType=t3.xlarge KeyName=kp-gasida SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2

# CloudFormation 스택 배포 완료 후 작업용 EC2 IP 출력
aws cloudformation describe-stacks --stack-name mylab --query 'Stacks[*].Outputs[0].OutputValue' --output text --region ap-northeast-2

# [모니터링] CloudFormation 스택 상태 : 생성 완료 확인
while true; do 
  date
  AWS_PAGER="" aws cloudformation list-stacks \
    --stack-status-filter CREATE_IN_PROGRESS CREATE_COMPLETE CREATE_FAILED DELETE_IN_PROGRESS DELETE_FAILED \
    --query "StackSummaries[*].{StackName:StackName, StackStatus:StackStatus}" \
    --output table
  sleep 1
done

# EC2 SSH 접속 : 바로 접속하지 말고, 3~5분 정도 후에 접속 할 것
ssh -i ~/.ssh/kp-gasida.pem ubuntu@$(aws cloudformation describe-stacks --stack-name mylab --query 'Stacks[*].Outputs[0].OutputValue' --output text --region ap-northeast-2)
...
(⎈|default:N/A) root@k3s-s:~# <- kubeps 가 나오지 않을 경우 ssh logout 후 다시 ssh 접속 할 것!

k3s 클러스터 구성 확인

  • k3s 설치 옵션 : aws cloudformation 에 ec2 에 userdata 로 실행되어 있음
# Install k3s-server
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC=" --disable=traefik"  sh -s - server --token kanstoken --cluster-cidr "172.16.0.0/16" --service-cidr "10.10.200.0/24" --write-kubeconfig-mode 644 

# Install k3s-agent
curl -sfL https://get.k3s.io | K3S_URL=https://192.168.10.10:6443 K3S_TOKEN=kanstoken  sh -s -
  • 경량화를 위해 k8s와 다른 k3s의 내부
# 노드 확인
kubectl get node -owide
NAME     STATUS   ROLES                  AGE   VERSION        INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION   CONTAINER-RUNTIME
k3s-s    Ready    control-plane,master   23m   v1.30.5+k3s1   192.168.10.10    <none>        Ubuntu 22.04.5 LTS   6.8.0-1015-aws   containerd://1.7.21-k3s2
k3s-w1   Ready    <none>                 23m   v1.30.5+k3s1   192.168.10.101   <none>        Ubuntu 22.04.5 LTS   6.8.0-1015-aws   containerd://1.7.21-k3s2
k3s-w2   Ready    <none>                 23m   v1.30.5+k3s1   192.168.10.102   <none>        Ubuntu 22.04.5 LTS   6.8.0-1015-aws   containerd://1.7.21-k3s2
k3s-w3   Ready    <none>                 23m   v1.30.5+k3s1   192.168.10.103   <none>        Ubuntu 22.04.5 LTS   6.8.0-1015-aws   containerd://1.7.21-k3s2

# kubecolor alias 로 kc 설정 되어 있음
kc describe node k3s-s  # Taints 없음
kc describe node k3s-w1


# 파드 확인
kubectl get pod -n kube-system
NAME                                      READY   STATUS    RESTARTS   AGE
coredns-7b98449c4-jmhgk                   1/1     Running   0          21m
local-path-provisioner-6795b5f9d8-w6h8s   1/1     Running   0          21m
metrics-server-cdcc87586-m4ndt            1/1     Running   0          21m

#
kubectl top node
kubectl top pod -A --sort-by='cpu'
kubectl top pod -A --sort-by='memory'
kubectl get storageclass


# config 정보(위치) 확인
kubectl get pod -v=6
I1006 13:04:02.858105    4325 loader.go:395] Config loaded from file:  /etc/rancher/k3s/k3s.yaml
I1006 13:04:02.872677    4325 round_trippers.go:553] GET https://127.0.0.1:6443/api/v1/namespaces/default/pods?limit=500 200 OK in 5 milliseconds
No resources found in default namespace.

cat /etc/rancher/k3s/k3s.yaml
export | grep KUBECONFIG

# 네트워크 정보 확인 : flannel CNI(vxlan mode), podCIDR
ip -c addr
ip -c route
cat /run/flannel/subnet.env
kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}' ;echo
kubectl describe node | grep -A3 Annotations
brctl show

# 서비스와 엔드포인트 확인
kubectl get svc,ep -A


# iptables 정보 확인
iptables -t filter -S
iptables -t nat -S
iptables -t mangle -S

# tcp listen 포트 정보 확인
ss -tnlp

k3s 설정 확인

  • node, pod 확인 > apiserver,proxy,etcd등 기본 구성요소 없음
  • config 조회시 kubeconfig 조회가능,
  • apiserver는 https://127.0.0.1:6443 에서 실행 중 > 확인시 k3s binary
  • k3s journal ctl 조회> k3s binary 내부에서 database(sqlite), 기타 kube-* 구성요소 실행
  • sudo journalctl -u k3s | grep Running

2. Ingress

URI, 호스트명, 경로 등과 같은 web 컨셉을 인지하는 프로토콜 인식 설정 메커니즘을 사용해 HTTP(또는 HTTPS) 네트워크 서비스를 제공할 수 있다. Ingress 개념은 Kubernetes API를 통해 정의한 규칙에 따라 트래픽을 다양한 백엔드로 매핑할 수 있게 한다.

Make your HTTP (or HTTPS) network service available using a protocol-aware configuration mechanism, that understands web concepts like URIs, hostnames, paths, and more. The Ingress concept lets you map traffic to different backends based on rules you define via the Kubernetes API.

Ingress, k8s docs


Ingress 오브젝트는 클러스터 내부의 서비스(ClusterIP, NodePort, Loadbalancer)를 외부로 노출(HTTP/HTTPS) – Web Proxy 역할을 한다.


기존 TCP/IP기반의 L4 레벨의 로드밸런서처럼 작동하였던 Service 리소스와 다르게, Ingress는 L7 레벨의 로드밸런서처럼 작동한다. 기본적인 로드밸런싱 외에도, L7수준에서 작동하기에 호스트 및 경로 기반 라우팅, SSL(HTTPS등) 처리등이 가능하다는 장점을 갖는다.


Kubernetes에서 Ingress 오브젝트는 규칙과 설정을 저장하는 표준 API스펙? 인터페이스이다. 실제로 트래픽 처리는 Ingress Controller 라는 별도의 구현체를 사용하여야한다. CRI, CNI, CSI 등과 같이 k8s에서는 표준 인터페이스를 제시하고, 실제 구현체는 사용자의 선택에 따라 개별적으로 사용함으로써 오픈소스인 k8s는 유연성과 확장성을 가질 수 있게 된다

2.1. Ingress 통신 흐름

요약:

  • Nginx 인그레스 컨트롤러 경우,
  • 외부에서 인그레스로 접속 시,
  • Nginx 인그레스 컨트롤러 파드로 인입되고,
  • 이후 애플리케이션 파드의 IP로 직접 통신

클러스터 내부를 외부에 노출 과정의 발전 단계

Pod에서의 노출, Service에서의 노출은 과거 글 참조

4. Ingress Controller 파드를 배치

  • 서비스 앞단에 HTTP 고급 라우팅 등 기능 동작을 위한 배치
  • 인그레스(정책)이 적용된 인그레스 컨트롤러 파드(예. nginx pod)를 앞단에 배치하여 고급 라우팅 등 기능을 제공


5. Ingress Controller 이중화 구성

  • Active(Leader) – Standby(Follower) 로 Active 파드 장애에 대비


6. Ingress Controller 파드를 외부 노출

  • 인그레스 컨트롤러 파드를 외부에서 접속하기 위해서 노출(expose)
  • 인그레스 컨트롤러 노출 시 서비스(NodePort Type) 보다는 좀 더 많은 기능을 제공하는 서비스(LoadBalancer Type)를 권장 (80/443 포트 오픈 시)


7. Ingress와 파드간 내부 연결의 효율화

  • 인그레스 컨트롤러 파드(Layer7 동작)에서 서비스 파드의 IP로 직접 연결
  • 인그레스 컨트롤러 파드는 K8S API서버로부터 서비스의 엔드포인트 정보(파드 IP)를 획득 후 바로 파드의 IP로 연결 – Why endpoints & not services
  • 지원되는 인그레스 컨트롤러 : Nginx, Traefix 등 현재 대부분의 인그레스 컨트롤러가 지원함

2.2. Nginx Ingress Controller

Ingress가 클러스터에서 작동하려면 Ingress 컨트롤러가 실행되고 있어야 한다. 하나 이상의 Ingress 컨트롤러를 선택하여 클러스터에 설정되어 있는지 확인해야 한다. 이 페이지에서는 배포할 수 있는 일반적인 Ingress 컨트롤러들을 나열하고 있다.

In order for an Ingress to work in your cluster, there must be an ingress controller running. You need to select at least one ingress controller and make sure it is set up in your cluster. This page lists common ingress controllers that you can deploy.

Ingress Controllers, k8s doc


ingress-nginx는 NGINX를 리버스 프록시 및 로드 밸런서로 사용하는 Kubernetes의 Ingress 컨트롤러이다.

ingress-nginx is an Ingress controller for Kubernetes using NGINX as a reverse proxy and load balancer.

ingress-nginx controller, github

인그레스 컨트롤러: 인그레스의 실제 동작 구현은 인그레스 컨트롤러(Nginx, Kong 등)가 처리


Ingress NGINX Controller for Kubernetes

How it works > configmap 설정을 nginx config 에 적용(by lua), 변경 시 (최소) reload


NGINX Ingress Controller at a high level

아래 그림은 Kubernetes 클러스터 내에서 A,B 각 네임스페이스에 존재하는 두 개의 웹 애플리케이션을 인터넷상의 클라이언트에게 노출하는 NGINX Ingress Controller의 예시를 보여준다.


클러스터 관리자와 사용자(user)는 kubernetes api(kubectl등과 같은 api 제어도구)를 사용해 Ingress를 관리한다. 고객(Client)는 퍼블릭 엔드포인트(DNS주소)를 통해 ingress-nginx pod에 접근하고, 해당 인그레드 파드에서 뒷단의 실제 워크로드(파드)로 접근을 전달한다.


The NGINX Ingress Controller pod


NGINX Ingress Controller 파드는 하나의 컨테이너로 구성되며, 다음을 포함한다

  • 클러스터 내에서 생성된 Ingress 및 기타 리소스에 따라 NGINX를 구성하는 NGINX Ingress Controller 프로세스
  • NGINX MAster 프로세스, NGINX Worker 프로세스를 제어
  • 클라이언트 트래픽을 처리하고 백엔드 애플리케이션으로 트래픽을 로드 밸런싱하는 NGINX Worker 프로세스들

다음은 이 프로세스들이 상호 작용하는 방식과 외부 엔티티들과의 상호작용을 보여주는 아키텍처 다이어그램이다. 상세설명은.. 원문..참조.. . controller가 동적으로 nginx.conf를 변경한다 이외에 일반적인 nginx package / nginx pod와의 차이가 있는가? 잘 모르겠음..

Ingress Nginx 컨트롤러 생성

  • ingress-nginx controller 생성
# 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

# 확인
kubectl get all -n ingress
kc describe svc -n ingress ingress-nginx-controller

# externalTrafficPolicy 설정
kubectl patch svc -n ingress ingress-nginx-controller -p '{"spec":{"externalTrafficPolicy": "Local"}}'

# 기본 nginx conf 파일 확인
kc describe cm -n ingress ingress-nginx-controller
kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf

# 관련된 정보 확인 : 포드(Nginx 서버), 서비스, 디플로이먼트, 리플리카셋, 컨피그맵, 롤, 클러스터롤, 서비스 어카운트 등
kubectl get all,sa,cm,secret,roles -n ingress
kc describe clusterroles ingress-nginx
kubectl get pod,svc,ep -n ingress -o wide -l app.kubernetes.io/component=controller

# 버전 정보 확인
POD_NAMESPACE=ingress
POD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app.kubernetes.io/name=ingress-nginx --field-selector=status.phase=Running -o name)
kubectl exec $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version

결과

  • helm 설치 결과 (helm get all -n ingress ingress-nginx) 및 상태 조회

2.3. Ingress 실습 및 통신 흐름 확인

실습 구성도

  • 컨트롤플레인 노드에 인그레스 컨트롤러(Nginx) 파드를 생성, NodePort 로 외부에 노출
  • 인그레스 정책 설정 : Host/Path routing, 실습의 편리를 위해서 도메인 없이 IP로 접속 설정 가능


deployment, service 생성

  • svc1-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy1-websrv
spec:
  replicas: 1
  selector:
    matchLabels:
      app: websrv
  template:
    metadata:
      labels:
        app: websrv
    spec:
      containers:
      - name: pod-web
        image: nginx
---
apiVersion: v1
kind: Service
metadata:
  name: svc1-web
spec:
  ports:
    - name: web-port
      port: 9001
      targetPort: 80
  selector:
    app: websrv
  type: ClusterIP
  • svc2-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy2-guestsrv
spec:
  replicas: 2
  selector:
    matchLabels:
      app: guestsrv
  template:
    metadata:
      labels:
        app: guestsrv
    spec:
      containers:
      - name: pod-guest
        image: gcr.io/google-samples/kubernetes-bootcamp:v1
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: svc2-guest
spec:
  ports:
    - name: guest-port
      port: 9002
      targetPort: 8080
  selector:
    app: guestsrv
  type: NodePort
  • svc3-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy3-adminsrv
spec:
  replicas: 3
  selector:
    matchLabels:
      app: adminsrv
  template:
    metadata:
      labels:
        app: adminsrv
    spec:
      containers:
      - name: pod-admin
        image: k8s.gcr.io/echoserver:1.5
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: svc3-admin
spec:
  ports:
    - name: admin-port
      port: 9003
      targetPort: 8080
  selector:
    app: adminsrv
  • 생성 및 확인
# 모니터링
watch -d 'kubectl get ingress,svc,ep,pod -owide'

# 생성
kubectl taint nodes k3s-s role=controlplane:NoSchedule
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc1-pod.yaml
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc2-pod.yaml
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc3-pod.yaml
kubectl apply -f svc1-pod.yaml,svc2-pod.yaml,svc3-pod.yaml

# 확인 : svc1, svc3 은 ClusterIP 로 클러스터 외부에서는 접속할 수 없다 >> Ingress 는 연결 가능!
kubectl get pod,svc,ep

Ingress 생성

  • ingress1.yaml
cat <<EOT> ingress1.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-1
  annotations:
    #nginx.ingress.kubernetes.io/upstream-hash-by: "true"
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc1-web
            port:
              number: 80
      - path: /guest
        pathType: Prefix
        backend:
          service:
            name: svc2-guest
            port:
              number: 8080
      - path: /admin
        pathType: Prefix
        backend:
          service:
            name: svc3-admin
            port:
              number: 8080
EOT

  • ingrss 생성 및 확인
# 모니터링
watch -d 'kubectl get ingress,svc,ep,pod -owide'

# 생성
kubectl apply -f ingress1.yaml

# 확인
kubectl get ingress
kc describe ingress ingress-1
...
Rules:
  Host        Path  Backends
  ----        ----  --------
  *           
              /        svc1-web:80 ()
              /guest   svc2-guest:8080 ()
              /admin   svc3-admin:8080 ()
...

# 설정이 반영된 nginx conf 파일 확인
kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf
kubectl exec deploy/ingress-nginx-controller -n ingress -it -- cat /etc/nginx/nginx.conf | grep 'location /' -A5
		location /guest/ {

			set $namespace      "default";
			set $ingress_name   "ingress-1";
			set $service_name   "svc2-guest";
			set $service_port   "8080";
--
  		location /admin/ {

			set $namespace      "default";
			set $ingress_name   "ingress-1";
			set $service_name   "svc3-admin";
			set $service_port   "8080";
--
  		location / {

			set $namespace      "default";
			set $ingress_name   "ingress-1";
			set $service_name   "svc1-web";
			set $service_port   "80";
--
...

결과

  • pod, svc 생성 > ClusterIP로 외부접근 불가
  • ingress 생성 및 nginx.conf 업데이트 확인

2.3.1. Ingress를 통한 내부 접속

Nginx 인그레스 컨트롤러를 통한 접속(HTTP 인입) 경로

  • 인그레스 컨트롤러 파드에서 서비스 파드의 IP로 직접 연결 (아래 오른쪽 그림)
인그레스 접속 경로 :
Ingress → 애플리케이션 서비스(Service) → 애플리케이션(Deploy, Pod 등)
인그레스 접속 경로(서비스 Bypass) :
Ingress → 애플리케이션(Deploy, Pod 등)

인그레스(Nginx 인그레스 컨트롤러)를 통한 접속(HTTP 인입) 확인

  • HTTP 부하분산 & PATH 기반 라우팅, 애플리케이션 파드에 연결된 서비스는 Bypass
# (krew 플러그인 설치 시) 인그레스 정책 확인
kubectl ingress-nginx ingresses
INGRESS NAME   HOST+PATH   ADDRESSES       TLS   SERVICE      SERVICE PORT   ENDPOINTS
ingress-1      /           192.168.10.10   NO    svc1-web     80             1
ingress-1      /guest      192.168.10.10   NO    svc2-guest   8080           2
ingress-1      /admin      192.168.10.10   NO    svc3-admin   8080           3

#
kubectl get ingress
NAME        CLASS   HOSTS   ADDRESS        PORTS   AGE
ingress-1   nginx   *       10.10.200.24   80      3m44s
 
kubectl describe ingress ingress-1 | sed -n "5, \$p"
Rules:
  Host        Path   Backends
  ----        ----   --------
  *           /      svc1-web:80 ()
              /guest svc2-guest:8080 ()
              /admin svc3-admin:8080 ()


# 접속 로그 확인 : kubetail 설치되어 있음 - 출력되는 nginx 의 로그의 IP 확인
kubetail -n ingress -l app.kubernetes.io/component=controller

-------------------------------
# 자신의 집 PC에서 인그레스를 통한 접속 : 각각 
echo -e "Ingress1 sv1-web URL = http://$(curl -s ipinfo.io/ip):30080"
echo -e "Ingress1 sv2-guest URL = http://$(curl -s ipinfo.io/ip):30080/guest"
echo -e "Ingress1 sv3-admin URL = http://$(curl -s ipinfo.io/ip):30080/admin"

# svc1-web 접속
MYIP=<EC2 공인 IP>
MYIP=13.124.93.150
curl -s $MYIP:30080

# svvc2-guest 접속
curl -s $MYIP:30080/guest
curl -s $MYIP:30080/guest
for i in {1..100}; do curl -s $MYIP:30080/guest ; done | sort | uniq -c | sort -nr

# svc3-admin 접속 > 기본적으로 Nginx 는 라운드로빈 부하분산 알고리즘을 사용 >> Client_address 와 XFF 주소는 어떤 주소인가요?
curl -s $MYIP:30080/admin
curl -s $MYIP:30080/admin | egrep '(client_address|x-forwarded-for)'
for i in {1..100}; do curl -s $MYIP:30080/admin | grep Hostname ; done | sort | uniq -c | sort -nr


# (옵션) 디플로이먼트의 파드 갯수를 증가/감소 설정 후 접속 테스트 해보자
  • 노드에서 아래 패킷 캡쳐 확인: flannel vxlan, 파드 간 통신 시 IP 정보 확인
#
ngrep -tW byline -d ens5 '' udp port 8472 or tcp port 80

#
tcpdump -i ens5 udp port 8472 -nn

# vethY는 각자 k3s-s 의 가장 마지막 veth 를 지정
tcpdump -i vethY tcp port 8080 -nn
tcpdump -i vethY tcp port 8080 -w /tmp/ingress-nginx.pcap

# 자신의 PC에서 k3s-s EC2 공인 IP로 pcap 다운로드
scp ubuntu@<k3s-s EC2 공인 IP>:/tmp/ingress-nginx.pcap ~/Downloads
scp ubuntu@43.202.1.177:/tmp/ingress-nginx.pcap ~/Downloads

결과

  • 통신확인
    • client_address > ingress-nginx pod IP
    • XFF > 접근 시도한 PC IP

2.3.2. 패킷 분석

인그레스 접속 경로(서비스 Bypass) :
Ingress → 애플리케이션(Deploy, Pod 등)

외부에서 접속(그림 왼쪽) 후 Nginx 파드(Layer7 동작)는 HTTP 헤더에 정보 추가(XFF)후 파드의 IP로 직접 전달

패킷 캡쳐

  • 노드에서 아래 패킷 캡쳐 확인: flannel vxlan, 파드 간 통신 시 IP 정보 확인
#
ngrep -tW byline -d ens5 '' udp port 8472 or tcp port 80

#
tcpdump -i ens5 udp port 8472 -nn

# vethY는 각자 k3s-s 의 가장 마지막 veth 를 지정
tcpdump -i vethY tcp port 8080 -nn
tcpdump -i vethY tcp port 8080 -w /tmp/ingress-nginx.pcap

# 자신의 PC에서 k3s-s EC2 공인 IP로 pcap 다운로드
scp ubuntu@<k3s-s EC2 공인 IP>:/tmp/ingress-nginx.pcap ~/Downloads
scp ubuntu@43.202.1.177:/tmp/ingress-nginx.pcap ~/Downloads

# for i in {1..100}; do curl -s $MYIP:30080/admin | grep Hostname ; done | sort | uniq -c | sort -nr

결과

  • X-Real-IP,XFF > 요청을 보낸 클라이언트
  • XFH? X-Forwarded-Host > 요청을 받은 EC2 IP
  • Source > ingress-nginx pod
  • Destination > 실제 앱 pod
  • 플로 그래프로 조회시 ingress-nginx(172.16.0.3)에서 각 앱pod (172.16.2.3, 172.16.1.4, 172.16.3.5로 분산됨 확인)

2.3.3. Nginx 분산 알고리즘 변경

ingress-nginx controller의 기본 로드밸런싱 알고리즘은 round_robin(rr)이다.

그 외의 로드밸런싱 알고리즘으로는 IP 또는 그외의 변수의 hashing을 사용한 고정연결 / 세션 쿠키를 지원한다. 그외의 방식은 지원하지 않는다.

문서상으로는 (Peak) ewma 또한 지원하는듯하나… 음..? 음..? 일단 ewma 는 Exponential Weighted Moving Average의 약자로 지수 가중 이동 평균

로드밸런싱 방식은 ingress 리소스의 annotation을 추가하는 방식으로 제어가 가능하다.

로드밸런싱 알고리즘 변경

  • 주석처리되어있던 annotation 해제 후 재적용
# mypc
for i in {1..100}; do curl -s $MYIP:30080/admin | grep Hostname ; done | sort | uniq -c | sort -nr
while true; do curl -s --connect-timeout 1 $MYIP:30080/admin | grep Hostname ; date "+%Y-%m-%d %H:%M:%S" ; echo "--------------" ; sleep 1; done

# 아래 ingress 설정 중 IP-Hash 설정 > # 주석 제거
sed -i 's/#nginx.ingress/nginx.ingress/g' ingress1.yaml
kubectl apply -f ingress1.yaml

# 접속 확인
for i in {1..100}; do curl -s $MYIP:30080/admin | grep Hostname ; done | sort | uniq -c | sort -nr
while true; do curl -s --connect-timeout 1 $MYIP:30080/admin | grep Hostname ; date "+%Y-%m-%d %H:%M:%S" ; echo "--------------" ; sleep 1; done

# 다시 원복(라운드 로빈) > # 주석 추가
sed -i 's/nginx.ingress/#nginx.ingress/g' ingress1.yaml
kubectl apply -f ingress1.yaml

# 접속 확인
for i in {1..100}; do curl -s $MYIP:30080/admin | grep Hostname ; done | sort | uniq -c | sort -nr
while true; do curl -s --connect-timeout 1 $MYIP:30080/admin | grep Hostname ; date "+%Y-%m-%d %H:%M:%S" ; echo "--------------" ; sleep 1; done

결과

  • nginx.ingress.kubernetes.io/upstream-hash-by: “true”
  • 주석시 기본 rr적용, 주석해제시 hashed 적용

2.3.4. Host 기반 라우팅

ingress는 L7영역에서 작동하기에, 호스트 필드를 이해하고 그에 따른 트래픽 라우팅 또한 가능하다.

호스트 기반 라우팅

  • ingress2.yaml
cat <<EOT> ingress2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-2
spec:
  ingressClassName: nginx
  rules:
  - host: kans.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc3-admin
            port:
              number: 8080
  - host: "*.kans.com"
    http:
      paths:
      - path: /echo
        pathType: Prefix
        backend:
          service:
            name: svc3-admin
            port:
              number: 8080
EOT
  • domain 변경 후 생성 및 확인
# 터미널1
watch -d 'kubectl get ingresses,svc,ep,pod -owide'

# 도메인 변경
MYDOMAIN1=<각자 자신의 닉네임의 도메인> 예시) gasida.com
MYDOMAIN1=gasida.com
sed -i "s/kans.com/$MYDOMAIN1/g" ingress2.yaml

# 생성
kubectl apply -f ingress2.yaml,svc3-pod.yaml

# 확인
kubectl get ingress
kubectl describe ingress ingress-2

kubectl describe ingress ingress-2 | sed -n "5, \$p"
Rules:
  Host        Path  Backends
  ----        ----  --------
  kans.com    /     svc3-admin:8080 ()
  *.kans.com  /echo svc3-admin:8080 ()
  • 로컬 DNS 설정 및 접속 확인
# 로그 모니터링
kubetail -n ingress -l app.kubernetes.io/component=controller

# (옵션) ingress nginx 파드 vethY 에서 패킷 캡처 후 확인 해 볼 것

------------
# 자신의 PC 에서 접속 테스트
# svc3-admin 접속 > 결과 확인 : 왜 접속이 되지 않는가? HTTP 헤더에 Host 필드를 잘 확인해보자!
curl $MYIP:30080 -v
curl $MYIP:30080/echo -v

# mypc에서 접속을 위한 설정
## /etc/hosts 수정 : 도메인 이름으로 접속하기 위해서 변수 지정
## 윈도우 C:\Windows\System32\drivers\etc\hosts
## 맥 sudo vim /etc/hosts
MYDOMAIN1=<각자 자신의 닉네임의 도메인>
MYDOMAIN2=<test.각자 자신의 닉네임의 도메인>
MYDOMAIN1=nasir.com
MYDOMAIN2=test.nasir.com
echo $MYIP $MYDOMAIN1 $MYDOMAIN2

echo "$MYIP $MYDOMAIN1" | sudo tee -a /etc/hosts
echo "$MYIP $MYDOMAIN2" | sudo tee -a /etc/hosts
cat /etc/hosts | grep $MYDOMAIN1

# svc3-admin 접속 > 결과 확인
curl $MYDOMAIN1:30080 -v
curl $MYDOMAIN1:30080/admin
curl $MYDOMAIN1:30080/echo
curl $MYDOMAIN1:30080/echo/1

curl $MYDOMAIN2:30080 -v
curl $MYDOMAIN2:30080/admin
curl $MYDOMAIN2:30080/echo
curl $MYDOMAIN2:30080/echo/1
curl $MYDOMAIN2:30080/echo/1/2

## (옵션) /etc/hosts 파일 변경 없이 접속 방안
curl -H "host: $MYDOMAIN1" $MYIP:30080

결과

  • 리소스 생성 결과
  • EC2 IP로 요청시 404
  • / (루트)로 라우팅이 잡힌 nasir.com은 /admin, /echo 접근가능
  • /echo로 라우팅이 잡힌 test.nasir.com은 /echo만 접근 가능

2.3.5 Canary 업그레이드


k8s deployment 오브젝트의 기본 업데이트 전략은 롤링업데이트이다. ingress-nginx를 사용하면 트래픽을 제어할 수 있어 Canary, Blue/Green 같은 고급 배포전략을 사용할 수 있다.

Name:                   nginx-deployment
Namespace:              default
CreationTimestamp:      Thu, 30 Nov 2017 10:56:25 +0000
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision=2
Selector:               app=nginx
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge


롤링업데이트는 신규버전 업데이트시 개별 인스턴스를 하나씩 전환하는 방식이다.

Ramped (also known as rolling-update or incremental)

설정이 간단하다는 장점이 있으나 업데이트 중 롤백의 까다로움, 배포 중 (트래픽을 제어할 수 없어) 구버전과 신버전이 공존한다는 단점이 존재한다.


블루/그린 업데이트의 경우 구버전/신버전의 인스턴스를 모두 생성한 뒤 한번에 트래픽을 이전하는 배포 전략이다

Blue/Green

업데이트/롤백이 즉각적으로 이루어진다는 장점이 있으나 전환단계 구성시 순간적으로 2배의 컴퓨팅 리소스가 필요하며, stateful한 워크로드에는 적용하기 어렵다는 단점이 있다.


Canary 업데이트의 경우 롤링과 유사하게 순차적으로 업데이트하나 트래픽 전달 비율을 조정하여 일부 트래픽만 신버전으로 보내며 확인할 수 있다.

Canary

ingress-nginx 컨트롤러에서 canary의 경우 annotation을 통해 제어할 수 있다.

header, cookie, weight 등의 기준을 사용할 수 있다.

  • Canary
    • nginx.ingress.kubernetes.io/canary: “true”
    • # header류
      • nginx.ingress.kubernetes.io/canary-by-header
      • nginx.ingress.kubernetes.io/canary-by-header-value
      • nginx.ingress.kubernetes.io/canary-by-header-pattern
    • # cookie
      • nginx.ingress.kubernetes.io/canary-by-cookie
    • # weight
      • nginx.ingress.kubernetes.io/canary-weight
      • nginx.ingress.kubernetes.io/canary-weight-total

Canary 업그레이드 실습

  • canary-svc1-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dp-v1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: svc-v1
  template:
    metadata:
      labels:
        app: svc-v1
    spec:
      containers:
      - name: pod-v1
        image: k8s.gcr.io/echoserver:1.5
        ports:
        - containerPort: 8080
      terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Service
metadata:
  name: svc-v1
spec:
  ports:
    - name: web-port
      port: 9001
      targetPort: 8080
  selector:
    app: svc-v1
  • canary-svc2-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dp-v2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: svc-v2
  template:
    metadata:
      labels:
        app: svc-v2
    spec:
      containers:
      - name: pod-v2
        image: k8s.gcr.io/echoserver:1.6
        ports:
        - containerPort: 8080
      terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Service
metadata:
  name: svc-v2
spec:
  ports:
    - name: web-port
      port: 9001
      targetPort: 8080
  selector:
    app: svc-v2
  • 생성 및 확인
# 터미널1
watch -d 'kubectl get ingress,svc,ep,pod -owide'

# 생성
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/canary-svc1-pod.yaml
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/canary-svc2-pod.yaml
kubectl apply -f canary-svc1-pod.yaml,canary-svc2-pod.yaml

# 확인
kubectl get svc,ep,pod

# 파드 버전 확인: 1.13.0 vs 1.13.1
for pod in $(kubectl get pod -o wide -l app=svc-v1 |awk 'NR>1 {print $6}'); do curl -s $pod:8080 | egrep '(Hostname|nginx)'; done
	Hostname: dp-v1-cdd8dc687-gcgsz
		server_version=nginx: 1.13.0 - lua: 10008
for pod in $(kubectl get pod -o wide -l app=svc-v2 |awk 'NR>1 {print $6}'); do curl -s $pod:8080 | egrep '(Hostname|nginx)'; done
	Hostname: dp-v2-785f69bd6-hh624
		server_version=nginx: 1.13.1 - lua: 10008
  • canary-ingress1.yaml
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
  • canary-ingress2.yaml
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
  • Canary 업그레이드 확인
# 터미널1
watch -d 'kubectl get ingress,svc,ep'

# 도메인 변경
MYDOMAIN1=<각자 자신의 닉네임의 도메인> 예시) gasida.com
sed -i "s/kans.com/$MYDOMAIN1/g" canary-ingress1.yaml
sed -i "s/kans.com/$MYDOMAIN1/g" canary-ingress2.yaml

# 생성
kubectl apply -f canary-ingress1.yaml,canary-ingress2.yaml

# 로그 모니터링
kubetail -n ingress -l app.kubernetes.io/component=controller

# 접속 테스트
curl -s $MYDOMAIN1:30080
curl -s $MYDOMAIN1:30080 | grep nginx

# 접속 시 v1 v2 버전별 비율이 어떻게 되나요? 왜 이렇게 되나요?
for i in {1..100};  do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
for i in {1..1000}; do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
while true; do curl -s --connect-timeout 1 $MYDOMAIN1:30080 | grep Hostname ; echo "--------------" ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; done

# 비율 조정 >> 개발 배포 버전 전략에 유용하다!
kubectl annotate --overwrite ingress ingress-canary-v2 nginx.ingress.kubernetes.io/canary-weight=50

# 접속 테스트
for i in {1..100};  do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr
for i in {1..1000}; do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr

# (옵션) 비율 조정 << 어떻게 비율이 조정될까요?
kubectl annotate --overwrite ingress ingress-canary-v2 nginx.ingress.kubernetes.io/canary-weight=100
for i in {1..100};  do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr

# (옵션) 비율 조정 << 어떻게 비율이 조정될까요?
kubectl annotate --overwrite ingress ingress-canary-v2 nginx.ingress.kubernetes.io/canary-weight=0
for i in {1..100};  do curl -s $MYDOMAIN1:30080 | grep nginx ; done | sort | uniq -c | sort -nr

실습

  • 기본 svc,pod 작동 확인
  • ingress2 > 10%만 svc2로 / ingress1 > 모든 트래픽 svc1
    • svc2:svc1=1:9 응답
  • svc2 50% 비율 조정 > svc2:svc1=5:5 응답
  • svc2 100% 비율 조정 > svc2:svc1=10:0 응답
  • svc2 0% 비율 조정 > svc2:svc1=0:10 응답

2.3. HTTPS 처리 (TLS 종료)

TLS Termination은 클라이언트로 부터 들어온 암호화된 트래픽(HTTPS)을 그 앞단의 별도 장치(로드밸런서 또는 프록시서버)에서 암호화를 해제하여 내부 서버로는 트래픽을 평문(HTTP)으로 처리하는 기법이다.

SSL termination

외부 인터넷망은 위험하다. 암호화가 필요하다. 그러나 암/복호화는 CPU자원을 소모하는 작업이다. 따라서 이를 별도의 장치에서 수행하고, 신뢰되는 내부 서버망에는 평문으로 통신하도록하여 웹 서버의 성능을 개선하고, 개별서버들 대신 로드밸런서/프록시 서버에서 집중적으로 인증서를 관리할 수 있어 관리 효율 또한 개선된다.

TLS/SSL x Termination/Offloading의 2×2 4개의 용어가 혼재되어 사용되나, 같은 개념을 일컫는다

TLS 종료 실습

  • svc-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-https
  labels:
    app: https
spec:
  containers:
  - name: container
    image: k8s.gcr.io/echoserver:1.6
  terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Service
metadata:
  name: svc-https
spec:
  selector:
    app: https
  ports:
  - port: 8080
  • svc-termination-ingress.yaml
cat <<EOT> ssl-termination-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: https
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - kans.com
    secretName: secret-https
  rules:
  - host: kans.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: svc-https
            port:
              number: 8080
EOT
  • 생성 확인 및 secret 생성 후 접속 확인
# 서비스와 파드 생성
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc-pod.yaml
kubectl apply -f svc-pod.yaml

# 도메인 변경
MYDOMAIN1=<각자 자신의 닉네임의 도메인> 예시) gasida.com
MYDOMAIN1=kans.com
echo $MYDOMAIN1
sed -i "s/kans.com/$MYDOMAIN1/g" ssl-termination-ingress.yaml

# 인그레스 생성
kubectl apply -f ssl-termination-ingress.yaml

# 인증서 생성
# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=dkos.com/O=dkos.com"mkdir key && cd key
MYDOMAIN1=kans.com
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=$MYDOMAIN1/O=$MYDOMAIN1"
tree

# Secret 생성
kubectl create secret tls secret-https --key tls.key --cert tls.crt

# Secret 확인 
kubectl get secrets secret-https
kubectl get secrets secret-https -o yaml

-------------------
# 자신의 PC 에서 접속 확인 : PC 웹브라우저
# 접속 확인 : -k 는 https 접속 시 : 접속 포트 정보 확인
curl -Lk https://$MYDOMAIN1:30443

## (옵션) /etc/hosts 파일 변경 없이 접속 방안
curl -Lk -H "host: $MYDOMAIN1" https://$MYDOMAIN1:30443
  • Nginx SSL Termination 패킷 확인
# 패킷 캡처 명령어 참고
export IngHttp=$(kubectl get service -n ingress-nginx ingress-nginx-controller -o jsonpath='{.spec.ports[0].nodePort}')
export IngHttps=$(kubectl get service -n ingress-nginx ingress-nginx-controller -o jsonpath='{.spec.ports[1].nodePort}')
tcpdump -i <nginx 파드 veth> -nnq tcp port 80 or tcp port 443 or tcp port 8080 or tcp port $IngHttp or tcp port $IngHttps
tcpdump -i <nginx 파드 veth> -nn  tcp port 80 or tcp port 443 or tcp port 8080 or tcp port $IngHttp or tcp port $IngHttps -w /tmp/ingress.pcap

결과

  • 외부 https 접근 확인
  • 패킷 확인
    • MyPC에서 ingress-nginx pod 까지는 HTTPS(443)
    • ingress-nginx pod에서 pod까지는 HTTP(8080)
      • 116.43.168.146: MyPC
      • 172.16.0.3: ingress-nginx pod
      • 172.16.3.9: pod-https
    • (필터링 하려면 tls.record.opaque_type == 23 or http)

3. Gateway API

Gateway API는 동적 인프라 프로비저닝과 고급 트래픽 라우팅을 제공하는 API 종류들의 모음이다.
네트워크 서비스를 확장 가능하고, 역할 기반이며, 프로토콜을 인식하는 설정 메커니즘을 사용하여 노출할 수 있다. Gateway API는 동적 인프라 프로비저닝과 고급 트래픽 라우팅을 제공하는 API 종류들을 포함하는 추가 기능이다.

Gateway API is a family of API kinds that provide dynamic infrastructure provisioning and advanced traffic routing.

Make network services available by using an extensible, role-oriented, protocol-aware configuration mechanism. Gateway API is an add-on containing API kinds that provide dynamic infrastructure provisioning and advanced traffic routing.

Gateway API, k8s doc

Gateway API는 기존의 Ingress 에 좀 더 기능을 추가하였고, 역할에 따른 분리가 가능하다.

  • 서비스 메시(istio)에서 제공하는 Rich 한 기능 중 일부 기능들과 혹은 운영 관리에 필요한 기능들을 추가
  • 추가 기능 : 헤더 기반 라우팅, 헤더 변조, 트래픽 미러링(쉽게 트래픽 복제), 역할 기반
The Kubernetes Gateway API: Introduction


Resource model

Gateway API는 세개의 API 종류로 구성되어 있다:

  1. GatewayClass: 공통 구성으로 관리되는 여러 Gateway를 정의하며, 특정 클래스의 Gateway를 관리하는 컨트롤러에 의해 관리.
  2. Gateway: 클라우드 로드 밸런서와 같은 트래픽 처리 인프라의 인스턴스를 정의.
  3. HTTPRoute: Gateway 리스너에서 백엔드 네트워크 엔드포인트의 표현으로 트래픽을 매핑하기 위한 HTTP 특정 규칙을 정의. 이러한 엔드포인트는 종종 service로 표현된다.

Gateway API는 조직의 역할 지향적 특성을 지원하기 위해 상호 의존적인 관계를 가진 다양한 API 종류로 구성되어 있다.

  • GatewayClass는 이 클래스의 Gateway를 관리하는 게이트웨이 컨트롤러를 지칭;
  • Gateway 객체는 정확히 하나의 GatewayClass와 연결되어 있음;
  • 하나 이상의 route(HTTPRoute)가 Gateway에 연결
  • Gateway는 자신의 리스너에 첨부될 수 있는 route를 필터링하여 각 리소스에서 라우팅을 관리할 수 있다 (양방향)


Request flow

다음 그림처럼, HTTP 트래픽은 Gateway로 수신되어 HTTPRoute로 전달되고, Service를 거쳐 실제 Pod로 전달된다.

4. Gloo Gateway

Gloo Gateway는 Solo.io에서 개발한 API Gateway 구현체이다. solo.io는 2017년 미국 메사추세츠 케임브릿지에 설립된 회사로, Envoy proxy, Istio service mesh, Cilium CNI와 같은 오픈소스를 활용하여 GlooPlatform 이라는 이름의 서비스를 만들고, Gloo Gateway, Gloo Mesh, Gloo Network 등의 서비스를 제공하고있다.

Introducing Gloo Platform

Gloo Gateway는 Kubernetes Gateway API와 완벽하게 호환되며, Solo의 custom Gateway API의 기능들 (예: RouteOption, VirtualHostOption, Upstreams, RateLimitConfig, AuthConfig)을 추가로 사용할 수 있다. 이러한 리소스들은 특정 컴포넌트(예: 호스트, 경로, 또는 게이트웨이 리스너)에 대해 라우팅, 보안, 복원성 규칙을 중앙에서 구성하는 데 도움을 준다.

Gloo Gateway is fully conformant with the Kubernetes Gateway API and extends its functionality with Solo’s custom Gateway APIs, such as RouteOption, VirtualHostOption, Upstreams, RateLimitConfig, or AuthConfig. These resources help to centrally configure routing, security, and resiliency rules for a specific component, such as a host, route, or gateway listener.

k8s Gateway API, gloo gateway docs

Kubernetes Gateway API 기반의 Envoy proxy를 사용하여 구성되었고, k8s Gateway API의 자체 기능과 Gloo Gateway 확장기능을 사용해 다음과 같은 주요 기능을 사용할 수 있다.


Architecture)


다음 이미지에서 Gloo Gateway의 컨트롤/데이터 플레인을 구성하는 다양한 구성요소와 작동 순서 및 방식을 확인할 수 있다.

  • controlplane > gloo pod
  • dataplane > envo
Component architecture
  1. gloo pod) Config/Secret watcher: Gateways, HTTPRoutes, RouteOptions와 같은 리소스의 변경을 감지
  2. gloo pod) Config/Secret watcher: 변경 감지 시 translation engine로 전달
  3. gloo pod) Translation engine: 변경 사항을 Envoy의 구성파일로 전환하고, 모든 envoy 구성은 xDS 스냅샷으로 통합됨
  4. gloo pod) Reporter: 처리된 모든 리소스의 상태보고를 받음
  5. gloo pod) Reporter: 리소스의 상태를 etcd에 기록
  6. gloo pod) xDS server: xDS 스냅샷 수신
  7. Envoy) Gateway proxies: xDS 서버에 저장된 최신의 envoy 구성 pull
  8. Envoy) Gateway proxies: user는 gateway proxy가 노출한 IP/hostname으로 요청 송신
  9. Envoy) Gateway proxies: xDS 스냅샷에 저장된 listener/route 설정에 따라 실제 트래픽을 클러스터 내부 목적지에 전달

일단은.. Istio에서의 컨트롤플레인을 구성하는 istiod의 역할을 gloo pod가 수행한다정도?

Leave a Reply