<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          kubernetes1.22安裝使用ingress-nginx

          共 15767字,需瀏覽 32分鐘

           ·

          2021-12-25 05:37

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

          運行原理

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

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

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

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

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

          安裝

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

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

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

          #?如果你不喜歡使用?helm?chart?進行安裝也可以使用下面的命令一鍵安裝
          #?kubectl?apply?-f?https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.0/deploy/static/provider/cloud/deploy.yaml
          ??helm?repo?add?ingress-nginx?https://kubernetes.github.io/ingress-nginx
          ??helm?repo?update
          ??helm?fetch?ingress-nginx/ingress-nginx
          ??tar?-xvf?ingress-nginx-4.0.13.tgz?&&?cd?ingress-nginx
          ??tree?.
          .
          ├──?CHANGELOG.md
          ├──?Chart.yaml
          ├──?OWNERS
          ├──?README.md
          ├──?ci
          │???├──?controller-custom-ingressclass-flags.yaml
          │???├──?daemonset-customconfig-values.yaml
          │???├──?daemonset-customnodeport-values.yaml
          │???├──?daemonset-headers-values.yaml
          │???├──?daemonset-internal-lb-values.yaml
          │???├──?daemonset-nodeport-values.yaml
          │???├──?daemonset-podannotations-values.yaml
          │???├──?daemonset-tcp-udp-configMapNamespace-values.yaml
          │???├──?daemonset-tcp-udp-values.yaml
          │???├──?daemonset-tcp-values.yaml
          │???├──?deamonset-default-values.yaml
          │???├──?deamonset-metrics-values.yaml
          │???├──?deamonset-psp-values.yaml
          │???├──?deamonset-webhook-and-psp-values.yaml
          │???├──?deamonset-webhook-values.yaml
          │???├──?deployment-autoscaling-behavior-values.yaml
          │???├──?deployment-autoscaling-values.yaml
          │???├──?deployment-customconfig-values.yaml
          │???├──?deployment-customnodeport-values.yaml
          │???├──?deployment-default-values.yaml
          │???├──?deployment-headers-values.yaml
          │???├──?deployment-internal-lb-values.yaml
          │???├──?deployment-metrics-values.yaml
          │???├──?deployment-nodeport-values.yaml
          │???├──?deployment-podannotations-values.yaml
          │???├──?deployment-psp-values.yaml
          │???├──?deployment-tcp-udp-configMapNamespace-values.yaml
          │???├──?deployment-tcp-udp-values.yaml
          │???├──?deployment-tcp-values.yaml
          │???├──?deployment-webhook-and-psp-values.yaml
          │???├──?deployment-webhook-resources-values.yaml
          │???└──?deployment-webhook-values.yaml
          ├──?templates
          │???├──?NOTES.txt
          │???├──?_helpers.tpl
          │???├──?_params.tpl
          │???├──?admission-webhooks
          │???│???├──?job-patch
          │???│???│???├──?clusterrole.yaml
          │???│???│???├──?clusterrolebinding.yaml
          │???│???│???├──?job-createSecret.yaml
          │???│???│???├──?job-patchWebhook.yaml
          │???│???│???├──?psp.yaml
          │???│???│???├──?role.yaml
          │???│???│???├──?rolebinding.yaml
          │???│???│???└──?serviceaccount.yaml
          │???│???└──?validating-webhook.yaml
          │???├──?clusterrole.yaml
          │???├──?clusterrolebinding.yaml
          │???├──?controller-configmap-addheaders.yaml
          │???├──?controller-configmap-proxyheaders.yaml
          │???├──?controller-configmap-tcp.yaml
          │???├──?controller-configmap-udp.yaml
          │???├──?controller-configmap.yaml
          │???├──?controller-daemonset.yaml
          │???├──?controller-deployment.yaml
          │???├──?controller-hpa.yaml
          │???├──?controller-ingressclass.yaml
          │???├──?controller-keda.yaml
          │???├──?controller-poddisruptionbudget.yaml
          │???├──?controller-prometheusrules.yaml
          │???├──?controller-psp.yaml
          │???├──?controller-role.yaml
          │???├──?controller-rolebinding.yaml
          │???├──?controller-service-internal.yaml
          │???├──?controller-service-metrics.yaml
          │???├──?controller-service-webhook.yaml
          │???├──?controller-service.yaml
          │???├──?controller-serviceaccount.yaml
          │???├──?controller-servicemonitor.yaml
          │???├──?default-backend-deployment.yaml
          │???├──?default-backend-hpa.yaml
          │???├──?default-backend-poddisruptionbudget.yaml
          │???├──?default-backend-psp.yaml
          │???├──?default-backend-role.yaml
          │???├──?default-backend-rolebinding.yaml
          │???├──?default-backend-service.yaml
          │???├──?default-backend-serviceaccount.yaml
          │???└──?dh-param-secret.yaml
          └──?values.yaml

          4?directories,?81?files

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

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

          #?ci/daemonset-prod.yaml
          controller:
          ??name:?controller
          ??image:
          ????repository:?cnych/ingress-nginx
          ????tag:?"v1.1.0"
          ????digest:

          ??dnsPolicy:?ClusterFirstWithHostNet

          ??hostNetwork:?true

          ??publishService:??#?hostNetwork?模式下設置為false,通過節(jié)點IP地址上報ingress?status數(shù)據(jù)
          ????enabled:?false

          ??#?是否需要處理不帶?ingressClass?注解或者?ingressClassName?屬性的?Ingress?對象
          ??#?設置為?true?會在控制器啟動參數(shù)中新增一個?--watch-ingress-without-class?標注
          ??watchIngressWithoutClass:?false

          ??kind:?DaemonSet

          ??tolerations:???#?kubeadm?安裝的集群默認情況下master是有污點,需要容忍這個污點才可以部署
          ??-?key:?"node-role.kubernetes.io/master"
          ????operator:?"Equal"
          ????effect:?"NoSchedule"

          ??nodeSelector:???#?固定到master1節(jié)點
          ????kubernetes.io/hostname:?master1

          ??service:??#?HostNetwork?模式不需要創(chuàng)建service
          ????enabled:?false

          ??admissionWebhooks:?#?強烈建議開啟?admission?webhook
          ????enabled:?true
          ????createSecretJob:
          ??????resources:
          ????????limits:
          ??????????cpu:?10m
          ??????????memory:?20Mi
          ????????requests:
          ??????????cpu:?10m
          ??????????memory:?20Mi
          ????patchWebhookJob:
          ??????resources:
          ????????limits:
          ??????????cpu:?10m
          ??????????memory:?20Mi
          ????????requests:
          ??????????cpu:?10m
          ??????????memory:?20Mi
          ????patch:
          ??????enabled:?true
          ??????image:
          ????????repository:?cnych/ingress-nginx-webhook-certgen
          ????????tag:?v1.1.1
          ????????digest:

          defaultBackend:??#?配置默認后端
          ??enabled:?true
          ??name:?defaultbackend
          ??image:
          ????repository:?cnych/ingress-nginx-defaultbackend
          ????tag:?"1.5"

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

          ??kubectl?create?ns?ingress-nginx
          ??helm?upgrade?--install?ingress-nginx?.?-f?./ci/daemonset-prod.yaml?--namespace?ingress-nginx
          Release?"ingress-nginx"?does?not?exist.?Installing?it?now.

          NAME:?ingress-nginx
          LAST?DEPLOYED:?Thu?Dec?16?16:47:20?2021
          NAMESPACE:?ingress-nginx
          STATUS:?deployed
          REVISION:?1
          TEST?SUITE:?None
          NOTES:
          The?ingress-nginx?controller?has?been?installed.
          It?may?take?a?few?minutes?for?the?LoadBalancer?IP?to?be?available.
          You?can?watch?the?status?by?running?'kubectl?--namespace?ingress-nginx?get?services?-o?wide?-w?ingress-nginx-controller'

          An?example?Ingress?that?makes?use?of?the?controller:
          ??apiVersion:?networking.k8s.io/v1
          ??kind:?Ingress
          ??metadata:
          ????name:?example
          ????namespace:?foo
          ??spec:
          ????ingressClassName:?nginx
          ????rules:
          ??????-?host:?www.example.com
          ????????http:
          ??????????paths:
          ????????????-?backend:
          ????????????????service:
          ??????????????????name:?exampleService
          ??????????????????port:
          ????????????????????number:?80
          ??????????????path:?/
          ????#?This?section?is?only?required?if?TLS?is?to?be?enabled?for?the?Ingress
          ????tls:
          ??????-?hosts:
          ????????-?www.example.com
          ????????secretName:?example-tls

          If?TLS?is?enabled?for?the?Ingress,?a?Secret?containing?the?certificate?and?key?must?also?be?provided:

          ??apiVersion:?v1
          ??kind:?Secret
          ??metadata:
          ????name:?example-tls
          ????namespace:?foo
          ??data:
          ????tls.crt:?
          ????tls.key:?
          ??type:?kubernetes.io/tls

          部署完成后查看 Pod 的運行狀態(tài):

          ??kubectl?get?svc?-n?ingress-nginx
          NAME?????????????????????????????????TYPE????????CLUSTER-IP??????EXTERNAL-IP???PORT(S)???AGE
          ingress-nginx-controller-admission???ClusterIP???10.96.15.99?????????????443/TCP???11m
          ingress-nginx-defaultbackend?????????ClusterIP???10.97.250.253???????????80/TCP????11m
          ??kubectl?get?pods?-n?ingress-nginx
          NAME????????????????????????????????????????????READY???STATUS????RESTARTS???AGE
          ingress-nginx-controller-5dfdd4659c-9g7c2???????1/1?????Running???0??????????11m
          ingress-nginx-defaultbackend-84854cd6cb-xb7rv???1/1?????Running???0??????????11m
          ??POD_NAME=$(kubectl?get?pods?-l?app.kubernetes.io/name=ingress-nginx?-n?ingress-nginx?-o?jsonpath='{.items[0].metadata.name}')
          ??kubectl?exec?-it?$POD_NAME?-n?ingress-nginx?--?/nginx-ingress-controller?--version
          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.
          I1216?08:51:22.179525???????7?main.go:223]?"Creating?API?client"?host="https://10.96.0.1:443"
          -------------------------------------------------------------------------------
          NGINX?Ingress?controller
          ??Release:???????v1.1.0
          ??Build:?????????cacbee86b6ccc45bde8ffc184521bed3022e7dee
          ??Repository:????https://github.com/kubernetes/ingress-nginx
          ??nginx?version:?nginx/1.19.9

          -------------------------------------------------------------------------------

          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"
          I1216?08:51:22.200478???????7?main.go:86]?"Valid?default?backend"?service="ingress-nginx/ingress-nginx-defaultbackend"
          I1216?08:51:22.611100???????7?main.go:104]?"SSL?fake?certificate?created"?file="/etc/ingress-controller/ssl/default-fake-certificate.pem"
          I1216?08:51:22.627386???????7?ssl.go:531]?"loading?tls?certificate"?path="/usr/local/certificates/cert"?key="/usr/local/certificates/key"
          I1216?08:51:22.651187???????7?nginx.go:255]?"Starting?NGINX?Ingress?controller"

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

          ??kubectl?get?ingressclass
          NAME????CONTROLLER?????????????PARAMETERS???AGE
          nginx???k8s.io/ingress-nginx??????????18m
          ??kubectl?get?ingressclass?nginx?-o?yaml
          apiVersion:?networking.k8s.io/v1
          kind:?IngressClass
          metadata:
          ??......
          ??name:?nginx
          ??resourceVersion:?"1513966"
          ??uid:?70340e62-cab6-4a11-9982-2108f1db786b
          spec:
          ??controller:?k8s.io/ingress-nginx

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

          第一個示例

          安裝成功后,現(xiàn)在我們來為一個 nginx 應用創(chuàng)建一個 Ingress 資源,如下所示:

          #?my-nginx.yaml
          apiVersion:?apps/v1
          kind:?Deployment
          metadata:
          ??name:?my-nginx
          spec:
          ??selector:
          ????matchLabels:
          ??????app:?my-nginx
          ??template:
          ????metadata:
          ??????labels:
          ????????app:?my-nginx
          ????spec:
          ??????containers:
          ??????-?name:?my-nginx
          ????????image:?nginx
          ????????ports:
          ????????-?containerPort:?80
          ---
          apiVersion:?v1
          kind:?Service
          metadata:
          ??name:?my-nginx
          ??labels:
          ????app:?my-nginx
          spec:
          ??ports:
          ??-?port:?80
          ????protocol:?TCP
          ????name:?http
          ??selector:
          ????app:?my-nginx
          ---
          apiVersion:?networking.k8s.io/v1
          kind:?Ingress
          metadata:
          ??name:?my-nginx
          ??namespace:?default
          spec:
          ??ingressClassName:?nginx??#?使用?nginx?的?IngressClass(關聯(lián)的?ingress-nginx?控制器)
          ??rules:
          ??-?host:?ngdemo.qikqiak.com??#?將域名映射到?my-nginx?服務
          ????http:
          ??????paths:
          ??????-?path:?/
          ????????pathType:?Prefix
          ????????backend:
          ??????????service:??#?將所有請求發(fā)送到?my-nginx?服務的?80?端口
          ????????????name:?my-nginx
          ????????????port:
          ??????????????number:?80
          #?不過需要注意大部分Ingress控制器都不是直接轉發(fā)到Service
          #?而是只是通過Service來獲取后端的Endpoints列表,直接轉發(fā)到Pod,這樣可以減少網(wǎng)絡跳轉,提高性能

          直接創(chuàng)建上面的資源對象:

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

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

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

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

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

          ??kubectl?exec?-it?$POD_NAME?-n?ingress-nginx?--?cat?/etc/nginx/nginx.conf

          ......
          upstream?upstream_balancer?{
          ????????server?0.0.0.1;?#?placeholder
          ????????balancer_by_lua_block?{
          ????????????????balancer.balance()
          ????????}
          ????????keepalive?320;
          ????????keepalive_timeout??60s;
          ????????keepalive_requests?10000;
          }

          ......
          ##?start?server?ngdemo.qikqiak.com
          server?{
          ????????server_name?ngdemo.qikqiak.com?;

          ????????listen?80??;
          ????????listen?[::]:80??;
          ????????listen?443??ssl?http2?;
          ????????listen?[::]:443??ssl?http2?;

          ????????set?$proxy_upstream_name?"-";

          ????????ssl_certificate_by_lua_block?{
          ????????????????certificate.call()
          ????????}

          ????????location?/?{

          ????????????????set?$namespace??????"default";
          ????????????????set?$ingress_name???"my-nginx";
          ????????????????set?$service_name???"my-nginx";
          ????????????????set?$service_port???"80";
          ????????????????set?$location_path??"/";
          ????????????????set?$global_rate_limit_exceeding?n;
          ????????????????......
          ????????????????proxy_next_upstream_timeout?????????????0;
          ????????????????proxy_next_upstream_tries???????????????3;

          ????????????????proxy_pass?http://upstream_balancer;

          ????????????????proxy_redirect??????????????????????????off;

          ????????}

          }
          ##?end?server?ngdemo.qikqiak.com
          ......

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

          Nginx 配置

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

          Basic Auth

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

          ??htpasswd?-c?auth?foo
          New?password:
          Re-type?new?password:
          Adding?password?for?user?foo

          然后根據(jù)上面的 auth 文件創(chuàng)建一個 secret 對象:

          ??kubectl?create?secret?generic?basic-auth?--from-file=auth
          secret/basic-auth?created
          ??kubectl?get?secret?basic-auth?-o?yaml
          apiVersion:?v1
          data:
          ??auth:?Zm9vOiRhcHIxJFUxYlFZTFVoJHdIZUZQQ1dyZTlGRFZONTQ0dXVQdC4K
          kind:?Secret
          metadata:
          ??name:?basic-auth
          ??namespace:?default
          type:?Opaque

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

          apiVersion:?networking.k8s.io/v1
          kind:?Ingress
          metadata:
          ??name:?ingress-with-auth
          ??namespace:?default
          ??annotations:
          ????nginx.ingress.kubernetes.io/auth-type:?basic??#?認證類型
          ????nginx.ingress.kubernetes.io/auth-secret:?basic-auth??#?包含?user/password?定義的?secret?對象名
          ????nginx.ingress.kubernetes.io/auth-realm:?'Authentication?Required?-?foo'??#?要顯示的帶有適當上下文的消息,說明需要身份驗證的原因
          spec:
          ??ingressClassName:?nginx??#?使用?nginx?的?IngressClass(關聯(lián)的?ingress-nginx?控制器)
          ??rules:
          ??-?host:?bauth.qikqiak.com??#?將域名映射到?my-nginx?服務
          ????http:
          ??????paths:
          ??????-?path:?/
          ????????pathType:?Prefix
          ????????backend:
          ??????????service:??#?將所有請求發(fā)送到?my-nginx?服務的?80?端口
          ????????????name:?my-nginx
          ????????????port:
          ??????????????number:?80

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

          ??kubectl?get?ingress
          NAME????????????????CLASS????HOSTS????????????????????????ADDRESS?????????PORTS???AGE
          ingress-with-auth???nginx????bauth.qikqiak.com????????????192.168.31.31???80??????6m55s
          ??curl?-v?http://192.168.31.31?-H?'Host:?bauth.qikqiak.com'
          *???Trying?192.168.31.31...
          *?TCP_NODELAY?set
          *?Connected?to?192.168.31.31?(192.168.31.31)?port?80?(#0)
          >?GET?/?HTTP/1.1
          >?Host:?bauth.qikqiak.com
          >?User-Agent:?curl/7.64.1
          >?Accept:?*/*
          >
          <

          401?Authorization?Required

          401?Authorization?Required



          nginx



          *?Connection?#0?to?host?192.168.31.31?left?intact
          *?Closing?connection?0

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

          ??curl?-v?http://192.168.31.31?-H?'Host:?bauth.qikqiak.com'?-u?'foo:foo'
          *???Trying?192.168.31.31...
          *?TCP_NODELAY?set
          *?Connected?to?192.168.31.31?(192.168.31.31)?port?80?(#0)
          *?Server?auth?using?Basic?with?user?'foo'
          >?GET?/?HTTP/1.1
          >?Host:?bauth.qikqiak.com
          >?Authorization:?Basic?Zm9vOmZvbw==
          >?User-Agent:?curl/7.64.1
          >?Accept:?*/*
          >
          <



          Welcome?to?nginx!



          Welcome?to?nginx!


          If?you?see?this?page,?the?nginx?web?server?is?successfully?installed?and
          working.?Further?configuration?is?required.



          For?online?documentation?and?support?please?refer?to
          nginx.org.

          Commercial?support?is?available?at
          nginx.com.



          Thank?you?for?using?nginx.




          *?Connection?#0?to?host?192.168.31.31?left?intact
          *?Closing?connection?0

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

          apiVersion:?networking.k8s.io/v1
          kind:?Ingress
          metadata:
          ??annotations:
          ????#?配置外部認證服務地址
          ????nginx.ingress.kubernetes.io/auth-url:?https://httpbin.org/basic-auth/user/passwd
          ??name:?external-auth
          ??namespace:?default
          spec:
          ??ingressClassName:?nginx
          ??rules:
          ??-?host:?external-bauth.qikqiak.com
          ????http:
          ??????paths:
          ??????-?path:?/
          ????????pathType:?Prefix
          ????????backend:
          ??????????service:
          ????????????name:?my-nginx
          ????????????port:
          ??????????????number:?80

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

          ??kubectl?get?ingress
          NAME????????????????CLASS????HOSTS????????????????????????ADDRESS?????????PORTS???AGE
          external-auth??????????external-bauth.qikqiak.com???????????????????80??????72s
          ??curl?-k?http://192.168.31.31?-v?-H?'Host:?external-bauth.qikqiak.com'
          *???Trying?192.168.31.31...
          *?TCP_NODELAY?set
          *?Connected?to?192.168.31.31?(192.168.31.31)?port?80?(#0)
          >?GET?/?HTTP/1.1
          >?Host:?external-bauth.qikqiak.com
          >?User-Agent:?curl/7.64.1
          >?Accept:?*/*
          >
          <

          401?Authorization?Required

          401?Authorization?Required



          nginx



          *?Connection?#0?to?host?192.168.31.31?left?intact
          *?Closing?connection?0

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

          ??curl?-k?http://192.168.31.31?-v?-H?'Host:?external-bauth.qikqiak.com'?-u?'user:passwd'
          *???Trying?192.168.31.31...
          *?TCP_NODELAY?set
          *?Connected?to?192.168.31.31?(192.168.31.31)?port?80?(#0)
          *?Server?auth?using?Basic?with?user?'user'
          >?GET?/?HTTP/1.1
          >?Host:?external-bauth.qikqiak.com
          >?Authorization:?Basic?dXNlcjpwYXNzd2Q=
          >?User-Agent:?curl/7.64.1
          >?Accept:?*/*
          >
          <



          Welcome?to?nginx!



          Welcome?to?nginx!


          If?you?see?this?page,?the?nginx?web?server?is?successfully?installed?and
          working.?Further?configuration?is?required.



          For?online?documentation?and?support?please?refer?to
          nginx.org.

          Commercial?support?is?available?at
          nginx.com.



          Thank?you?for?using?nginx.




          *?Connection?#0?to?host?192.168.31.31?left?intact
          *?Closing?connection?0

          如果用戶名或者密碼錯誤則同樣會出現(xiàn)401的狀態(tài)碼:

          ??curl?-k?http://192.168.31.31?-v?-H?'Host:?external-bauth.qikqiak.com'?-u?'user:passwd123'
          *???Trying?192.168.31.31...
          *?TCP_NODELAY?set
          *?Connected?to?192.168.31.31?(192.168.31.31)?port?80?(#0)
          *?Server?auth?using?Basic?with?user?'user'
          >?GET?/?HTTP/1.1
          >?Host:?external-bauth.qikqiak.com
          >?Authorization:?Basic?dXNlcjpwYXNzd2QxMjM=
          >?User-Agent:?curl/7.64.1
          >?Accept:?*/*
          >
          *?Authentication?problem.?Ignoring?this.
          <

          401?Authorization?Required

          401?Authorization?Required



          nginx



          *?Connection?#0?to?host?192.168.31.31?left?intact
          *?Closing?connection?0

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

          URL Rewrite

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

          location?/app/?{
          ??proxy_pass?http://127.0.0.1/remote/;
          }

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

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

          apiVersion:?networking.k8s.io/v1
          kind:?Ingress
          metadata:
          ??name:?rewrite
          ??annotations:
          ????nginx.ingress.kubernetes.io/rewrite-target:?/$2
          spec:
          ??ingressClassName:?nginx
          ??rules:
          ??-?host:?rewrite.qikqiak.com
          ????http:
          ??????paths:
          ??????-?path:?/gateway(/|$)(.*)
          ????????pathType:?Prefix
          ????????backend:
          ??????????service:
          ????????????name:?my-nginx
          ????????????port:
          ??????????????number:?80

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

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

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

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

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

          apiVersion:?networking.k8s.io/v1
          kind:?Ingress
          metadata:
          ??name:?rewrite
          ??annotations:
          ????nginx.ingress.kubernetes.io/app-root:?/gateway/
          ????nginx.ingress.kubernetes.io/rewrite-target:?/$2
          spec:
          ??ingressClassName:?nginx
          ??rules:
          ??-?host:?rewrite.qikqiak.com
          ????http:
          ??????paths:
          ??????-?path:?/gateway(/|$)(.*)
          ????????pathType:?Prefix
          ????????backend:
          ??????????service:
          ????????????name:?my-nginx
          ????????????port:
          ??????????????number:?80

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

          apiVersion:?networking.k8s.io/v1
          kind:?Ingress
          metadata:
          ??name:?rewrite
          ??annotations:
          ????nginx.ingress.kubernetes.io/app-root:?/gateway/
          ????nginx.ingress.kubernetes.io/rewrite-target:?/$2
          ????nginx.ingress.kubernetes.io/configuration-snippet:?|
          ??????rewrite?^(/gateway)$?$1/?redirect;
          spec:
          ??ingressClassName:?nginx
          ??rules:
          ??-?host:?rewrite.qikqiak.com
          ????http:
          ??????paths:
          ??????-?path:?/gateway(/|$)(.*)
          ????????pathType:?Prefix
          ????????backend:
          ??????????service:
          ????????????name:?my-nginx
          ????????????port:
          ??????????????number:?80

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

          灰度發(fā)布

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

          ingress-nginx 的 Annotations 支持以下 4 種 Canary 規(guī)則:

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

          需要注意的是金絲雀規(guī)則按優(yōu)先順序進行排序:canary-by-header - > canary-by-cookie - > canary-weight

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

          • 基于權重的 Canary 規(guī)則

          • 基于用戶請求的 Canary 規(guī)則

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

          第一步. 部署 Production 應用

          首先創(chuàng)建一個 production 環(huán)境的應用資源清單:

          #?production.yaml
          apiVersion:?apps/v1
          kind:?Deployment
          metadata:
          ??name:?production
          ??labels:
          ????app:?production
          spec:
          ??selector:
          ????matchLabels:
          ??????app:?production
          ??template:
          ????metadata:
          ??????labels:
          ????????app:?production
          ????spec:
          ??????containers:
          ??????-?name:?production
          ????????image:?cnych/echoserver
          ????????ports:
          ????????-?containerPort:?8080
          ????????env:
          ??????????-?name:?NODE_NAME
          ????????????valueFrom:
          ??????????????fieldRef:
          ????????????????fieldPath:?spec.nodeName
          ??????????-?name:?POD_NAME
          ????????????valueFrom:
          ??????????????fieldRef:
          ????????????????fieldPath:?metadata.name
          ??????????-?name:?POD_NAMESPACE
          ????????????valueFrom:
          ??????????????fieldRef:
          ????????????????fieldPath:?metadata.namespace
          ??????????-?name:?POD_IP
          ????????????valueFrom:
          ??????????????fieldRef:
          ????????????????fieldPath:?status.podIP
          ---
          apiVersion:?v1
          kind:?Service
          metadata:
          ??name:?production
          ??labels:
          ????app:?production
          spec:
          ??ports:
          ??-?port:?80
          ????targetPort:?8080
          ????name:?http
          ??selector:
          ????app:?production

          然后創(chuàng)建一個用于 production 環(huán)境訪問的 Ingress 資源對象:

          #?production-ingress.yaml
          apiVersion:?networking.k8s.io/v1
          kind:?Ingress
          metadata:
          ??name:?production
          spec:
          ??ingressClassName:?nginx
          ??rules:
          ??-?host:?echo.qikqiak.com
          ????http:
          ??????paths:
          ??????-?path:?/
          ????????pathType:?Prefix
          ????????backend:
          ??????????service:
          ????????????name:?production
          ????????????port:
          ??????????????number:?80

          直接創(chuàng)建上面的幾個資源對象:

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

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

          ??curl?http://echo.qikqiak.com

          Hostname:?production-856d5fb99-d6bds

          Pod?Information:
          ?node?name:?node1
          ?pod?name:?production-856d5fb99-d6bds
          ?pod?namespace:?default
          ?pod?IP:?10.244.1.111

          Server?values:
          ?server_version=nginx:?1.13.3?-?lua:?10008

          Request?Information:
          ?client_address=10.244.0.0
          ?method=GET
          ?real?path=/
          ?query=
          ?request_version=1.1
          ?request_scheme=http
          ?request_uri=http://echo.qikqiak.com:8080/

          Request?Headers:
          ?accept=*/*
          ?host=echo.qikqiak.com
          ?user-agent=curl/7.64.1
          ?x-forwarded-for=171.223.99.184
          ?x-forwarded-host=echo.qikqiak.com
          ?x-forwarded-port=80
          ?x-forwarded-proto=http
          ?x-real-ip=171.223.99.184
          ?x-request-id=e680453640169a7ea21afba8eba9e116
          ?x-scheme=http

          Request?Body:
          ?-no?body?in?request-

          第二步. 創(chuàng)建 Canary 版本參考將上述 Production 版本的 production.yaml 文件,再創(chuàng)建一個 Canary 版本的應用。

          #?canary.yaml
          apiVersion:?apps/v1
          kind:?Deployment
          metadata:
          ??name:?canary
          ??labels:
          ????app:?canary
          spec:
          ??selector:
          ????matchLabels:
          ??????app:?canary
          ??template:
          ????metadata:
          ??????labels:
          ????????app:?canary
          ????spec:
          ??????containers:
          ??????-?name:?canary
          ????????image:?cnych/echoserver
          ????????ports:
          ????????-?containerPort:?8080
          ????????env:
          ??????????-?name:?NODE_NAME
          ????????????valueFrom:
          ??????????????fieldRef:
          ????????????????fieldPath:?spec.nodeName
          ??????????-?name:?POD_NAME
          ????????????valueFrom:
          ??????????????fieldRef:
          ????????????????fieldPath:?metadata.name
          ??????????-?name:?POD_NAMESPACE
          ????????????valueFrom:
          ??????????????fieldRef:
          ????????????????fieldPath:?metadata.namespace
          ??????????-?name:?POD_IP
          ????????????valueFrom:
          ??????????????fieldRef:
          ????????????????fieldPath:?status.podIP
          ---
          apiVersion:?v1
          kind:?Service
          metadata:
          ??name:?canary
          ??labels:
          ????app:?canary
          spec:
          ??ports:
          ??-?port:?80
          ????targetPort:?8080
          ????name:?http
          ??selector:
          ????app:?canary

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

          第三步. Annotation 規(guī)則配置

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

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

          #?canary-ingress.yaml
          apiVersion:?networking.k8s.io/v1
          kind:?Ingress
          metadata:
          ??name:?canary
          ??annotations:
          ????nginx.ingress.kubernetes.io/canary:?"true"???#?要開啟灰度發(fā)布機制,首先需要啟用?Canary
          ????nginx.ingress.kubernetes.io/canary-weight:?"30"??#?分配30%流量到當前Canary版本
          spec:
          ??ingressClassName:?nginx
          ??rules:
          ??-?host:?echo.qikqiak.com
          ????http:
          ??????paths:
          ??????-?path:?/
          ????????pathType:?Prefix
          ????????backend:
          ??????????service:
          ????????????name:?canary
          ????????????port:
          ??????????????number:?80

          直接創(chuàng)建上面的資源對象即可:

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

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

          ??for?i?in?$(seq?1?10);?do?curl?-s?echo.qikqiak.com?|?grep?"Hostname";?done
          Hostname:?production-856d5fb99-d6bds
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?production-856d5fb99-d6bds

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

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

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

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

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

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

          ??for?i?in?$(seq?1?10);?do?curl?-s?-H?"canary:?never"?echo.qikqiak.com?|?grep?"Hostname";?done
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds
          Hostname:?production-856d5fb99-d6bds

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

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

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

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

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

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

          ??for?i?in?$(seq?1?10);?do?curl?-s?-H?"canary:?user-value"?echo.qikqiak.com?|?grep?"Hostname";?done
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4

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

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

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

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

          ??for?i?in?$(seq?1?10);?do?curl?-s?-b?"users_from_Beijing=always"?echo.qikqiak.com?|?grep?"Hostname";?done
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4
          Hostname:?canary-66cb497b7f-48zx4

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

          HTTPS

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

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

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

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

          這個時候我們就可以創(chuàng)建一個 HTTPS 訪問應用的:

          apiVersion:?networking.k8s.io/v1
          kind:?Ingress
          metadata:
          ??name:?ingress-with-auth
          ??annotations:
          ????#?認證類型
          ????nginx.ingress.kubernetes.io/auth-type:?basic
          ????#?包含?user/password?定義的?secret?對象名
          ????nginx.ingress.kubernetes.io/auth-secret:?basic-auth
          ????#?要顯示的帶有適當上下文的消息,說明需要身份驗證的原因
          ????nginx.ingress.kubernetes.io/auth-realm:?'Authentication?Required?-?foo'
          spec:
          ??ingressClassName:?nginx
          ??tls:??#?配置?tls?證書
          ??-?hosts:
          ????-?foo.bar.com
          ????secretName:?foo-tls
          ??rules:
          ??-?host:?foo.bar.com
          ????http:
          ??????paths:
          ??????-?path:?/
          ????????pathType:?Prefix
          ????????backend:
          ??????????service:
          ????????????name:?my-nginx
          ????????????port:
          ??????????????number:?80

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

          TCP與UDP

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

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

          #?mongo.yaml
          apiVersion:?apps/v1
          kind:?Deployment
          metadata:
          ??name:?mongo
          ??labels:
          ????app:?mongo
          spec:
          ??selector:
          ????matchLabels:
          ??????app:?mongo
          ??template:
          ????metadata:
          ??????labels:
          ????????app:?mongo
          ????spec:
          ??????volumes:
          ??????-?name:?data
          ????????emptyDir:?{}
          ??????containers:
          ??????-?name:?mongo
          ????????image:?mongo:4.0
          ????????ports:
          ????????-?containerPort:?27017
          ????????volumeMounts:
          ????????-?name:?data
          ??????????mountPath:?/data/db
          ---
          apiVersion:?v1
          kind:?Service
          metadata:
          ??name:?mongo
          spec:
          ??selector:
          ????app:?mongo
          ??ports:
          ??-?port:?27017

          直接創(chuàng)建上面的資源對象:

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

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

          apiVersion:?v1
          kind:?ConfigMap
          metadata:
          ??name:?tcp-services
          ??namespace:?ingress-nginx
          data:
          ??"27017":?default/mongo:27017

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

          #?ci/daemonset-prod.yaml
          #?......?其他部分省略,和之前的保持一致

          tcp:??#?配置?tcp?服務
          ??27017:?"default/mongo:27017"??#?使用?27017?端口去映射?mongo?服務
          ??#?9000:?"default/test:8080"???#?如果還需要暴露其他?TCP?服務,繼續(xù)添加即可

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

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

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

          ??kubectl?get?configmap?-n?ingress-nginx?ingress-nginx-tcp?-o?yaml
          apiVersion:?v1
          data:
          ??"27017":?default/mongo:27017
          kind:?ConfigMap
          metadata:
          ??......
          ??name:?ingress-nginx-tcp
          ??namespace:?ingress-nginx

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

          ??kubectl?get?pods?-n?ingress-nginx
          NAME????????????????????????????????????????????READY???STATUS????RESTARTS????????AGE
          ingress-nginx-controller-gc582??????????????????1/1?????Running???0???????????????5m17s
          ??kubectl?get?pod?ingress-nginx-controller-gc582?-n?ingress-nginx?-o?yaml
          apiVersion:?v1
          kind:?Pod
          ......
          ??containers:
          ??-?args:
          ????-?/nginx-ingress-controller
          ????-?--default-backend-service=$(POD_NAMESPACE)/ingress-nginx-defaultbackend
          ????-?--election-id=ingress-controller-leader
          ????-?--controller-class=k8s.io/ingress-nginx
          ????-?--configmap=$(POD_NAMESPACE)/ingress-nginx-controller
          ????-?--tcp-services-configmap=$(POD_NAMESPACE)/ingress-nginx-tcp??#?tcp?配置參數(shù)
          ????-?--validating-webhook=:8443
          ????-?--validating-webhook-certificate=/usr/local/certificates/cert
          ????-?--validating-webhook-key=/usr/local/certificates/key
          ......
          ????ports:
          ......
          ????-?containerPort:?27017
          ??????hostPort:?27017
          ??????name:?27017-tcp
          ??????protocol:?TCP
          ......

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

          ??mongo?--host?192.168.31.31?--port?27017
          MongoDB?shell?version?v4.0.3
          connecting?to:?mongodb://192.168.31.31:27017/
          Implicit?session:?session?{?"id"?:?UUID("10f462eb-32b8-443b-ad85-99820db1aaa0")?}
          MongoDB?server?version:?4.0.27
          ......

          >
          ?show?dbs
          admin???0.000GB
          config??0.000GB
          local???0.000GB
          >

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

          ??kubectl?exec?-it?ingress-nginx-controller-gc582?-n?ingress-nginx?--?cat?/etc/nginx/nginx.conf
          ......
          stream?{
          ????......
          ????#?TCP?services
          ????server?{
          ????????????preread_by_lua_block?{
          ????????????????????ngx.var.proxy_upstream_name="tcp-default-mongo-27017";
          ????????????}
          ????????????listen??????????????????27017;
          ????????????listen??????????????????[::]:27017;
          ????????????proxy_timeout???????????600s;
          ????????????proxy_next_upstream?????on;
          ????????????proxy_next_upstream_timeout?600s;
          ????????????proxy_next_upstream_tries???3;
          ????????????proxy_pass??????????????upstream_balancer;
          ????}
          ????#?UDP?services
          }

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

          apiVersion:?v1
          kind:?ConfigMap
          metadata:
          ??name:?udp-services
          ??namespace:?ingress-nginx
          data:
          ??53:?"kube-system/kube-dns:53"

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

          #?ci/daemonset-prod.yaml
          #?......?其他部分省略,和之前的保持一致

          tcp:??#?配置?tcp?服務
          ??27017:?"default/mongo:27017"??#?使用?27017?端口去映射?mongo?服務
          ??#?9000:?"default/test:8080"???#?如果還需要暴露其他?TCP?服務,繼續(xù)添加即可

          udp:??#?配置?udp?服務
          ??53:?"kube-system/kube-dns:53"

          然后重新更新即可。

          全局配置

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

          containers:
          ??-?args:
          ????-?/nginx-ingress-controller
          ????-?--configmap=$(POD_NAMESPACE)/ingress-nginx-controller
          ????......

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

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

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

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

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

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

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

          #?ci/daemonset-prod.yaml
          controller:
          ??config:
          ????allow-snippet-annotations:?"true"
          ????client-header-buffer-size:?32k??#?注意不是下劃線
          ????client-max-body-size:?5m
          ????use-gzip:?"true"
          ????gzip-level:?"7"
          ????large-client-header-buffers:?4?32k
          ????proxy-connect-timeout:?11s
          ????proxy-read-timeout:?12s
          ????keep-alive:?"75"???#?啟用keep-alive,連接復用,提高QPS
          ????keep-alive-requests:?"100"
          ????upstream-keepalive-connections:?"10000"
          ????upstream-keepalive-requests:?"100"
          ????upstream-keepalive-timeout:?"60"
          ????disable-ipv6:?"true"
          ????disable-ipv6-dns:?"true"
          ????max-worker-connections:?"65535"
          ????max-worker-open-files:?"10240"

          #?其他省略

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

          initContainers:
          -?command:
          ??-?/bin/sh
          ??-?-c
          ??-?|
          ????mount?-o?remount?rw?/proc/sys
          ????sysctl?-w?net.core.somaxconn=65535??#?具體的配置視具體情況而定
          ????sysctl?-w?net.ipv4.tcp_tw_reuse=1
          ????sysctl?-w?net.ipv4.ip_local_port_range="1024?65535"
          ????sysctl?-w?fs.file-max=1048576
          ????sysctl?-w?fs.inotify.max_user_instances=16384
          ????sysctl?-w?fs.inotify.max_user_watches=524288
          ????sysctl?-w?fs.inotify.max_queued_events=16384
          image:?busybox
          imagePullPolicy:?IfNotPresent
          name:?init-sysctl
          securityContext:
          ??capabilities:
          ????add:
          ????-?SYS_ADMIN
          ????drop:
          ????-?ALL
          ......

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

          controller:
          ??#?其他省略,配置?initContainers
          ??extraInitContainers:
          ??-?name:?init-sysctl
          ????image:?busybox
          ????securityContext:
          ??????capabilities:
          ????????add:
          ????????-?SYS_ADMIN
          ????????drop:
          ????????-?ALL
          ????command:
          ????-?/bin/sh
          ????-?-c
          ????-?|
          ??????mount?-o?remount?rw?/proc/sys
          ??????sysctl?-w?net.core.somaxconn=65535??#?socket監(jiān)聽的backlog上限
          ??????sysctl?-w?net.ipv4.tcp_tw_reuse=1??#?開啟重用,允許將?TIME-WAIT?sockets?重新用于新的TCP連接
          ??????sysctl?-w?net.ipv4.ip_local_port_range="1024?65535"
          ??????sysctl?-w?fs.file-max=1048576
          ??????sysctl?-w?fs.inotify.max_user_instances=16384
          ??????sysctl?-w?fs.inotify.max_user_watches=524288
          ??????sysctl?-w?fs.inotify.max_queued_events=16384

          同樣重新部署即可:

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

          部署完成后通過 initContainers 就可以修改節(jié)點內核參數(shù)了,生產環(huán)境建議對節(jié)點內核參數(shù)進行相應的優(yōu)化。

          瀏覽 57
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91在线你懂的 | www.俺来也.com | 日本免费观看入网视频免费观看 | 免费看片18 | 免费黄色电影中文字幕 |