為Kubernetes叢集中服務部署Nginx入口服務

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

這段日子,一直在搞與Kubernetes有關的東東:像什麼Kubernetes叢集搭建、DNS外掛程式安裝和配置、整合Ceph RBD持久卷、Private Registry鏡像庫訪問等,這些都緣於正在開發的一個類PaaS小平台的需要:“平台雖小,五髒俱全”。整個平台由Kubernetes叢集承載,對於K8s叢集內部的Service來說,目前還欠缺一個服務入口。之前的《Kubernetes叢集中的Nginx配置熱更新方案》一文實際上就是入口方案設計的一個前奏,而本文則是說明一下Nginx入口服務部署設計和實施過程中遇到的一些坑。

一、Nginx入口方案簡述

Nginx作為叢集入口服務,從功能上說,一般都是充當反向 Proxy和負載平衡的角色。在我們這裡它更多是用於反向 Proxy,因為負載平衡的事情“移交”給了K8s去實現了。k8s通過ClusterIP- 一種VIP機制,預設基於iptables的負載分擔實現服務要求的負載平衡(如iptable nat table的規則:-m statistic –mode random –probability 0.33332999982),查看iptables nat鏈的rules,可以看到如下範例:

# iptables -t nat -nL... ...Chain KUBE-SVC-UQG6736T32JE3S7H (2 references)target     prot opt source               destinationKUBE-SEP-Z7UQLD332S673VAF  all  --  0.0.0.0/0            0.0.0.0/0            /* default/nginx-kit: */ statistic mode random probability 0.50000000000KUBE-SEP-TWOIACCAJCPK3HWO  all  --  0.0.0.0/0            0.0.0.0/0            /* default/nginx-kit: */... ..

接下來,我們簡單說說我們的Nginx入口方案。事先聲明:這絕對不是一個理想的方案,因為它還有諸多缺陷,只是在目前平台需求上下文和資源的約束前提下,它可以作為我們的一個可用的過渡方案,方案如下:

  • Nginx以Kubernetes service的形式運行於K8s cluster內部,並限制只能被K8s調度到帶有label: role=entry的Node上;
  • 最外層,通過DNS網域名稱的輪詢機制,實現使用者請求在Node這一層上的“負載平衡”;
  • 訪問某個NodeIP:NodePort的請求,被轉寄到Nginx ClusterIP: Port,並通過iptables nat的負載機制,分發到Nginx service的多個real endpoints上;
  • 位於real endpoint上的Nginx程式處理使用者請求,並根據配置,將請求proxy_pass到後端服務的ClusterIP:Port上,並最終由k8s實現將請求均衡分發到後端服務的endpoint。

二、Nginx入口服務部署

部署前,我們先來給運行Nginx Pod的Node打label:

# kubectl label node/10.47.136.60 role=entrynode "10.47.136.60" labeled# kubectl label node/10.47.136.60 role=entrynode "10.47.136.60" labeled# kubectl get nodes --show-labelsNAME            STATUS    AGE       LABELS10.46.181.146   Ready     39d       beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=10.46.181.146,role=entry,zone=ceph10.47.136.60    Ready     39d       beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=10.47.136.60,role=entry,zone=ceph

在Nginx配置熱載入方案一文中,我們提到一個nginx pod中包含三個Container:nginx、nginx-conf-generator和init container,Nginx service的yaml樣本如下:

//nginx-kit.yamlapiVersion: extensions/v1beta1kind: Deploymentmetadata:  name: nginx-kitspec:  replicas: 2  template:    metadata:      labels:        run: nginx-kit      annotations:        pod.beta.kubernetes.io/init-containers: '[          {               "name": "nginx-kit-init-container",               "image": "registry.cn-beijing.aliyuncs.com/xxxx/nginx-conf-generator",               "imagePullPolicy": "IfNotPresent",               "command": ["/root/conf-generator/nginx-conf-gen", "-mode", "gen-once"],               "volumeMounts": [                   {                      "name": "conf-volume",                      "mountPath": "/etc/nginx/conf.d"                   }               ]          }        ]'    spec:      containers:      - name: nginx-conf-generator        volumeMounts:        - mountPath: /etc/nginx/conf.d          name: conf-volume        image: registry.cn-beijing.aliyuncs.com/xxxx/nginx-conf-generator:latest        imagePullPolicy: IfNotPresent      - name: xxxx-nginx        volumeMounts:        - mountPath: /etc/nginx/conf.d          name: conf-volume        image: registry.cn-hangzhou.aliyuncs.com/xxxx/nginx:latest        imagePullPolicy: IfNotPresent        command: ["/home/auto-reload-nginx.sh"]        ports:        - containerPort: 80      volumes:      - name: conf-volume        emptyDir: {}      nodeSelector:        role: entry---apiVersion: v1kind: Servicemetadata:  name: nginx-kit  labels:    run: nginx-kitspec:  type: NodePort  ports:  - port: 80    nodePort: 28888    protocol: TCP  selector:    run: nginx-kit

關於這個yaml,有幾點我們是必須要說說的:

1、關於init container

通過上述yaml檔案內容,我們可以看到init container和nginx-conf-generator container都是基於同一鏡像建立的,只是工作mode不同罷了。在deployment描述檔案中,init container的描述需要放在deployment.spec.template.metadata下面,而不是deployment的metadata下面。如果按照後者編寫,那麼init container將不會被建立和啟動,nginx container啟動後也就會提示:找不到”default.conf”。

另外,雖然源自同一個image,但init container啟動時卻提示在$PATH裡找不到名為”-mode”的可執行程式,顯然init container中的ENTRYPOINT並不起作用,nginx-conf-generator的Dockerfile節選如下:

//DockerfileFrom ubuntu:14.04... ...ENTRYPOINT ["/root/conf-generator/nginx-conf-gen"]

為此我們在init container的”command”命令參數中增加了可執行程式全路徑以供container執行:

 "command" : ["/root/conf-generator/nginx-conf-gen", "-mode", "gen-once"],

最後,通過上面yaml檔案建立nginx-kit服務依舊要用kubectl apply,而不是kubectl create,否則init container不會被理會。

2、關於nginx conf模板

由於種種原因,當前我們是通過server host的location path來映射後端cluster中的不同Service的,nginx default.conf模板如下:

server {    listen 80;    #server_name opp.neusoft.com;    {{range .}}    location {{.Path}} {        proxy_pass http://{{.ClusterIP}}:{{.Port}}/;        proxy_redirect off;        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    }    {{end}}    #error_page  404              /404.html;    # redirect server error pages to the static page /50x.html    #    error_page   500 502 503 504  /50x.html;    location = /50x.html {        root   /usr/share/nginx/html;    }}

這裡要注意的是proxy_pass directive後面值的寫法,如果你選擇這樣寫:

proxy_pass http://{{.ClusterIP}}:{{.Port}};

那麼當訪問某個路徑時,比如:localhost/volume/api/v1/pools時,nginx後端的Service收到的url訪問路徑將是:/volume/api/v1/pools,volume這個location path並不能被去除,後端的Service在做路由匹配時基本都是會出錯的。fix的方法是賦予proxy_pass directive下面這樣的值:

proxy_pass http://{{.ClusterIP}}:{{.Port}}/;

沒錯,在最後加上一個”/”,這樣nginx所反向 Proxy的Service將會收到/api/v1/pools這樣的訪問URl路徑。

2016, bigwhite. 著作權.

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.