가시다님의 KANS [3기] 스터디 내용을 정리한 포스트 입니다.
Kubernetes에서 Ingress는 클러스터 외부의 사용자들이 클러스터 내부의 서비스에 접근할 수 있도록 설정하는 방법 중 하나입니다. Kubernetes는 기본적으로 클러스터 내부에서만 통신이 가능하므로, 외부에서 접근할 수 있도록 하려면 특정 설정이 필요합니다. 그 중 하나가 Ingress입니다.
- Ingress 리소스
• Ingress는 HTTP(S) 라우팅 규칙을 정의하는 Kubernetes 리소스입니다.
• Ingress는 클러스터 외부로부터 들어오는 요청을 특정 서비스로 라우팅하는 규칙을 설정합니다.
• 예를 들어, 도메인 이름 기반, 경로 기반 등의 라우팅을 설정할 수 있습니다.
- Ingress Controller
• Ingress 자체는 클러스터 내에 경로만 정의할 뿐, 실제 트래픽을 라우팅하는 작업은 Ingress Controller가 담당합니다.
• Ingress Controller는 클러스터 내에서 동작하며, 다양한 형태의 트래픽을 처리할 수 있도록 외부 트래픽을 적절한 서비스로 연결해 줍니다.
• 대표적인 Ingress Controller에는 NGINX, HAProxy, Traefik 등이 있습니다.
- 로드 밸런싱
• Ingress는 클러스터 내 여러 서비스에 대한 HTTP(S) 트래픽을 로드 밸런싱할 수 있습니다.
• 단일 IP 주소로 여러 서비스에 접근할 수 있게 하거나, 경로 기반으로 여러 애플리케이션을 호스팅할 수 있습니다.
- TLS/SSL 지원
• Ingress는 HTTPS 요청을 처리하기 위한 TLS/SSL 인증서를 설정할 수 있습니다.
• 이를 통해 보안 연결을 사용할 수 있으며, Ingress Controller는 HTTPS 트래픽을 클러스터 내부로 라우팅할 수 있습니다.
- 호스트 및 경로 기반 라우팅
• Ingress는 요청 URL의 도메인 이름(호스트)이나 경로를 기반으로 다른 서비스로 트래픽을 라우팅할 수 있습니다.
• 예를 들어, example.com의 /api는 backend-api 서비스로, /web은 frontend 서비스로 라우팅하는 방식입니다.
Kubernetes 환경에서 Ingress를 사용하는 이유는 클러스터 외부로부터 내부 서비스에 대한 HTTP 및 HTTPS 트래픽을 효율적으로 관리하고 제어하기 위함입니다. Ingress를 사용하면 외부 사용자가 여러 애플리케이션에 간편하게 접근할 수 있도록 다양한 기능을 제공하며, 클러스터 네트워크 관리의 복잡성을 줄여줍니다.
- 다중 서비스 관리의 간소화
• Kubernetes 내에서는 각 서비스에 대한 접근을 위해 NodePort나 LoadBalancer를 사용할 수 있지만, 이 방법들은 각 서비스마다 고유의 IP 주소와 포트를 필요로 합니다.
• Ingress는 단일 IP 주소와 도메인으로 여러 서비스에 접근할 수 있도록 도와줍니다. 예를 들어, example.com 도메인 아래에서 경로 기반으로 여러 서비스를 연결할 수 있습니다. 이를 통해 한 개의 도메인과 IP로 다양한 애플리케이션을 제공할 수 있습니다.
- 경로 및 호스트 기반 라우팅
• Ingress는 요청 URL의 경로나 호스트 이름을 기반으로 트래픽을 라우팅할 수 있습니다. 예를 들어, example.com/api는 백엔드 API 서버로, example.com/web은 프론트엔드 서버로 트래픽을 보낼 수 있습니다.
• 이와 같은 라우팅 기능을 통해 여러 애플리케이션을 한 도메인이나 IP 주소에서 동시에 서비스할 수 있습니다.
- TLS/SSL 지원 및 보안 관리
• Ingress는 TLS/SSL 인증서를 관리하여 HTTPS 연결을 제공할 수 있습니다. 이 기능을 사용하면 보안이 중요한 애플리케이션의 통신을 보호할 수 있습니다.
• 인증서 설정을 Ingress에서 중앙 관리함으로써, 여러 서비스에 대한 보안 연결을 한 번에 설정할 수 있고, 개별 서비스마다 SSL 인증서를 따로 설정할 필요가 없습니다.
- 비용 효율성
• Kubernetes의 LoadBalancer는 클라우드 환경에서 각 서비스마다 개별적인 로드 밸런서를 사용하게 되어 비용이 증가할 수 있습니다. 특히 많은 서비스가 있을 경우 비용이 상당히 커집니다.
• Ingress를 사용하면 단일 IP 주소와 로드 밸런서로 다수의 서비스에 트래픽을 전달할 수 있어, 비용을 크게 절감할 수 있습니다.
- 확장성과 유연성
• Ingress는 동적으로 서비스에 대한 트래픽을 라우팅할 수 있기 때문에, 서비스가 추가되거나 변경되더라도 Ingress 규칙만 업데이트하면 됩니다.
• 이를 통해 애플리케이션의 배포 및 확장을 매우 유연하게 관리할 수 있으며, 운영 중에 경로 설정을 쉽게 변경할 수 있습니다.
- 로드 밸런싱
• Ingress는 기본적으로 클러스터 내 서비스들에 대한 로드 밸런싱을 지원합니다. 이를 통해 외부 트래픽이 여러 파드에 고르게 분산되도록 설정할 수 있으며, 서비스의 가용성을 높일 수 있습니다.
- 오토스케일링 및 모니터링
• Ingress Controller를 사용하면 자동화된 트래픽 관리 및 모니터링이 가능합니다. 이를 통해 트래픽 패턴을 분석하고, 서비스가 자동으로 스케일링될 수 있도록 설정할 수 있습니다.
• 예를 들어, 특정 서비스로 가는 트래픽이 급증할 경우, Ingress 설정을 통해 쉽게 오토스케일링을 트리거할 수 있습니다.
- 다양한 Ingress Controller 선택 가능
• Kubernetes에서는 NGINX, HAProxy, Traefik 등의 다양한 Ingress Controller를 지원합니다. 이를 통해 환경에 맞는 최적의 솔루션을 선택할 수 있고, 각 Controller가 제공하는 추가적인 기능을 사용할 수 있습니다.


