Advanced - Ingress
什麼是 Ingress
Ingress 是 Kubernetes 中用於管理外部 HTTP 和 HTTPS 流量進入集群內部服務的資源。它提供了一種靈活的方式來暴露服務,並允許根據路徑或主機名等條件實現流量路由。
為什麼需要 Ingress?
在 Kubernetes 中,常見的流量暴露方式有以下幾種:
- ClusterIP(預設):僅允許集群內部訪問服務。
- NodePort:將服務暴露在每個節點的指定端口上,外部流量可以通過節點 IP 和該端口訪問。
- LoadBalancer:依賴雲提供商的負載均衡器服務將流量分配到後端。
然而,當應用需要更高級的流量管理功能(例如路由、TLS 終止或虛擬主機支持)時,這些方式會變得繁瑣。Ingress 則是一種高效的解決方案。
Ingress 的功能
- 基於路徑的路由
- 根據 URL 路徑將流量導向不同的服務。
- 基於主機名的路由
- 根據請求的主機名實現虛擬主機支持。
- TLS 支持
- 配置 HTTPS 流量並終止 TLS。
- 負載均衡
- 自動 將流量分配給服務的後端 Pod。
- 反向代理
- 支持自訂的 HTTP 標頭。
Ingress Controller
Ingress 本身是一種 Kubernetes 資源,但需要搭配 Ingress Controller 使用。Ingress Controller 是實際負責處理流量並執行 Ingress 規則的實現。常見的 Ingress Controller 包括:
- NGINX Ingress Controller
- HAProxy Ingress Controller
- Traefik
- Istio Gateway
在安裝集群時,必須先部署至少一個 Ingress Controller 才能使 Ingress 資源生效。
實作一個 Ingress
安裝 Ingress
- 首先我們透過 kubectl 來安裝 nginx 的 Ingress Controller,我們可以看到他自動幫我們建立相關的服務
kubectl.exe apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml
---
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
serviceaccount/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
configmap/ingress-nginx-controller created
service/ingress-nginx-controller created
service/ingress-nginx-controller-admission created
deployment.apps/ingress-nginx-controller created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
ingressclass.networking.k8s.io/nginx created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
- 查看運作是否成功
kubectl.exe get all -n ingress-nginx
---
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-admission-create-zkf5b 0/1 Completed 0 60s
pod/ingress-nginx-admission-patch-8srbl 0/1 Completed 1 60s
pod/ingress-nginx-controller-644549d9cb-kj99l 1/1 Running 0 60s
...以下省略...
建立單一 Service
- 首先會建立一個 deployment 來創立兩個 pod
single-service/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: v1-deployment
labels:
type: demo
spec:
replicas: 2
selector:
matchLabels:
type: demo
template:
metadata:
labels:
type: demo
spec:
containers:
- name: v1-container
image: hello-world:v1.0.0
ports:
- containerPort: 8080
- 接著建立 Service 讓他可以通到這兩個 Pod 身上
single-service/service.yaml
apiVersion: v1
kind: Service
metadata:
name: v1-service
spec:
selector:
type: demo
ports:
- protocol: TCP
port: 8000
targetPort: 8080
nodePort: 30390
type: NodePort # 這裡我們將直接暴露的Loadbalancer改成NodePort
- 建立 ingress,我們設定 defaultBackend 讓所有流量都預設轉導到上面的 Service 中的 8000port,形成 loadbalancer -> servide -> pod 的流程
single-service/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: v1-ingress
spec:
ingressClassName: nginx
defaultBackend:
service:
name: v1-service
port:
number: 8000
- 透過 kubectl 指令,將他們全部跑起來,並查看狀態
kubectl.exe apply -f single-service\deployment.yaml,single-service\service.yaml,single-service\ingress.yaml
---
deployment.apps/v1-deployment created
service/v1-service created
ingress.networking.k8s.io/v1-ingress created
kubectl.exe get all
---
NAME READY STATUS RESTARTS AGE
pod/v1-deployment-5d8c74549f-2s86s 1/1 Running 0 35s
pod/v1-deployment-5d8c74549f-xrjbw 1/1 Running 0 35s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 97d
service/v1-service NodePort 10.99.160.139 <none> 8000:30390/TCP 35s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/v1-deployment 2/2 2 2 35s
NAME DESIRED CURRENT READY AGE
replicaset.apps/v1-deployment-5d8c74549f 2 2 2 35s
kubectl.exe get ingress
---
NAME CLASS HOSTS ADDRESS PORTS AGE
v1-ingress nginx * localhost 80 53s
- 透果指令來呼叫 8000port,看看是否可以通到最 裡面的 pod 並給予回應
(Invoke-WebRequest -Uri http://localhost -UseBasicParsing).Content
---
{"data":"Hello world v1!"}
建立 Fanout and Visual hosting
- 一樣定義 deployment,但這次我們有兩個 deployment,對應不同的版本
simple-fanout/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: v1-deployment
labels:
type: v1-demo
spec:
replicas: 2
selector:
matchLabels:
type: v1-demo
template:
metadata:
labels:
type: v1-demo
spec:
containers:
- name: v1-container
image: hello-world:v1.0.0
ports:
- containerPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: v2-deployment
labels:
type: v2-demo
spec:
replicas: 2
selector:
matchLabels:
type: v2-demo
template:
metadata:
labels:
type: v2-demo
spec:
containers:
- name: v2-container
image: hello-world:v2.0.0
ports:
- containerPort: 8080
- 接著也是定義 Service,我們建立兩個 Service,分別對應他們的 deployment
simple-fanout/service.yaml
apiVersion: v1
kind: Service
metadata:
name: v1-service
spec:
selector:
type: v1-demo
ports:
- protocol: TCP
port: 8000
targetPort: 8080
type: NodePort
---
apiVersion: v1
kind: Service
metadata:
name: v2-service
spec:
selector:
type: v2-demo
ports:
- protocol: TCP
port: 8000
targetPort: 8080
type: NodePort
- 在定義 ingress 的時候,我們設定不同的 host,讓他分別導向不同的 Service
simple-fanout/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
ingressClassName: nginx
rules:
- host: v1.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: v1-service
port:
number: 8000
- host: v2.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: v2-service
port:
number: 8000
- 透過 kubectl 來執行他們
kubectl.exe apply -f simple-fanout/deployment.yaml,simple-fanout/service.yaml,simple-fanout/ingress.yaml
---
deployment.apps/v1-deployment created
deployment.apps/v2-deployment created
service/v1-service created
service/v2-service created
ingress.networking.k8s.io/my-ingress created
- 我們透過 kubectl describe 來查看 Ingress 設定如何
kubectl.exe describe ingress my-ingress
---
Name: my-ingress
Labels: <none>
Namespace: default
Address: localhost
Ingress Class: nginx
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
v1.com
/ v1-service:8000 (10.1.1.11:8080,10.1.1.13:8080)
v2.com
/ v2-service:8000 (10.1.1.12:8080,10.1.1.14:8080)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 38s (x2 over 86s) nginx-ingress-controller Scheduled for sync
- 透過修改 host,讓虛擬網域都設定為本機上,在檔案最後面都加上映射的網域
Windows
notepad C:\WINDOWS\system32\drivers\etc\hosts
---
// 在最後面加上下面這兩行,並存檔
127.0.0.1 v1.com
127.0.0.1 v2.com
Linux
sudo vim /etc/hosts
// 在最後面加上下面這兩行
127.0.0.1 v1.com
127.0.0.1 v2.com
// 存檔
:wq!
- 使用指令測試看看,成功的話就大功告成了!
(Invoke-WebRequest -Uri http://v1.com -UseBasicParsing).Content
---
{"data":"Hello world v1!"}
(Invoke-WebRequest -Uri http://v2.com -UseBasicParsing).Content
---
{"data":"Hello world v2!"}