Kubernetes Ingress管理

Ingress介紹

Kubernetes暴露服務的方式目前有三種:LoadBlancer Service、NodePort Service、Ingress。node

在詳細說明Ingress以前,咱們先大概的說一說,kubernetes集中內服務想要暴露出去須要面臨的幾個問題:nginx

一、Pod漂移問題

衆所周知,kubernetes具備強大的副本控制能力,能保證在任意副本(Pod)掛掉時自動從其餘 節點上啓動一個新的,還能夠動態擴縮容等。也就是說單個pod可能在任什麼時候刻出如今任何節點上,也可能在任什麼時候刻死在任何節點上。那麼隨着pod的建立和銷燬,pod ip也會隨着動態變化。那麼如何把這個動態的pod ip暴露出去?爲了解決這個問題,kubernetes引入了service機制。service能夠以標籤的形式選定一組帶有指定標籤的pod,並監控和自動負載他們的pod ip,這樣一來,咱們就只須要向外暴露service的ip就能夠了,這就是nodeport的模式:即在每一個節點上開啓一個端口,而後轉發到內部service ip上。以下圖:git

node port

二、端口管理問題

在上面的問題中,咱們經過引入Service並暴露nodeport的方式解決了pod的漂移問題。可是咱們在引入nodeport後,又會面臨一個新的問題:隨着服務愈來愈多,咱們在每一個node節點上開啓的nodeport也會愈來愈多,最終變得難以維護。這時候,就引入了一種新的思考方式:能不能使用nginx或者haproxy等負載均衡的方式只監聽一個端口,好比80,而後按照域名日後端轉發?固然能夠,最簡單的實現就是使用daemonset的方式在node上監聽80,而後配置好轉發規則。由於nginx外網綁定了宿主機80端口(就像nodeport),自己又在集羣內,直接向後轉發到相應的service ip便可。以下圖所示:github

nginx 轉發

三、域名分配及動態更新問題

從上面的思路,採用nginx彷佛已經解決問題了。但其實這裏面有一個很大的缺陷:每次有新服務加入,怎麼樣修改nginx配置?總不能每次都手動改下nginx鏡像,而後再來個rolling update前端的nginx pod吧?redis

由此,kubernetes引入了ingress。ingress簡單的理解就是,你原來要改nginx配置,而後配置各類域名對應哪一個service,如今把這個動做抽象出來,變成了一個ingress對象,能夠直接使用yml來建立。這樣就不用不每次去修改nginx了,直接修改yml,而後更新便可。後端

Ingress一共包含三大組件:Ingress、Ingress Controller以及Nginx。Ingress Controller經過與kubernetes api交互,動態的去感知集羣中ingress規則變化,而後讀取它,再按照本身的模板生成一段nginx配置,再寫到nginx pod裏,最後reload一下nginx。工做流以下圖:api

Ingress

在實際部署中,kubernetes已經將nginx和ingress controller合併爲一個組件,因此nginx無需單獨部署,只須要部署ingress controller便可。網絡

Nginx Ingress配置

一、部署默認後端

咱們知道前端的Nginx最終要負載到後端service上,那麼若是訪問到不存在的域名怎麼辦?官方給出的建議是部署一個默認後端,對於未知請求所有負載到這個默認後端上,這個後端別的事啥也不幹,只是返回一個404。架構

部署以下:

kubectl create -f default-backend.yml

default-backend.yml文件能夠直接在官方Ingress倉庫找到,下面給出一個詳細地址:

https://raw.githubusercontent.com/kubernetes/ingress/master/examples/deployment/nginx/default-backend.yaml

二、部署Ingress Controller

Ingress Controller官方提供了多種方式部署。我的仍是推薦使用Daemonset的方式,官方也有給出的示例文件,能夠參考這裏

個人配置相對於官方示例文件,有一點小小的改動,貼在下面:

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: nginx-ingress-lb
  labels:
    name: nginx-ingress-lb
  namespace: kube-system
spec:
  template:
    metadata:
      labels:
        name: nginx-ingress-lb
      annotations:
        prometheus.io/port: '10254'
        prometheus.io/scrape: 'true'
    spec:
      terminationGracePeriodSeconds: 60
      #hostNetwork: true #看到網上有人講,須要指定該配置項才能生效,但我在實際測試中,並不須要此項,多是由於採用的網絡架構不同,備註一下,以作說明。
      containers:
      - image: dk-reg.op.douyuyuba.com/library/nginx-ingress-controller:0.9.0-beta.8
        name: nginx-ingress-lb
        readinessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
        livenessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          timeoutSeconds: 1
        ports:
        - containerPort: 80
          hostPort: 80
        - containerPort: 443
          hostPort: 443
        env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        args:
        - /nginx-ingress-controller
        - --default-backend-service=kube-system/default-http-backend
        - --apiserver-host=http://10.1.61.132:8080 #ingress默認經過https鏈接api server,由於我這裏api server僅支持https,因此須要指定--apiserver-host的地址

部署:

