前天才發現,區區一個 nginx ingress controller 竟然2個不同的實現。一個叫 kubernetes/ingress-nginx ,是由 kubernetes 社區維護的,對應的容器鏡像是 quay.io/kubernetes-ingress-controller/nginx-ingress-controller
,namespace 是 ingress-nginx
;一個叫 nginxinc/kubernetes-ingress ,是由 nginx 公司與社區共同維護的,對應的容器鏡像是 nginx/nginx-ingress
,namespace 是 nginx-ingress
。
之前我們用的是 nginxinc/kubernetes-ingress
(詳見之前的博文), 不知道有2個不同的實現,在排查問題時有時查的是 kubernetes/ingress-nginx
的資料,南轅北轍,當時還納悶明明按照文檔進行了設置,為什么不起作用呢?
由於使用 nginxinc/kubernetes-ingress
后遭遇 K8s 中 ASP.NET Core 應用獲取不到客戶端真實 IP 地址 的問題(X-Forwarded-For
轉發問題),於是被迫見異思遷試試換成 kubernetes/ingress-nginx 作為 nginx ingress controller 。
接下來是 kubernetes/ingress-nginx
的部署步驟。
首先刪除之前的 nginxinc/kubernetes-ingress
部署。
kubectl delete all --all -n nginx-ingress
kubectl delete namespace nginx-ingress
接着從 github 上簽出 kubernetes/ingress-nginx
倉庫,用其中的 mandatory.yaml 配置文件進行部署。
git clone https://github.com/kubernetes/ingress-nginx
cd deploy/static
kubectl apply -f mandatory.yaml
部署完成后,查看已部署的資源:
$ kubectl get all -n ingress-nginx
NAME READY STATUS RESTARTS AGE
pod/nginx-ingress-controller-6885bc7778-m62kv 1/1 Running 0 37m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-ingress-controller 1/1 1 1 37m
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-ingress-controller-6885bc7778 1 1 1 37m
還少個 service ,我們這里用 nodePort 的方式部署 service ,於是選用 deploy/static/provider/baremetal/service-nodeport.yaml
部署文件,在其中添加 nodePort: 31080
指定端口。
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
type: NodePort
ports:
- name: http
nodePort: 31080
port: 80
targetPort: 80
protocol: TCP
# ....
部署 service
kubectl apply -f service-nodeport.yaml
查看部署結果
$ kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.96.151.144 <none> 80:31080/TCP,443:32428/TCP 9
登錄 worker 節點用 curl 命令驗證 nginx 是否正常工作
$ curl -i localhost:31080/healthz
HTTP/1.1 200 OK
Server: nginx/1.17.8
返回 200 ,說明 nginx OK。
注:kubernetes/ingress-nginx
默認實現了健康檢查地址 /healthz
,nginxinc/kubernetes-ingress
沒有實現,需要自己實現(詳見博問)。
登錄 nginx-ingress-controller pod ,查看 nginx 配置。
kubectl exec -it deployment/nginx-ingress-controller -n ingress-nginx /bin/bash
發現 kubernetes/ingress-nginx
中基於 ingress 規則生成的 nginx 配置全都放在 /etc/nginx/nginx.conf
中,而 nginxinc/kubernetes-ingress
是在 /etc/nginx/conf.d/
目錄中用一個專門的配置文件存放,文件名以 ingress 所在的命名空間名稱開頭。
最后是最關鍵的時刻,驗證 kubernetes/ingress-nginx
是否也存在 X-Forwarded-For
轉發問題。
在 ConfigMap 中添加啟用 use-forwarded-headers 。
data:
use-forwarded-headers: "true"
kubernetes/ingress-nginx
不負眾望!沒有 X-Forwarded-For
轉發問題,應用中可以正常獲取到客戶端真實 IP 地址。
對比一下兩者處理 X-Forwarded-For
的區別。
1)nginxinc/kubernetes-ingress
生成的 nginx 配置是
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
X-Forwarded-For
的值是 "116.62.124.68, 192.168.107.192"
。
2)kubernetes/ingress-nginx
生成的 nginx 配置是
proxy_set_header X-Forwarded-For $remote_addr;
X-Forwarded-For
的值是 "116.62.124.68"
。kubernetes/ingress-nginx
收到的請求是通過阿里雲負載均衡轉發過來的,客戶端真實 IP 地址也是藏在 X-Forwarded-For
中,但它足智多謀,會將 X-Forwarded-For
中的 IP 地址傳給 $remote_addr
。
如果在 ConfigMap 中添加下面的配置,kubernetes/ingress-nginx
的表現就和 nginxinc/kubernetes-ingress
一樣了。
data:
compute-full-forwarded-for: "true"
一次成功的見異思遷,情定 kubernetes/ingress-nginx
。