激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

云服務器|WEB服務器|FTP服務器|郵件服務器|虛擬主機|服務器安全|DNS服務器|服務器知識|Nginx|IIS|Tomcat|

香港云服务器
服務器之家 - 服務器技術 - 服務器知識 - Kubernetes1.22安裝使用ingress-nginx

Kubernetes1.22安裝使用ingress-nginx

2021-12-22 22:13k8s技術圈陽明 服務器知識

我們知道 Kubernetes 控制器使用控制循環模式來檢查控制器中所需的狀態是否已更新或是否需要變更,所以 ingress-nginx 需要使用集群中的不同對象來構建模型。

Kubernetes1.22安裝使用ingress-nginx

我們已經了解了 Ingress 資源對象只是一個路由請求描述配置文件,要讓其真正生效還需要對應的 Ingress 控制器才行,Ingress 控制器有很多,這里我們先介紹使用最多的 ingress-nginx,它是基于 Nginx 的 Ingress 控制器。

運行原理

ingress-nginx 控制器主要是用來組裝一個 nginx.conf 的配置文件,當配置文件發生任何變動的時候就需要重新加載 Nginx 來生效,但是并不會只在影響 upstream 配置的變更后就重新加載 Nginx,控制器內部會使用一個 lua-nginx-module 來實現該功能。

我們知道 Kubernetes 控制器使用控制循環模式來檢查控制器中所需的狀態是否已更新或是否需要變更,所以 ingress-nginx 需要使用集群中的不同對象來構建模型,比如 Ingress、Service、Endpoints、Secret、ConfigMap 等可以生成反映集群狀態的配置文件的對象,控制器需要一直 Watch 這些資源對象的變化,但是并沒有辦法知道特定的更改是否會影響到最終生成的 nginx.conf 配置文件,所以一旦 Watch 到了任何變化控制器都必須根據集群的狀態重建一個新的模型,并將其與當前的模型進行比較,如果模型相同則就可以避免生成新的 Nginx 配置并觸發重新加載,否則還需要檢查模型的差異是否只和端點有關,如果是這樣,則然后需要使用 HTTP POST 請求將新的端點列表發送到在 Nginx 內運行的 Lua 處理程序,并再次避免生成新的 Nginx 配置并觸發重新加載,如果運行和新模型之間的差異不僅僅是端點,那么就會基于新模型創建一個新的 Nginx 配置了,這樣構建模型最大的一個好處就是在狀態沒有變化時避免不必要的重新加載,可以節省大量 Nginx 重新加載。

下面簡單描述了需要重新加載的一些場景:

  • 創建了新的 Ingress 資源
  • TLS 添加到現有 Ingress
  • 從 Ingress 中添加或刪除 path 路徑
  • Ingress、Service、Secret 被刪除了
  • Ingress 的一些缺失引用對象變可用了,例如 Service 或 Secret
  • 更新了一個 Secret

對于集群規模較大的場景下頻繁的對 Nginx 進行重新加載顯然會造成大量的性能消耗,所以要盡可能減少出現重新加載的場景。

安裝

由于 ingress-nginx 所在的節點需要能夠訪問外網(不是強制的),這樣域名可以解析到這些節點上直接使用,所以需要讓 ingress-nginx 綁定節點的 80 和 443 端口,所以可以使用 hostPort 來進行訪問,當然對于線上環境來說為了保證高可用,一般是需要運行多個 ·ingress-nginx 實例的,然后可以用一個 nginx/haproxy 作為入口,通過 keepalived 來訪問邊緣節點的 vip 地址。

!!! info "邊緣節點" 所謂的邊緣節點即集群內部用來向集群外暴露服務能力的節點,集群外部的服務通過該節點來調用集群內部的服務,邊緣節點是集群內外交流的一個 Endpoint。

這里我們使用 Helm Chart(后面會詳細講解)的方式來進行安裝:

  1. # 如果你不喜歡使用 helm chart 進行安裝也可以使用下面的命令一鍵安裝
  2. # kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.0/deploy/static/provider/cloud/deploy.yaml
  3. ? helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
  4. ? helm repo update
  5. ? helm fetch ingress-nginx/ingress-nginx
  6. ? tar -xvf ingress-nginx-4.0.13.tgz && cd ingress-nginx
  7. ? tree .
  8. .
  9. ├── CHANGELOG.md
  10. ├── Chart.yaml
  11. ├── OWNERS
  12. ├── README.md
  13. ├── ci
  14. │ ├── controller-custom-ingressclass-flags.yaml
  15. │ ├── daemonset-customconfig-values.yaml
  16. │ ├── daemonset-customnodeport-values.yaml
  17. │ ├── daemonset-headers-values.yaml
  18. │ ├── daemonset-internal-lb-values.yaml
  19. │ ├── daemonset-nodeport-values.yaml
  20. │ ├── daemonset-podannotations-values.yaml
  21. │ ├── daemonset-tcp-udp-configMapNamespace-values.yaml
  22. │ ├── daemonset-tcp-udp-values.yaml
  23. │ ├── daemonset-tcp-values.yaml
  24. │ ├── deamonset-default-values.yaml
  25. │ ├── deamonset-metrics-values.yaml
  26. │ ├── deamonset-psp-values.yaml
  27. │ ├── deamonset-webhook-and-psp-values.yaml
  28. │ ├── deamonset-webhook-values.yaml
  29. │ ├── deployment-autoscaling-behavior-values.yaml
  30. │ ├── deployment-autoscaling-values.yaml
  31. │ ├── deployment-customconfig-values.yaml
  32. │ ├── deployment-customnodeport-values.yaml
  33. │ ├── deployment-default-values.yaml
  34. │ ├── deployment-headers-values.yaml
  35. │ ├── deployment-internal-lb-values.yaml
  36. │ ├── deployment-metrics-values.yaml
  37. │ ├── deployment-nodeport-values.yaml
  38. │ ├── deployment-podannotations-values.yaml
  39. │ ├── deployment-psp-values.yaml
  40. │ ├── deployment-tcp-udp-configMapNamespace-values.yaml
  41. │ ├── deployment-tcp-udp-values.yaml
  42. │ ├── deployment-tcp-values.yaml
  43. │ ├── deployment-webhook-and-psp-values.yaml
  44. │ ├── deployment-webhook-resources-values.yaml
  45. │ └── deployment-webhook-values.yaml
  46. ├── templates
  47. │ ├── NOTES.txt
  48. │ ├── _helpers.tpl
  49. │ ├── _params.tpl
  50. │ ├── admission-webhooks
  51. │ │ ├── job-patch
  52. │ │ │ ├── clusterrole.yaml
  53. │ │ │ ├── clusterrolebinding.yaml
  54. │ │ │ ├── job-createSecret.yaml
  55. │ │ │ ├── job-patchWebhook.yaml
  56. │ │ │ ├── psp.yaml
  57. │ │ │ ├── role.yaml
  58. │ │ │ ├── rolebinding.yaml
  59. │ │ │ └── serviceaccount.yaml
  60. │ │ └── validating-webhook.yaml
  61. │ ├── clusterrole.yaml
  62. │ ├── clusterrolebinding.yaml
  63. │ ├── controller-configmap-addheaders.yaml
  64. │ ├── controller-configmap-proxyheaders.yaml
  65. │ ├── controller-configmap-tcp.yaml
  66. │ ├── controller-configmap-udp.yaml
  67. │ ├── controller-configmap.yaml
  68. │ ├── controller-daemonset.yaml
  69. │ ├── controller-deployment.yaml
  70. │ ├── controller-hpa.yaml
  71. │ ├── controller-ingressclass.yaml
  72. │ ├── controller-keda.yaml
  73. │ ├── controller-poddisruptionbudget.yaml
  74. │ ├── controller-prometheusrules.yaml
  75. │ ├── controller-psp.yaml
  76. │ ├── controller-role.yaml
  77. │ ├── controller-rolebinding.yaml
  78. │ ├── controller-service-internal.yaml
  79. │ ├── controller-service-metrics.yaml
  80. │ ├── controller-service-webhook.yaml
  81. │ ├── controller-service.yaml
  82. │ ├── controller-serviceaccount.yaml
  83. │ ├── controller-servicemonitor.yaml
  84. │ ├── default-backend-deployment.yaml
  85. │ ├── default-backend-hpa.yaml
  86. │ ├── default-backend-poddisruptionbudget.yaml
  87. │ ├── default-backend-psp.yaml
  88. │ ├── default-backend-role.yaml
  89. │ ├── default-backend-rolebinding.yaml
  90. │ ├── default-backend-service.yaml
  91. │ ├── default-backend-serviceaccount.yaml
  92. │ └── dh-param-secret.yaml
  93. └── values.yaml
  94.  
  95. 4 directories, 81 files

