上節講到當k8s集群多個業務需要80端口提供業務時,可以使用LoadBlance Service,但是存在一個問題,負載均衡器一般都是雲環境中廠商提供的時候才有,以往的經驗就是部署一個nginx 代理進行轉發,k8s也有相同的功能,就是Ingress,其后端控制器可以選擇Nginx、Haproxy等,常見的是Ingress Nginx。
本系列使用kubespray 離線部署時,選擇的Ingress后端控制器為nginx,講解的時候都以此為基礎。
創建web001資源配置文件:
[root@ylserver10686071 ~]# cat web001.yml apiVersion: apps/v1 kind: Deployment metadata: name: web001 namespace: prod spec: replicas: 2 selector: matchLabels: k8s-app: web001 template: metadata: labels: k8s-app: web001 spec: containers: - name: tomcat image: tomcat:8.0 ports: - name: web001-8080 containerPort: 8080 protocol: TCP --- kind: Service apiVersion: v1 metadata: name: web001-svc namespace: prod spec: type: ClusterIP ports: - name: web001-svc protocol: TCP port: 8080 targetPort: 8080 selector: k8s-app: web001
創建web001 ingress資源配置文件:
[root@ylserver10686071 ~]# cat web001-ingress.yml kind: Ingress apiVersion: networking.k8s.io/v1 metadata: name: web001-ingress namespace: prod annotations: kubernetes.io/ingress.class: nginx spec: rules: - host: web001.example.com http: paths: - path: / pathType: Prefix backend: service: name: web001-svc port: number: 8080
- kind: Ingress 指定資源類型為Ingress
- kubernetes.io/ingress.class: nginx Ingress Controller 類型,這里為 nginx,其他的還有haproxy、traefik、Istio等
- host: web001.example.com 匹配的域名,一個IP可以有多個域名
- path: / 結合 pathType: Prefix 表示匹配所有 / 為前綴的 URL
- backend 指定后端地址,這里以service 匹配來作為后端地址
創建web001 相關資源:
[root@ylserver10686071 ~]# kubectl apply -f web001.yml deployment.apps/web001 created service/web001-svc created [root@ylserver10686071 ~]# kubectl apply -f web001-ingress.yml ingress.networking.k8s.io/web001-ingress created [root@ylserver10686071 ~]#
查看資源相關信息,可以看到域名 web001.example.com 直接轉發到 POD 對應的端口地址:
[root@ylserver10686071 ~]# kubectl get pods -n prod -o wide|grep web001 web001-69bd6f8c5f-26hlv 1/1 Running 0 2m17s 10.233.75.69 ylserver10686071 <none> <none> web001-69bd6f8c5f-nvgmj 1/1 Running 0 2m17s 10.233.72.47 ylserver10686073 <none> <none> [root@ylserver10686071 ~]# kubectl describe ingress web001-ingress -n prod Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress Name: web001-ingress Namespace: prod Address: 10.68.60.71,10.68.60.72,10.68.60.73 Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>) Rules: Host Path Backends ---- ---- -------- web001.example.com / web001-svc:8080 (10.233.72.47:8080,10.233.75.69:8080) Annotations: kubernetes.io/ingress.class: nginx Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Sync 2m22s (x2 over 2m27s) nginx-ingress-controller Scheduled for sync Normal Sync 2m22s (x2 over 2m27s) nginx-ingress-controller Scheduled for sync Normal Sync 2m22s (x2 over 2m27s) nginx-ingress-controller Scheduled for sync [root@ylserver10686071 ~]#
修改本地電腦hosts表,將域名 web001.example.com 指向k8s集群地址,瀏覽器進行訪問:
###此處本地C:\Windows\System32\drivers\etc\hosts添加以下記錄 10.68.60.71 web001.example.com
將deployment web001的副本數調為3,可以看到ingress 后端會自動添加新的POD地址:
[root@ylserver10686071 ~]# kubectl scale deployment web001 -n prod --replicas=3 deployment.apps/web001 scaled [root@ylserver10686071 ~]# kubectl describe ingress web001-ingress -n prod Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress Name: web001-ingress Namespace: prod Address: 10.68.60.71,10.68.60.72,10.68.60.73 Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>) Rules: Host Path Backends ---- ---- -------- web001.example.com / web001-svc:8080 (10.233.67.40:8080,10.233.72.47:8080,10.233.75.69:8080) Annotations: kubernetes.io/ingress.class: nginx Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Sync 11m (x2 over 11m) nginx-ingress-controller Scheduled for sync Normal Sync 11m (x2 over 11m) nginx-ingress-controller Scheduled for sync Normal Sync 11m (x2 over 11m) nginx-ingress-controller Scheduled for sync [root@ylserver10686071 ~]#
Ingress 工作原理如上圖所示,分析下其運行原理:
- Ingress Controller 通過跟Ingress 交互得到域名對應的Service,接着通過Kubernetes API 獲取Service地址信息,最終將得到的信息寫入負載均衡器,負載均衡器reload該規則便可實現服務發現,即動態映射
- 外部請求進來時,負載均衡器攔截請求,比如nginx,最后根據域名相應規則轉發到對應的POD地址
- 基於以上原理,負載均衡器都是使用Daemonset部署到每台Node節點上,最后宿主機通過iptables dnat規則轉發到負載均衡器POD地址
實驗驗證一下,查看負載均衡器POD的IP地址:
[root@ylserver10686071 ~]# kubectl get pods -n ingress-nginx -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES ingress-nginx-controller-pnjkj 1/1 Running 0 14d 10.233.75.33 ylserver10686071 <none> <none> ingress-nginx-controller-qgwc2 1/1 Running 0 14d 10.233.72.35 ylserver10686073 <none> <none> ingress-nginx-controller-ttbxr 1/1 Running 1 14d 10.233.67.17 ylserver10686072 <none> <none> [root@ylserver10686071 ~]#
查看宿主機iptables dnat轉發規則:
[root@ylserver10686071 ingress_nginx]# iptables-save |grep "DNAT"|grep "destination" -A CNI-DN-a7c2c7254f00d8a8825ce -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.233.75.33:80 -A CNI-DN-a7c2c7254f00d8a8825ce -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.233.75.33:443 -A CNI-DN-a7c2c7254f00d8a8825ce -p tcp -m tcp --dport 10254 -j DNAT --to-destination 10.233.75.33:10254 [root@ylserver10686071 ingress_nginx]#
總結一下:
- k8s集群對外提供服務時,80和443端口復用除了使用負載均衡器外,比較常用的是使用Ingress Controller進行轉發
- Ingress Controller 規則可以動態加載,不會影響其他業務的正常運行
- Ingress Controller中使用負載均衡器時一些高級用法,例如client_max_body_size、timeout等可以通過相關的配置生效,一般都是在annotations 對象處進行屬性聲明。