開始天真地以為隻要寫一個 ingress 配置檔案并部署好就行了。但部署後發現所有 node 伺服器上沒有任何程序監聽 80 端口,顯然不對。原來 k8s 沒有内置 ingress controller ,需要安裝第三方的 ingress controller ,比如 nginx ingress controller ,上面通過 cnblogs-ingress.yaml 隻是建立了 ingress 資源
更新:這裡用的是 nginxinc/kubernetes-ingress ,還有個 kubernetes/ingress-nginx ,它們的差別見 Differences Between nginxinc/kubernetes-ingress and kubernetes/ingress-nginx Ingress Controllers ,後來我們選用了
kubernetes/ingress-nginx
,詳見博文。
開始天真地以為隻要寫一個 ingress 配置檔案并部署好就行了。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cnblogs-ingress
spec:
rules:
- host: q.cnblogs.com
http:
paths:
- backend:
serviceName: q-web
servicePort: 80
# kubectl apply -f cnblogs-ingress.yaml
# kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
cnblogs-ingress q.cnblogs.com 80 6h18
但部署後發現所有 node 伺服器上沒有任何程序監聽 80 端口,顯然不對。
從 k8s 幫助文檔中知道了答案:
You must have an ingress controller to satisfy an Ingress. Only creating an Ingress resource has no effect.
In order for the Ingress resource to work, the cluster must have an ingress controller running.
Unlike other types of controllers which run as part of the kube-controller-manager binary, Ingress controllers are not started automatically with a cluster. Use this page to choose the ingress controller implementation that best fits your cluster.
原來 k8s 沒有内置 ingress controller ,需要安裝第三方的 ingress controller ,比如 nginx ingress controller ,上面通過 cnblogs-ingress.yaml 隻是建立了 ingress 資源。那為什麼通過 deployment.yaml 建立了 deployment 資源就能正常部署 pod ?那是因為 kube-controller-manager 中内置了 deployment controller 。
我們選用 nginx ingress controller ,部署操作步驟如下(參考文檔):
1)從 github 上簽出 kubernetes-ingress 倉庫
$ git clone https://github.com/nginxinc/kubernetes-ingress/
$ cd kubernetes-ingress
$ git checkout v1.6.1 -f
$ cd deployments
2)建立 namespace 與 ServiceAccount ,都叫 nginx-ingress
kubectl apply -f common/ns-and-sa.yaml
3)建立 cluster role 與 cluster role binding
kubectl apply -f rbac/rbac.yaml
4)建立 secret
使用自己的證書檔案建立 secret
kubectl create secret tls default-server-secret --cert=path/to/cert.pem --key=path/to/key.pem
或者使用 nginx-ingress 自帶的證書建立 sescret
kubectl apply -f common/default-server-secret.yaml
5)建立 ConfigMap
kubectl apply -f common/nginx-config.yaml
6)建立 custom resource definitions
kubectl apply -f common/custom-resource-definitions.yaml
7)建立 DaemonSet
kubectl apply -f daemon-set/nginx-ingress.yaml
8)檢視 pod 是否部署成功
$ kubectl get pods --namespace=nginx-ingress 1 ↵
NAME READY STATUS RESTARTS AGE
nginx-ingress-7xdzp 1/1 Running 5 12m
nginx-ingress-rs4th 1/1 Running 0 114s
nginx-ingress-w2fnh 1/1 Running 0 12m
nginx-ingress-z54r6 1/1 Running 5 12m
9)建立監聽 31080 端口的 NodePort 類型的 service
配置檔案 nodeport.yaml (去掉了443端口)
注0:nodePort 隻能使用 30000-32767 範圍的端口。
注1:去掉了443端口,我們在最前端使用了阿裡雲負載均衡,請求都通過 http 轉發。
apiVersion: v1
kind: Service
metadata:
name: nginx-ingress
namespace: nginx-ingress
spec:
type: NodePort
ports:
- nodePort: 31080
port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: nginx-ingress
部署指令
kubectl apply -f service/nodeport.yaml
10)檢查 nginx-ingress 部署成功
進入 nginx-ingress 容器
kubectl exec -it daemonset/nginx-ingress -n nginx-ingress /bin/bash
檢視 nginx 配置
cat /etc/nginx/conf.d/production-cnblogs-ingress.conf
确認 ingress 中添加的轉發規則已被導入
upstream production-cnblogs-ingress-q.cnblogs.com-q-web-80 {
zone production-cnblogs-ingress-q.cnblogs.com-q-web-80 256k;
random two least_conn;
server 192.168.107.211:80 max_fails=1 fail_timeout=10s max_conns=0;
server 192.168.186.72:80 max_fails=1 fail_timeout=10s max_conns=0;
}
server {
listen 80;
server_tokens on;
server_name q.cnblogs.com;
location / {
proxy_http_version 1.1;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
client_max_body_size 1m;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering on;
proxy_pass http://production-cnblogs-ingress-q.cnblogs.com-q-web-80;
}
}
至此 nginx-ingress 部署成功。
解決轉發 X-Forwarded-Proto 請求頭問題
解決方法:在 ingress 配置檔案中添加
nginx.org/redirect-to-https: "true"
,詳見博問 K8s Nginx Ingress Controller 轉發 X-Forwarded-Proto 請求頭的問題
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cnblogs-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.org/redirect-to-https: "true"
添加 proxy_set_header 配置
通過 ingress 的 nginx.org/location-snippets 注解添加如下的配置:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cnblogs-ingress
annotations:
nginx.org/location-snippets: |
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
七層負載均衡對 nginx-ingress 進行健康檢查問題
詳見博問 阿裡雲負載均衡對 K8s Nginx Ingress 的健康檢查問題
基于二級域名自動轉發到 service 的實作方法
詳見博問 K8s Ingress 如何自動根據主機名中的二級域名比對 service
應用擷取不到用戶端真實 IP 位址的問題
詳見博問 K8s 中 ASP.NET Core 應用擷取不到用戶端真實 IP 位址