Ingress
Ingress 是 Kubernetes 的一種 API 對象,将叢集内部的 Service 通過 HTTP/HTTPS 方式暴露到叢集外部,并通過規則定義 HTTP/HTTPS 的路由。Ingress 具備如下特性:叢集外部可通路的 URL、負載均衡、SSL Termination、按域名路由(name-based virtual hosting)。
Ingress Controller (通常需要負載均衡器配合)負責實作 Ingress API 對象所聲明的能力。如下圖所示:
- Ingress Controller 監聽所有 worker 節點上的 80/443 端口
- Ingress Controller 将所有對域名為 a.kuboard.cn 的 HTTP/HTTPS 請求路由到 Service B 的 9080 端口
- Service B 将請求進一步轉發到其标簽所選擇的 Pod 容器組(通過 targetPort 指定容器組上的端口号)
該圖中,請求被轉發的過程為:
- 假設您将 a.kuboard.cn 的 DNS 解析到了叢集中的一個 worker 節點的 IP 位址 192.168.2.69。(如果您的 worker 節點有外網位址,請使用外網位址,這樣您可以從外網通路您的服務)
- 從用戶端機器執行指令 curl http://a.kuboard.cn/abc/,該請求您将被轉發到 192.168.2.69 這個位址的 80 端口,并被 Ingress Controller 接收
- Ingress Controller 根據請求的域名 a.kuboard.cn 和路徑 abc 比對叢集中所有的 Ingress 資訊,并最終找到 Ingress B 中有這個配置,其對應的 Service 為 Service B 的 9080 端口
- Ingress Controller 通過 kube-proxy 将請求轉發到 Service B 對應的任意一個 Pod 上 與 Service B 的 9080 端口對應的容器端口上。(從 Ingress Controller 到 Pod 的負載均衡由 kube-proxy + Service 實作)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5COzYzYzEDNkRGOjJGZlRDZ2ETN4YTZjZmMmVWYygzY28CXwEzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL0M3Lc9CX6MHc0RHaiojIsJye.png)
Ingress Controller
如上所述,您必須在 Kubernetes 叢集中安裝了 Ingress Controller,您配置的 Ingress 才能生效。
劃重點
Ingress 隻是 Kubernetes 中的一種配置資訊;Ingress Controller 才是監聽 80/443 端口,并根據 Ingress 上配置的路由資訊執行 HTTP 路由轉發的元件。
Ingress Controller 有多種實作可供選擇,請參考 Kubernetes 官方文檔 Additional controllers
,比較常用的有 Nginx Ingress Controller for Kubernetes等。
在 Kubernetes中安裝Nginx Ingress Controller for Kubernetes
在您 Kubernetes 叢集中的安裝。該 Ingress Controller 以 DaemonSet 的類型部署到 Kubernetes,且監聽了 hostPort 80/443,YAML 片段如下所示:
如果您打算使用其他 Ingress Controller,您可以 解除安裝 Nginx Ingress Controller;如果您尚未安裝任何 Ingress Controller,請參考 安裝 Nginx Ingress Controller,以便可以完成本教程的後續内容。
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: nginx-ingress
namespace: nginx-ingress
# ...
spec:
selector:
matchLabels:
app: nginx-ingress
template:
metadata:
labels:
app: nginx-ingress
spec:
serviceAccountName: nginx-ingress
containers:
- image: nginx/nginx-ingress:1.5.3
name: nginx-ingress
ports:
- name: http
containerPort: 80
hostPort: 80
- name: https
containerPort: 443
hostPort: 443
TIP
- Ingress Controller 并非隻能監聽 80/443 端口,您可以根據自己網絡拓撲的需要,選擇合适的端口
- 根據您安裝 Ingress Controller 的方式不同,您的 Ingress Controller 并不一定監聽了所有 worker 節點的 80/443 端口(本教程不涉及此主題)
- 您也可以在 Kubernetes 叢集中安裝多種 Ingress Controller,請參考 Using multiple Ingress controllers
融入到網絡拓撲中
如前所述,Kubernetes Ingress 隻能監聽到節點的 80/443 端口,且 Ingress 可以完成 L7 路由的功能。由于 Kubernetes Ingress 配置更便捷,推薦使用 Kubernetes Ingress 替代正常的網際網路應用架構中的 Nginx 反向代理。那麼,如何使部署在内網的 Kubernetes 叢集上的 Ingress Controller 的 80/443 端口可以在外網通路到呢?
本教程推薦如下兩種做法,結合您自己對安全性、可靠性等因素的考量,您可以演化出适合自己的拓撲結構。
暴露單worker節點
如下圖所示,暴露單個 worker 節點的步驟如下:
- 為您 Kubernetes 叢集中的某一個 worker 節點配置外網 IP 位址 Z.Z.Z.Z
- 将您在 Ingress 中使用到的域名(假設是a.demo.kuboard.cn)解析到該外網 IP 位址 Z.Z.Z.Z
- 設定合理的安全組規則(開放該外網 IP 位址 80/443 端口的入方向通路)
文檔 安裝 Kubernetes 單Master節點 中使用的就是這種拓撲結構。這種方式下,Ingress Controller 存在單點故障的可能性。
使用外部負載均衡器
如下圖所示,使用外部負載均衡器的步驟如下:
- 建立一個叢集外部的負載均衡器,該負載均衡器擁有一個外網 IP 位址 Z.Z.Z.Z,并監聽 80/443 端口的 TCP 協定
- 将負載均衡器在 80/443 端口上監聽到的 TCP 請求轉發到 Kubernetes 叢集中所有(或某些)worker 節點的 80/443 端口,可開啟按源IP位址的會話保持
- 将您在 Ingress 中使用到的域名(假設是a.demo.kuboard.cn)解析到該負載均衡器的外網 IP 位址 Z.Z.Z.Z
文檔 安裝 Kubernetes 高可用 中使用的就是這種拓撲結構。
實戰:通過 Ingress 使您的應用程式在網際網路可用
前提
- 假設您已經完成了 公布應用程式 中的實戰部分
- 假設您已經将 Ingress 融入到您的網絡拓撲中,并且将 *.demo.kuboard.cn (請使用您自己的域名)解析到對應的外網 IP 位址 (暫時可以通過修改主機hosts檔案的方式來實作)
- 使用kubectl
建立檔案 nginx-deployment.yaml
vim nginx-deployment.yaml
檔案内容如下
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
建立檔案 nginx-service.yaml
vim nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
app: nginx
spec:
selector:
app: nginx
ports:
- name: nginx-port
protocol: TCP
port: 80
nodePort: 32600
targetPort: 80
type: NodePort
建立檔案 nginx-ingress.yaml
vim nginx-ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-ingress-for-nginx # Ingress 的名字,僅用于辨別
spec:
rules: # Ingress 中定義 L7 路由規則
- host: a.demo.kuboard.cn # 根據 virtual hostname 進行路由(請使用您自己的域名)
http:
paths: # 按路徑進行路由
- path: /
backend:
serviceName: nginx-service # 指定後端的 Service 為之前建立的 nginx-service
servicePort: 80
執行指令
kubectl apply -f nginx-deployment.yaml
kubectl apply -f nginx-service.yaml
kubectl apply -f nginx-ingress.yaml
kubectl get ingress -o wide
# 請使用您自己的域名,或者使用浏覽器通路(前提是已經修改了主機的hosts檔案)
curl a.demo.kuboard.cn