- 클라이언트 요청 (외부 트래픽 발생)
• 사용자가 브라우저나 HTTP 클라이언트를 통해 example.com과 같은 도메인으로 HTTP 또는 HTTPS 요청을 보냅니다.
• 예를 들어, 클라이언트가 https://example.com/api로 요청을 보낸다고 가정합니다.
- DNS 해석 (도메인 네임 시스템)
• 클라이언트는 도메인을 IP 주소로 변환하기 위해 DNS 서버에 요청을 보냅니다.
• DNS 서버는 example.com에 대한 A 레코드 또는 CNAME 레코드를 조회하여 Ingress Controller가 외부에서 접근 가능한 IP 주소를 반환합니다.
• 이때 반환되는 IP 주소는 클러스터 외부에서 Ingress Controller로 트래픽을 전달할 수 있는 엔드포인트(IP)입니다. 일반적으로 클라우드 환경에서는 LoadBalancer가 이 IP 주소를 제공합니다.
- 트래픽이 Ingress Controller로 전달됨
• 클라이언트의 요청은 Ingress Controller의 외부 IP 주소로 도달합니다.
• Ingress Controller는 클러스터 내부에서 실행되는 네트워크 프록시 역할을 하며, 외부에서 들어오는 HTTP/HTTPS 요청을 관리하고 내부 서비스로 전달합니다.
• Ingress Controller는 요청을 분석하여 해당 요청이 어느 서비스로 전달되어야 하는지 결정합니다.
- Ingress 규칙에 따른 요청 매칭
• Ingress Controller는 정의된 Ingress 리소스의 규칙을 기반으로 요청 URL, 경로, 또는 호스트 이름을 확인합니다.
• 예를 들어, /api로 시작하는 요청은 backend-api 서비스로, /web 경로는 frontend 서비스로 전달할 수 있도록 설정되어 있을 수 있습니다.
• 경로 기반 라우팅 또는 호스트 기반 라우팅을 사용하여 특정 파드로 트래픽을 전달합니다.
• Ingress Controller는 서비스를 경유하지 않고 바로 목적지 파드의 IP로 통신을 하게됩니다.
- Pod에서 요청 처리
• 트래픽이 적절한 Pod로 전달되면, 해당 Pod 내 애플리케이션이 요청을 처리하고 응답을 생성합니다.
• 각 Pod는 컨테이너에서 애플리케이션이 실행되고 있으며, 요청에 대한 실제 비즈니스 로직을 처리하게 됩니다.
- 응답 반환
• Pod에서 처리된 응답은 Ingress Controller로 전달됩니다.
• Ingress Controller는 클라이언트에게 응답을 전달합니다. 이 과정에서 클라이언트는 example.com/api로 요청한 결과를 받게 됩니다.
# 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


# 모니터링
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

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
# 모니터링
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

Nginx 인그레스 컨트롤러를 통한 접속(HTTP 인입) 경로 : 인그레스 컨트롤러 파드에서 서비스 파드의 IP로 직접 연결

# (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

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"
Ingress1 sv1-web URL = http://43.203.127.178:30080

Ingress1 sv2-guest URL = http://43.203.127.178:30080/guest

Ingress1 sv3-admin URL = http://43.203.127.178:30080/admin

# svc1-web 접속
MYIP=<EC2 공인 IP>
MYIP=43.203.127.178
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

#
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


# 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
다시 분산 접속되는 것을 확인 할 수 있다.
# 터미널1
watch -d 'kubectl get ingresses,svc,ep,pod -owide'
# 도메인 변경
MYDOMAIN1=kgetall.click
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 ()
...

# 로그 모니터링
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=kans.com
MYDOMAIN2=test.kans.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

카나리 업그레이드(Canary Upgrade)는 애플리케이션의 새 버전을 배포할 때, 전체 트래픽에 적용하기 전에 일부 트래픽에만 새 버전을 배포하여 안정성을 검증하는 방식입니다.
# 터미널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