kubectl create -f ingress-nginx-daemonset.yml

三、部署Ingress

前面咱們說到Ingress其實就是個規則,指定哪一個域名轉發到哪一個service,因此說首先得有個service。不過service的具體配置這裏不做說明。咱們就以kubernetes-dashboard和kibana爲例:

kubectl get svc kubernetes-dashboard --namespace=kube-system
NAME                   CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE       
kubernetes-dashboard   10.254.213.109   <none>        80/TCP    13d       
kibana                 10.254.213.110   <none>        5601/TCP    13d

建立一個dashboard-kibana-ingress.yml以下:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: dashboard-kibana-ingress
  namespace: kube-system
spec:
  rules:
  - host: dashboard.dz11.com
    http:
      paths:
      - path: /
        backend:
          serviceName: kubernetes-dashboard
          servicePort: 80
  - host: kibana.dz11.com
    http:
      paths:
      - backend:
          serviceName: kibana
          servicePort: 5601

部署:

kubectl create -f dashboard-kibana-ingress.yml

四、配置Ingress TLS

默認狀況下,ingress只提供了http服務,而沒有https服務,要部署一個https服務,首先得有https證書。證書的生成,這裏不作說明。

建立secret

假定,咱們如今已經有了一個ca.crt的證書文件和一個server.key的密鑰文件。咱們須要建立一個secret。在建立secret以前,先要把證書及密鑰內容經過base64編碼。以下:

cat ca.crt | base64 -w 0
cat server.key|base64 -w 0

建立ingress-secret.yml文件,內容以下:

apiVersion: v1
kind: Secret
metadata:
  name: ingress-secret
  namespace: default
type: kubernetes.io/tls
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlIWlRDQ0JrMmdBd0lCQWdJTUxQbnRoUStHZlJJOTNHd0dNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1HQXhDekFKDQpCZ05WQkFZVEFrSkZNUmt3RndZRFZRUUtFeEJIYkc5aVlXeFRhV2R1SUc1MkxYTmhNVFl3TkFZRFZRUURFeTFIDQpiRzlpWVd4VGFXZHVJRVJ2YldGcGJpQldZV3hwWkdGMGFXOXVJRU5CSUMwZ1UwaEJNalUySUMwZ1J6SXdIaGNODQpNVGN3TlRJMU1EWTBNRFEyV2hjTk1UZ3hNVEk0TWpNMU9UVTVXakE0TVNFd0h3WURWUVFMRXhoRWIyMWhhVzRnDQpRMjl1ZEhKdmJDQldZV3hwWkdGMFpXUXhFekFSQmdOVkJBTU1DaW91WkhveE1TNWpiMjB3Z2dFaU1BMEdDU3FHDQpTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDaTA5bjg0WGdhWGo0YStvaERyQXJONWVLeEpYbXV0QmJNDQpqNVFJdEZDa2l0dUg3OWxtNmtMcThSL2E0ZHdEc1h6czZXVWNRRHBjbUlqNzdOYlBQYzJrZVZlcDMxeVZLSUpKDQpkYWhFd2V5NlVFBQeWwwS2xOeFdMODhETGtMZUFvby8rNVNBaUIzUktsUUswMXREWnIrem4rYkxZVUQ4YzU4DQ
  tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBb3RQWi9PRjRHbDQrR3ZxSVE2d0t6ZVhpc1NWNXJyUVd6SStVQ0xSUXBJcmJoKy9aClp1cEM2dkVmMnVIY0E3Rjg3T2xsSEVBNlhKaUkrK3pXenozTnBIbFhxZDljbFNpQ1NYV29STUhzdWtKL1RFbUcKRUhsOTI3M1BFZU1QclhqSUpEeC85K1ZQRUlFRnlHc3hYamFaR2FtZnJYNmJvMVVFaExlMlEySVpWMDh1UU1EMQpUTVArb0VyZHY1MkUzZlAyxxxxxNBSjNUNWtrUm5IaE5TWDFIankySnFBcHNDYW5pKzI4MmV2NGlYYkwwCks1NVA4N3BqdGw4WGtWTGZDbXJYTSt6dEs4aGNkQ3ZCOHU0NkpNRWQ2R1JjeXpBWHJ6b1dYM3RxUGVDdGxrazgKcEVMRXVFSmJpV2hYRjZEVUtlK1NpeHIyMTJHdm5JcncreTBxendJREFRQUJBb0lCQVFDTFhTSWQ1R2xrd0RjTgo1bE1OQU1xNmtrRmw5N3BmZ25wbEdack5uRy9OZGFBU2lJS2VLSEdnSDBOeGw1RTFoQXQxeHdvb2xQeWUxbHVnCnJJVHJHbTNSa1o0cm9pYmU

執行建立:

kubect create -f ingress-secret.yml

也能夠經過命令行的方式直接建立一個secret:

kubectl create secret tls ingress-secret --key server.key --cert ca.crt

修改ingress,開啓tls

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: dashboard-kibana-ingress
  namespace: kube-system