Helm Chart 包下載下來后解壓就可以看到里面包含的模板文件,其中的 ci 目錄中就包含了各種場景下面安裝的 Values 配置文件,values.yaml 文件中包含的是所有可配置的默認值,我們可以對這些默認值進行覆蓋,我們這里測試環境就將 master1 節點看成邊緣節點,所以我們就直接將 ingress-nginx 固定到 master1 節點上,采用 hostNetwork 模式(生產環境可以使用 LB + DaemonSet hostNetwork 模式),為了避免創建的錯誤 Ingress 等資源對象影響控制器重新加載,所以我們也強烈建議大家開啟準入控制器,ingess-nginx 中會提供一個用于校驗資源對象的 Admission Webhook,我們可以通過 Values 文件進行開啟。然后新建一個名為 ci/daemonset-prod.yaml 的 Values 文件,用來覆蓋 ingress-nginx 默認的 Values 值。

Kubernetes1.22安裝使用ingress-nginx

對應的 Values 配置文件如下所示:

  1. # ci/daemonset-prod.yaml
  2. controller:
  3. name: controller
  4. image:
  5. repository: cnych/ingress-nginx
  6. tag: "v1.1.0"
  7. digest:
  8.  
  9. dnsPolicy: ClusterFirstWithHostNet
  10.  
  11. hostNetwork: true
  12.  
  13. publishService: # hostNetwork 模式下設置為false,通過節點IP地址上報ingress status數據
  14. enabled: false
  15.  
  16. # 是否需要處理不帶 ingressClass 注解或者 ingressClassName 屬性的 Ingress 對象
  17. # 設置為 true 會在控制器啟動參數中新增一個 --watch-ingress-without-class 標注
  18. watchIngressWithoutClass: false
  19.  
  20. kind: DaemonSet
  21.  
  22. tolerations: # kubeadm 安裝的集群默認情況下master是有污點,需要容忍這個污點才可以部署
  23. - key: "node-role.kubernetes.io/master"
  24. operator: "Equal"
  25. effect: "NoSchedule"
  26.  
  27. nodeSelector: # 固定到master1節點
  28. kubernetes.io/hostname: master1
  29.  
  30. service: # HostNetwork 模式不需要創建service
  31. enabled: false
  32.  
  33. admissionWebhooks: # 強烈建議開啟 admission webhook
  34. enabled: true
  35. createSecretJob:
  36. resources:
  37. limits:
  38. cpu: 10m
  39. memory: 20Mi
  40. requests:
  41. cpu: 10m
  42. memory: 20Mi
  43. patchWebhookJob:
  44. resources:
  45. limits:
  46. cpu: 10m
  47. memory: 20Mi
  48. requests:
  49. cpu: 10m
  50. memory: 20Mi
  51. patch:
  52. enabled: true
  53. image:
  54. repository: cnych/ingress-nginx-webhook-certgen
  55. tag: v1.1.1
  56. digest:
  57.  
  58. defaultBackend: # 配置默認后端
  59. enabled: true
  60. name: defaultbackend
  61. image:
  62. repository: cnych/ingress-nginx-defaultbackend
  63. tag: "1.5"

然后使用如下命令安裝 ingress-nginx 應用到 ingress-nginx 的命名空間中:

  1. ? kubectl create ns ingress-nginx
  2. ? helm upgrade --install ingress-nginx . -f ./ci/daemonset-prod.yaml --namespace ingress-nginx
  3. Release "ingress-nginx" does not exist. Installing it now.
  4.  
  5. NAME: ingress-nginx
  6. LAST DEPLOYED: Thu Dec 16 16:47:20 2021
  7. NAMESPACE: ingress-nginx
  8. STATUS: deployed
  9. REVISION: 1
  10. TEST SUITE: None
  11. NOTES:
  12. The ingress-nginx controller has been installed.
  13. It may take a few minutes for the LoadBalancer IP to be available.
  14. You can watch the status by running 'kubectl --namespace ingress-nginx get services -o wide -w ingress-nginx-controller'
  15.  
  16. An example Ingress that makes use of the controller:
  17. apiVersion: networking.k8s.io/v1
  18. kind: Ingress
  19. metadata:
  20. name: example
  21. namespace: foo
  22. spec:
  23. ingressClassName: nginx
  24. rules:
  25. - host: www.example.com
  26. http:
  27. paths:
  28. - backend:
  29. service:
  30. name: exampleService
  31. port:
  32. number: 80
  33. path: /
  34. # This section is only required if TLS is to be enabled for the Ingress
  35. tls:
  36. - hosts:
  37. - www.example.com
  38. secretName: example-tls
  39.  
  40. If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:
  41.  
  42. apiVersion: v1
  43. kind: Secret
  44. metadata:
  45. name: example-tls
  46. namespace: foo
  47. data:
  48. tls.crt:
  49. tls.key: key>
  50. type: kubernetes.io/tls

部署完成后查看 Pod 的運行狀態:

  1. ? kubectl get svc -n ingress-nginx
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. ingress-nginx-controller-admission ClusterIP 10.96.15.99 443/TCP 11m
  4. ingress-nginx-defaultbackend ClusterIP 10.97.250.253 80/TCP 11m
  5. ? kubectl get pods -n ingress-nginx
  6. NAME READY STATUS RESTARTS AGE
  7. ingress-nginx-controller-5dfdd4659c-9g7c2 1/1 Running 0 11m
  8. ingress-nginx-defaultbackend-84854cd6cb-xb7rv 1/1 Running 0 11m
  9. ? POD_NAME=$(kubectl get pods -l app.kubernetes.io/name=ingress-nginx -n ingress-nginx -o jsonpath='{.items[0].metadata.name}')
  10. ? kubectl exec -it $POD_NAME -n ingress-nginx -- /nginx-ingress-controller --version
  11. kubectl logs -f ingress-nginx-controller-5dfdd4659c-9g7c2 -n ingress-nginxW1216 08:51:22.179213 7 client_config.go:615] Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.
  12. I1216 08:51:22.179525 7 main.go:223] "Creating API client" host="https://10.96.0.1:443"
  13. -------------------------------------------------------------------------------
  14. NGINX Ingress controller
  15. Release: v1.1.0
  16. Build: cacbee86b6ccc45bde8ffc184521bed3022e7dee
  17. Repository: https://github.com/kubernetes/ingress-nginx
  18. nginx version: nginx/1.19.9
  19.  
  20. -------------------------------------------------------------------------------
  21.  
  22. I1216 08:51:22.198221 7 main.go:267] "Running in Kubernetes cluster" major="1" minor="22" git="v1.22.2" state="clean" commit="8b5a19147530eaac9476b0ab82980b4088bbc1b2" platform="linux/amd64"
  23. I1216 08:51:22.200478 7 main.go:86] "Valid default backend" service="ingress-nginx/ingress-nginx-defaultbackend"
  24. I1216 08:51:22.611100 7 main.go:104] "SSL fake certificate created" file="/etc/ingress-controller/ssl/default-fake-certificate.pem"
  25. I1216 08:51:22.627386 7 ssl.go:531] "loading tls certificate" path="/usr/local/certificates/cert" key="/usr/local/certificates/key"
  26. I1216 08:51:22.651187 7 nginx.go:255] "Starting NGINX Ingress controller"

當看到上面的信息證明 ingress-nginx 部署成功了,這里我們安裝的是最新版本的控制器,安裝完成后會自動創建一個 名為 nginx 的 IngressClass 對象:

  1. ? kubectl get ingressclass
  2. NAME CONTROLLER PARAMETERS AGE
  3. nginx k8s.io/ingress-nginx 18m
  4. ? kubectl get ingressclass nginx -o yaml
  5. apiVersion: networking.k8s.io/v1
  6. kind: IngressClass
  7. metadata:
  8. ......
  9. name: nginx
  10. resourceVersion: "1513966"
  11. uid: 70340e62-cab6-4a11-9982-2108f1db786b
  12. spec:
  13. controller: k8s.io/ingress-nginx

過這里我們只提供了一個 controller 屬性,如果還需要配置一些額外的參數,則可以在安裝的 values 文件中進行配置。

第一個示例