# 터미널1
watch -d 'kubectl get ingress,svc,ep'
# 도메인 변경
MYDOMAIN1=kgetall.click
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
기존(1.13.0) 과 신규(1.13.1)버젼 접속이 9:1 비율로 이뤄지고 있다.
# 5:5 비율로 조정
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
5:5 비율로 균등하게 접속되고 있다.
# (옵션) 비율 조정 << 어떻게 비율이 조정될까요?
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
기존 버젼으로만 접속됨
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
# 서비스와 파드 생성
curl -s -O https://raw.githubusercontent.com/gasida/NDKS/main/7/svc-pod.yaml
kubectl apply -f svc-pod.yaml
# 도메인 변경
MYDOMAIN1=kgetall.click
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

Gateway API는 클러스터 외부와 내부 간의 트래픽을 관리하기 위한 새로운 네트워크 API입니다. 기존의 Ingress API보다 더 유연하고 확장 가능하도록 설계되어, 복잡한 트래픽 제어를 쉽게 할 수 있게 도와줍니다. 이는 주로 클라우드 네이티브 애플리케이션에서 로드 밸런싱, 라우팅, 인증 등을 보다 세밀하게 제어하는 데 사용됩니다.
기존의 Ingress 에 좀 더 기능을 추가, 역할 분리(role-oriented)

Request flow

Gateway API의 주요 개념


- GatewayClass: Gateway의 동작 방식을 정의합니다. 클러스터에서 사용할 수 있는 게이트웨이의 유형(예: 특정 클라우드 제공자의 로드 밸런서, 자체 정의 로드 밸런서)을 설정합니다.
- Gateway: 네트워크 트래픽이 클러스터에 들어오는 진입점을 정의합니다. Gateway는 GatewayClass에 의해 구성되며, 특정 IP 주소와 포트에서 들어오는 요청을 처리합니다.
- HTTPRoute, TCPRoute, UDPRoute: Gateway가 처리하는 트래픽을 라우팅하는 방법을 지정합니다. HTTPRoute는 HTTP/HTTPS 트래픽을, TCPRoute와 UDPRoute는 각각 TCP와 UDP 트래픽을 처리하는 방법을 설정합니다.
- Routes: 특정 요청을 어떤 서비스로 보낼지 정의합니다. 예를 들어, 도메인 또는 URL 경로에 따라 다른 서비스로 트래픽을 보낼 수 있습니다.
- 더 높은 유연성 및 확장성
• Ingress API는 제한적인 라우팅 옵션과 트래픽 관리 기능을 제공하는 반면, Gateway API는 HTTP, TCP, UDP와 같은 다양한 프로토콜을 지원하고, 더 복잡한 라우팅 규칙을 정의할 수 있습니다. 따라서 트래픽이 더 세밀하게 분배될 수 있습니다.
• 다중 프로토콜 지원으로 복잡한 애플리케이션과 트래픽 흐름을 처리하기에 이상적입니다.
- 게이트웨이 및 라우팅의 분리
• Ingress는 라우팅 규칙과 리소스 간의 의존성을 가지지만, Gateway API는 이를 분리합니다. Gateway는 네트워크의 진입점만 정의하고, Route는 트래픽을 라우팅하는 규칙을 정의합니다. 이 분리 덕분에 트래픽 정책 및 네트워크 진입점을 독립적으로 관리할 수 있습니다.
- 더 나은 관리 가능성 및 운영 효율성
• 클러스터 운영자가 Gateway를 설정한 후 개발자는 독립적으로 Route를 관리할 수 있어, 권한 분리와 운영의 효율성을 높일 수 있습니다. 이로 인해 개발팀과 운영팀 간의 협업이 더 원활해집니다.
- 다양한 네트워크 제공자 및 커스텀 확장 지원
• GatewayClass를 통해 다양한 네트워크 제공자나 벤더가 표준화된 방식으로 자신들의 네트워크 기술을 Kubernetes에 통합할 수 있습니다. 이를 통해 로드 밸런서와 같은 네트워크 장비를 쉽게 확장하거나 맞춤 설정할 수 있습니다.
- 다양한 정책 적용 및 보안 강화
• 트래픽 관리뿐만 아니라 보안 정책(예: 인증서 관리, TLS 종단점 설정 등)을 더 세밀하게 구성할 수 있습니다. 이를 통해 각 애플리케이션마다 별도의 보안 정책을 설정하고 강화할 수 있습니다.
• 트래픽 제한, 재시도 정책, 타임아웃 같은 고급 트래픽 제어 기능을 제공하여 네트워크 안정성과 신뢰성을 높일 수 있습니다.
- 클라우드 네이티브 네트워크 표준
• Gateway API는 네트워크 관리의 표준으로 자리 잡아가고 있으며, 다양한 클라우드 제공자와 네트워크 벤더들이 이를 지원하고 있습니다. 표준 API로 클라우드 환경 간의 일관된 네트워크 구성을 유지할 수 있습니다.
Gloo Gateway는 Kubernetes에서 API 게이트웨이와 인그레스 컨트롤러 역할을 수행하는 오픈 소스 프로젝트로, 주로 마이크로서비스 환경에서 사용되는 트래픽 관리 솔루션입니다. Solo.io에서 개발한 Gloo는 Envoy 프록시를 기반으로 구축되었으며, 고급 라우팅 기능, 보안, 관측 기능 등을 제공하여 복잡한 클라우드 네이티브 애플리케이션의 네트워크 트래픽을 쉽게 관리할 수 있습니다.

