在 Kubernetes 集群中,Ingress是授權入站連接到達集群服務的規則集合,為您提供七層負載均衡能力。您可以給 Ingress 配置提供外部可訪問的 URL、負載均衡、SSL、基於名稱的虛擬主機等。
目前主要廣泛應用的有:Nginx、Traefik、Envoy三種
一、K8S服務暴露介紹
從 kubernetes 1.2 版本開始,kubernetes提供了 Ingress 對象來實現對外暴露服務;到目前為止 kubernetes 總共有三種暴露服務的方式:
- LoadBlancer Service
- NodePort Service
- Ingress
1、LoadBlancer Service
LoadBlancer Service 是 kubernetes 深度結合雲平台的一個組件;當使用 LoadBlancer Service 暴露服務時,實際上是通過向底層雲平台申請創建一個負載均衡器來向外暴露服務;目前 LoadBlancer Service 支持的雲平台已經相對完善,比如國外的 GCE、DigitalOcean,國內的 阿里雲,私有雲 Openstack 等等,由於 LoadBlancer Service 深度結合了雲平台,所以只能在一些雲平台上來使用
2、NodePort Service
NodePort Service 顧名思義,實質上就是通過在集群的每個 node 上暴露一個端口,然后將這個端口映射到某個具體的 service 來實現的,雖然每個 node 的端口有很多(0~65535),但是由於安全性和易用性(服務多了就亂了,還有端口沖突問題)實際使用可能並不多
3、Ingress
使用Ingress時一般會有三個組件:
- 反向代理負載均衡器
- Ingress Controller
- Ingress
3.1、反向代理負載均衡器
反向代理負載均衡器很簡單,說白了就是 nginx、apache 等中間件,新版k8s已經將Nginx與Ingress Controller合並為一個組件,所以Nginx無需單獨部署,只需要部署Ingress Controller即可
在集群中反向代理負載均衡器可以自由部署,可以使用 Replication Controller、Deployment、DaemonSet 等等方式
3.2、Ingress Controller
Ingress Controller 實質上可以理解為是個監視器,Ingress Controller 通過不斷地跟 kubernetes API 打交道,實時的感知后端 service、pod 等變化,比如新增和減少 pod,service 增加與減少等;當得到這些變化信息后,Ingress Controller 再結合下文的 Ingress 生成配置,然后更新反向代理負載均衡器,並刷新其配置,達到服務發現的作用
3.3、Ingress
Ingress 簡單理解就是個規則定義;比如說某個域名對應某個 service,即當某個域名的請求進來時轉發給某個 service;這個規則將與 Ingress Controller 結合,然后 Ingress Controller 將其動態寫入到負載均衡器配置中,從而實現整體的服務發現和負載均衡
整體關系如下圖所示:
從上圖中可以很清晰的看到,實際上請求進來還是被負載均衡器攔截,比如 nginx,然后 Ingress Controller 通過跟 Ingress 交互得知某個域名對應哪個 service,再通過跟 kubernetes API 交互得知 service 地址等信息;綜合以后生成配置文件實時寫入負載均衡器,然后負載均衡器 reload 該規則便可實現服務發現,即動態映射
二、Ingress是授權入站連接到達集群服務的規則集合
- 從外部流量調度到nodeprot上的service
- 從service調度到ingress-controller
- ingress-controller根據ingress中的定義(虛擬主機或者后端的url)
- 根據虛擬主機名調度到后端的一組pod中
再來一張整體流程圖:
Ingress中Nginx-Ingress工作原理:
- ingress controller通過和kubernetes api交互,動態的去感知集群中ingress規則變化,
- 然后讀取它,按照自定義的規則,規則就是寫明了哪個域名對應哪個service,生成一段nginx配置,
- 再寫到nginx-ingress-control的pod里,這個Ingress controller的pod里運行着一個Nginx服務,控制器會把生成的nginx配置寫入/etc/nginx.conf文件中,
- 然后reload一下使配置生效。以此達到域名分配置和動態更新的問題。
三、安裝部署
首先說明一下使用Ingress功能的步驟:
1.安裝部署Ingress Controller Pod
2.部署后端服務
3.部署Ingress-Nginx service
4.部署Ingress
1、下載yaml文件
部署文件介紹
1. mandatory.yaml
配置部署的主文件,也是以下各yaml文件的合集,一般情況下只需要修改部署此文件即可。
2.namespace.yaml
創建一個獨立的命名空間 ingress-nginx
3.configmap.yaml
ConfigMap是存儲通用的配置變量的,類似於配置文件,使用戶可以將分布式系統中用於不同模塊的環境變量統一到一個對象中管理;而它與配置文件的區別在於它是存在集群的“環境”中的,並且支持K8S集群中所有通用的操作調用方式。
從數據角度來看,ConfigMap的類型只是鍵值組,用於存儲被Pod或者其他資源對象(如RC)訪問的信息。這與secret的設計理念有異曲同工之妙,主要區別在於ConfigMap通常不用於存儲敏感信息,而只存儲簡單的文本信息。
ConfigMap可以保存環境變量的屬性,也可以保存配置文件。
創建pod時,對configmap進行綁定,pod內的應用可以直接引用ConfigMap的配置。相當於configmap為應用/運行環境封裝配置。
pod使用ConfigMap,通常用於:設置環境變量的值、設置命令行參數、創建配置文件。
4.rbac.yaml
負責Ingress的RBAC授權的控制,其創建了Ingress用到的ServiceAccount、ClusterRole、Role、RoleBinding、ClusterRoleBinding
5.with-rbac.yaml
是Ingress的核心,用於創建ingress-controller。前面提到過,ingress-controller的作用是將新加入的Ingress進行轉化為Nginx的配置
2、部署Ingress-nginx,當前最新版本0.21.0
把上面的mandatory.yaml文件下載好后,先替換里面的image,再進行部署
# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
# sed -i 's#quay.io/kubernetes-ingress-controller#registry-vpc.cn-beijing.aliyuncs.com/xiaoban#g' mandatory.yaml
# kubectl apply -f mandatory.yaml
namespace/ingress-nginx created
configmap/nginx-configuration created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.extensions/nginx-ingress-controller created
3、配置自由調度 node
# ingress 有多種方式 1. deployment 自由調度 replicas
2. daemonset 全局調度 分配到所有node里(資源耗費嚴重)
# deployment 自由調度過程中,由於我們需要 約束 controller 調度到指定的 node 中,所以需要對 node 進行 label 標簽
# kubectl label nodes es-61 ingress=proxy
# kubectl get nodes --show-labels
需要對with-rbac.yaml文件部分進行修改
spec: replicas: 2 .... spec: serviceAccountName: nginx-ingress-serviceaccount #hostNetwork: true nodeSelector: ingress: proxy #跟上面設置的label對應好 ....
采用裸機部署的話最好固定NodePort
# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/baremetal/service-nodeport.yaml
# vim service-nodeport.yaml apiVersion: v1 kind: Service metadata: name: ingress-nginx namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: type: NodePort ports: - name: http port: 80 targetPort: 80 protocol: TCP nodePort: 30080 - name: https port: 443 targetPort: 443 protocol: TCP nodePort: 30443 selector: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx ---
部署一個服務進行驗證:

apiVersion: v1 kind: Service metadata: name: myapp namespace: default spec: selector: app: myapp release: canary ports: - name: http targetPort: 80 port: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp-backend-pod namespace: default spec: replicas: 2 selector: matchLabels: app: myapp release: canary template: metadata: labels: app: myapp release: canary spec: containers: - name: myapp image: ikubernetes/myapp:v7 ports: - name: http containerPort: 80
新建ingress規則:
# vim ingress-myapp.yaml
apiVersion: extensions/v1beta1 #api版本 kind: Ingress #清單類型 metadata: #元數據 name: ingress-myapp #ingress的名稱 namespace: default #所屬名稱空間 annotations: #注解信息 kubernetes.io/ingress.class: "nginx" spec: #規格 rules: #定義后端轉發的規則 - host: myapp.wjoyxt.com #通過域名進行轉發 http: paths: - path: #配置訪問路徑,如果通過url進行轉發,需要修改;空默認為訪問的路徑為"/" backend: #配置后端服務 serviceName: myapp servicePort: 80
查看ingress-myapp的詳細信息
# kubectl describe ing ingress-myapp
查看nginx-ingress-controller是否注入了nginx的配置
# kubectl exec -n ingress-nginx nginx-ingress-controller-5c84666c56-b7xgz cat /etc/nginx/nginx.conf | less
此時在本地執行 curl -H "Host:myapp.wjoyxt.com" 172.17.213.60:30080 即可看到結果。
使用反向代理的話,修改對應的ingress規則即可,比如:
# vim ingress-app.yaml apiVersion: extensions/v1beta1 #api版本 kind: Ingress #清單類型 metadata: #元數據 name: ingress-myapp #ingress的名稱 namespace: default #所屬名稱空間 annotations: #注解信息 nginx.ingress.kubernetes.io/rewrite-target: / #重寫/路徑 spec: #規格 rules: #定義后端轉發的規則 - host: myapp.wjoyxt.com #通過域名進行轉發 http: paths: - path: /app1 #配置訪問路徑,如果通過url進行轉發,需要修改;空默認為訪問的路徑為"/" backend: #配置后端服務 serviceName: myapp servicePort: 80
此時,訪問 myapp.wjoyxt.com:30080/app1 即可。
4、配置基於域名的 https,ingress
創建基於自身域名的證書
#openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout myapp.wjoyxt.com.key -out myapp.wjoyxt.com.pem -subj "/CN=myapp.wjoyxt.com"
導入域名的證書到集群的secret中,名稱自定義
# kubectl create secret tls myapp-ingress-secret --namespace=kube-system --cert myapp.wjoyxt.com.pem --key myapp.wjoyxt.com.key
查看secret
[root@es-60 ~]# kubectl get secret -n kube-system NAME TYPE DATA AGE myapp-ingress-secret kubernetes.io/tls 2 8s
[root@es-60 ~]# kubectl describe secret myapp-ingress-secret -n kube-system
Name: myapp-ingress-secret
Namespace: kube-system
Labels: <none>
Annotations: <none>
Type: kubernetes.io/tls
Data
====
tls.crt: 1115 bytes
tls.key: 1704 bytes
將證書應用到對應的服務中,更新服務的ingress
# vim ingress-app.yaml apiVersion: extensions/v1beta1 #api版本 kind: Ingress #清單類型 metadata: #元數據 name: ingress-myapp #ingress的名稱 namespace: default #所屬名稱空間 annotations: #注解信息 kubernetes.io/ingress.class: "nginx" spec: #規格 tls: - hosts: - myapp.wjoyxt.com #與secret證書的域名需要保持一致 secretName: myapp-ingress-secret rules: #定義后端轉發的規則 - host: myapp.wjoyxt.com #通過域名進行轉發 http: paths: - path: #配置訪問路徑,如果通過url進行轉發,需要修改;空默認為訪問的路徑為"/" backend: #配置后端服務 serviceName: myapp servicePort: 80
# kubectl apply -f ingress-app.yaml #重新部署,更新nginx配置
此時可以實現 https://myapp.wjoyxt.com:30443 訪問