安裝成功后,現在我們來為一個 nginx 應用創建一個 Ingress 資源,如下所示:

  1. # my-nginx.yaml
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5. name: my-nginx
  6. spec:
  7. selector:
  8. matchLabels:
  9. app: my-nginx
  10. template:
  11. metadata:
  12. labels:
  13. app: my-nginx
  14. spec:
  15. containers:
  16. - name: my-nginx
  17. image: nginx
  18. ports:
  19. - containerPort: 80
  20. ---
  21. apiVersion: v1
  22. kind: Service
  23. metadata:
  24. name: my-nginx
  25. labels:
  26. app: my-nginx
  27. spec:
  28. ports:
  29. - port: 80
  30. protocol: TCP
  31. name: http
  32. selector:
  33. app: my-nginx
  34. ---
  35. apiVersion: networking.k8s.io/v1
  36. kind: Ingress
  37. metadata:
  38. name: my-nginx
  39. namespace: default
  40. spec:
  41. ingressClassName: nginx # 使用 nginx 的 IngressClass(關聯的 ingress-nginx 控制器)
  42. rules:
  43. - host: ngdemo.qikqiak.com # 將域名映射到 my-nginx 服務
  44. http:
  45. paths:
  46. - path: /
  47. pathType: Prefix
  48. backend:
  49. service: # 將所有請求發送到 my-nginx 服務的 80 端口
  50. name: my-nginx
  51. port:
  52. number: 80
  53. # 不過需要注意大部分Ingress控制器都不是直接轉發到Service
  54. # 而是只是通過Service來獲取后端的Endpoints列表,直接轉發到Pod,這樣可以減少網絡跳轉,提高性能

直接創建上面的資源對象:

  1. ? kubectl apply -f my-nginx.yaml
  2. deployment.apps/my-nginx created
  3. service/my-nginx created
  4. ingress.networking.k8s.io/my-nginx created
  5. ? kubectl get ingress
  6. NAME CLASS HOSTS ADDRESS PORTS AGE
  7. my-nginx nginx ngdemo.qikqiak.com 192.168.31.31 80 30m

在上面的 Ingress 資源對象中我們使用配置 ingressClassName: nginx 指定讓我們安裝的 ingress-nginx 這個控制器來處理我們的 Ingress 資源,配置的匹配路徑類型為前綴的方式去匹配 /,將來自域名 ngdemo.qikqiak.com 的所有請求轉發到 my-nginx 服務的后端 Endpoints 中去。

上面資源創建成功后,然后我們可以將域名 ngdemo.qikqiak.com 解析到 ingress-nginx 所在的邊緣節點中的任意一個,當然也可以在本地 /etc/hosts 中添加對應的映射也可以,然后就可以通過域名進行訪問了。

Kubernetes1.22安裝使用ingress-nginx

下圖顯示了客戶端是如何通過 Ingress 控制器連接到其中一個 Pod 的流程,客戶端首先對 ngdemo.qikqiak.com 執行 DNS 解析,得到 Ingress 控制器所在節點的 IP,然后客戶端向 Ingress 控制器發送 HTTP 請求,然后根據 Ingress 對象里面的描述匹配域名,找到對應的 Service 對象,并獲取關聯的 Endpoints 列表,將客戶端的請求轉發給其中一個 Pod。

Kubernetes1.22安裝使用ingress-nginx

前面我們也提到了 ingress-nginx 控制器的核心原理就是將我們的 Ingress 這些資源對象映射翻譯成 Nginx 配置文件 nginx.conf,我們可以通過查看控制器中的配置文件來驗證這點:

  1. ? kubectl exec -it $POD_NAME -n ingress-nginx -- cat /etc/nginx/nginx.conf
  2.  
  3. ......
  4. upstream upstream_balancer {
  5. server 0.0.0.1; # placeholder
  6. balancer_by_lua_block {
  7. balancer.balance()
  8. }
  9. keepalive 320;
  10. keepalive_timeout 60s;
  11. keepalive_requests 10000;
  12. }
  13.  
  14. ......
  15. ## start server ngdemo.qikqiak.com
  16. server {
  17. server_name ngdemo.qikqiak.com ;
  18.  
  19. listen 80 ;
  20. listen [::]:80 ;
  21. listen 443 ssl http2 ;
  22. listen [::]:443 ssl http2 ;
  23.  
  24. set $proxy_upstream_name "-";
  25.  
  26. ssl_certificate_by_lua_block {
  27. certificate.call()
  28. }
  29.  
  30. location / {
  31.  
  32. set $namespace "default";
  33. set $ingress_name "my-nginx";
  34. set $service_name "my-nginx";
  35. set $service_port "80";
  36. set $location_path "/";
  37. set $global_rate_limit_exceeding n;
  38. ......
  39. proxy_next_upstream_timeout 0;
  40. proxy_next_upstream_tries 3;
  41.  
  42. proxy_pass http://upstream_balancer;
  43.  
  44. proxy_redirect off;
  45.  
  46. }
  47.  
  48. }
  49. ## end server ngdemo.qikqiak.com
  50. ......

我們可以在 nginx.conf 配置文件中看到上面我們新增的 Ingress 資源對象的相關配置信息,不過需要注意的是現在并不會為每個 backend 后端都創建一個 upstream 配置塊,現在是使用 Lua 程序進行動態處理的,所以我們沒有直接看到后端的 Endpoints 相關配置數據。

Nginx 配置

如果我們還想進行一些自定義配置,則有幾種方式可以實現:使用 Configmap 在 Nginx 中設置全局配置、通過 Ingress 的 Annotations 設置特定 Ingress 的規則、自定義模板。接下來我們重點給大家介紹使用注解來對 Ingress 對象進行自定義。

Basic Auth

我們可以在 Ingress 對象上配置一些基本的 Auth 認證,比如 Basic Auth,可以用 htpasswd 生成一個密碼文件來驗證身份驗證。

  1. ? htpasswd -c auth foo
  2. New password:
  3. Re-type new password:
  4. Adding password for user foo

然后根據上面的 auth 文件創建一個 secret 對象:

  1. ? kubectl create secret generic basic-auth --from-file=auth
  2. secret/basic-auth created
  3. ? kubectl get secret basic-auth -o yaml
  4. apiVersion: v1
  5. data:
  6. auth: Zm9vOiRhcHIxJFUxYlFZTFVoJHdIZUZQQ1dyZTlGRFZONTQ0dXVQdC4K
  7. kind: Secret
  8. metadata:
  9. name: basic-auth
  10. namespace: default
  11. type: Opaque

然后對上面的 my-nginx 應用創建一個具有 Basic Auth 的 Ingress 對象:

  1. apiVersion: networking.k8s.io/v1
  2. kind: Ingress
  3. metadata:
  4. name: ingress-with-auth
  5. namespace: default
  6. annotations:
  7. nginx.ingress.kubernetes.io/auth-type: basic # 認證類型
  8. nginx.ingress.kubernetes.io/auth-secret: basic-auth # 包含 user/password 定義的 secret 對象名
  9. nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - foo' # 要顯示的帶有適當上下文的消息,說明需要身份驗證的原因
  10. spec:
  11. ingressClassName: nginx # 使用 nginx 的 IngressClass(關聯的 ingress-nginx 控制器)
  12. rules:
  13. - host: bauth.qikqiak.com # 將域名映射到 my-nginx 服務
  14. http:
  15. paths:
  16. - path: /
  17. pathType: Prefix
  18. backend:
  19. service: # 將所有請求發送到 my-nginx 服務的 80 端口
  20. name: my-nginx
  21. port:
  22. number: 80