Envoy 기반 프록시
• Gloo Gateway는 고성능 L7 프록시인 Envoy를 기반으로 하여 트래픽을 처리합니다. Envoy는 성능과 확장성이 뛰어나고, HTTP, gRPC, TCP 같은 다양한 프로토콜을 지원합니다. 이를 통해 Gloo Gateway는 복잡한 트래픽 시나리오를 효과적으로 처리할 수 있습니다.고급 라우팅
• Gloo는 트래픽을 세밀하게 라우팅할 수 있습니다. 경로 기반 라우팅, 헤더 및 쿼리 매개변수 기반 라우팅, 트래픽 분할 등을 지원하여 특정 트래픽을 특정 서비스로 유연하게 전달할 수 있습니다.
• 트래픽을 여러 버전의 애플리케이션으로 나누는 카나리 배포, A/B 테스트 등을 손쉽게 수행할 수 있습니다.멀티 클러스터 및 하이브리드 환경 지원
• Gloo는 여러 Kubernetes 클러스터와 하이브리드 클라우드 환경에서도 네트워크 트래픽을 효과적으로 관리할 수 있습니다. 이를 통해 복잡한 배포 환경에서 일관된 트래픽 정책을 적용할 수 있습니다.API Gateway 기능
• Gloo는 API 게이트웨이로서 REST, gRPC, GraphQL 같은 다양한 API를 관리할 수 있습니다. 트래픽을 라우팅할 뿐만 아니라 API 변환, 인증, 권한 부여, 속도 제한 등의 기능을 제공합니다.보안 기능
• Gloo는 mTLS(mutual TLS), JWT 인증, OAuth와 같은 보안 기능을 지원합니다. 이를 통해 애플리케이션 간의 통신을 안전하게 보호하고, 인증된 트래픽만 허용할 수 있습니다.
• WAF(웹 애플리케이션 방화벽) 기능을 통해 웹 공격으로부터 애플리케이션을 보호할 수 있습니다.통합 및 확장성
• Gloo는 다양한 API 소스(예: REST API, gRPC 서비스, Lambda 함수 등)를 통합하여 하나의 인터페이스로 관리할 수 있는 기능을 제공합니다.
• 플러그인 아키텍처를 통해 새로운 기능을 쉽게 추가하고 확장할 수 있어, 사용자가 요구하는 다양한 네트워크 환경에 맞게 맞춤형 구성을 할 수 있습니다.관찰성
• Gloo Gateway는 Prometheus, Grafana, Jaeger와 같은 관찰 도구와 통합되어 모니터링 및 추적 기능을 제공합니다. 트래픽 흐름, 오류, 성능을 실시간으로 모니터링할 수 있으며, 이를 통해 문제를 빠르게 감지하고 대응할 수 있습니다.Function Gateway 기능
• Gloo는 서버리스 컴퓨팅과 통합할 수 있는 기능도 제공합니다. AWS Lambda, Google Cloud Functions, Azure Functions 등의 서버리스 기능을 API로 노출하여 클라우드 네이티브 애플리케이션을 더 쉽게 관리할 수 있습니다.
• 마이크로서비스 라우팅: 다양한 서비스 간의 트래픽을 효율적으로 관리하고, A/B 테스트나 카나리 배포를 통해 애플리케이션 업그레이드를 안전하게 수행할 수 있습니다.
• API 관리: REST API, GraphQL API 등을 통합하여 하나의 API 게이트웨이에서 관리하고 보호할 수 있습니다.
• 보안 및 인증: 다양한 인증 및 권한 부여 메커니즘을 사용하여 서비스 간의 안전한 통신을 보장할 수 있습니다.
• 다양한 클러스터 환경 관리: 여러 클러스터 간의 트래픽을 일관되게 관리하고 정책을 적용할 수 있어 하이브리드 클라우드 환경에서 유용합니다.
• 유연성: Envoy 기반으로 다양한 트래픽 처리 시나리오에 대응할 수 있습니다.
• 확장성: 여러 프로토콜과 클라우드 플랫폼을 통합할 수 있으며, 플러그인 구조를 통해 기능을 확장할 수 있습니다.
• 보안: 고급 보안 기능을 통해 트래픽과 API를 안전하게 보호할 수 있습니다.
• 관측 기능: 실시간 트래픽 모니터링 및 성능 분석 도구와의 통합을 통해 운영 효율성을 높일 수 있습니다.

Simple ingress

Shared gateway

Sharded gateway with central ingress

- 기존 설정에 따라 중앙 인그레스 엔드포인트로 다른 유형의 프록시를 사용하고 싶을 수 있습니다.
- 예를 들어 모든 트래픽이 통과해야 하는 HAProxy 또는 AWS NLB/ALB 인스턴스가 있을 수 있습니다

API gateway for a service mesh

#
cat <<EOT> kind-1node.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000
hostPort: 30000
- containerPort: 30001
hostPort: 30001
- containerPort: 30002
hostPort: 30002
EOT
# Install KinD Cluster
kind create cluster --image kindest/node:v1.30.0 --config kind-1node.yaml --name myk8s
# 노드에 기본 툴 설치
docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree psmisc lsof wget bsdmainutils bridge-utils net-tools dnsutils tcpdump ngrep iputils-ping git vim -y'
# 노드/파드 확인
kubectl get nodes -o wide
kubectl get pod -A

