Kubernetes Ingress實戰
本節內容:
- 服務發現與負載均衡
- Ingress實戰
一、服務發現與負載均衡
在前面的安裝部署kubernetes集群中已經簡單用示例來演示了Pod和Service,Kubernetes通過Service資源在Kubernetes集群內針對容器實現了服務發現和負載均衡。而Service就是kubernetes服務發現與負載均衡中的一種。
目前,kubernetes中的負載均衡大致可以分為以下幾種機制,每種機制都有其特定的應用場景:
- Service:直接用Service提供cluster內部的負載均衡,並借助cloud provider提供的LB提供外部訪問
- Ingress Controller:還是用Service提供cluster內部的負載均衡,但是通過自定義LB提供外部訪問
- Service Load Balancer:把load balancer直接跑在容器中,實現Bare Metal的Service Load Balancer
- Custom Load Balancer:自定義負載均衡,並替代kube-proxy,一般在物理部署Kubernetes時使用,方便接入公司已有的外部服務
1. Service
Service是對一組提供相同功能的Pods的抽象,並為它們提供一個統一的入口。借助Service,應用可以方便的實現服務發現與負載均衡,並實現應用的零宕機升級。Service通過標簽來選取服務後端,一般配合Replication Controller或者Deployment來保證後端容器的正常運行。這些匹配標簽的Pod IP和端口列表組成endpoints,由kube-proxy負責將服務IP負載均衡到這些endpoints上。
Service有四種類型:
- ClusterIP:默認類型,自動分配一個僅cluster內部可以訪問的虛擬IP
- NodePort:在ClusterIP基礎上為Service在每臺機器上綁定一個端口,這樣就可以 通過 <NodeIP>:NodePort 來訪問該服務
- LoadBalancer:在NodePort的基礎上,借助cloud provider創建一個外部的負載均 衡器,並將請求轉發到 <NodeIP>:NodePort
- ExternalName:將服務通過DNS CNAME記錄方式轉發到指定的域名(通 過 spec.externlName 設定)。需要kube-dns版本在1.7以上。
另外,也可以將已有的服務以Service的形式加入到Kubernetes集群中來,只需要在創建 Service的時候不指定Label selector,而是在Service創建好後手動為其添加endpoint。
Service雖然解決了服務發現和負載均衡的問題,但它在使用上還是有一些限制,比如
- 只支持4層負載均衡,沒有7層功能
- 對外訪問的時候,NodePort類型需要在外部搭建額外的負載均衡,而LoadBalancer要求kubernetes必須跑在支持的cloud provider上面。
2. Ingress和Ingress Controller簡介
(1)Ingress
Ingress就是為了解決這些限制而引入的新資源,主要用來將服務暴露到cluster外面,並且可以自定義服務的訪問策略。比如想要通過負載均衡器實現不同子域名到不同服務的訪問:
foo.bar.com --| |-> foo.bar.com s1:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com s2:80
可以這樣來定義Ingress:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test spec: rules: - host: foo.bar.com http: paths: - backend: serviceName: s1 servicePort: 80 - host: bar.foo.com http: paths: - backend: serviceName: s2 servicePort: 80
【註意】:Ingress本身並不會自動創建負載均衡器,cluster中需要運行一個ingress controller來根據Ingress的定義來管理負載均衡器。
目前社區提供了 nginx和gce的參考實現
簡單的說,ingress就是從kubernetes集群外訪問集群的入口,將用戶的URL請求轉發到不同的service上。Ingress相當於nginx、apache等負載均衡方向代理服務器,其中還包括規則定義,即URL的路由信息,路由信息得的刷新由Ingress controller來提供。
(2)Ingress Controller
Ingress Controller 實質上可以理解為是個監視器,Ingress Controller 通過不斷地跟 kubernetes API 打交道,實時的感知後端 service、pod 等變化,比如新增和減少 pod,service 增加與減少等;當得到這些變化信息後,Ingress Controller 再結合下文的 Ingress 生成配置,然後更新反向代理負載均衡器,並刷新其配置,達到服務發現的作用。
二、Ingress實戰
在使用Ingress resource之前,有必要先了解下面幾件事情。Ingress是beta版本的resource,在kubernetes1.1之前還沒有。你需要一個Ingress Controller來實現Ingress,單純的創建一個Ingress沒有任何意義。
目前社區提供了 nginx和gce的參考實現。當然還有其他實現,開源的 NGINX 和 NGINX Plus 開發了相應的 Ingress controller。
- GCE/GKE會在master節點上部署一個ingress controller。你可以在一個pod中部署任意個自定義的ingress controller。你必須正確地annotate每個ingress,比如 運行多個ingress controller 和 關閉glbc
- 在非GCE/GKE的環境中,你需要在pod中部署一個controller。
(1)使用 NGINX 和 NGINX Plus 的 Ingress Controller 進行 Kubernetes 的負載均衡
https://github.com/nginxinc/kubernetes-ingress/tree/master/examples/complete-example
[root@node1 nginx_ingress]# kubectl create -f nginx-ingress-rbac.yaml [root@node1 nginx_ingress]# kubectl create -f default-server-secret.yaml secret "default-server-secret" created [root@node1 nginx_ingress]# kubectl create -f nginx-ingress-rc.yaml replicationcontroller "nginx-ingress-rc" created [root@node1 nginx_ingress]# kubectl get pods -l app=nginx-ingress -o wide NAME READY STATUS RESTARTS AGE IP NODE nginx-ingress-rc-rs1vh 1/1 Running 0 37s 172.30.87.4 172.16.7.151 # 查看pod日誌 [root@node1 nginx_ingress]# kubectl logs nginx-ingress-rc-rs1vh I0924 07:27:37.663514 1 main.go:58] Starting NGINX Ingress controller Version 1.0.0 2017/09/24 07:27:37 [notice] 20#20: signal process started I0924 07:27:37.975349 1 event.go:218] Event(v1.ObjectReference{Kind:"Secret", Namespace:"default", Name:"default-server-secret", UID:"4e2d9567-9f5a-11e7-9acc-005056b7609a", APIVersion:"v1", ResourceVersion:"1019701", FieldPath:""}): type: ‘Normal‘ reason: ‘Updated‘ the default server Secret default/default-server-secret was updated 2017/09/24 07:27:37 [notice] 26#26: signal process started 2017/09/24 07:27:38 [notice] 30#30: signal process started 2017/09/24 07:27:38 [notice] 34#34: signal process started 2017/09/24 07:27:38 [notice] 38#38: signal process started I0924 07:27:38.073475 1 event.go:218] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"kube-system", Name:"traefik-web-ui", UID:"5d604da9-9f61-11e7-9acc-005056b7609a", APIVersion:"extensions", ResourceVersion:"1024008", FieldPath:""}): type: ‘Normal‘ reason: ‘AddedOrUpdated‘ Configuration for kube-system/traefik-web-ui was added or updated 2017/09/24 07:27:38 [notice] 44#44: signal process started I0924 07:27:38.100887 1 event.go:218] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"traefik-ingress", UID:"5d693739-9f61-11e7-9acc-005056b7609a", APIVersion:"extensions", ResourceVersion:"1024009", FieldPath:""}): type: ‘Normal‘ reason: ‘AddedOrUpdated‘ Configuration for default/traefik-ingress was added or updated
(2)配置需要測試的service
部署兩個服務nginx 1.7和nginx 1.8:
apiVersion: v1 kind: Service metadata: name: frontend spec: ports: - port: 80 targetPort: 80 selector: app: nginx1-7 --- apiVersion: apps/v1beta1 kind: Deployment metadata: name: nginx1-7-deployment spec: replicas: 2 template: metadata: labels: app: nginx1-7 spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80nginx1-7.yaml
apiVersion: v1 kind: Service metadata: name: my-nginx spec: ports: - port: 80 targetPort: 80 selector: app: nginx1-8 --- apiVersion: apps/v1beta1 kind: Deployment metadata: name: nginx1-8-deployment spec: replicas: 2 template: metadata: labels: app: nginx1-8 spec: containers: - name: nginx image: nginx:1.8 ports: - containerPort: 80nginx1-8.yaml
[root@node1 nginx_ingress]# kubectl create -f nginx1-7.yaml service "frontend" created deployment "nginx1-7-deployment" created [root@node1 nginx_ingress]# kubectl create -f nginx1-8.yaml service "my-nginx" created deployment "nginx1-8-deployment" created
(3)創建Ingress
假設這兩個服務要暴露到集群外部。要創建一個ingress:
[root@node1 nginx_ingress]# vim test-ingress.yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test spec: rules: - host: n17.my.com http: paths: - backend: serviceName: nginx1-7 servicePort: 80 - host: n18.my.com http: paths: - backend: serviceName: nginx1-8 servicePort: 80
創建ingress:
[root@node1 nginx_ingress]# kubectl create -f test-ingress.yaml ingress "test" created [root@node1 nginx_ingress]# kubectl get ing NAME HOSTS ADDRESS PORTS AGE test n17.my.com,n18.my.com 80 52s
打開客戶機的/etc/hosts,配置172.16.7.151和n17.my.com,n18.my.com的對應關系,然後在瀏覽器訪問n17.my.com或n18.my.com就可以訪問到對應的服務。
如果想修改訪問規則,修改test-ingress.yaml,使用kubectl replace -f更新就可以了。
Kubernetes Ingress實戰