理解Kubernetes中的Nginx Ingress
Ingress有什麼作用?管理叢集外部對叢集內服務的訪問,典型如HTTP請求。它可以提供負載均衡、SSL終結和基於域名的虛擬主機訪問。我們發現這些功能都比較容易實現,將叢集內的服務暴露到叢集外部,可以使用“NodePort”型別的Service,負載均衡可以使用HAProxy來實現,SSL終結功能部署七層反向代理就可以,基於域名的虛擬主機訪問也同樣比較容易實現,那為什麼Kubernetes要引入Ingress API物件呢?
Ingress的潛力
Ingress的功能如開篇所述,可以使用其他技術實現,但是實際在操作過程中發現並沒那麼簡單。在沒有Ingress參與的情況下,將叢集內服務暴露到叢集外使用“NodePort”型別的Service,那需要給每個微服務都建立此類Service,當服務較多時,排障將非常複雜,協調主機埠使用也會讓人抓狂。在叢集外部署Nginx或Apache,SSL終結和基於域名的虛擬主機訪問可以實現,但是服務發現和配置管理又是個挑戰,叢集外的Nginx和Apache感知不到叢集中服務的增加和減少,需要人為配置,這對叢集管理員來說,簡直是個噩夢。幸好,Ingress來了。
安裝
安裝服務到Kubernetes一般都比較容易,使用“kubectl apply”後面跟上yaml檔案即可。當然也可以使用Kubernetes的包管理工具-Helm。“nginx ingress”根據環境,可選有三種安裝方法:
- 使用helm。
- kubectl apply + yamlfiles。
- 在minikube或MicroK8s中,外掛方式安裝。
筆者使用這篇文章介紹的方法安裝Kubernetes叢集,這裡選用第二種方式安裝“nginx ingress ”,執行下面命令(因版本更新較快,實際部署請參考官網):
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.1/deploy/static/provider/baremetal/deploy.yaml
安裝會從“k8s.gcr.io”映象倉拉取映象,如果拉取失敗可選擇阿里雲或其他。
檢視增加的叢集資源。
[[email protected] ~]# kubectl get all -n ingress-nginx NAME READY STATUS RESTARTS AGE pod/ingress-nginx-admission-create-7k9kt 0/1 Completed 0 14d pod/ingress-nginx-admission-patch-5bcmq 0/1 Completed 1 14d pod/ingress-nginx-controller-687578654b-f92bq 1/1 Running 3 (42d ago) 14d NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/ingress-nginx-controller NodePort 10.1.70.249 <none> 80:30305/TCP,443:31330/TCP 14d service/ingress-nginx-controller-admission ClusterIP 10.1.124.31 <none> 443/TCP 14d NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/ingress-nginx-controller 1/1 1 1 14d NAME DESIRED CURRENT READY AGE replicaset.apps/ingress-nginx-controller-687578654b 1 1 1 14d NAME COMPLETIONS DURATION AGE job.batch/ingress-nginx-admission-create 1/1 5s 14d job.batch/ingress-nginx-admission-patch 1/1 7s 14d
因為叢集是自建的,“ingress-nginx-controller”服務型別為“NodePort”,後面訪問服務需要使用這樣的方式:NodeIP+30305/31330+Path。
使用
上步操作成功執行後,便可以建立Ingress型別的API物件了,筆者叢集中提前部署一Web服務,Service資訊如下:
[[email protected] ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx ClusterIP 10.1.133.186 <none> 80/TCP 14h
建立Ingress API物件。
1> --- 2> apiVersion: networking.k8s.io/v1 3> kind: Ingress 4> metadata: 5> name: self-nginx 6> namespace: test 7> annotations: 8> nginx.ingress.kubernetes.io/rewrite-target: / 9> spec: 10> ingressClassName: nginx 11> rules: 12> - host: mynginx.example.com 13> http: 14> paths: 15> - path: /testpath 16> pathType: Prefix 17> backend: 18> service: 19> name: nginx 20> port: 21> number: 80
如果沒有將前面安裝的nginx ingress配置為預設的Ingress,需要加入第10行。否則即使ingress資源提交到API Server,“nginx ingress controller”也沒有反應。獲取“ingressClassName”的值。
[[email protected] ~]# kubectl get ingressclass NAME CONTROLLER PARAMETERS AGE nginx k8s.io/ingress-nginx <none> 14d
檢視建立的Ingress。
[[email protected] ~]# kubectl get ingress NAME CLASS HOSTS ADDRESS PORTS AGE self-nginx nginx mynginx.example.com 192.168.52.132 80 125m
通過Ingress訪問Web服務(如果域名沒有解析,修改/etc/hosts檔案)。
[[email protected] nginx]# curl mynginx.example.com:30305/testpath hello kubernetes!
原理
Nginx Ingress的部署和使用不難,最重要是熟悉它的工作原理,這樣在遇到問題時才能迅速定位。“ingress-nginx-controller” Pod裡面僅執行一個容器,但是這個容器裡面卻有多個守護程序,重要的有兩個:controller和nginx。進入Pod執行ps命令檢視:
[[email protected] ~]# kubectl exec -it ingress-nginx-controller-687578654b-f92bq -n ingress-nginx -- /bin/bash bash-5.1$ ps PID USER TIME COMMAND 1 www-data 0:00 /usr/bin/dumb-init -- /nginx-ingress-controller --election-id=ingress-controller-leader --controller-class=k8s.io/ingress-nginx --config 7 www-data 11:28 /nginx-ingress-controller --election-id=ingress-controller-leader --controller-class=k8s.io/ingress-nginx --configmap=ingress-nginx/ingr 25 www-data 0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /etc/nginx/nginx.conf 247 www-data 0:01 nginx: worker process 248 www-data 0:00 nginx: cache manager process
Controller是管理者,實現服務發現和自動配置功能,見下圖(下載自官網)。
nginx ingress工作原理
這幅圖看起來很複雜,其實用一句話就可以概括:“Ingress Controller”(即圖中的IC)相當於系統管理員,需求者提交Ingress資源到API Server,IC從API Server獲取Ingress資源,因為IC既瞭解Ingress資源又瞭解Nginx,它完成Ingress的“翻譯”,隨即更新Nginx的配置檔案,並執行reload操作,核心邏輯就是這樣。
上面我們給“nginx” Service建立了Ingress資源,訪問路徑配置為“/testpath”,現在進入“ingress-nginx-controller”Pod看下Nginx的配置檔案:/etc/nginx/nginx.conf。
關於虛擬主機“mynginx.example.com”的配置有200多行,刪掉無關的。
## start server mynginx.example.com server { server_name mynginx.example.com ; listen 80 ; listen 443 ssl http2 ; set $proxy_upstream_name "-"; ssl_certificate_by_lua_block { certificate.call() } location ~* "^/testpath" { set $namespace "test"; set $ingress_name "self-nginx"; set $service_name "nginx"; set $service_port "80"; set $location_path "/testpath"; set $global_rate_limit_exceeding n; ...... set $balancer_ewma_score -1; set $proxy_upstream_name "test-nginx-80"; set $proxy_host $proxy_upstream_name; set $pass_access_scheme $scheme; ...... rewrite "(?i)/testpath" / break; proxy_pass http://upstream_balancer; proxy_redirect off; } location ~* "^/" { set $namespace "test"; set $ingress_name "self-nginx"; set $service_name ""; set $service_port ""; set $location_path "/"; set $global_rate_limit_exceeding n; ...... proxy_pass http://upstream_balancer; proxy_redirect off; } } ## end server mynginx.example.com
從配置檔案中可以看到發往“/testpath”的請求完成一次跳轉後最終傳送給“upstream_balancer”,其在Nginx配置檔案中的定義如下:
upstream upstream_balancer { ### Attention!!! # # We no longer create "upstream" section for every backend. # Backends are handled dynamically using Lua. If you would like to debug # and see what backends ingress-nginx has in its memory you can # install our kubectl plugin https://kubernetes.github.io/ingress-nginx/kubectl-plugin. # Once you have the plugin you can use "kubectl ingress-nginx backends" command to # inspect current backends. # ### server 0.0.0.1; # placeholder balancer_by_lua_block { balancer.balance() } keepalive 320; keepalive_timeout 60s; keepalive_requests 10000; }
因Nginx配置檔案嚴重依賴Lua,這裡看到的資訊不直觀。為了看到後端服務,按照註釋,為kubectl安裝“ingress-nginx”外掛。在前面Nginx配置檔案有下面一行:
set $proxy_upstream_name "test-nginx-80";
指出域名“mynginx.example.com”的backend名為“test-nginx-80”。檢視Ingress的backends(省略無關行)。
[[email protected] ~]# kubectl ingress-nginx backends -n ingress-nginx [ { "name": "test-nginx-80", "service": { "metadata": { "creationTimestamp": null }, "spec": { "ports": [ { "name": "http", "protocol": "TCP", "port": 80, "targetPort": 80 } ], "selector": { "app": "nginx" }, "clusterIP": "10.1.133.186", "clusterIPs": [ "10.1.133.186" ], "type": "ClusterIP", "sessionAffinity": "None", "ipFamilies": [ "IPv4" ], "ipFamilyPolicy": "SingleStack", "internalTrafficPolicy": "Cluster" }, "status": { "loadBalancer": {} } }, "port": 80, "sslPassthrough": false, "endpoints": [ { "address": "10.244.1.26", "port": "80" } ], "sessionAffinityConfig": { "name": "", "mode": "", "cookieSessionAffinity": { "name": "" } }, "upstreamHashByConfig": { "upstream-hash-by-subset-size": 3 }, "noServer": false, "trafficShapingPolicy": { "weight": 0, "weightTotal": 0, "header": "", "headerValue": "", "headerPattern": "", "cookie": "" } }, ...... ]
從輸出中可以看到後端其實就是名為“nginx”的Service對應的Endpoints,它的IP是“10.244.1.26”。
[[email protected] ~]# kb get endpoints NAME ENDPOINTS AGE nginx 10.244.1.26:80 19h
這裡需要強調一點,Nginx Ingress並不將流量轉發給nginx service,而是直接轉發到後端的Pods,轉發策略也完全由Ingress Controller來決定。這樣不僅減少了一次DNAT,也能實現更豐富的負載均衡策略。Ingress資源中出現的Service物件只是為了選擇後端的Endpoints。
總結
文章對Nginx Ingress做了介紹,Kubernetes中可以選擇的Ingress有很多,讀者可以根據需要選擇。
- 2022 年會是您採用多雲的一年嗎?
- 做大做強雲端計算市場須立足實際
- 2022年雲端計算應用關鍵威脅調查
- 龍蜥社群:Anolis OS 23正式版將於2023年上線
- 雲身份安全是個大問題,它將如何重塑人們對雲端計算的信任?
- No.0 - 流計算產品綜合洞察@以終為始
- Kubernetes 的核心是 API 框架而非容器
- 雲端儲存架構中企業級資料流轉平臺技術方案
- 開源時代,紅帽如何成就客戶成功
- 人工智慧在雲端計算中能起到怎樣的作用?
- 邊緣計算將成新風口?能給我們帶來什麼影響
- 成本節約:最大雲謬論之一
- 到 2028 年,全球邊緣計算市場將超過600億美元
- 選擇混合雲還是多雲?企業要考慮這些因素
- 為什麼需要 Kubernetes 准入控制器
- 確保邊緣計算成功的五個關鍵
- Spring Cloud OpenFeign 的五個優化小技巧!
- 青雲儲存全面升級,自研QingStor U10000釋放更多資料潛能
- 雲原生下一步的發展方向是什麼?
- IDC:未來5年中國公有云市場高速增長,複合增長率達30.9%