# CRDs 설치 및 확인
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml
kubectl get crd

# [신규 터미널] 아래 bash 진입 후 glooctl 툴 사용
docker exec -it myk8s-control-plane bash
----------------------------------------
# Install Glooctl Utility
## glooctl install gateway # install gloo's function gateway functionality into the 'gloo-system' namespace
## glooctl install ingress # install very basic Kubernetes Ingress support with Gloo into namespace gloo-system
## glooctl install knative # install Knative serving with Gloo configured as the default cluster ingress
## curl -sL https://run.solo.io/gloo/install | sh
curl -sL https://run.solo.io/gloo/install | GLOO_VERSION=v1.17.7 sh
export PATH=$HOME/.gloo/bin:$PATH
# 버전 확인
glooctl version
----------------------------------------

# rosetta 비활성화
orb config set rosetta false
# orb 설정 확인
orb config show
# orbstack 재시작
orb stop
orb start

# [신규 터미널] 모니터링
watch -d kubectl get pod,svc,endpointslices,ep -n gloo-system
# Install Gloo Gateway
## --set kubeGateway.enabled=true: Kubernetes Gateway 기능을 활성화합니다.
## --set gloo.disableLeaderElection=true: Gloo의 리더 선출 기능을 비활성화합니다. (단일 인스턴스에서 Gloo를 실행 시 유용)
## --set discovery.enabled=false: 서비스 디스커버리 기능을 비활성화합니다.
helm repo add gloo https://storage.googleapis.com/solo-public-helm
helm repo update
helm install -n gloo-system gloo-gateway gloo/gloo \
--create-namespace \
--version 1.17.7 \
--set kubeGateway.enabled=true \
--set gloo.disableLeaderElection=true \
--set discovery.enabled=false
# Confirm that the Gloo control plane has successfully been deployed using this command
kubectl rollout status deployment/gloo -n gloo-system
# 설치 확인
kubectl get crd | grep 'networking.k8s.io'
kubectl get crd | grep -v 'networking.k8s.io'
kubectl get pod,svc,endpointslices -n gloo-system
#
kubectl explain gatewayclasses
kubectl get gatewayclasses
NAME CONTROLLER ACCEPTED AGE
gloo-gateway solo.io/gloo-gateway True 21m
kubectl get gatewayclasses -o yaml
apiVersion: v1
items:
- apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
labels:
app: gloo
name: gloo-gateway
spec:
controllerName: solo.io/gloo-gateway
...


#
watch -d kubectl get pod,svc,endpointslices,ep -n httpbin
# Install Httpbin Application
kubectl apply -f https://raw.githubusercontent.com/solo-io/solo-blog/main/gateway-api-tutorial/01-httpbin-svc.yaml
# 설치 확인
kubectl get deploy,pod,svc,endpointslices,sa -n httpbin
kubectl rollout status deploy/httpbin -n httpbin
# (옵션) NodePort 설정
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
labels:
app: httpbin
service: httpbin
name: httpbin
namespace: httpbin
spec:
type: NodePort
ports:
- name: http
port: 8000
targetPort: 80
nodePort: 30000
selector:
app: httpbin
EOF
# (옵션) 로컬 접속 확인
echo "httpbin web - http://localhost:30000" # macOS 사용자

# 02-gateway.yaml
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: http
spec:
gatewayClassName: gloo-gateway
listeners:
- protocol: HTTP
port: 8080
name: http
allowedRoutes:
namespaces:
from: All
# gateway 리소스 생성
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/02-gateway.yaml
# 확인 : Now we can confirm that the Gateway has been activated
kubectl get gateway -n gloo-system
kubectl get gateway -n gloo-system -o yaml | k neat
apiVersion: v1
items:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: http
namespace: gloo-system
spec:
gatewayClassName: gloo-gateway
listeners:
- allowedRoutes:
namespaces:
from: All
name: http
port: 8080
protocol: HTTP
...
# You can also confirm that Gloo Gateway has spun up an Envoy proxy instance in response to the creation of this Gateway object by deploying gloo-proxy-http:
kubectl get deployment gloo-proxy-http -n gloo-system
NAME READY UP-TO-DATE AVAILABLE AGE
gloo-proxy-http 1/1 1 1 5m22s
# envoy 사용 확인
kubectl get pod -n gloo-system
kubectl describe pod -n gloo-system |grep Image:
Image: quay.io/solo-io/gloo-envoy-wrapper:1.17.7
Image: quay.io/solo-io/gloo:1.17.7
Image: quay.io/solo-io/gloo-envoy-wrapper:1.17.7
# gloo-proxy-http 서비스는 External-IP는 Pending 상태
kubectl get svc -n gloo-system gloo-proxy-http
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
gloo-proxy-http LoadBalancer 10.96.71.22 <pending> 8080:31555/TCP 2m4s
# gloo-proxy-http NodePort 30001 설정
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/instance: http
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: gloo-proxy-http
app.kubernetes.io/version: 1.17.7
gateway.networking.k8s.io/gateway-name: http
gloo: kube-gateway
helm.sh/chart: gloo-gateway-1.17.7
name: gloo-proxy-http
namespace: gloo-system
spec:
ports:
- name: http
nodePort: 30001
port: 8080
selector:
app.kubernetes.io/instance: http
app.kubernetes.io/name: gloo-proxy-http
gateway.networking.k8s.io/gateway-name: http
type: LoadBalancer
EOF
kubectl get svc -n gloo-system gloo-proxy-http
# Port Forward
# We will use a simple port-forward to expose the proxy’s HTTP port for us to use.
# (Note that gloo-proxy-http is Gloo’s deployment of the Envoy data plane.)
kubectl port-forward deployment/gloo-proxy-http -n gloo-system 8080:8080 &