spec:
  tls:
  - hosts:
    - dashboard.dz11.com
    - kibana.dz11.com
    secretName: ingress-secret
  rules:
  - host: dashboard.dz11.com
    http:
      paths:
      - path: /
        backend:
          serviceName: kubernetes-dashboard
          servicePort: 80
  - host: kibana.dz11.com
    http:
      paths:
      - path: /
        backend:
          serviceName: kibana
          servicePort: 5601

注意:一個 Ingress 只能使用一個 secret(secretName 段只能有一個),也就是說只能用一個證書,更直白的說就是若是你在一個 Ingress 中配置了多個域名,那麼使用 TLS 的話必須保證證書支持該 Ingress 下全部域名;而且這個 secretName 必定要放在上面域名列表最後位置,不然會報錯 did not find expected key 沒法建立;同時上面的 hosts 段下域名必須跟下面的 rules 中徹底匹配

更須要注意一點:Kubernetes Ingress默認狀況下,當你不配置證書時,會默認給你一個 TLS 證書的,也就是說你 Ingress 中配置錯了,好比寫了2個 secretName、或者 hosts 段中缺了某個域名,那麼對於寫了多個 secretName 的狀況,全部域名全會走默認證書;對於 hosts 缺了某個域名的狀況,缺失的域名將會走默認證書,部署時必定要驗證一下證書,不能 「有了就行」;更新 Ingress 證書可能須要等一段時間纔會生效

一旦部署了https,默認請求的http會自動跳轉到https,因此在同時須要https和http並存的應用場景,也須要注意

最後從新部署下ingress便可:

kubectl delete -f dashboard-kibana-ingress.yml
kubectl create -f dashboard-kibana-ingress.yml

五、經過ingress暴露tcp服務

經過ingress暴露tcp服務,咱們須要先定義一個nginx-tcp-ingress-configmap.yaml的configmap,示例以下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: tcp-configmap-example
data:
  9000: "default/redis:6379"

配置ingress controller的yaml文件,以下:

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: nginx-ingress-lb
  labels:
    name: nginx-ingress-lb
  namespace: kube-system
spec:
  template:
    metadata:
      labels:
        name: nginx-ingress-lb
      annotations:
        prometheus.io/port: '10254'
        prometheus.io/scrape: 'true'
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - image: dk-reg.op.douyuyuba.com/library/nginx-ingress-controller:0.9.0-beta.8
        name: nginx-ingress-lb
        readinessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
        livenessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          timeoutSeconds: 1
        ports:
        - containerPort: 80
          hostPort: 80
        - containerPort: 443
          hostPort: 443
        env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        args:
        - /nginx-ingress-controller
        - --default-backend-service=kube-system/default-http-backend
        - --apiserver-host=http://10.1.61.132:8080
        - --tcp-services-configmap=default/nginx-tcp-ingress-configmap

以上表示暴露 default namespace 下服務名爲 redis,端口爲 6379 的服務到 nginx-ingress-lb 所在節點的 9000 端口。

六、經過configmap修改nginx controller的一些全局變量

經過上面啓動nginx controller的yaml文件,其實咱們能夠看出來,在啓動controller的時候,向啓動命令傳遞了一大堆參數,包括--default-backend-service以及--apiserver-host等。更多的參數,能夠直接參考相關文檔

咱們知道,nginx controller本質上就是一個nginx代理,這個代理使用了一大堆nginx默認參數啓動。而在某些特定場景下,這些咱們須要定製這些參數以更適用於咱們的需求。在controller啓動的時候,提供了一個--configmap的參數,咱們能夠將須要定製的參數保存到一個configmap中,並在controller啓動的時候,來讀取這個configmap,獲取其值,應用到controller中。具體哪些值能夠經過configmap來傳遞,能夠直接參考相關文檔

下面是一個簡單的示例:

定義一個名爲nginx-controller-configmap的yaml內容以下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-ingress-configmap
  namespace: default
data:
  proxy-body-size: 1024m

這個configmap定義了一個proxy-body-size的大小爲1024m,即nginx中client_max_body_size的參數爲1024m。

修改nginx-controller的yml文件nginx-ingress-daemonset.yaml啓動參數以下:

args:
        - /nginx-ingress-controller
        - --default-backend-service=kube-system/default-http-backend
        - --apiserver-host=http://10.1.61.132:8080
        - --configmap=default/nginx-ingress-configmap
        - --tcp-services-configmap=default/nginx-tcp-ingress-configmap

應用該yaml文件:

kubectl apply -f nginx-ingress-daemonset.yaml

須要說明的直接apply daemonset並不會當即生效,在這裏咱們提供一種簡單的方法讓其生效,就是手動經過kuecetl delete 的方式刪除舊的pod ,而後k8s會自動建立新的pod,新pod會自動應用新的配置。

而後咱們經過kubectl exec -it /bin/sh的方式登陸到新的pod,查看/etc/nginx/nginx.conf文件,能夠看到client_max_body_size由以前的默認1m修改成了1024m。

相關文章
相關標籤/搜索