Ssoon
[6주차] Gateway API 본문
CloudNet@ 가시다님이 진행하는 쿠버네티스 네트워크 스터디 3기
✅ 기본 환경
🧿 KinD Cluster 를 생성합니다.
(⎈|N/A:N/A) root@kind:~# 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
(⎈|N/A:N/A) root@kind:~# kind create cluster --image kindest/node:v1.30.0 --config kind-1node.yaml --name myk8s
Creating cluster "myk8s" ...
✓ Ensuring node image (kindest/node:v1.30.0) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-myk8s"
You can now use your cluster with:
kubectl cluster-info --context kind-myk8s
Have a nice day! 👋
(⎈|kind-myk8s:N/A) root@kind:~# 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'
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
myk8s-control-plane Ready control-plane 53s v1.30.0 172.18.0.2 <none> Debian GNU/Linux 12 (bookworm) 5.15.0-122-generic containerd://1.7.15
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-7db6d8ff4d-jg8zd 1/1 Running 0 41s
kube-system coredns-7db6d8ff4d-v47tp 1/1 Running 0 41s
kube-system etcd-myk8s-control-plane 1/1 Running 0 57s
kube-system kindnet-hqhb6 1/1 Running 0 41s
kube-system kube-apiserver-myk8s-control-plane 1/1 Running 0 57s
kube-system kube-controller-manager-myk8s-control-plane 1/1 Running 0 57s
kube-system kube-proxy-6hd4f 1/1 Running 0 41s
kube-system kube-scheduler-myk8s-control-plane 1/1 Running 0 57s
local-path-storage local-path-provisioner-988d74bc-kc8fk 1/1 Running 0 41s
🧿 Custom Resource Definition (CRD)이 생성합니다.
- gatewayclasses.gateway.networking.k8s.io: GatewayClass를 정의하는 CRD가 생성되었습니다. 이는 다양한 종류의 게이트웨이를 정의하는 데 사용됩니다.
- gateways.gateway.networking.k8s.io: Gateway를 정의하는 CRD가 생성되었습니다. 이는 실제 요청을 처리하는 게이트웨이 리소스입니다.
- httproutes.gateway.networking.k8s.io: HTTP 라우트를 정의하는 CRD가 생성되었습니다. 이는 들어오는 HTTP 요청을 어떤 게이트웨이에 라우팅할지를 정의합니다.
- referencegrants.gateway.networking.k8s.io: ReferenceGrant를 정의하는 CRD가 생성되었습니다. 이는 리소스에 대한 접근 권한을 부여하는 데 사용됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml
customresourcedefinition.apiextensions.k8s.io/gatewayclasses.gateway.networking.k8s.io created
customresourcedefinition.apiextensions.k8s.io/gateways.gateway.networking.k8s.io created
customresourcedefinition.apiextensions.k8s.io/httproutes.gateway.networking.k8s.io created
customresourcedefinition.apiextensions.k8s.io/referencegrants.gateway.networking.k8s.io created
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get crd
NAME CREATED AT
gatewayclasses.gateway.networking.k8s.io 2024-10-07T13:57:51Z
gateways.gateway.networking.k8s.io 2024-10-07T13:57:51Z
httproutes.gateway.networking.k8s.io 2024-10-07T13:57:51Z
referencegrants.gateway.networking.k8s.io 2024-10-07T13:57:51Z
🧿 Gloo 를 설치합니다.
- Docker 컨테이너에 접근: docker exec 명령어로 myk8s-control-plane이라는 이름의 Docker 컨테이너에 접속하여 bash 쉘을 실행합니다. 이는 Kubernetes 클러스터의 제어 평면 노드입니다.
- Gloo 설치: 이후 curl 명령어를 사용하여 Gloo 설치 스크립트를 다운로드하고, GLOO_VERSION을 설정하여 지정된 버전(1.17.7)을 설치합니다.
- PATH 환경 변수 업데이트: export 명령어를 사용하여 $HOME/.gloo/bin 경로를 PATH 환경 변수에 추가합니다. 이렇게 하면 이 경로에 있는 실행 파일(예: glooctl)을 터미널에서 쉽게 실행할 수 있습니다.
- Gloo 버전 확인: 이후 glooctl version 명령어를 입력하여 Gloo의 설치된 버전을 확인합니다. 이 명령어는 Gloo가 정상적으로 설치되었는지, 그리고 어떤 버전이 설치되었는지를 알려줍니다.
(⎈|kind-myk8s:N/A) root@kind:~# docker exec -it myk8s-control-plane bash
root@myk8s-control-plane:/# curl -sL https://run.solo.io/gloo/install | GLOO_VERSION=v1.17.7 sh
Using /usr/bin/python3
Attempting to download glooctl version v1.17.7
Downloading glooctl-linux-amd64...
Download complete!, validating checksum...
Checksum valid.
Gloo Gateway was successfully installed 🎉
Add the gloo CLI to your path with:
export PATH=$HOME/.gloo/bin:$PATH
Now run:
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
Please see visit the Gloo Installation guides for more: https://docs.solo.io/gloo-edge/latest/installation/
root@myk8s-control-plane:/# export PATH=$HOME/.gloo/bin:$PATH
root@myk8s-control-plane:/# glooctl version
Server: version undefined, could not find any version of gloo running
{
"client": {
"version": "1.17.7"
},
"kubernetesCluster": {
"major": "1",
"minor": "30",
"gitVersion": "v1.30.0",
"buildDate": "2024-05-13T22:00:36Z",
"platform": "linux/amd64"
}
}
🧿 Helm을 사용하여 Gloo API 게이트웨이를 설치합니다.
- Helm 레포지토리 추가
- Helm 레포지토리 업데이트
- Gloo API 게이트웨이 설치
- --create-namespace: 지정한 네임스페이스가 없을 경우 자동으로 생성합니다.
- --version 1.17.7: 설치할 Gloo 버전을 지정합니다.
- --set kubeGateway.enabled=true: Kubernetes Gateway 기능을 활성화합니다.
- --set gloo.disableLeaderElection=true: Gloo의 리더 선출 기능을 비활성화합니다. 이는 주로 단일 인스턴스에서 Gloo를 실행할 때 유용합니다.
- --set discovery.enabled=false: 서비스 디스커버리 기능을 비활성화합니다.
(⎈|kind-myk8s:N/A) root@kind:~# helm repo add gloo https://storage.googleapis.com/solo-public-helm
"gloo" has been added to your repositories
(⎈|kind-myk8s:N/A) root@kind:~# helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "gloo" chart repository
...Successfully got an update from the "geek-cookbook" chart repository
Update Complete. ⎈Happy Helming!⎈
(⎈|kind-myk8s:N/A) root@kind:~# 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
NAME: gloo-gateway
LAST DEPLOYED: Mon Oct 7 23:00:41 2024
NAMESPACE: gloo-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
🧿 Gloo API 게이트웨이가 Kubernetes 클러스터에 성공적으로 배포되었는지 확인합니다.
- kubectl rollout 명령어는 애플리케이션 배포와 관련된 상태를 모니터링하고 관리하는 데 사용됩니다.
- 배포 상태 확인: kubectl rollout status 명령어로 배포가 성공적으로 이루어졌는지 확인합니다.
- 이력 확인 및 롤백: kubectl rollout history와 kubectl rollout undo 명령어로 이전 배포 이력을 확인하거나 문제가 있을 때 이전 버전으로 되돌릴 수 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl rollout status deployment/gloo -n gloo-system
deployment "gloo" successfully rolled out
🧿 Kubernetes 클러스터에 설치된 Gloo Gateway와 관련된 CRD를 확인합니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get crd | grep 'networking.k8s.io'
gatewayclasses.gateway.networking.k8s.io 2024-10-07T13:57:51Z
gateways.gateway.networking.k8s.io 2024-10-07T13:57:51Z
httproutes.gateway.networking.k8s.io 2024-10-07T13:57:51Z
referencegrants.gateway.networking.k8s.io 2024-10-07T13:57:51Z
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get crd | grep -v 'networking.k8s.io'
NAME CREATED AT
authconfigs.enterprise.gloo.solo.io 2024-10-07T14:00:37Z
gatewayparameters.gateway.gloo.solo.io 2024-10-07T14:00:37Z
gateways.gateway.solo.io 2024-10-07T14:00:37Z
graphqlapis.graphql.gloo.solo.io 2024-10-07T14:00:38Z
httpgateways.gateway.solo.io 2024-10-07T14:00:37Z
httplisteneroptions.gateway.solo.io 2024-10-07T14:00:37Z
listeneroptions.gateway.solo.io 2024-10-07T14:00:37Z
proxies.gloo.solo.io 2024-10-07T14:00:38Z
ratelimitconfigs.ratelimit.solo.io 2024-10-07T14:00:38Z
routeoptions.gateway.solo.io 2024-10-07T14:00:37Z
routetables.gateway.solo.io 2024-10-07T14:00:37Z
settings.gloo.solo.io 2024-10-07T14:00:38Z
tcpgateways.gateway.solo.io 2024-10-07T14:00:37Z
upstreamgroups.gloo.solo.io 2024-10-07T14:00:38Z
upstreams.gloo.solo.io 2024-10-07T14:00:38Z
virtualhostoptions.gateway.solo.io 2024-10-07T14:00:38Z
virtualservices.gateway.solo.io 2024-10-07T14:00:38Z
🧿 gloo-system 네임스페이스 내의 파드(Pods), 서비스(Services), 그리고 엔드포인트 슬라이스(Endpoint Slices)를 확인합니다.
- pod/gateway-proxy-57c49d4f48-m5tvn
- Gloo Gateway의 게이트웨이 프록시 역할을 수행하며, 외부 트래픽을 처리하고 백엔드 서비스로 전달합니다.
- pod/gloo-748d877c4-6hbrj
- Gloo 컨트롤 플레인 역할을 하는 파드입니다. 이 파드는 게이트웨이 설정과 API 라우팅을 관리합니다.
- pod/gloo-resource-rollout-check-kqtjx 및 pod/gloo-resource-rollout-zqvnc
- 이 파드들은 Gloo의 리소스 롤아웃(배포 검증)을 위해 일시적으로 생성된 파드입니다. 작업을 완료한 후 자동으로 종료되었습니다.
- service/gateway-proxy
- TYPE: LoadBalancer → 이 서비스는 외부 트래픽을 처리하기 위해 로드 밸런서가 필요합니다.
- CLUSTER-IP: 10.96.58.102 → 클러스터 내에서 사용되는 IP 주소입니다.
- EXTERNAL-IP: <pending> → 외부 IP가 아직 할당되지 않았습니다. 클라우드 환경에서는 외부 로드 밸런서를 통해 서비스가 외부에 노출될 때 IP가 할당됩니다.
- PORT(S): 80:31577/TCP, 443:32455/TCP → HTTP(80)와 HTTPS(443) 트래픽을 처리하며, 클러스터 외부와의 연결을 위해 NodePort로 매핑됩니다.
- service/gloo
- TYPE: ClusterIP → 클러스터 내부에서만 접근할 수 있는 서비스입니다.
- CLUSTER-IP: 10.96.33.93 → 이 서비스에 접근할 수 있는 클러스터 내부 IP입니다.
- EXTERNAL-IP: <none> → 외부 IP가 할당되지 않았습니다. 클러스터 외부에서는 접근할 수 없습니다.
- PORT(S): 9977, 9976, 9988, 9966, 9979, 443 → Gloo 컨트롤 플레인이 사용하는 다양한 포트입니다.
- endpointslice.gateway-proxy-v8t8d
- ADDRESSTYPE: IPv4 → 이 엔드포인트는 IPv4 주소를 사용합니다.
- PORTS: 8080, 8443 → HTTP(8080)와 HTTPS(8443) 포트를 사용합니다.
- ENDPOINTS: 10.244.0.6 → 이 엔드포인트에 연결된 파드의 IP 주소입니다.
- endpointslice.gloo-cw4pz
- ADDRESSTYPE: IPv4 → 이 엔드포인트도 IPv4 주소를 사용합니다.
- PORTS: 9979, 9988, 9966 등 → Gloo 컨트롤 플레인이 사용하는 다양한 포트를 나타냅니다.
- ENDPOINTS: 10.244.0.7 → Gloo 파드의 IP 주소입니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get pod,svc,endpointslices -n gloo-system
NAME READY STATUS RESTARTS AGE
pod/gateway-proxy-57c49d4f48-m5tvn 1/1 Running 0 101s
pod/gloo-748d877c4-6hbrj 1/1 Running 0 101s
pod/gloo-resource-rollout-check-kqtjx 0/1 Completed 0 101s
pod/gloo-resource-rollout-zqvnc 0/1 Completed 0 101s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/gateway-proxy LoadBalancer 10.96.58.102 <pending> 80:31577/TCP,443:32455/TCP 101s
service/gloo ClusterIP 10.96.33.93 <none> 9977/TCP,9976/TCP,9988/TCP,9966/TCP,9979/TCP,443/TCP 101s
NAME ADDRESSTYPE PORTS ENDPOINTS AGE
endpointslice.discovery.k8s.io/gateway-proxy-v8t8d IPv4 8080,8443 10.244.0.6 101s
endpointslice.discovery.k8s.io/gloo-cw4pz IPv4 9979,9988,9966 + 3 more... 10.244.0.7 101s
✅ Httpbin Application
🧿 Kubernetes에서 https://raw.githubusercontent.com/solo-io/solo-blog/main/gateway-api-tutorial/01-httpbin-svc.yaml 파일에 정의된 리소스를 클러스터에 적용하여 HTTPBin 서비스를 배포합니다.
- HTTPBin 서비스 : HTTPBin은 요청을 테스트하고 HTTP 응답을 반환하는 간단한 웹 서비스입니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f https://raw.githubusercontent.com/solo-io/solo-blog/main/gateway-api-tutorial/01-httpbin-svc.yaml
namespace/httpbin created
serviceaccount/httpbin created
service/httpbin created
deployment.apps/httpbin created
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get deploy,pod,svc,endpointslices,sa -n httpbin
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/httpbin 0/1 1 0 6s
NAME READY STATUS RESTARTS AGE
pod/httpbin-5855dc8bdd-bhrs2 0/1 ContainerCreating 0 6s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/httpbin ClusterIP 10.96.243.6 <none> 8000/TCP 6s
NAME ADDRESSTYPE PORTS ENDPOINTS AGE
endpointslice.discovery.k8s.io/httpbin-jj6cs IPv4 <unset> <unset> 6s
NAME SECRETS AGE
serviceaccount/default 0 7s
serviceaccount/httpbin 0 6s
(⎈|kind-myk8s:N/A) root@kind:~# kubectl rollout status deploy/httpbin -n httpbin
Waiting for deployment "httpbin" rollout to finish: 0 of 1 updated replicas are available...
deployment "httpbin" successfully rolled out
✅ Gateway API kinds
🧿 Kubernetes Gateway API를 사용하여 HTTP 게이트웨이를 정의하는 Kubernetes 리소스를 배포합니다.
- Gateway는 네트워크 트래픽을 라우팅하는 역할을 합니다. Gloo Gateway와 함께 사용되어 외부 요청을 처리하고 적절한 서비스로 전달하는 역할을 합니다.
- listeners: 이 섹션은 Gateway가 어떤 종류의 네트워크 트래픽을 수신할지를 정의합니다.
- protocol: HTTP: 이 Gateway는 HTTP 프로토콜을 사용합니다.
- port: 8080: HTTP 요청은 8080 포트에서 수신됩니다.
- name: http: 리스너의 이름은 http입니다.
- allowedRoutes: 이 Gateway가 허용하는 라우트의 설정입니다.
- namespaces: 트래픽을 허용할 수 있는 네임스페이스를 정의합니다.
- from: All: 모든 네임스페이스에서 오는 라우트를 허용합니다.
- 8080 포트에서 HTTP 트래픽을 수신하고, Gloo Gateway를 통해 처리하도록 설정된 Gateway를 정의합니다. 모든 네임스페이스에서 오는 라우트를 허용하여, 다른 네임스페이스의 서비스도 이 Gateway를 통해 트래픽을 처리할 수 있게 됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -O https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/02-gateway.yaml
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 259 100 259 0 0 516 0 --:--:-- --:--:-- --:--:-- 515
(⎈|kind-myk8s:N/A) root@kind:~# cat 02-gateway.yaml
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: http
namespace: gloo-system
spec:
gatewayClassName: gloo-gateway
listeners:
- protocol: HTTP
port: 8080
name: http
allowedRoutes:
namespaces:
from: All
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f 02-gateway.yaml
gateway.gateway.networking.k8s.io/http created
🧿 gloo-system 네임스페이스에서 Gateway 리소스를 확인합니다.
- CLASS: gloo-gateway
- 이 Gateway가 속한 클래스는 gloo-gateway입니다. Gloo Gateway를 통해 관리되는 Gateway임을 나타냅니다.
- ADDRESS
- 이 필드는 Gateway가 외부에서 접근할 수 있는 IP 주소를 나타냅니다. 현재는 비어 있으므로, 아직 외부에서 접근할 수 있는 IP가 할당되지 않은 상태입니다. IP가 할당되면 여기 표시됩니다.
- PROGRAMMED: True
- 이 필드는 Gateway가 성공적으로 설정되었는지 나타냅니다. True로 설정된 경우, Gateway가 올바르게 구성되어 네트워크 트래픽을 처리할 준비가 되었음을 의미합니다
- Gateway는 Gloo Gateway를 통해 관리되고 있으며, 정상적으로 구성되어 HTTP 트래픽을 처리할 준비가 완료된 상태입니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get gateway -n gloo-system
NAME CLASS ADDRESS PROGRAMMED AGE
http gloo-gateway True 19s
(⎈|kind-myk8s:N/A) root@kind:~# 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
kind: List
metadata: {}
🧿 gloo-system 네임스페이스에서 gloo-proxy-http Deployment 리소스를 확인합니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get deployment gloo-proxy-http -n gloo-system
NAME READY UP-TO-DATE AVAILABLE AGE
gloo-proxy-http 1/1 1 1 7m25s
🧿 gloo-system 네임스페이스의 모든 Pod에 대한 정보를 조회하고, 그 중에서 이미지(Image) 관련 정보를 필터링하여 확인합니다.
- gateway-proxy-57c49d4f48-m5tvn: Gloo Gateway의 프록시 Pod입니다.
- gloo-748d877c4-6hbrj: Gloo의 핵심 기능을 제공하는 Pod입니다.
- gloo-proxy-http-587765f6b6-2klbx: HTTP 트래픽을 처리하는 Gloo Gateway의 프록시 Pod입니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get pod -n gloo-system
NAME READY STATUS RESTARTS AGE
gateway-proxy-57c49d4f48-m5tvn 1/1 Running 0 14m
gloo-748d877c4-6hbrj 1/1 Running 0 14m
gloo-proxy-http-587765f6b6-2klbx 1/1 Running 0 7m29s
(⎈|kind-myk8s:N/A) root@kind:~# 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-system 네임스페이스에서 gloo-proxy-http라는 Service 리소스의 정보를 확인합니다.
- TYPE: LoadBalancer
- Service의 유형입니다. LoadBalancer는 클러스터 외부에서 접근할 수 있도록 IP 주소를 할당받는 타입입니다. 이 타입의 Service는 보통 클라우드 환경에서 사용되어 외부 트래픽을 내부로 라우팅합니다.
- CLUSTER-IP: 10.96.228.182
- 이 Service에 대한 클러스터 내부 IP 주소입니다. 클러스터 내의 다른 리소스들이 이 IP를 통해 이 Service에 접근할 수 있습니다.
- EXTERNAL-IP: <pending>
- 외부에서 접근하기 위한 IP 주소입니다. 현재 <pending> 상태로, 외부 IP 주소가 아직 할당되지 않았음을 의미합니다. 보통 이 상태는 클라우드 제공자가 외부 IP를 할당 중일 때 나타납니다.
- PORT(S): 8080:32093/TCP
- Service가 노출하는 포트와 매핑되는 클러스터 포트입니다.
- 8080: 외부에서 접근하는 포트입니다.
- 32093: 클러스터 내부에서 이 Service로의 요청을 수신하는 포트입니다.
- /TCP: 이 포트에서 사용하는 프로토콜은 TCP입니다.
- Service가 노출하는 포트와 매핑되는 클러스터 포트입니다.
gloo-proxy-http Service는 Gloo Gateway의 HTTP 트래픽을 처리하기 위한 LoadBalancer 타입의 Service입니다. 현재 클러스터 내부 IP는 할당되었지만, 외부 IP는 아직 할당되지 않은 상태입니다. 외부에서 HTTP 트래픽은
8080 포트를 통해 접근할 수 있으며, 클러스터 내부에서는 32093 포트를 통해 요청을 수신합니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get svc -n gloo-system gloo-proxy-http
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
gloo-proxy-http LoadBalancer 10.96.228.182 <pending> 8080:32093/TCP 7m37s
🧿 Gloo Gateway의 HTTP 프록시를 위한 새로운 LoadBalancer 타입의 Service를 정의하고 외부에서 30001 포트를 통해 접근할 수 있도록 설정합니다.
- ports: Service가 노출하는 포트에 대한 정의입니다.
- name: 포트 이름을 지정합니다. 여기서는 http입니다.
- nodePort: 이 Service에 접근하기 위해 사용할 노드 포트입니다. 외부에서 접근할 수 있는 포트로, 30001로 설정되었습니다.
- port: Service의 클러스터 내부 포트입니다. 8080으로 설정되었습니다.
(⎈|kind-myk8s:N/A) root@kind:~# 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
Warning: resource services/gloo-proxy-http is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
service/gloo-proxy-http configured
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get svc -n gloo-system gloo-proxy-http
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
gloo-proxy-http LoadBalancer 10.96.228.182 <pending> 8080:30001/TCP 9m32s
🧿 kubectl port-forward를 사용하여 gloo-proxy-http 배포(deployment)에 대한 로컬 포트 포워딩을 설정합니다.
- kubectl port-forward: 이 명령어는 클러스터 내의 리소스에 대해 로컬 포트 포워딩을 설정합니다. 즉, 로컬 머신에서 특정 포트로 들어오는 요청을 클러스터 내의 리소스(여기서는 gloo-proxy-http 배포)로 전달합니다.
- deployment/gloo-proxy-http: 포워딩할 대상 리소스입니다. 여기서는 gloo-proxy-http라는 이름의 배포입니다.
- -n gloo-system: 포워딩할 리소스가 속한 네임스페이스입니다. 여기서는 gloo-system 네임스페이스에 있는 배포를 지정하고 있습니다.
- 8080:8080: 포트 포워딩의 매핑입니다.
- 첫 번째 8080: 로컬 머신의 포트 번호입니다. 이 포트에서 들어오는 요청이 전달됩니다.
- 두 번째 8080: 클러스터 내의 리소스가 수신하는 포트 번호입니다.
- &: 이 기호는 명령어를 백그라운드에서 실행하도록 합니다. 즉, 포트 포워딩을 설정한 후에도 쉘에서 다른 명령어를 입력할 수 있습니다.
로컬 머신의 8080 포트에서 들어오는 HTTP 요청을 Gloo Gateway의 gloo-proxy-http 배포의 8080 포트로 포워딩하는 설정입니다. 이로 인해 로컬 머신에서 http://localhost:8080으로 접근하면 Gloo Gateway의 해당 포트로 요청이 전달되어 클러스터 내부의 서비스와 상호작용할 수 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl port-forward deployment/gloo-proxy-http -n gloo-system 8080:8080 &
[1] 9197
(⎈|kind-myk8s:N/A) root@kind:~# Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
✅ HTTPRoute
🧿 Kubernetes Gateway API를 사용하여 HTTP 라우트를 정의/배포 합니다. 이 라우트는 Gloo Gateway와 HTTPBin 서비스 간의 트래픽을 관리합니다.
- parentRefs: 이 HTTPRoute가 연결된 부모 Gateway를 참조합니다. 여기서는 gloo-system 네임스페이스의 http라는 이름의 Gateway를 참조하고 있습니다.
- hostnames: 이 라우트가 적용될 호스트 이름을 지정합니다. 요청이 api.example.com으로 오면 이 라우트가 활성화됩니다.
- rules: 요청을 어떻게 처리할지를 정의하는 규칙입니다.
- matches: 이 규칙이 적용될 조건을 설정합니다.
- path: 요청 경로에 대한 조건입니다.
- type: 경로의 유형을 설정합니다. 여기서는 Exact로 설정하여, 경로가 정확히 일치해야 함을 의미합니다.
- value: 이 규칙이 적용될 경로입니다. 여기서는 /get으로 설정되어 있습니다.
- path: 요청 경로에 대한 조건입니다.
- backendRefs: 이 규칙이 적용될 백엔드 서비스를 정의합니다.
- name: 요청이 전달될 서비스의 이름입니다. 여기서는 httpbin으로 설정되어 있습니다.
- port: 해당 서비스에서 사용할 포트 번호입니다. 여기서는 8000으로 설정되어 있습니다.
- matches: 이 규칙이 적용될 조건을 설정합니다.
gloo-system 네임스페이스에 있는 http라는 Gateway에 연결되며, api.example.com 호스트의 /get 경로로 들어오는 HTTP 요청을 httpbin 서비스의 8000 포트로 전달합니다. 이는 외부 요청을 내부 서비스로 라우팅하는 데 사용됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -O https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/03-httpbin-route.yaml
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 381 100 381 0 0 813 0 --:--:-- --:--:-- --:--:-- 814
(⎈|kind-myk8s:N/A) root@kind:~# cat 03-httpbin-route.yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: httpbin
namespace: httpbin
labels:
example: httpbin-route
spec:
parentRefs:
- name: http
namespace: gloo-system
hostnames:
- "api.example.com"
rules:
- matches:
- path:
type: Exact
value: /get
backendRefs:
- name: httpbin
port: 8000
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f 03-httpbin-route.yaml
httproute.gateway.networking.k8s.io/httpbin created
🧿 httpbin 네임스페이스에서 정의된 HTTPRoute 리소스를 조회하여 해당 리소스의 상태를 확인합니다.
- HOSTNAMES: 이 HTTPRoute에 적용되는 호스트 이름입니다. ["api.example.com"]로 표시되어 있으며, 이는 이 라우트가 api.example.com 호스트에서 들어오는 요청을 처리한다는 의미입니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get httproute -n httpbin
NAME HOSTNAMES AGE
httpbin ["api.example.com"] 20s
(⎈|kind-myk8s:N/A) root@kind:~# 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
...
🧿 로컬 시스템의 /etc/hosts 파일에 api.example.com이라는 호스트 이름을 127.0.0.1 IP 주소에 매핑하는 내용을 추가합니다.
(⎈|kind-myk8s:N/A) root@kind:~# echo "127.0.0.1 api.example.com" | sudo tee -a /etc/hosts
127.0.0.1 api.example.com
🧿 curl을 사용하여 로컬의 HTTP 서버에 요청을 보내고, Gloo Gateway를 통해 httpbin 서비스에 접근하여 /get 엔드포인트에서 JSON 응답을 확인합니다.
- -H "Host: api.example.com": HTTP 요청에 Host 헤더를 추가합니다. 이 헤더는 서버에게 요청이 어떤 도메인으로 들어온 것인지 알려줍니다. 여기서는 api.example.com으로 설정되어 있습니다.
- http://localhost:8080/get: 요청할 URL입니다. 여기서는 로컬 머신의 8080 포트에서 /get 엔드포인트에 요청합니다.
- HTTP/1.1 200 OK: 요청이 성공적으로 처리되었음을 나타냅니다.
- server: envoy: 요청을 처리한 서버의 이름입니다. 여기서는 Envoy 프록시 서버가 사용되었습니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -is -H "Host: api.example.com" http://localhost:8080/get
HTTP/1.1 200 OK
server: envoy
date: Mon, 07 Oct 2024 14:29:21 GMT
content-type: application/json
content-length: 240
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 2
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "api.example.com",
"User-Agent": "curl/7.81.0",
"X-Envoy-Expected-Rq-Timeout-Ms": "15000"
},
"origin": "10.244.0.11",
"url": "http://api.example.com/get"
}
🧿 curl을 사용하여 http://localhost:8080/delay/1 엔드포인트에 대해 HTTP 요청을 전송 하여 응답을 확인합니다.
- -i: 응답 헤더를 포함하여 출력합니다.
- -s: 진행 상태 출력을 생략합니다.
- -H "Host: api.example.com": 요청 헤더에 Host를 설정하여 api.example.com을 지정합니다.
- http://localhost:8080/delay/1: 요청할 URL입니다.
- 상태 코드 404: 요청한 리소스가 서버에서 존재하지 않음을 의미합니다.
- 요청한 엔드포인트(/delay/1)가 httpbin 서비스에서 제공되지 않거나, Gloo Gateway 설정에서 올바르게 라우팅되지 않음.
(⎈|kind-myk8s:N/A) root@kind:~# curl -is -H "Host: api.example.com" http://localhost:8080/delay/1
HTTP/1.1 404 Not Found
date: Mon, 07 Oct 2024 14:30:30 GMT
server: envoy
content-length: 0
✅ 정규식 패턴 매칭 [Regex Matching Patterns]
🧿 Gloo Gateway에서 클라이언트 요청을 특정 패턴에 따라 httpbin 서비스로 라우팅 하는 HTTPRoute를 배포합니다.
- parentRefs:
- name: 이 HTTPRoute가 참조하는 Gateway의 이름입니다. 여기서는 http라는 이름을 가진 Gateway를 참조하고 있습니다.
- namespace: 해당 Gateway가 속한 네임스페이스로, gloo-system입니다.
- hostnames:
- 요청을 처리할 호스트 이름을 지정합니다. 여기서는 api.example.com에 대한 요청을 처리하도록 설정했습니다.
- rules:
- HTTP 요청을 매칭하고, 라우팅 규칙을 정의합니다.
- matches: 요청 경로를 매칭하는 규칙입니다.
- path:
- type: PathPrefix: 요청 경로가 /api/httpbin/로 시작하는 경우에 매칭됩니다.
- value: /api/httpbin/: 요청 경로의 접두사입니다.
- path:
- filters: 요청이 매칭되었을 때 적용할 변환 규칙입니다.
- type: URLRewrite: URL을 변환하는 필터입니다.
- urlRewrite: URL을 수정하는 방법을 정의합니다.
- path:
- type: ReplacePrefixMatch: 요청 경로의 접두사를 대체합니다.
- replacePrefixMatch: /: /api/httpbin/ 접두사를 /로 대체합니다. 즉, 클라이언트 요청에서 /api/httpbin/을 제거합니다.
- path:
- urlRewrite: URL을 수정하는 방법을 정의합니다.
- type: URLRewrite: URL을 변환하는 필터입니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -O https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/04-httpbin-rewrite.yaml
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 653 100 653 0 0 1150 0 --:--:-- --:--:-- --:--:-- 1151
(⎈|kind-myk8s:N/A) root@kind:~# cat 04-httpbin-rewrite.yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: httpbin
namespace: httpbin
spec:
parentRefs:
- name: http
namespace: gloo-system
hostnames:
- api.example.com
rules:
- 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: /
backendRefs:
- name: httpbin
port: 8000
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f 04-httpbin-rewrite.yaml
httproute.gateway.networking.k8s.io/httpbin configured
🧿 Gloo Gateway에서 설정한 HTTPRoute의 상세 정보를 확인합니다.
- api.example.com 도메인으로 들어오는 요청 중에서 경로가 /api/httpbin/으로 시작하는 모든 요청을 httpbin 서비스의 / 경로로 라우팅하는 역할을 합니다.
- 클라이언트가 http://api.example.com/api/httpbin/get 와 같은 요청을 보내면, Gloo Gateway는 이 요청을 httpbin 서비스의 /get 엔드포인트로 전달하게 됩니다.
- 요청 경로의 /api/httpbin/ 부분이 /로 대체되어 요청됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# 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/
...
🧿 api.example.com/api/httpbin/get로 요청을 보내면, Gloo Gateway가 이를 httpbin 서비스의 /get 엔드포인트로 잘 라우팅하고 있음을 확인합니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -is -H "Host: api.example.com" http://localhost:8080/api/httpbin/get
HTTP/1.1 200 OK
server: envoy
date: Mon, 07 Oct 2024 14:37:23 GMT
content-type: application/json
content-length: 290
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 1
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "api.example.com",
"User-Agent": "curl/7.81.0",
"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"
}
🧿 Gloo Gateway가 httpbin 서비스의 /delay/1 엔드포인트로 요청을 성공적으로 라우팅하고, 1초 지연된 응답을 반환했음을 확인합니다.
- x-envoy-upstream-service-time: 1003: 요청이 백엔드 서비스에 도달하는 데 걸린 시간(밀리초 단위)으로, 1003ms(1초) 지연이 있음을 보여줍니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -is -H "Host: api.example.com" http://localhost:8080/api/httpbin/delay/1
HTTP/1.1 200 OK
server: envoy
date: Mon, 07 Oct 2024 14:38:07 GMT
content-type: application/json
content-length: 344
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 1003
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Host": "api.example.com",
"User-Agent": "curl/7.81.0",
"X-Envoy-Expected-Rq-Timeout-Ms": "15000",
"X-Envoy-Original-Path": "/api/httpbin/delay/1"
},
"origin": "10.244.0.11",
"url": "http://api.example.com/delay/1"
}
✅ 업스트림 베어러 토큰을 사용한 변환 [Upstream Bearer Tokens]
Bearer 토큰이란?
- 정의: Bearer 토큰은 사용자가 인증을 받았음을 나타내는 문자열입니다. 이 토큰은 사용자의 권한을 증명하며, 이를 통해 특정 API 또는 자원에 접근할 수 있습니다.
- 형식: 일반적으로 긴 문자열 형식으로 되어 있으며, 보통 "Bearer"라는 키워드와 함께 사용됩니다. 예를 들어, Authorization: Bearer your_token_here와 같이 HTTP 헤더에 포함됩니다.
- 어떻게 작동하나요?
- 사용자 인증: 사용자가 로그인을 하면, 서버는 사용자의 신원을 확인하고 Bearer 토큰을 생성하여 사용자에게 반환합니다.
- 토큰 전송: 사용자는 이후 API 요청을 할 때 이 토큰을 HTTP 요청 헤더에 포함시켜 보냅니다.
- 토큰 검증: 서버는 수신한 토큰을 검증하여 요청한 사용자가 해당 자원에 접근할 수 있는 권한이 있는지를 확인합니다.
- 자원 접근: 토큰이 유효하면 요청한 자원에 접근할 수 있고, 그렇지 않으면 접근이 거부됩니다.
🧿 Gloo Gateway에서 특정 경로에 대해 요청을 처리하고, API 키를 추가하여 백엔드 시스템으로 라우팅
- parentRefs:
- 이 HTTPRoute는 gloo-system 네임스페이스의 http라는 이름을 가진 Gateway에 연결되어 있습니다. 이로 인해 해당 Gateway에서 이 경로로의 요청을 처리할 수 있습니다.
- hostnames:
- api.example.com이라는 호스트 이름으로 요청된 경우 이 라우트가 활성화됩니다.
- rules:
- 요청이 /api/httpbin/ 경로로 시작하는 경우 이 규칙이 적용됩니다.
- filters:
- URLRewrite:
- 요청 경로에서 /api/httpbin/ 부분을 /로 대체하여 백엔드 서비스에 요청을 전달합니다.
- RequestHeaderModifier:
- Authorization 헤더를 추가하여 요청에 Bearer my-api-key를 포함시킵니다. 이는 백엔드 서비스에 인증 정보를 전달하는 데 사용됩니다.
- URLRewrite:
- backendRefs:
- 이 요청이 httpbin이라는 이름을 가진 서비스의 8000번 포트로 전달됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -O https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/05-httpbin-rewrite-xform.yaml
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 785 100 785 0 0 1447 0 --:--:-- --:--:-- --:--:-- 1448
(⎈|kind-myk8s:N/A) root@kind:~# cat 05-httpbin-rewrite-xform.yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: httpbin
namespace: httpbin
spec:
parentRefs:
- name: http
namespace: gloo-system
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /api/httpbin/
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
backendRefs:
- name: httpbin
port: 8000
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f 05-httpbin-rewrite-xform.yaml
httproute.gateway.networking.k8s.io/httpbin configured
🧿 Gloo Gateway에서 설정한 HTTPRoute의 상세 정보를 확인합니다.
- Filters:
- URL Rewrite:
- Type: URLRewrite – URL을 수정할 것임을 나타냅니다.
- Path:
- Replace Prefix Match: / – 이 프리픽스에 해당하는 요청이 백엔드 서비스로 전송되기 전에 /로 대체됩니다.
- Type: ReplacePrefixMatch – 이 필터가 요청 경로에서 일치하는 프리픽스를 대체함을 나타냅니다.
- Request Header Modifier :
- Type: RequestHeaderModifier – 이 필터가 HTTP 요청 헤더를 수정할 것임을 나타냅니다.
- Add:
- Name: Authorization – 추가될 헤더의 이름입니다.
- Value: Bearer my-api-key – 백엔드 서비스에 대한 인증 요청에 포함될 값입니다.
- URL Rewrite:
- Matches:
- Path:
- Type: PathPrefix – 매칭이 경로의 프리픽스를 기준으로 수행됨을 나타냅니다.
- Value: /api/httpbin/ – 이 프리픽스가 있는 요청만 이 규칙을 통해 라우팅됩니다
- Path:
(⎈|kind-myk8s:N/A) root@kind:~# 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/
...
🧿 curl 명령어를 사용하여 httpbin 서비스에 대한 요청을 보내고 응답을 확인합니다.
- 헤더 정보:
- Authorization: Bearer my-api-key - 요청에 Bearer 토큰이 포함되어 있습니다. 이는 요청이 인증된 것임을 나타냅니다.
- Host: api.example.com - 요청의 호스트 헤더로, URL 재작성 규칙에 따라 이 호스트로 요청이 전달됩니다.
- X-Envoy-Original-Path: /api/httpbin/get - 원래의 요청 경로로, URL 재작성 규칙에 의해 /로 변경되기 전에 사용된 경로입니다.
- 요청 경로:
- url: http://api.example.com/get - 실제로 httpbin 서비스에 전달된 URL입니다. 경로가 재작성되어 원래의 /get 경로로 호출되었습니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -is -H "Host: api.example.com" http://localhost:8080/api/httpbin/get
HTTP/1.1 200 OK
server: envoy
date: Mon, 07 Oct 2024 14:45:42 GMT
content-type: application/json
content-length: 333
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 1
{
"args": {},
"headers": {
"Accept": "*/*",
"Authorization": "Bearer my-api-key",
"Host": "api.example.com",
"User-Agent": "curl/7.81.0",
"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"
}
✅ Migrate
이 섹션에서는 헤더 기반 라우팅을 사용한 다크 런칭과 백분율 기반 라우팅을 사용한 카나리아 릴리스라는 몇 가지 일반적인 서비스 마이그레이션 기술이 Gateway API 표준에서 어떻게 지원되는지 살펴보겠습니다.
🧿 my-workload라는 네임스페이스 아래에 두 개의 Deployment 와 각각에 대한 Service를 배포합니다.
- 먼저 마이그레이션 예제를 용이하게 하기 위해 두 가지 버전의 워크로드를 설정해 보겠습니다. 오픈 소스 Fake Service를 사용하여 이를 활성화합니다.
- HTTP와 gRPC 트래픽을 모두 처리할 수 있는 Fake 서비스로, 업스트림 서비스 통신과 서비스 메시 및 기타 시나리오를 테스트합니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -O https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/06-workload-svcs.yaml
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2189 100 2189 0 0 4521 0 --:--:-- --:--:-- --:--:-- 4522
(⎈|kind-myk8s:N/A) root@kind:~# cat 06-workload-svcs.yaml
apiVersion: v1
kind: Namespace
metadata:
name: my-workload
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-workload
namespace: my-workload
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-workload-v1
namespace: my-workload
labels:
app: my-workload-v1
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: my-workload-v1
version: v1
template:
metadata:
labels:
app: my-workload-v1
version: v1
annotations:
spec:
serviceAccountName: my-workload
containers:
- name: my-workload
image: nicholasjackson/fake-service:v0.7.8
ports:
- containerPort: 8080
env:
- name: "LISTEN_ADDR"
value: "0.0.0.0:8080"
- name: "NAME"
value: "my-workload-v1"
- name: "SERVER_TYPE"
value: "http"
- name: "MESSAGE"
value: "Hello From My Workload (v1)!"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-workload-v2
namespace: my-workload
labels:
app: my-workload-v2
version: v2
spec:
replicas: 1
selector:
matchLabels:
app: my-workload-v2
version: v2
template:
metadata:
labels:
app: my-workload-v2
version: v2
annotations:
spec:
serviceAccountName: my-workload
containers:
- name: my-workload
image: nicholasjackson/fake-service:v0.7.8
ports:
- containerPort: 8080
env:
- name: "LISTEN_ADDR"
value: "0.0.0.0:8080"
- name: "NAME"
value: "my-workload-v2"
- name: "SERVER_TYPE"
value: "http"
- name: "MESSAGE"
value: "Hello From My Workload (v2)!"
---
apiVersion: v1
kind: Service
metadata:
name: my-workload-v1
namespace: my-workload
spec:
selector:
app: my-workload-v1
ports:
- name: http
protocol: TCP
port: 8080
targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: my-workload-v2
namespace: my-workload
spec:
selector:
app: my-workload-v2
ports:
- name: http
protocol: TCP
port: 8080
targetPort: 8080
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f 06-workload-svcs.yaml
namespace/my-workload created
serviceaccount/my-workload created
deployment.apps/my-workload-v1 created
deployment.apps/my-workload-v2 created
service/my-workload-v1 created
service/my-workload-v2 created
🧿 Kubernetes 클러스터에서 my-workload 네임스페이스의 리소스 정보를 확인합니다.
- my-workload-v1과 my-workload-v2의 두 개의 서비스가 생성되었습니다.
- 두 서비스 모두 ClusterIP 유형이며, 각각의 클러스터 내에서 고유한 IP 주소를 할당받았습니다.
- EXTERNAL-IP는 <none>으로 표시되어 있으며, 이는 외부에 노출되지 않고 클러스터 내에서만 사용된다는 의미입니다.
- 두 서비스 모두 8080 포트를 사용하고 있습니다.
- 각 Endpoints Slice는 특정 서비스가 연결할 수 있는 파드의 IP 주소를 제공합니다.
- my-workload-v1은 IP 10.244.0.12, my-workload-v2는 IP 10.244.0.13을 사용하여 해당 서비스에 연결할 수 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get deploy,pod,svc,endpointslices -n my-workload
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/my-workload-v1 1/1 1 1 33s
deployment.apps/my-workload-v2 1/1 1 1 33s
NAME READY STATUS RESTARTS AGE
pod/my-workload-v1-644f98bbd9-7m4nn 1/1 Running 0 33s
pod/my-workload-v2-5bb5fcfcbc-xr57t 1/1 Running 0 33s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/my-workload-v1 ClusterIP 10.96.226.228 <none> 8080/TCP 33s
service/my-workload-v2 ClusterIP 10.96.211.1 <none> 8080/TCP 33s
NAME ADDRESSTYPE PORTS ENDPOINTS AGE
endpointslice.discovery.k8s.io/my-workload-v1-jl929 IPv4 8080 10.244.0.12 33s
endpointslice.discovery.k8s.io/my-workload-v2-slxs5 IPv4 8080 10.244.0.13 33s
✅ Simple V1 Routing
여러 서비스로의 라우팅을 시작하기 전에 먼저 /api/my-workload로 시작하는 경로의 HTTP 요청을 호스트 api.example.com으로 v1 워크로드로 전송하는 간단한 HTTPRoute를 빌드합니다.
🧿 HTTP 요청 라우팅을 정의하는 리소스 를 배호합니다.
- spec:
- parentRefs: 이 라우트가 연결된 Gateway를 지정합니다. 여기서는 http라는 이름의 Gateway가 gloo-system 네임스페이스에 있다고 정의하고 있습니다.
- hostnames: 이 HTTPRoute가 처리할 호스트 이름을 지정합니다. 여기서는 "api.example.com"입니다.
- rules: 요청 경로와 백엔드를 매핑하는 규칙을 정의합니다.
- matches: 경로를 매칭하는 조건입니다. 여기서는 PathPrefix 유형을 사용하여 /api/my-workload로 시작하는 경로를 매칭합니다.
- backendRefs: 요청이 전달될 백엔드 서비스 정보를 정의합니다. 여기서는 my-workload-v1이라는 이름의 서비스로, my-workload 네임스페이스에서 8080 포트로 연결됩니다.
api.example.com 호스트로 들어오는 /api/my-workload 경로에 대한 요청이 my-workload-v1 서비스로 라우팅됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -O https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/07-workload-route.yaml
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 464 100 464 0 0 942 0 --:--:-- --:--:-- --:--:-- 943
(⎈|kind-myk8s:N/A) root@kind:~# cat 07-workload-route.yaml
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
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f 07-workload-route.yaml
httproute.gateway.networking.k8s.io/my-workload created
🧿 현재 Kubernetes 클러스터에 있는 두 개의 HTTPRoute 리소스가 있습니다
- my-workload 네임스페이스의 my-workload
- 이 HTTPRoute는 api.example.com 도메인으로 오는 요청을 처리 , my-workload 네임스페이스의 my-workload-v1 서비스로 요청을 라우팅합니다.
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get httproute -A
NAMESPACE NAME HOSTNAMES AGE
httpbin httpbin ["api.example.com"] 29m
my-workload my-workload ["api.example.com"] 19s
🧿 Gloo Gateway에서 설정한 HTTPRoute의 상세 정보를 확인합니다.
(⎈|kind-myk8s:N/A) root@kind:~# 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 명령어를 통해 api.example.com에 요청을 보내고, my-workload-v1 서비스로 라우팅되어 정상적인 응답을 받은 것을 확인합니다.
- HTTP/1.1 200 OK: 요청이 성공적으로 처리되었음을 나타냅니다.
- Content: 응답 본문에서 "body": "Hello From My Workload (v1)!"를 통해 my-workload-v1에서 제공하는 메시지를 확인할 수 있습니다.
- IP Addresses: 서비스의 IP 주소(10.244.0.12)가 응답에 포함되어 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -is -H "Host: api.example.com" http://localhost:8080/api/my-workload
HTTP/1.1 200 OK
vary: Origin
date: Mon, 07 Oct 2024 14:50:04 GMT
content-length: 296
content-type: text/plain; charset=utf-8
x-envoy-upstream-service-time: 0
server: envoy
{
"name": "my-workload-v1",
"uri": "/api/my-workload",
"type": "HTTP",
"ip_addresses": [
"10.244.0.12"
],
"start_time": "2024-10-07T14:50:04.709278",
"end_time": "2024-10-07T14:50:04.709558",
"duration": "280.278µs",
"body": "Hello From My Workload (v1)!",
"code": 200
}
✅ Simulate a v2 Dark Launch with Header-Based Routing
Kubernetes 클러스터에 서비스의 새 클라우드 버전을 설치한 다음 선언적 정책을 사용하여 특정 헤더가 포함된 요청만 새 v2 인스턴스로 라우팅하여 예제에서 다크 런치를 시뮬레이션합니다.대부분의 사용자는 이전과 마찬가지로 서비스의 원래 v1을 계속 사용합니다.
🧿 HTTPRoute 구성을 배포합니다.
- version 헤더에 따라 my-workload-v1 또는 my-workload-v2로 라우팅하도록 구성되어 있습니다.
- 요청에 version: v2 헤더가 포함된 경우 my-workload-v2 서비스로 라우팅되고, 그렇지 않은 경우에는 기본적으로 my-workload-v1 서비스로 라우팅됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -O https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/08-workload-route-header
.yaml
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 864 100 864 0 0 1789 0 --:--:-- --:--:-- --:--:-- 1788
(⎈|kind-myk8s:N/A) root@kind:~# cat 08-workload-route-header.yaml
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
# Add a matcher to route requests with a v2 version header to v2
headers: #요청의 헤더에 version이 v2로 설정되어 있을 때만 이 규칙이 적용됩니다
- name: version
value: v2
backendRefs: #my-workload-v2라는 백엔드 서비스로 요청이 라우팅됩니다
- name: my-workload-v2
namespace: my-workload
port: 8080
- matches: #이 규칙은 version 헤더가 없는 경우에도 적용됩니다.
# Route requests without the version header to v1 as before
- path:
type: PathPrefix
value: /api/my-workload
backendRefs: # my-workload-v1이라는 백엔드 서비스로 라우팅됩니다
- name: my-workload-v1
namespace: my-workload
port: 8080
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f 08-workload-route-header.yaml
httproute.gateway.networking.k8s.io/my-workload configured
🧿 Gloo Gateway에서 설정한 HTTPRoute의 상세 정보를 확인합니다.
- 이 HTTPRoute는 요청이 api.example.com에서 들어오고, 경로가 /api/my-workload로 시작할 때 두 가지 규칙을 기반으로 라우팅을 수행합니다.
- 첫 번째 규칙: version 헤더가 v2일 경우 my-workload-v2로 라우팅됩니다.
- 두 번째 규칙: version 헤더가 없거나 다른 값일 경우 my-workload-v1으로 라우팅됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# 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-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
...
🧿 curl 명령어를 통해 api.example.com에 요청을 보내고, my-workload-v1 서비스로 라우팅되어 정상적인 응답을 받은 것을 확인합니다.
- -H "Host: api.example.com": HTTP 요청 헤더에 Host를 추가합니다. 이 경우 api.example.com이 요청의 호스트 이름으로 설정되어 있습니다.
- http://localhost:8080/api/my-workload: 요청을 보낼 URL입니다. 여기서는 로컬호스트의 8080 포트로 /api/my-workload 경로에 요청을 보냅니다.
- body: 응답 본문 내용입니다. "Hello From My Workload (v1)!"라는 메시지가 포함되어 있습니다.
요청의 경로가 /api/my-workload로 시작하고, version 헤더가 없기 때문에 my-workload-v1로 라우팅되었습니다. 응답은 요청이 성공적으로 처리되었음을 나타내며, 백엔드 서비스에서 보낸 메시지도 포함되어 있습니다
(⎈|kind-myk8s:N/A) root@kind:~# curl -is -H "Host: api.example.com" http://localhost:8080/api/my-workload
HTTP/1.1 200 OK
vary: Origin
date: Mon, 07 Oct 2024 14:53:19 GMT
content-length: 296
content-type: text/plain; charset=utf-8
x-envoy-upstream-service-time: 0
server: envoy
{
"name": "my-workload-v1",
"uri": "/api/my-workload",
"type": "HTTP",
"ip_addresses": [
"10.244.0.12"
],
"start_time": "2024-10-07T14:53:19.604205",
"end_time": "2024-10-07T14:53:19.604310",
"duration": "104.968µs",
"body": "Hello From My Workload (v1)!",
"code": 200
}
(⎈|kind-myk8s:N/A) root@kind:~# curl -is -H "Host: api.example.com" http://localhost:8080/api/my-workload | grep body
"body": "Hello From My Workload (v1)!",
🧿 curl 명령어를 통해 api.example.com 요청의 헤더에 version을 v2로 설정 요청을 보내고, my-workload-v2 서비스로 라우팅되어 정상적인 응답을 받은 것을 확인합니다.
- -H "Host: api.example.com": 요청의 호스트 이름을 api.example.com으로 설정합니다.
- -H "version: v2": 요청의 헤더에 version을 v2로 설정합니다. 이는 특정 백엔드 서비스로의 라우팅을 트리거합니다.
- http://localhost:8080/api/my-workload: 요청을 보낼 URL로, 로컬호스트의 8080 포트로 /api/my-workload 경로에 요청을 보냅니다.
- body: 응답 본문 내용입니다. "Hello From My Workload (v2)!"라는 메시지가 포함되어 있습니다.
요청의 경로가 /api/my-workload로 시작하고, version 헤더가 v2이기 때문에 이전에 설정한 HTTPRoute 규칙에 맞게 my-workload-v2가 호출된 것입니다. 응답 본문에는 my-workload-v2 서비스에서 반환한 메시지가 포함되어 있으며, 요청이 성공적으로 처리되었음을 확인할 수 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -is -H "Host: api.example.com" -H "version: v2" http://localhost:8080/api/my-workload
HTTP/1.1 200 OK
vary: Origin
date: Mon, 07 Oct 2024 14:53:36 GMT
content-length: 296
content-type: text/plain; charset=utf-8
x-envoy-upstream-service-time: 0
server: envoy
{
"name": "my-workload-v2",
"uri": "/api/my-workload",
"type": "HTTP",
"ip_addresses": [
"10.244.0.13"
],
"start_time": "2024-10-07T14:53:36.247107",
"end_time": "2024-10-07T14:53:36.247384",
"duration": "276.561µs",
"body": "Hello From My Workload (v2)!",
"code": 200
}
(⎈|kind-myk8s:N/A) root@kind:~# curl -is -H "Host: api.example.com" -H "version: v2" http://localhost:8080/api/my-workload | grep body
"body": "Hello From My Workload (v2)!",
✅ Expand V2 Testing with Percentage-Based Routing
성공적인 다크 런칭 이후에는 점진적으로 이전 버전에서 새 버전으로 사용자 트래픽을 전환하는 블루-그린 전략을 사용하는 기간이 필요할 수 있습니다. 트래픽을 균등하게 분할하고 트래픽의 절반을 v1로, 나머지 절반을 v2로 보내는 라우팅 정책으로 이를 살펴보겠습니다.
이를 달성하기 위해 다크 런칭을 주도한 헤더 기반 라우팅 규칙을 제거하여 HTTPRoute를 수정합니다. 그런 다음 아래에 표시된 대로 각 경로에 적용되는 50-50 가중치로 대체합니다.
🧿 Kubernetes HTTPRoute 설정은 요청을 두 개의 백엔드 서비스 (my-workload-v1 및 my-workload-v2)로 분산시키는 규칙을 구성합니다. 이를 통해 각 서비스에 대해 50%의 트래픽을 보내게 됩니다.
- backendRefs: 요청을 처리할 백엔드 서비스에 대한 정보입니다. 요청이 매칭 조건을 만족할 경우, 이들 백엔드 서비스로 트래픽이 전달됩니다.
- 각 백엔드 서비스에 대한 설정은 다음과 같습니다:
- name: 백엔드 서비스의 이름입니다. my-workload-v1과 my-workload-v2입니다.
- namespace: 각 백엔드 서비스가 속한 네임스페이스입니다. 둘 다 my-workload로 설정되어 있습니다.
- port: 백엔드 서비스가 요청을 수신할 포트 번호입니다. 여기서는 둘 다 8080입니다.
- weight: 이 백엔드 서비스에 할당된 가중치입니다. 두 서비스 모두 50으로 설정되어 있으므로, 요청은 50-50 비율로 분산됩니다.
- 각 백엔드 서비스에 대한 설정은 다음과 같습니다:
(⎈|kind-myk8s:N/A) root@kind:~# curl -O https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/09-workload-route-split.
yaml
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 647 100 647 0 0 1376 0 --:--:-- --:--:-- --:--:-- 1379
(⎈|kind-myk8s:N/A) root@kind:~# cat 09-workload-route-split.yaml
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
# Configure a 50-50 traffic split across v1 and v2
backendRefs:
- name: my-workload-v1
namespace: my-workload
port: 8080
weight: 50
- name: my-workload-v2
namespace: my-workload
port: 8080
weight: 50
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f 09-workload-route-split.yaml
httproute.gateway.networking.k8s.io/my-workload configured
🧿Gloo Gateway에서 설정한 HTTPRoute의 상세 정보를 확인합니다.
- 이 HTTPRoute 설정은 특정 호스트(api.example.com)로 들어오는 요청을 두 개의 백엔드 서비스 (my-workload-v1, my-workload-v2)로 50-50 비율로 분산시키도록 구성되어 있습니다. 요청의 경로가 /api/my-workload로 시작하는 경우에만 이 규칙이 적용됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# 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-workload-v2
Namespace: my-workload
Port: 8080
Weight: 50
Matches:
Path:
Type: PathPrefix
Value: /api/my-workload
...
🧿 curl 명령어를 사용하여 여러 번 요청을 보내고, 두 백엔드 서비스에서 반환한 응답을 확인합니다.
- 요청을 100 보내고 응답을 분석한 결과, 두 백엔드 서비스 간의 트래픽 분산이 약 56% 대 44% / 로 나타났습니다.
- my-workload-v1 서비스가 약간 더 많은 요청을 처리한 것으로 보입니다.
- 설정한 가중치(각각 50)에도 불구하고, 실제 트래픽 분산이 정확히 50-50이 아닐 수 있음을 보여줍니다. 이는 무작위 요청 처리나 시스템의 불규칙성 등 여러 요인으로 인해 발생할 수 있습니다.
(⎈|kind-myk8s:N/A) root@kind:~# 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
56 "body": "Hello From My Workload (v1)!",
44 "body": "Hello From My Workload (v2)!",
'쿠버네티스 네트워크 스터디 3기' 카테고리의 다른 글
[7주차] Service Mesh : Istio 통한 외부 노출 (0) | 2024.10.15 |
---|---|
[7주차] Service Mesh : Istio 설치 (Sidecar mode) (0) | 2024.10.15 |
[6주차] Ingress (0) | 2024.10.07 |
[5주차] IPVS (0) | 2024.10.03 |
[5주차] LoadBalancer - MetalLB (16) | 2024.10.02 |
Comments