# Our route watches for HTTP requests directed at the host api.example.com with the request path /get and then forwards the request to the httpbin service on port 8000.
# Let’s establish this route now:
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/03-httpbin-route.yaml
#
kubectl get httproute -n httpbin
NAME HOSTNAMES AGE
httpbin ["api.example.com"] 3m15s
kubectl describe httproute -n httpbin
...
Spec:
Hostnames:
api.example.com
Parent Refs:
Group: gateway.networking.k8s.io
Kind: Gateway
Name: http
Namespace: gloo-system
Rules:
Backend Refs:
Group:
Kind: Service
Name: httpbin
Port: 8000
Weight: 1
Matches:
Path:
Type: Exact
Value: /get
...
# let’s use curl to display the response with the -i option to additionally show the HTTP response code and headers.
echo "127.0.0.1 api.example.com" | sudo tee -a /etc/hosts
echo "httproute - http://api.example.com:30001/get" # 웹브라우저
혹은
curl -is -H "Host: api.example.com" http://localhost:8080/get # kubectl port-forward 사용 시
HTTP/1.1 200 OK
server: envoy
date: Sun, 06 Oct 2024 07:55:34 GMT
content-type: application/json
content-length: 239
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 25
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "api.example.com",
"User-Agent": "curl/8.7.1",
"X-Envoy-Expected-Rq-Timeout-Ms": "15000"
},
"origin": "10.244.0.11",
"url": "http://api.example.com/get"
}

# 호출 응답 왜 그럴까?
curl -is -H "Host: api.example.com" http://localhost:8080/delay/1
HTTP/1.1 404 Not Found
date: Wed, 03 Jul 2024 07:19:21 GMT
server: envoy
content-length: 0
#
echo "httproute - http://api.example.com:30001/delay/1" # 웹브라우저
# nodeport 직접 접속
echo "httproute - http://api.example.com:30000/delay/1" # 1초 후 응답
echo "httproute - http://api.example.com:30000/delay/5" # 5초 후 응답

# Here are the modifications we’ll apply to our HTTPRoute:
- matches:
# Switch from an Exact Matcher(정확한 매팅) to a PathPrefix (경로 매팅) Matcher
- path:
type: PathPrefix
value: /api/httpbin/
filters:
# Replace(변경) the /api/httpbin matched prefix with /
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
#
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/04-httpbin-rewrite.yaml
# 확인
kubectl describe httproute -n httpbin
...
Spec:
Hostnames:
api.example.com
Parent Refs:
Group: gateway.networking.k8s.io
Kind: Gateway
Name: http
Namespace: gloo-system
Rules:
Backend Refs:
Group:
Kind: Service
Name: httpbin
Port: 8000
Weight: 1
Filters:
Type: URLRewrite
URL Rewrite:
Path:
Replace Prefix Match: /
Type: ReplacePrefixMatch
Matches:
Path:
Type: PathPrefix
Value: /api/httpbin/
#
echo "httproute - http://api.example.com:30001/api/httpbin/get" # 웹브라우저
혹은
curl -is -H "Host: api.example.com" http://localhost:8080/api/httpbin/get # kubectl port-forward 사용 시
HTTP/1.1 200 OK
server: envoy
date: Sun, 06 Oct 2024 08:08:09 GMT
content-type: application/json
content-length: 289
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 18 # envoy 가 업스트림 httpbin 요청 처리에 걸리 시간 0.018초
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "api.example.com",
"User-Agent": "curl/8.7.1",
"X-Envoy-Expected-Rq-Timeout-Ms": "15000",
"X-Envoy-Original-Path": "/api/httpbin/get"
},
"origin": "10.244.0.11",
"url": "http://api.example.com/get"
}

# 아래 NodePort 와 GW API 통한 접속 비교
echo "httproute - http://api.example.com:30001/api/httpbin/get"
echo "httproute - http://api.example.com:30000/api/httpbin/get" # NodePort 직접 접근
---
#
echo "httproute - http://api.example.com:30001/api/httpbin/delay/1" # 웹브라우저
혹은
curl -is -H "Host: api.example.com" http://localhost:8080/api/httpbin/delay/1 # kubectl port-forward 사용 시
HTTP/1.1 200 OK
server: envoy
date: Wed, 03 Jul 2024 07:31:47 GMT
content-type: application/json
content-length: 342
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 1023 # envoy 가 업스트림 httpbin 요청 처리에 걸리 시간 1초 이상
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "api.example.com",
"User-Agent": "curl/8.6.0",
"X-Envoy-Expected-Rq-Timeout-Ms": "15000",
"X-Envoy-Original-Path": "/api/httpbin/delay/1"
},
"origin": "10.244.0.7",
"url": "http://api.example.com/delay/1"
}
curl -is -H "Host: api.example.com" http://localhost:8080/api/httpbin/delay/2