直接創建上面的資源對象,然后通過下面的命令或者在瀏覽器中直接打開配置的域名:

  1. ? kubectl get ingress
  2. NAME CLASS HOSTS ADDRESS PORTS AGE
  3. ingress-with-auth nginx bauth.qikqiak.com 192.168.31.31 80 6m55s
  4. ? curl -v http://192.168.31.31 -H 'Host: bauth.qikqiak.com'
  5. * Trying 192.168.31.31...
  6. * TCP_NODELAY set
  7. * Connected to 192.168.31.31 (192.168.31.31) port 80 (#0)
  8. > GET / HTTP/1.1
  9. > Host: bauth.qikqiak.com
  10. > User-Agent: curl/7.64.1
  11. > Accept: */*
  12. >
  13. < HTTP/1.1 401 Unauthorized
  14. < Date: Thu, 16 Dec 2021 10:49:03 GMT
  15. < Content-Type: text/html
  16. < Content-Length: 172
  17. < Connection: keep-alive
  18. < WWW-Authenticate: Basic realm="Authentication Required - foo"
  19. <
  20.  
  21.  
  22.  
  23. 401 Authorization Required


  24. nginx
  25.  
  26.  
  27. * Connection #0 to host 192.168.31.31 left intact
  28. * Closing connection 0

我們可以看到出現了 401 認證失敗錯誤,然后帶上我們配置的用戶名和密碼進行認證:

  1. ? curl -v http://192.168.31.31 -H 'Host: bauth.qikqiak.com' -u 'foo:foo'
  2. * Trying 192.168.31.31...
  3. * TCP_NODELAY set
  4. * Connected to 192.168.31.31 (192.168.31.31) port 80 (#0)
  5. * Server auth using Basic with user 'foo'
  6. > GET / HTTP/1.1
  7. > Host: bauth.qikqiak.com
  8. > Authorization: Basic Zm9vOmZvbw==
  9. > User-Agent: curl/7.64.1
  10. > Accept: */*
  11. >
  12. < HTTP/1.1 200 OK
  13. < Date: Thu, 16 Dec 2021 10:49:38 GMT
  14. < Content-Type: text/html
  15. < Content-Length: 615
  16. < Connection: keep-alive
  17. < Last-Modified: Tue, 02 Nov 2021 14:49:22 GMT
  18. < ETag: "61814ff2-267"
  19. < Accept-Ranges: bytes
  20. <
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27. Welcome to nginx!

  28. If you see this page, the nginx web server is successfully installed and

  29. working. Further configuration is required.

     

  30.  
  31. For online documentation and support please refer to

  32. "http://nginx.org/">nginx.org.
  33. Commercial support is available at
  34. "http://nginx.com/">nginx.com.

     

  35.  
  36. Thank you for using nginx.

  37.  
  38.  
  39. * Connection #0 to host 192.168.31.31 left intact
  40. * Closing connection 0

可以看到已經認證成功了。除了可以使用我們自己在本地集群創建的 Auth 信息之外,還可以使用外部的 Basic Auth 認證信息,比如我們使用 https://httpbin.org 的外部 Basic Auth 認證,創建如下所示的 Ingress 資源對象:

  1. apiVersion: networking.k8s.io/v1
  2. kind: Ingress
  3. metadata:
  4. annotations:
  5. # 配置外部認證服務地址
  6. nginx.ingress.kubernetes.io/auth-url: https://httpbin.org/basic-auth/user/passwd
  7. name: external-auth
  8. namespace: default
  9. spec:
  10. ingressClassName: nginx
  11. rules:
  12. - host: external-bauth.qikqiak.com
  13. http:
  14. paths:
  15. - path: /
  16. pathType: Prefix
  17. backend:
  18. service:
  19. name: my-nginx
  20. port:
  21. number: 80

上面的資源對象創建完成后,再進行簡單的測試:

  1. ? kubectl get ingress
  2. NAME CLASS HOSTS ADDRESS PORTS AGE
  3. external-auth external-bauth.qikqiak.com 80 72s
  4. ? curl -k http://192.168.31.31 -v -H 'Host: external-bauth.qikqiak.com'
  5. * Trying 192.168.31.31...
  6. * TCP_NODELAY set
  7. * Connected to 192.168.31.31 (192.168.31.31) port 80 (#0)
  8. > GET / HTTP/1.1
  9. > Host: external-bauth.qikqiak.com
  10. > User-Agent: curl/7.64.1
  11. > Accept: */*
  12. >
  13. < HTTP/1.1 401 Unauthorized
  14. < Date: Thu, 16 Dec 2021 10:57:25 GMT
  15. < Content-Type: text/html
  16. < Content-Length: 172
  17. < Connection: keep-alive
  18. < WWW-Authenticate: Basic realm="Fake Realm"
  19. <
  20.  
  21.  
  22.  
  23. 401 Authorization Required


  24. nginx
  25.  
  26.  
  27. * Connection #0 to host 192.168.31.31 left intact
  28. * Closing connection 0

然后使用正確的用戶名和密碼測試:

  1. ? curl -k http://192.168.31.31 -v -H 'Host: external-bauth.qikqiak.com' -u 'user:passwd'
  2. * Trying 192.168.31.31...
  3. * TCP_NODELAY set
  4. * Connected to 192.168.31.31 (192.168.31.31) port 80 (#0)
  5. * Server auth using Basic with user 'user'
  6. > GET / HTTP/1.1
  7. > Host: external-bauth.qikqiak.com
  8. > Authorization: Basic dXNlcjpwYXNzd2Q=
  9. > User-Agent: curl/7.64.1
  10. > Accept: */*
  11. >
  12. < HTTP/1.1 200 OK
  13. < Date: Thu, 16 Dec 2021 10:58:31 GMT
  14. < Content-Type: text/html
  15. < Content-Length: 615
  16. < Connection: keep-alive
  17. < Last-Modified: Tue, 02 Nov 2021 14:49:22 GMT
  18. < ETag: "61814ff2-267"
  19. < Accept-Ranges: bytes
  20. <
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27. Welcome to nginx!

  28. If you see this page, the nginx web server is successfully installed and

  29. working. Further configuration is required.

     

  30.  
  31. For online documentation and support please refer to

  32. "http://nginx.org/">nginx.org.
  33. Commercial support is available at
  34. "http://nginx.com/">nginx.com.

     

  35.  
  36. Thank you for using nginx.

  37.  
  38.  
  39. * Connection #0 to host 192.168.31.31 left intact
  40. * Closing connection 0

如果用戶名或者密碼錯誤則同樣會出現401的狀態碼:

  1. ? curl -k http://192.168.31.31 -v -H 'Host: external-bauth.qikqiak.com' -u 'user:passwd123'
  2. * Trying 192.168.31.31...
  3. * TCP_NODELAY set
  4. * Connected to 192.168.31.31 (192.168.31.31) port 80 (#0)
  5. * Server auth using Basic with user 'user'
  6. > GET / HTTP/1.1
  7. > Host: external-bauth.qikqiak.com
  8. > Authorization: Basic dXNlcjpwYXNzd2QxMjM=
  9. > User-Agent: curl/7.64.1
  10. > Accept: */*
  11. >
  12. < HTTP/1.1 401 Unauthorized
  13. < Date: Thu, 16 Dec 2021 10:59:18 GMT
  14. < Content-Type: text/html
  15. < Content-Length: 172
  16. < Connection: keep-alive
  17. * Authentication problem. Ignoring this.
  18. < WWW-Authenticate: Basic realm="Fake Realm"
  19. <
  20.  
  21.  
  22.  
  23. 401 Authorization Required


  24. nginx
  25.  
  26.  
  27. * Connection #0 to host 192.168.31.31 left intact
  28. * Closing connection 0

當然除了 Basic Auth 這一種簡單的認證方式之外,ingress-nginx 還支持一些其他高級的認證,比如我們可以使用 GitHub OAuth 來認證 Kubernetes 的 Dashboard。

URL Rewrite

ingress-nginx 很多高級的用法可以通過 Ingress 對象的 annotation 進行配置,比如常用的 URL Rewrite 功能。很多時候我們會將 ingress-nginx 當成網關使用,比如對訪問的服務加上 /app 這樣的前綴,在 nginx 的配置里面我們知道有一個 proxy_pass 指令可以實現:

  1. location /app/ {
  2. proxy_pass http://127.0.0.1/remote/;
  3. }

proxy_pass 后面加了 /remote 這個路徑,此時會將匹配到該規則路徑中的 /app 用 /remote 替換掉,相當于截掉路徑中的 /app。同樣的在 Kubernetes 中使用 ingress-nginx 又該如何來實現呢?我們可以使用 rewrite-target 的注解來實現這個需求,比如現在我們想要通過 rewrite.qikqiak.com/gateway/ 來訪問到 Nginx 服務,則我們需要對訪問的 URL 路徑做一個 Rewrite,在 PATH 中添加一個 gateway 的前綴,關于 Rewrite 的操作在 ingress-nginx 官方文檔中也給出對應的說明:

Kubernetes1.22安裝使用ingress-nginx

按照要求我們需要在 path 中匹配前綴 gateway,然后通過 rewrite-target 指定目標,Ingress 對象如下所示:

  1. apiVersion: networking.k8s.io/v1
  2. kind: Ingress
  3. metadata:
  4. name: rewrite
  5. annotations:
  6. nginx.ingress.kubernetes.io/rewrite-target: /$2
  7. spec:
  8. ingressClassName: nginx
  9. rules:
  10. - host: rewrite.qikqiak.com
  11. http:
  12. paths:
  13. - path: /gateway(/|$)(.*)
  14. pathType: Prefix
  15. backend:
  16. service:
  17. name: my-nginx
  18. port:
  19. number: 80

更新后,我們可以預見到直接訪問域名肯定是不行了,因為我們沒有匹配 / 的 path 路徑:

  1. ? curl rewrite.qikqiak.com
  2. default backend - 404

但是我們帶上 gateway 的前綴再去訪問:

Kubernetes1.22安裝使用ingress-nginx

我們可以看到已經可以訪問到了,這是因為我們在 path 中通過正則表達式 /gateway(/|$)(.*) 將匹配的路徑設置成了 rewrite-target 的目標路徑了,所以我們訪問 rewite.qikqiak.com/gateway/ 的時候實際上相當于訪問的就是后端服務的 / 路徑。

要解決我們訪問主域名出現 404 的問題,我們可以給應用設置一個 app-root 的注解,這樣當我們訪問主域名的時候會自動跳轉到我們指定的 app-root 目錄下面,如下所示:

  1. apiVersion: networking.k8s.io/v1
  2. kind: Ingress
  3. metadata:
  4. name: rewrite
  5. annotations:
  6. nginx.ingress.kubernetes.io/app-root: /gateway/
  7. nginx.ingress.kubernetes.io/rewrite-target: /$2
  8. spec:
  9. ingressClassName: nginx
  10. rules:
  11. - host: rewrite.qikqiak.com
  12. http:
  13. paths:
  14. - path: /gateway(/|$)(.*)
  15. pathType: Prefix
  16. backend:
  17. service:
  18. name: my-nginx
  19. port:
  20. number: 80

這個時候我們更新應用后訪問主域名 rewrite.qikqiak.com 就會自動跳轉到 rewrite.qikqiak.com/gateway/ 路徑下面去了。但是還有一個問題是我們的 path 路徑其實也匹配了 /app 這樣的路徑,可能我們更加希望我們的應用在最后添加一個 / 這樣的 slash,同樣我們可以通過 configuration-snippet 配置來完成,如下 Ingress 對象:

  1. apiVersion: networking.k8s.io/v1
  2. kind: Ingress
  3. metadata:
  4. name: rewrite
  5. annotations:
  6. nginx.ingress.kubernetes.io/app-root: /gateway/
  7. nginx.ingress.kubernetes.io/rewrite-target: /$2
  8. nginx.ingress.kubernetes.io/configuration-snippet: |
  9. rewrite ^(/gateway)$ $1/ redirect;
  10. spec:
  11. ingressClassName: nginx
  12. rules:
  13. - host: rewrite.qikqiak.com
  14. http:
  15. paths:
  16. - path: /gateway(/|$)(.*)
  17. pathType: Prefix
  18. backend:
  19. service:
  20. name: my-nginx
  21. port:
  22. number: 80

更新后我們的應用就都會以 / 這樣的 slash 結尾了。這樣就完成了我們的需求,如果你原本對 nginx 的配置就非常熟悉的話應該可以很快就能理解這種配置方式了。

灰度發布

在日常工作中我們經常需要對服務進行版本更新升級,所以我們經常會使用到滾動升級、藍綠發布、灰度發布等不同的發布操作。而 ingress-nginx 支持通過 Annotations 配置來實現不同場景下的灰度發布和測試,可以滿足金絲雀發布、藍綠部署與 A/B 測試等業務場景。

ingress-nginx 的 Annotations 支持以下 4 種 Canary 規則:

  • nginx.ingress.kubernetes.io/canary-by-header:基于 Request Header 的流量切分,適用于灰度發布以及 A/B 測試。當 Request Header 設置為 always 時,請求將會被一直發送到 Canary 版本;當 Request Header 設置為 never 時,請求不會被發送到 Canary 入口;對于任何其他 Header 值,將忽略 Header,并通過優先級將請求與其他金絲雀規則進行優先級的比較。
  • nginx.ingress.kubernetes.io/canary-by-header-value:要匹配的 Request Header 的值,用于通知 Ingress 將請求路由到 Canary Ingress 中指定的服務。當 Request Header 設置為此值時,它將被路由到 Canary 入口。該規則允許用戶自定義 Request Header 的值,必須與上一個 annotation (canary-by-header) 一起使用。
  • nginx.ingress.kubernetes.io/canary-weight:基于服務權重的流量切分,適用于藍綠部署,權重范圍 0 - 100 按百分比將請求路由到 Canary Ingress 中指定的服務。權重為 0 意味著該金絲雀規則不會向 Canary 入口的服務發送任何請求,權重為 100 意味著所有請求都將被發送到 Canary 入口。
  • nginx.ingress.kubernetes.io/canary-by-cookie:基于 cookie 的流量切分,適用于灰度發布與 A/B 測試。用于通知 Ingress 將請求路由到 Canary Ingress 中指定的服務的cookie。當 cookie 值設置為 always 時,它將被路由到 Canary 入口;當 cookie 值設置為 never 時,請求不會被發送到 Canary 入口;對于任何其他值,將忽略 cookie 并將請求與其他金絲雀規則進行優先級的比較。

需要注意的是金絲雀規則按優先順序進行排序:canary-by-header - > canary-by-cookie - > canary-weight

總的來說可以把以上的四個 annotation 規則劃分為以下兩類:

基于權重的 Canary 規則

Kubernetes1.22安裝使用ingress-nginx

基于用戶請求的 Canary 規則

Kubernetes1.22安裝使用ingress-nginx

下面我們通過一個示例應用來對灰度發布功能進行說明。

第一步. 部署 Production 應用

首先創建一個 production 環境的應用資源清單:

  1. # production.yaml
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5. name: production
  6. labels:
  7. app: production
  8. spec:
  9. selector:
  10. matchLabels:
  11. app: production
  12. template:
  13. metadata:
  14. labels:
  15. app: production
  16. spec:
  17. containers:
  18. - name: production
  19. image: cnych/echoserver
  20. ports:
  21. - containerPort: 8080
  22. env:
  23. - name: NODE_NAME
  24. valueFrom:
  25. fieldRef:
  26. fieldPath: spec.nodeName
  27. - name: POD_NAME
  28. valueFrom:
  29. fieldRef:
  30. fieldPath: metadata.name
  31. - name: POD_NAMESPACE
  32. valueFrom:
  33. fieldRef:
  34. fieldPath: metadata.namespace
  35. - name: POD_IP
  36. valueFrom:
  37. fieldRef:
  38. fieldPath: status.podIP
  39. ---
  40. apiVersion: v1
  41. kind: Service
  42. metadata:
  43. name: production
  44. labels:
  45. app: production
  46. spec:
  47. ports:
  48. - port: 80
  49. targetPort: 8080
  50. name: http
  51. selector:
  52. app: production

然后創建一個用于 production 環境訪問的 Ingress 資源對象:

  1. # production-ingress.yaml
  2. apiVersion: networking.k8s.io/v1
  3. kind: Ingress
  4. metadata:
  5. name: production
  6. spec:
  7. ingressClassName: nginx
  8. rules:
  9. - host: echo.qikqiak.com
  10. http:
  11. paths:
  12. - path: /
  13. pathType: Prefix
  14. backend:
  15. service:
  16. name: production
  17. port:
  18. number: 80

直接創建上面的幾個資源對象:

  1. ? kubectl apply -f production.yaml
  2. ? kubectl apply -f production-ingress.yaml
  3. ? kubectl get pods -l app=production
  4. NAME READY STATUS RESTARTS AGE
  5. production-856d5fb99-d6bds 1/1 Running 0 2m50s
  6. ? kubectl get ingress
  7. NAME CLASS HOSTS ADDRESS PORTS AGE
  8. production echo.qikqiak.com 10.151.30.11 80 90s

應用部署成功后,將域名 echo.qikqiak.com 映射到 master1 節點(ingress-nginx 所在的節點)的 IP即可正常訪問應用:

  1. ? curl http://echo.qikqiak.com
  2.  
  3. Hostname: production-856d5fb99-d6bds
  4.  
  5. Pod Information:
  6. node name: node1
  7. pod name: production-856d5fb99-d6bds
  8. pod namespace: default
  9. pod IP: 10.244.1.111
  10.  
  11. Server values:
  12. server_version=nginx: 1.13.3 - lua: 10008
  13.  
  14. Request Information:
  15. client_address=10.244.0.0
  16. method=GET
  17. real path=/
  18. query=
  19. request_version=1.1
  20. request_scheme=http
  21. request_uri=http://echo.qikqiak.com:8080/
  22.  
  23. Request Headers:
  24. accept=*/*
  25. host=echo.qikqiak.com
  26. user-agent=curl/7.64.1
  27. x-forwarded-for=171.223.99.184
  28. x-forwarded-host=echo.qikqiak.com
  29. x-forwarded-port=80
  30. x-forwarded-proto=http
  31. x-real-ip=171.223.99.184
  32. x-request-id=e680453640169a7ea21afba8eba9e116
  33. x-scheme=http
  34.  
  35. Request Body:
  36. -no body in request-

第二步. 創建 Canary 版本

參考將上述 Production 版本的 production.yaml 文件,再創建一個 Canary 版本的應用。

  1. # canary.yaml
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5. name: canary
  6. labels:
  7. app: canary
  8. spec:
  9. selector:
  10. matchLabels:
  11. app: canary
  12. template:
  13. metadata:
  14. labels:
  15. app: canary
  16. spec:
  17. containers:
  18. - name: canary
  19. image: cnych/echoserver
  20. ports:
  21. - containerPort: 8080
  22. env:
  23. - name: NODE_NAME
  24. valueFrom:
  25. fieldRef:
  26. fieldPath: spec.nodeName
  27. - name: POD_NAME
  28. valueFrom:
  29. fieldRef:
  30. fieldPath: metadata.name
  31. - name: POD_NAMESPACE
  32. valueFrom:
  33. fieldRef:
  34. fieldPath: metadata.namespace
  35. - name: POD_IP
  36. valueFrom:
  37. fieldRef:
  38. fieldPath: status.podIP
  39. ---
  40. apiVersion: v1
  41. kind: Service
  42. metadata:
  43. name: canary
  44. labels:
  45. app: canary
  46. spec:
  47. ports:
  48. - port: 80
  49. targetPort: 8080
  50. name: http
  51. selector:
  52. app: canary

接下來就可以通過配置 Annotation 規則進行流量切分了。

第三步. Annotation 規則配置

1. 基于權重:基于權重的流量切分的典型應用場景就是藍綠部署,可通過將權重設置為 0 或 100 來實現。例如,可將 Green 版本設置為主要部分,并將 Blue 版本的入口配置為 Canary。最初,將權重設置為 0,因此不會將流量代理到 Blue 版本。一旦新版本測試和驗證都成功后,即可將 Blue 版本的權重設置為 100,即所有流量從 Green 版本轉向 Blue。

創建一個基于權重的 Canary 版本的應用路由 Ingress 對象。

  1. # canary-ingress.yaml
  2. apiVersion: networking.k8s.io/v1
  3. kind: Ingress
  4. metadata:
  5. name: canary
  6. annotations:
  7. nginx.ingress.kubernetes.io/canary: "true" # 要開啟灰度發布機制,首先需要啟用 Canary
  8. nginx.ingress.kubernetes.io/canary-weight: "30" # 分配30%流量到當前Canary版本
  9. spec:
  10. ingressClassName: nginx
  11. rules:
  12. - host: echo.qikqiak.com
  13. http:
  14. paths:
  15. - path: /
  16. pathType: Prefix
  17. backend:
  18. service:
  19. name: canary
  20. port:
  21. number: 80

直接創建上面的資源對象即可:

  1. ? kubectl apply -f canary.yaml
  2. ? kubectl apply -f canary-ingress.yaml
  3. ? kubectl get pods
  4. NAME READY STATUS RESTARTS AGE
  5. canary-66cb497b7f-48zx4 1/1 Running 0 7m48s
  6. production-856d5fb99-d6bds 1/1 Running 0 21m
  7. ......
  8. ? kubectl get svc
  9. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  10. canary ClusterIP 10.106.91.106 80/TCP 8m23s
  11. production ClusterIP 10.105.182.15 80/TCP 22m
  12. ......
  13. ? kubectl get ingress
  14. NAME CLASS HOSTS ADDRESS PORTS AGE
  15. canary echo.qikqiak.com 10.151.30.11 80 108s
  16. production echo.qikqiak.com 10.151.30.11 80 22m

Canary 版本應用創建成功后,接下來我們在命令行終端中來不斷訪問這個應用,觀察 Hostname 變化:

  1. ? for i in $(seq 1 10); do curl -s echo.qikqiak.com | grep "Hostname"; done
  2. Hostname: production-856d5fb99-d6bds
  3. Hostname: canary-66cb497b7f-48zx4
  4. Hostname: production-856d5fb99-d6bds
  5. Hostname: production-856d5fb99-d6bds
  6. Hostname: production-856d5fb99-d6bds
  7. Hostname: production-856d5fb99-d6bds
  8. Hostname: production-856d5fb99-d6bds
  9. Hostname: canary-66cb497b7f-48zx4
  10. Hostname: canary-66cb497b7f-48zx4
  11. Hostname: production-856d5fb99-d6bds

由于我們給 Canary 版本應用分配了 30% 左右權重的流量,所以上面我們訪問10次有3次訪問到了 Canary 版本的應用,符合我們的預期。

2. 基于 Request Header: 基于 Request Header 進行流量切分的典型應用場景即灰度發布或 A/B 測試場景。

在上面的 Canary 版本的 Ingress 對象中新增一條 annotation 配置 nginx.ingress.kubernetes.io/canary-by-header: canary(這里的 value 可以是任意值),使當前的 Ingress 實現基于 Request Header 進行流量切分,由于 canary-by-header 的優先級大于 canary-weight,所以會忽略原有的 canary-weight 的規則。

  1. annotations:
  2. nginx.ingress.kubernetes.io/canary: "true" # 要開啟灰度發布機制,首先需要啟用 Canary
  3. nginx.ingress.kubernetes.io/canary-by-header: canary # 基于header的流量切分
  4. nginx.ingress.kubernetes.io/canary-weight: "30" # 會被忽略,因為配置了 canary-by-headerCanary版本

更新上面的 Ingress 資源對象后,我們在請求中加入不同的 Header 值,再次訪問應用的域名。

注意:當 Request Header 設置為 never 或 always 時,請求將不會或一直被發送到 Canary 版本,對于任何其他 Header 值,將忽略 Header,并通過優先級將請求與其他 Canary 規則進行優先級的比較。

  1. ? for i in $(seq 1 10); do curl -s -H "canary: never" echo.qikqiak.com | grep "Hostname"; done
  2. Hostname: production-856d5fb99-d6bds
  3. Hostname: production-856d5fb99-d6bds
  4. Hostname: production-856d5fb99-d6bds
  5. Hostname: production-856d5fb99-d6bds
  6. Hostname: production-856d5fb99-d6bds
  7. Hostname: production-856d5fb99-d6bds
  8. Hostname: production-856d5fb99-d6bds
  9. Hostname: production-856d5fb99-d6bds
  10. Hostname: production-856d5fb99-d6bds
  11. Hostname: production-856d5fb99-d6bds

這里我們在請求的時候設置了 canary: never 這個 Header 值,所以請求沒有發送到 Canary 應用中去。如果設置為其他值呢:

  1. ? for i in $(seq 1 10); do curl -s -H "canary: other-value" echo.qikqiak.com | grep "Hostname"; done
  2. Hostname: production-856d5fb99-d6bds
  3. Hostname: production-856d5fb99-d6bds
  4. Hostname: canary-66cb497b7f-48zx4
  5. Hostname: production-856d5fb99-d6bds
  6. Hostname: production-856d5fb99-d6bds
  7. Hostname: production-856d5fb99-d6bds
  8. Hostname: production-856d5fb99-d6bds
  9. Hostname: canary-66cb497b7f-48zx4
  10. Hostname: production-856d5fb99-d6bds
  11. Hostname: canary-66cb497b7f-48zx4

由于我們請求設置的 Header 值為 canary: other-value,所以 ingress-nginx 會通過優先級將請求與其他 Canary 規則進行優先級的比較,我們這里也就會進入 canary-weight: "30" 這個規則去。

這個時候我們可以在上一個 annotation (即 canary-by-header)的基礎上添加一條 nginx.ingress.kubernetes.io/canary-by-header-value: user-value 這樣的規則,就可以將請求路由到 Canary Ingress 中指定的服務了。

  1. annotations:
  2. nginx.ingress.kubernetes.io/canary: "true" # 要開啟灰度發布機制,首先需要啟用 Canary
  3. nginx.ingress.kubernetes.io/canary-by-header-value: user-value
  4. nginx.ingress.kubernetes.io/canary-by-header: canary # 基于header的流量切分
  5. nginx.ingress.kubernetes.io/canary-weight: "30" # 分配30%流量到當前Canary版本

同樣更新 Ingress 對象后,重新訪問應用,當 Request Header 滿足 canary: user-value時,所有請求就會被路由到 Canary 版本:

  1. ? for i in $(seq 1 10); do curl -s -H "canary: user-value" echo.qikqiak.com | grep "Hostname"; done
  2. Hostname: canary-66cb497b7f-48zx4
  3. Hostname: canary-66cb497b7f-48zx4
  4. Hostname: canary-66cb497b7f-48zx4
  5. Hostname: canary-66cb497b7f-48zx4
  6. Hostname: canary-66cb497b7f-48zx4
  7. Hostname: canary-66cb497b7f-48zx4
  8. Hostname: canary-66cb497b7f-48zx4
  9. Hostname: canary-66cb497b7f-48zx4
  10. Hostname: canary-66cb497b7f-48zx4
  11. Hostname: canary-66cb497b7f-48zx4

3. 基于 Cookie:與基于 Request Header 的 annotation 用法規則類似。例如在 A/B 測試場景下,需要讓地域為北京的用戶訪問 Canary 版本。那么當 cookie 的 annotation 設置為 nginx.ingress.kubernetes.io/canary-by-cookie: "users_from_Beijing",此時后臺可對登錄的用戶請求進行檢查,如果該用戶訪問源來自北京則設置 cookie users_from_Beijing 的值為 always,這樣就可以確保北京的用戶僅訪問 Canary 版本。

同樣我們更新 Canary 版本的 Ingress 資源對象,采用基于 Cookie 來進行流量切分,

  1. annotations:
  2. nginx.ingress.kubernetes.io/canary: "true" # 要開啟灰度發布機制,首先需要啟用 Canary
  3. nginx.ingress.kubernetes.io/canary-by-cookie: "users_from_Beijing" # 基于 cookie
  4. nginx.ingress.kubernetes.io/canary-weight: "30" # 會被忽略,因為配置了 canary-by-cookie

更新上面的 Ingress 資源對象后,我們在請求中設置一個 users_from_Beijing=always 的 Cookie 值,再次訪問應用的域名。

  1. ? for i in $(seq 1 10); do curl -s -b "users_from_Beijing=always" echo.qikqiak.com | grep "Hostname"; done
  2. Hostname: canary-66cb497b7f-48zx4
  3. Hostname: canary-66cb497b7f-48zx4
  4. Hostname: canary-66cb497b7f-48zx4
  5. Hostname: canary-66cb497b7f-48zx4
  6. Hostname: canary-66cb497b7f-48zx4
  7. Hostname: canary-66cb497b7f-48zx4
  8. Hostname: canary-66cb497b7f-48zx4
  9. Hostname: canary-66cb497b7f-48zx4
  10. Hostname: canary-66cb497b7f-48zx4
  11. Hostname: canary-66cb497b7f-48zx4

我們可以看到應用都被路由到了 Canary 版本的應用中去了,如果我們將這個 Cookie 值設置為 never,則不會路由到 Canary 應用中。

HTTPS

如果我們需要用 HTTPS 來訪問我們這個應用的話,就需要監聽 443 端口了,同樣用 HTTPS 訪問應用必然就需要證書,這里我們用 openssl 來創建一個自簽名的證書:

  1. ? openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=foo.bar.com"

然后通過 Secret 對象來引用證書文件:

  1. # 要注意證書文件名稱必須是 tls.crt 和 tls.key
  2. ? kubectl create secret tls foo-tls --cert=tls.crt --key=tls.key
  3. secret/who-tls created

這個時候我們就可以創建一個 HTTPS 訪問應用的:

  1. apiVersion: networking.k8s.io/v1
  2. kind: Ingress
  3. metadata:
  4. name: ingress-with-auth
  5. annotations:
  6. # 認證類型
  7. nginx.ingress.kubernetes.io/auth-type: basic
  8. # 包含 user/password 定義的 secret 對象名
  9. nginx.ingress.kubernetes.io/auth-secret: basic-auth
  10. # 要顯示的帶有適當上下文的消息,說明需要身份驗證的原因
  11. nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - foo'
  12. spec:
  13. ingressClassName: nginx
  14. tls: # 配置 tls 證書
  15. - hosts:
  16. - foo.bar.com
  17. secretName: foo-tls
  18. rules:
  19. - host: foo.bar.com
  20. http:
  21. paths:
  22. - path: /
  23. pathType: Prefix
  24. backend:
  25. service:
  26. name: my-nginx
  27. port:
  28. number: 80

除了自簽名證書或者購買正規機構的 CA 證書之外,我們還可以通過一些工具來自動生成合法的證書,cert-manager 是一個云原生證書管理開源項目,可以用于在 Kubernetes 集群中提供 HTTPS 證書并自動續期,支持 Let's Encrypt/HashiCorp/Vault 這些免費證書的簽發。在 Kubernetes 中,可以通過 Kubernetes Ingress 和 Let's Encrypt 實現外部服務的自動化 HTTPS。

TCP與UDP

由于在 Ingress 資源對象中沒有直接對 TCP 或 UDP 服務的支持,要在 ingress-nginx 中提供支持,需要在控制器啟動參數中添加 --tcp-services-configmap 和 --udp-services-configmap 標志指向一個 ConfigMap,其中的 key 是要使用的外部端口,value 值是使用格式 ::[PROXY]:[PROXY] 暴露的服務,端口可以使用端口號或者端口名稱,最后兩個字段是可選的,用于配置 PROXY 代理。

比如現在我們要通過 ingress-nginx 來暴露一個 MongoDB 服務,首先創建如下的應用:

  1. # mongo.yaml
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5. name: mongo
  6. labels:
  7. app: mongo
  8. spec:
  9. selector:
  10. matchLabels:
  11. app: mongo
  12. template:
  13. metadata:
  14. labels:
  15. app: mongo
  16. spec:
  17. volumes:
  18. - name: data
  19. emptyDir: {}
  20. containers:
  21. - name: mongo
  22. image: mongo:4.0
  23. ports:
  24. - containerPort: 27017
  25. volumeMounts:
  26. - name: data
  27. mountPath: /data/db
  28. ---
  29. apiVersion: v1
  30. kind: Service
  31. metadata:
  32. name: mongo
  33. spec:
  34. selector:
  35. app: mongo
  36. ports:
  37. - port: 27017

直接創建上面的資源對象:

  1. ? kubectl apply -f mongo.yaml
  2. ? kubectl get svc
  3. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  4. mongo ClusterIP 10.98.117.228 27017/TCP 2m26s
  5. ? kubectl get pods -l app=mongo
  6. NAME READY STATUS RESTARTS AGE
  7. mongo-84c587f547-gd7pv 1/1 Running 0 2m5s

現在我們要通過 ingress-nginx 來暴露上面的 MongoDB 服務,我們需要創建一個如下所示的 ConfigMap:

  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadata:
  4. name: tcp-services
  5. namespace: ingress-nginx
  6. data:
  7. "27017": default/mongo:27017

然后在 ingress-nginx 的啟動參數中添加 --tcp-services-configmap=$(POD_NAMESPACE)/ingress-nginx-tcp 這樣的配置即可,由于我們這里使用的是 Helm Chart 進行安裝的,我們只需要去覆蓋 Values 值重新安裝即可,修改 ci/daemonset-prod.yaml 文件:

  1. # ci/daemonset-prod.yaml
  2. # ...... 其他部分省略,和之前的保持一致
  3.  
  4. tcp: # 配置 tcp 服務
  5. 27017: "default/mongo:27017" # 使用 27017 端口去映射 mongo 服務
  6. # 9000: "default/test:8080" # 如果還需要暴露其他 TCP 服務,繼續添加即可

配置完成后重新更新當前的 ingress-nginx:

  1. ? helm upgrade --install ingress-nginx . -f ./ci/daemonset-prod.yaml --namespace ingress-nginx

重新部署完成后會自動生成一個名為 ingress-nginx-tcp 的 ConfigMap 對象,如下所示:

  1. ? kubectl get configmap -n ingress-nginx ingress-nginx-tcp -o yaml
  2. apiVersion: v1
  3. data:
  4. "27017": default/mongo:27017
  5. kind: ConfigMap
  6. metadata:
  7. ......
  8. name: ingress-nginx-tcp
  9. namespace: ingress-nginx

在 ingress-nginx 的啟動參數中也添加上 --tcp-services-configmap=$(POD_NAMESPACE)/ingress-nginx-tcp 這樣的配置:

  1. ? kubectl get pods -n ingress-nginx
  2. NAME READY STATUS RESTARTS AGE
  3. ingress-nginx-controller-gc582 1/1 Running 0 5m17s
  4. ? kubectl get pod ingress-nginx-controller-gc582 -n ingress-nginx -o yaml
  5. apiVersion: v1
  6. kind: Pod
  7. ......
  8. containers:
  9. - args:
  10. - /nginx-ingress-controller
  11. - --default-backend-service=$(POD_NAMESPACE)/ingress-nginx-defaultbackend
  12. - --election-id=ingress-controller-leader
  13. - --controller-class=k8s.io/ingress-nginx
  14. - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
  15. - --tcp-services-configmap=$(POD_NAMESPACE)/ingress-nginx-tcp # tcp 配置參數
  16. - --validating-webhook=:8443
  17. - --validating-webhook-certificate=/usr/local/certificates/cert
  18. - --validating-webhook-key=/usr/local/certificates/key
  19. ......
  20. ports:
  21. ......
  22. - containerPort: 27017
  23. hostPort: 27017
  24. name: 27017-tcp
  25. protocol: TCP
  26. ......

現在我們就可以通過 ingress-nginx 暴露的 27017 端口去訪問 Mongo 服務了:

  1. ? mongo --host 192.168.31.31 --port 27017
  2. MongoDB shell version v4.0.3
  3. connecting to: mongodb://192.168.31.31:27017/
  4. Implicit session: session { "id" : UUID("10f462eb-32b8-443b-ad85-99820db1aaa0") }
  5. MongoDB server version: 4.0.27
  6. ......
  7.  
  8. > show dbs
  9. admin 0.000GB
  10. config 0.000GB
  11. local 0.000GB
  12. >

同樣的我們也可以去查看最終生成的 nginx.conf 配置文件:

  1. ? kubectl exec -it ingress-nginx-controller-gc582 -n ingress-nginx -- cat /etc/nginx/nginx.conf
  2. ......
  3. stream {
  4. ......
  5. # TCP services
  6. server {
  7. preread_by_lua_block {
  8. ngx.var.proxy_upstream_name="tcp-default-mongo-27017";
  9. }
  10. listen 27017;
  11. listen [::]:27017;
  12. proxy_timeout 600s;
  13. proxy_next_upstream on;
  14. proxy_next_upstream_timeout 600s;
  15. proxy_next_upstream_tries 3;
  16. proxy_pass upstream_balancer;
  17. }
  18. # UDP services
  19. }

TCP 相關的配置位于 stream 配置塊下面。從 Nginx 1.9.13 版本開始提供 UDP 負載均衡,同樣我們也可以在 ingress-nginx 中來代理 UDP 服務,比如我們可以去暴露 kube-dns 的服務,同樣需要創建一個如下所示的 ConfigMap:

  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadata:
  4. name: udp-services
  5. namespace: ingress-nginx
  6. data:
  7. 53: "kube-system/kube-dns:53"

然后需要在 ingress-nginx 參數中添加一個 - --udp-services-configmap=$(POD_NAMESPACE)/udp-services 這樣的配置,當然我們這里只需要去修改 Values 文件值即可,修改 ci/daemonset-prod.yaml 文件:

  1. # ci/daemonset-prod.yaml
  2. # ...... 其他部分省略,和之前的保持一致
  3.  
  4. tcp: # 配置 tcp 服務
  5. 27017: "default/mongo:27017" # 使用 27017 端口去映射 mongo 服務
  6. # 9000: "default/test:8080" # 如果還需要暴露其他 TCP 服務,繼續添加即可
  7.  
  8. udp: # 配置 udp 服務
  9. 53: "kube-system/kube-dns:53"

然后重新更新即可。

全局配置

除了可以通過 annotations 對指定的 Ingress 進行定制之外,我們還可以配置 ingress-nginx 的全局配置,在控制器啟動參數中通過標志 --configmap 指定了一個全局的 ConfigMap 對象,我們可以將全局的一些配置直接定義在該對象中即可:

  1. containers:
  2. - args:
  3. - /nginx-ingress-controller
  4. - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
  5. ......

比如這里我們用于全局配置的 ConfigMap 名為 ingress-nginx-controller:

  1. ? kubectl get configmap -n ingress-nginx
  2. NAME DATA AGE
  3. ingress-nginx-controller 1 5d2h

比如我們可以添加如下所示的一些常用配置:

  1. ? kubectl edit configmap ingress-nginx-controller -n ingress-nginx
  2. apiVersion: v1
  3. data:
  4. allow-snippet-annotations: "true"
  5. client-header-buffer-size: 32k # 注意不是下劃線
  6. client-max-body-size: 5m
  7. use-gzip: "true"
  8. gzip-level: "7"
  9. large-client-header-buffers: 4 32k
  10. proxy-connect-timeout: 11s
  11. proxy-read-timeout: 12s
  12. keep-alive: "75" # 啟用keep-alive,連接復用,提高QPS
  13. keep-alive-requests: "100"
  14. upstream-keepalive-connections: "10000"
  15. upstream-keepalive-requests: "100"
  16. upstream-keepalive-timeout: "60"
  17. disable-ipv6: "true"
  18. disable-ipv6-dns: "true"
  19. max-worker-connections: "65535"
  20. max-worker-open-files: "10240"
  21. kind: ConfigMap
  22. ......

修改完成后 Nginx 配置會自動重載生效,我們可以查看 nginx.conf 配置文件進行驗證:

  1. ? kubectl exec -it ingress-nginx-controller-gc582 -n ingress-nginx -- cat /etc/nginx/nginx.conf |grep large_client_header_buffers
  2. large_client_header_buffers 4 32k;

由于我們這里是 Helm Chart 安裝的,為了保證重新部署后配置還在,我們同樣需要通過 Values 進行全局配置:

  1. # ci/daemonset-prod.yaml
  2. controller:
  3. config:
  4. allow-snippet-annotations: "true"
  5. client-header-buffer-size: 32k # 注意不是下劃線
  6. client-max-body-size: 5m
  7. use-gzip: "true"
  8. gzip-level: "7"
  9. large-client-header-buffers: 4 32k
  10. proxy-connect-timeout: 11s
  11. proxy-read-timeout: 12s
  12. keep-alive: "75" # 啟用keep-alive,連接復用,提高QPS
  13. keep-alive-requests: "100"
  14. upstream-keepalive-connections: "10000"
  15. upstream-keepalive-requests: "100"
  16. upstream-keepalive-timeout: "60"
  17. disable-ipv6: "true"
  18. disable-ipv6-dns: "true"
  19. max-worker-connections: "65535"
  20. max-worker-open-files: "10240"
  21.  
  22. # 其他省略

此外往往我們還需要對 ingress-nginx 部署的節點進行性能優化,修改一些內核參數,使得適配 Nginx 的使用場景,一般我們是直接去修改節點上的內核參數,為了能夠統一管理,我們可以使用 initContainers 來進行配置:

  1. initContainers:
  2. - command:
  3. - /bin/sh
  4. - -c
  5. - |
  6. mount -o remount rw /proc/sys
  7. sysctl -w net.core.somaxconn=65535 # 具體的配置視具體情況而定
  8. sysctl -w net.ipv4.tcp_tw_reuse=1
  9. sysctl -w net.ipv4.ip_local_port_range="1024 65535"
  10. sysctl -w fs.file-max=1048576
  11. sysctl -w fs.inotify.max_user_instances=16384
  12. sysctl -w fs.inotify.max_user_watches=524288
  13. sysctl -w fs.inotify.max_queued_events=16384
  14. image: busybox
  15. imagePullPolicy: IfNotPresent
  16. name: init-sysctl
  17. securityContext:
  18. capabilities:
  19. add:
  20. - SYS_ADMIN
  21. drop:
  22. - ALL
  23. ......

由于我們這里使用的是 Helm Chart 安裝的 ingress-nginx,同樣只需要去配置 Values 值即可,模板中提供了對 initContainers 的支持,配置如下所示:

  1. controller:
  2. # 其他省略,配置 initContainers
  3. extraInitContainers:
  4. - name: init-sysctl
  5. image: busybox
  6. securityContext:
  7. capabilities:
  8. add:
  9. - SYS_ADMIN
  10. drop:
  11. - ALL
  12. command:
  13. - /bin/sh
  14. - -c
  15. - |
  16. mount -o remount rw /proc/sys
  17. sysctl -w net.core.somaxconn=65535 # socket監聽的backlog上限
  18. sysctl -w net.ipv4.tcp_tw_reuse=1 # 開啟重用,允許將 TIME-WAIT sockets 重新用于新的TCP連接
  19. sysctl -w net.ipv4.ip_local_port_range="1024 65535"
  20. sysctl -w fs.file-max=1048576
  21. sysctl -w fs.inotify.max_user_instances=16384
  22. sysctl -w fs.inotify.max_user_watches=524288
  23. sysctl -w fs.inotify.max_queued_events=16384

同樣重新部署即可:

  1. ? helm upgrade --install ingress-nginx . -f ./ci/daemonset-prod.yaml --namespace ingress-nginx

部署完成后通過 initContainers 就可以修改節點內核參數了,生產環境建議對節點內核參數進行相應的優化。

原文鏈接:https://mp.weixin.qq.com/s/XoUaW-vBtQFxwNM3UdD8QA

延伸 · 閱讀

精彩推薦
654
主站蜘蛛池模板: 国产噜噜噜噜久久久久久久久 | 国产一级毛片高清视频完整版 | 中国洗澡偷拍在线播放 | a免费毛片 | 国产91一区二区三区 | 日韩黄色av | 欧美福利视频一区二区 | 亚洲尻逼视频 | 午夜av男人的天堂 | 激情网站视频 | av不卡免费在线观看 | 久久色在线 | 亚洲导航深夜福利涩涩屋 | 手机国产乱子伦精品视频 | 操穴视频 | 免费看成年人网站 | 久草免费资源视频 | 成人区精品一区二区婷婷 | 黄色免费小网站 | 国产精品成人亚洲一区二区 | 国产亚洲精品久久久久久久久 | h视频在线免费观看 | 色人久久 | 色女人在线| 欧美一级做性受免费大片免费 | 国产精品久久久久久久久久尿 | 亚洲一区二区三区精品在线观看 | 在线播放免费人成毛片乱码 | 成人一区二区在线观看视频 | 精品亚洲va在线va天堂资源站 | 色诱亚洲精品久久久久久 | 成人综合在线观看 | 伊人在线| 国产91在线高潮白浆在线观看 | 亚洲视频高清 | 青草久久久久 | 久草最新在线 | 视频h在线| 久久蜜桃精品一区二区三区综合网 | fc2成人免费人成在线观看播放 | 国产精品久久久久久久久久久久午夜 |