1. 程式人生 > >Kubernetes Ingress實戰

Kubernetes Ingress實戰

環境 rules upd 機制 onf acc paths multipl 支持

本節內容:

  • 服務發現與負載均衡
  • 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有四種類型:

  1. ClusterIP:默認類型,自動分配一個僅cluster內部可以訪問的虛擬IP
  2. NodePort:在ClusterIP基礎上為Service在每臺機器上綁定一個端口,這樣就可以 通過 <NodeIP>:NodePort 來訪問該服務
  3. LoadBalancer:在NodePort的基礎上,借助cloud provider創建一個外部的負載均 衡器,並將請求轉發到 <NodeIP>:NodePort
  4. 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: 80
nginx1-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: 80
nginx1-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實戰