# The new filters stanza in our HTTPRoute now looks like this:
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
# Add a Bearer token to supply a static API key when routing to backend system
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: Authorization
value: Bearer my-api-key
#
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/05-httpbin-rewrite-xform.yaml
#
kubectl describe httproute -n httpbin
...
Spec:
...
Rules:
Backend Refs:
Group:
Kind: Service
Name: httpbin
Port: 8000
Weight: 1
Filters:
Type: URLRewrite
URL Rewrite:
Path:
Replace Prefix Match: /
Type: ReplacePrefixMatch
Request Header Modifier:
Add:
Name: Authorization
Value: Bearer my-api-key
Type: RequestHeaderModifier
Matches:
Path:
Type: PathPrefix
Value: /api/httpbin/
#
echo "httproute - http://api.example.com:30001/api/httpbin/get" # 웹브라우저
혹은
curl -is -H "Host: api.example.com" http://localhost:8080/api/httpbin/get # kubectl port-forward 사용 시
HTTP/1.1 200 OK
server: envoy
date: Sun, 06 Oct 2024 08:20:00 GMT
content-type: application/json
content-length: 332
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 11
{
"args": {},
"headers": {
"Accept": "*/*",
"Authorization": "Bearer my-api-key",
"Host": "api.example.com",
"User-Agent": "curl/8.7.1",
"X-Envoy-Expected-Rq-Timeout-Ms": "15000",
"X-Envoy-Original-Path": "/api/httpbin/get"
},
"origin": "10.244.0.11",
"url": "http://api.example.com/get"
}

# You should see the response below, indicating deployments for both v1 and v2 of my-workload have been created in the my-workload namespace.
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/06-workload-svcs.yaml
# v1,v2 2가지 버전 워크로드 확인
kubectl get deploy,pod,svc,endpointslices -n my-workload


apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: my-workload
namespace: my-workload
labels:
example: my-workload-route
spec:
parentRefs:
- name: http
namespace: gloo-system
hostnames:
- "api.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api/my-workload
backendRefs:
- name: my-workload-v1
namespace: my-workload
port: 8080
#
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/07-workload-route.yaml
#
kubectl get httproute -A
NAMESPACE NAME HOSTNAMES AGE
httpbin httpbin ["api.example.com"] 41m
my-workload my-workload ["api.example.com"] 39s
#
kubectl describe httproute -n my-workload
...
Spec:
Hostnames:
api.example.com
Parent Refs:
Group: gateway.networking.k8s.io
Kind: Gateway
Name: http
Namespace: gloo-system
Rules:
Backend Refs:
Group:
Kind: Service
Name: my-workload-v1
Namespace: my-workload
Port: 8080
Weight: 1
Matches:
Path:
Type: PathPrefix
Value: /api/my-workload
#
curl -is -H "Host: api.example.com" http://localhost:8080/api/my-workload


v1을 계속 사용할 것 입니다. rules:
- matches:
- path:
type: PathPrefix
value: /api/my-workload
# Add a matcher to route requests with a v2 version header to v2
# version=v2 헤더값이 있는 사용자만 v2 라우팅
headers:
- name: version
value: v2
backendRefs:
- name: my-workload-v2
namespace: my-workload
port: 8080
- matches:
# Route requests without the version header to v1 as before
# 대다수 일반 사용자는 기존 처럼 v1 라우팅
- path:
type: PathPrefix
value: /api/my-workload
backendRefs:
- name: my-workload-v1
namespace: my-workload
port: 8080
#
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/08-workload-route-header.yaml
#
kubectl describe httproute -n my-workload
...
Spec:
...
Rules:
Backend Refs:
Group:
Kind: Service
Name: my-workload-v2
Namespace: my-workload
Port: 8080
Weight: 1
Matches:
Headers:
Name: version
Type: Exact
Value: v2
Path:
Type: PathPrefix
Value: /api/my-workload
Backend Refs:
Group:
Kind: Service
Name: my-workload-v1
Namespace: my-workload
Port: 8080
Weight: 1
Matches:
Path:
Type: PathPrefix
Value: /api/my-workload
# Now we’ll test the original route, with no special headers supplied, and confirm that traffic still goes to v1:
curl -is -H "Host: api.example.com" http://localhost:8080/api/my-workload
curl -is -H "Host: api.example.com" http://localhost:8080/api/my-workload | grep body
"body": "Hello From My Workload (v1)!",
# But it we supply the version: v2 header, note that our gateway routes the request to v2 as expected:
curl -is -H "Host: api.example.com" -H "version: v2" http://localhost:8080/api/my-workload

curl -is -H "Host: api.example.com" -H "version: v2" http://localhost:8080/api/my-workload | grep body


rules:
- matches:
- path:
type: PathPrefix
value: /api/my-workload
# Configure a 50-50 traffic split across v1 and v2 : 버전 1,2 50:50 비율
backendRefs:
- name: my-workload-v1
namespace: my-workload
port: 8080
weight: 50
- name: my-workload-v2
namespace: my-workload
port: 8080
weight: 50
# Apply this 50-50 routing policy with kubectl:
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/09-workload-route-split.yaml
#
kubectl describe httproute -n my-workload
...
# 반복 접속 후 대략 비률 확인
for i in {1..100}; do curl -s -H "Host: api.example.com" http://localhost:8080/api/my-workload/ | grep body; done | sort | uniq -c | sort -nr

# [신규 터미널] 모니터링
kubectl get httproute -n my-workload my-workload -o yaml -w
#
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/10-workload-route-split-bad-dest.yaml
#
kubectl describe httproute -n my-workload
...
Spec:
Hostnames:
api.example.com
Parent Refs:
Group: gateway.networking.k8s.io
Kind: Gateway
Name: http
Namespace: gloo-system
Rules:
Backend Refs:
Group:
Kind: Service
Name: my-workload-v1
Namespace: my-workload
Port: 8080
Weight: 50
Group:
Kind: Service
Name: my-bad-workload-v2
Namespace: my-workload
Port: 8080
Weight: 50
Matches:
Path:
Type: PathPrefix
Value: /api/my-workload
Status:
Parents:
Conditions:
Last Transition Time: 2024-10-06T08:38:25Z
Message: Service "my-bad-workload-v2" not found
Observed Generation: 4
Reason: BackendNotFound
Status: False
Type: ResolvedRefs
Last Transition Time: 2024-10-06T08:25:47Z
Message:
Observed Generation: 4
Reason: Accepted
Status: True
Type: Accepted
Controller Name: solo.io/gloo-gateway
Parent Ref:
Group: gateway.networking.k8s.io
Kind: Gateway
Name: http
Namespace: gloo-system
#
curl -is -H "Host: api.example.com" http://localhost:8080/api/my-workload
curl -is -H "Host: api.example.com" http://localhost:8080/api/my-workload
HTTP/1.1 500 Internal Server Error
date: Wed, 03 Jul 2024 08:21:11 GMT
server: envoy
content-length: 0
#
for i in {1..100}; do curl -s -H "Host: api.example.com" http://localhost:8080/api/my-workload/ | grep body; done | sort | uniq -c | sort -nr

100개의 트래픽중 51개가 v1으로 보내짐
#
docker exec -it myk8s-control-plane bash
-----------------------------------
export PATH=$HOME/.gloo/bin:$PATH
glooctl check
Checking Gateways... OK
Checking Proxies... 1 Errors!
Detected Kubernetes Gateway integration!
Checking Kubernetes GatewayClasses... OK
Checking Kubernetes Gateways... OK
Checking Kubernetes HTTPRoutes... 1 Errors!
Skipping Gloo Instance check -- Gloo Federation not detected.
Error: 2 errors occurred:
* Found proxy with warnings by 'gloo-system': gloo-system gloo-system-http
Reason: warning:
Route Warning: InvalidDestinationWarning. Reason: invalid destination in weighted destination list: *v1.Upstream { blackhole_ns.kube-svc:blackhole-ns-blackhole-cluster-8080 } not found
* HTTPRoute my-workload.my-workload.http status (ResolvedRefs) is not set to expected (True). Reason: BackendNotFound, Message: Service "my-bad-workload-v2" not found
# 원인 관련 정보 확인
kubectl get httproute my-workload -n my-workload -o yaml
...
status:
parents:
- conditions:
- lastTransitionTime: "2023-11-28T21:09:20Z"
message: ""
observedGeneration: 6
reason: BackendNotFound
status: "False"
type: ResolvedRefs
...
# 정상 설정으로 해결 configuration is again clean.
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/09-workload-route-split.yaml
kubectl get httproute my-workload -n my-workload -o yaml
#
glooctl check
...

#
kubectl -n gloo-system port-forward deployment/gloo-proxy-http 19000 &
# 아래 관리 페이지에서 각각 메뉴 링크 클릭 확인
echo "Envoy Proxy Admin - http://localhost:19000"
echo "Envoy Proxy Admin - http://localhost:19000/stats/prometheus"

#
curl -s http://localhost:19000/stats | grep -E "(^cluster.kube-svc_httpbin-httpbin-8000_httpbin.upstream.*(2xx|5xx))"
cluster.kube-svc_httpbin-httpbin-8000_httpbin.upstream_rq_2xx: 32
cluster.kube-svc_httpbin-httpbin-8000_httpbin.upstream_rq_5xx: 7
# If we apply a curl request that forces a 500 failure from the httpbin backend, using the /status/500 endpoint, I’d expect the number of 2xx requests to remain the same, and the number of 5xx requests to increment by one:
curl -is -H "Host: api.example.com" http://localhost:8080/api/httpbin/status/500
HTTP/1.1 500 Internal Server Error
server: envoy
date: Wed, 03 Jul 2024 08:30:06 GMT
content-type: text/html; charset=utf-8
access-control-allow-origin: *
access-control-allow-credentials: true
content-length: 0
x-envoy-upstream-service-time: 28
#
curl -s http://localhost:19000/stats | grep -E "(^cluster.httpbin-httpbin-8000_httpbin.upstream.*(2xx|5xx))"
cluster.kube-svc_httpbin-httpbin-8000_httpbin.upstream_rq_2xx: 32
cluster.kube-svc_httpbin-httpbin-8000_httpbin.upstream_rq_5xx: 15
