<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>

          真一文搞定 ingress-nginx 的使用

          共 12940字,需瀏覽 26分鐘

           ·

          2020-12-18 15:52

          前面我們學(xué)習(xí)了在 Kubernetes 集群內(nèi)部使用 kube-dns 實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)的功能,那么我們部署在 Kubernetes 集群中的應(yīng)用如何暴露給外部的用戶(hù)使用呢?我們知道可以使用 NodePortLoadBlancer 類(lèi)型的 Service 可以把應(yīng)用暴露給外部用戶(hù)使用,除此之外,Kubernetes 還為我們提供了一個(gè)非常重要的資源對(duì)象可以用來(lái)暴露服務(wù)給外部用戶(hù),那就是 Ingress。對(duì)于小規(guī)模的應(yīng)用我們使用 NodePort 或許能夠滿(mǎn)足我們的需求,但是當(dāng)你的應(yīng)用越來(lái)越多的時(shí)候,你就會(huì)發(fā)現(xiàn)對(duì)于 NodePort 的管理就非常麻煩了,這個(gè)時(shí)候使用 Ingress 就非常方便了,可以避免管理大量的端口。

          Ingress 其實(shí)就是從 Kuberenets 集群外部訪問(wèn)集群的一個(gè)入口,將外部的請(qǐng)求轉(zhuǎn)發(fā)到集群內(nèi)不同的 Service 上,其實(shí)就相當(dāng)于 nginx、haproxy 等負(fù)載均衡代理服務(wù)器,可能你會(huì)覺(jué)得我們直接使用 nginx 就實(shí)現(xiàn)了,但是只使用 nginx 這種方式有很大缺陷,每次有新服務(wù)加入的時(shí)候怎么改 Nginx 配置?不可能讓我們?nèi)ナ謩?dòng)更改或者滾動(dòng)更新前端的 Nginx Pod 吧?那我們?cè)偌由弦粋€(gè)服務(wù)發(fā)現(xiàn)的工具比如 consul 如何?貌似是可以,對(duì)吧?Ingress 實(shí)際上就是這樣實(shí)現(xiàn)的,只是服務(wù)發(fā)現(xiàn)的功能自己實(shí)現(xiàn)了,不需要使用第三方的服務(wù)了,然后再加上一個(gè)域名規(guī)則定義,路由信息的刷新依靠 Ingress Controller 來(lái)提供。

          Ingress Controller 可以理解為一個(gè)監(jiān)聽(tīng)器,通過(guò)不斷地監(jiān)聽(tīng) kube-apiserver,實(shí)時(shí)的感知后端 Service、Pod 的變化,當(dāng)?shù)玫竭@些信息變化后,Ingress Controller 再結(jié)合 Ingress 的配置,更新反向代理負(fù)載均衡器,達(dá)到服務(wù)發(fā)現(xiàn)的作用。其實(shí)這點(diǎn)和服務(wù)發(fā)現(xiàn)工具 consul、 consul-template 非常類(lèi)似。

          ingress flow

          現(xiàn)在可以供大家使用的 Ingress Controller 有很多,比如 traefik、nginx-controller、Kubernetes Ingress Controller for Kong、HAProxy Ingress controller,當(dāng)然你也可以自己實(shí)現(xiàn)一個(gè) Ingress Controller,現(xiàn)在普遍用得較多的是 traefik 和 nginx-controller,traefik 的性能較 nginx-controller 差,但是配置使用要簡(jiǎn)單許多,我們這里會(huì)重點(diǎn)給大家介紹 nginx-controller 的使用。

          安裝

          NGINX Ingress Controller 是使用 Kubernetes Ingress 資源對(duì)象構(gòu)建的,用 ConfigMap 來(lái)存儲(chǔ) Nginx 配置的一種 Ingress Controller 實(shí)現(xiàn)。

          要使用 Ingress 對(duì)外暴露服務(wù),就需要提前安裝一個(gè) Ingress Controller,我們這里就先來(lái)安裝 NGINX Ingress Controller,由于 nginx-ingress 所在的節(jié)點(diǎn)需要能夠訪問(wèn)外網(wǎng),這樣域名可以解析到這些節(jié)點(diǎn)上直接使用,所以需要讓 nginx-ingress 綁定節(jié)點(diǎn)的 80 和 443 端口,所以可以使用 hostPort 來(lái)進(jìn)行訪問(wèn),當(dāng)然對(duì)于線上環(huán)境來(lái)說(shuō)為了保證高可用,一般是需要運(yùn)行多個(gè) nginx-ingress 實(shí)例的,然后可以用一個(gè) nginx/haproxy 作為入口,通過(guò) keepalived 來(lái)訪問(wèn)邊緣節(jié)點(diǎn)的 vip 地址。

          所謂的邊緣節(jié)點(diǎn)即集群內(nèi)部用來(lái)向集群外暴露服務(wù)能力的節(jié)點(diǎn),集群外部的服務(wù)通過(guò)該節(jié)點(diǎn)來(lái)調(diào)用集群內(nèi)部的服務(wù),邊緣節(jié)點(diǎn)是集群內(nèi)外交流的一個(gè) Endpoint。

          所以我們這里需要更改下資源清單文件:

          ??helm?repo?add?ingress-nginx?https://kubernetes.github.io/ingress-nginx
          ??helm?repo?update
          ??helm?fetch?ingress-nginx/ingress-nginx
          ??tar?-xvf?ingress-nginx-3.15.2.tgz

          我們這里測(cè)試環(huán)境只有 master1 節(jié)點(diǎn)可以訪問(wèn)外網(wǎng),這里我們就直接講 ingress-nginx 固定到 master1 節(jié)點(diǎn)上,采用 hostNetwork 模式(生產(chǎn)環(huán)境可以使用 LB + DaemonSet hostNetwork 模式)。然后新建一個(gè)名為 values-prod.yaml 的 Values 文件,用來(lái)覆蓋 ingress-nginx 默認(rèn)的 Values 值,對(duì)應(yīng)的數(shù)據(jù)如下所示:

          #?values-prod.yaml
          controller:
          ??name:?controller
          ??image:
          ????repository:?cnych/ingress-nginx
          ????tag:?"v0.41.2"
          ????digest:?

          ??dnsPolicy:?ClusterFirstWithHostNet
          ???
          ??hostNetwork:?true

          ??publishService:??#?hostNetwork?模式下設(shè)置為false,通過(guò)節(jié)點(diǎn)IP地址上報(bào)ingress?status數(shù)據(jù)
          ????enabled:?false

          ??kind:?DaemonSet

          ??nodeSelector:?
          ????role:?lb

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

          defaultBackend:
          ??enabled:?true
          ??name:?defaultbackend
          ??image:
          ????repository:?cnych/ingress-nginx-defaultbackend
          ????tag:?"1.5"

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

          ??kubectl?create?ns?ingress-nginx
          ??helm?install?--namespace?ingress-nginx?ingress-nginx?./ingress-nginx?-f?./ingress-nginx/values-prod.yaml?
          NAME:?ingress-nginx
          LAST?DEPLOYED:?Fri?Dec?11?14:19:05?2020
          NAMESPACE:?ingress-nginx
          STATUS:?deployed
          REVISION:?1
          TEST?SUITE:?None
          NOTES:
          The?ingress-nginx?controller?has?been?installed.
          Get?the?application?URL?by?running?these?commands:
          ??export?POD_NAME=$(kubectl?--namespace?ingress-nginx?get?pods?-o?jsonpath="{.items[0].metadata.name}"?-l?"app=ingress-nginx,component=controller,release=ingress-nginx")
          ??kubectl?--namespace?ingress-nginx?port-forward?$POD_NAME?8080:80
          ??echo?"Visit?http://127.0.0.1:8080?to?access?your?application."

          An?example?Ingress?that?makes?use?of?the?controller:

          ??apiVersion:?networking.k8s.io/v1beta1
          ??kind:?Ingress
          ??metadata:
          ????annotations:
          ??????kubernetes.io/ingress.class:?nginx
          ????name:?example
          ????namespace:?foo
          ??spec:
          ????rules:
          ??????-?host:?www.example.com
          ????????http:
          ??????????paths:
          ????????????-?backend:
          ????????????????serviceName:?exampleService
          ????????????????servicePort:?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 的運(yùn)行狀態(tài):

          ??kubectl?get?svc?-n?ingress-nginx
          NAME?????????????????????????????????TYPE????????CLUSTER-IP???????EXTERNAL-IP???PORT(S)???AGE
          ingress-nginx-controller-admission???ClusterIP???10.110.143.167???????????443/TCP???2m21s
          ingress-nginx-defaultbackend?????????ClusterIP???10.104.156.141???????????80/TCP????2m21s
          ??kubectl?get?pods?-n?ingress-nginx
          NAME????????????????????????????????????????????READY???STATUS????RESTARTS???AGE
          ingress-nginx-controller-596955b554-vfmhq???????1/1?????Running???0??????????31s
          ingress-nginx-defaultbackend-7bf9445d94-lkgw5???1/1?????Running???0??????????3m52s
          ??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
          -------------------------------------------------------------------------------
          NGINX?Ingress?controller
          ??Release:???????v0.41.2
          ??Build:?????????d8a93551e6e5798fc4af3eb910cef62ecddc8938
          ??Repository:????https://github.com/kubernetes/ingress-nginx
          ??nginx?version:?nginx/1.19.4

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

          當(dāng)看到上面的信息證明 ingress-nginx 部署成功了。

          Ingress

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

          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:?extensions/v1beta1
          kind:?Ingress
          metadata:
          ??name:?my-nginx
          ??annotations:
          ????kubernetes.io/ingress.class:?"nginx"
          spec:
          ??rules:
          ??-?host:?ngdemo.qikqiak.com??#?將域名映射到?my-nginx?服務(wù)
          ????http:
          ??????paths:
          ??????-?path:?/
          ????????backend:
          ??????????serviceName:?my-nginx??#?將所有請(qǐng)求發(fā)送到?my-nginx?服務(wù)的?80?端口
          ??????????servicePort:?80?????#?不過(guò)需要注意大部分Ingress?controller都不是直接轉(zhuǎn)發(fā)到Service
          ????????????????????????????#?而是只是通過(guò)Service來(lái)獲取后端的Endpoints列表,直接轉(zhuǎn)發(fā)到Pod,這樣可以減少網(wǎng)絡(luò)跳轉(zhuǎn),提高性能

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

          ??kubectl?apply?-f?ngdemo.yaml
          deployment.apps?"my-nginx"?created
          service?"my-nginx"?created
          ingress.extensions?"my-nginx"?created

          注意我們?cè)?Ingress 資源對(duì)象中添加了一個(gè) annotations:kubernetes.io/ingress.class: "nginx",這就是指定讓這個(gè) Ingress 通過(guò) nginx-ingress 來(lái)處理。

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

          ngdemo

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

          ingress controller workflow

          URL Rewrite

          NGINX Ingress Controller 很多高級(jí)的用法可以通過(guò) Ingress 對(duì)象的 annotation 進(jìn)行配置,比如常用的 URL Rewrite 功能,比如我們有一個(gè) todo 的前端應(yīng)用,代碼位于 https://github.com/cnych/todo-app,直接部署這個(gè)應(yīng)用進(jìn)行測(cè)試:

          ??kubectl?apply?-f?https://github.com/cnych/todo-app/raw/master/k8s/mongo.yaml
          ??kubectl?apply?-f?https://github.com/cnych/todo-app/raw/master/k8s/web.yaml
          ??kubectl?get?pods
          NAME????????????????????????READY???STATUS????RESTARTS???AGE
          mongo-5c9fd978bb-txn9j??????1/1?????Running???0??????????149m
          todo-566957d785-tdgs6???????1/1?????Running???0??????????3m31s
          ......
          ??kubectl?get?svc
          NAME???????????????????????TYPE????????CLUSTER-IP???????EXTERNAL-IP???PORT(S)??????????????????????AGE
          kubernetes?????????????????ClusterIP???10.96.0.1????????????????443/TCP??????????????????????54d
          mongo??????????????????????ClusterIP???10.96.95.11??????????????27017/TCP????????????????????150m
          todo???????????????????????ClusterIP???10.111.105.47????????????3000/TCP?????????????????????145m
          ......

          對(duì)應(yīng)的 Ingress 資源對(duì)象如下所示:

          apiVersion:?extensions/v1beta1
          kind:?Ingress
          metadata:
          ??name:?todo
          ??annotations:
          ????kubernetes.io/ingress.class:?"nginx"
          spec:
          ??rules:
          ??-?host:?todo.qikqiak.com
          ????http:
          ??????paths:
          ??????-?path:?/
          ????????backend:
          ??????????serviceName:?todo
          ??????????servicePort:?3000

          就是一個(gè)很常規(guī)的 Ingress 對(duì)象,部署該對(duì)象后,將域名解析后就可以正常訪問(wèn)到應(yīng)用:

          ingress nginx demo

          現(xiàn)在我們需要對(duì)訪問(wèn)的 URL 路徑做一個(gè) Rewrite,比如在 PATH 中添加一個(gè) app 的前綴,關(guān)于 Rewrite 的操作在 ingress-nginx 官方文檔中也給出對(duì)應(yīng)的說(shuō)明:

          ingress nginx rewrite

          按照要求我們需要在 path 中匹配前綴 app,然后通過(guò) rewrite-target 指定目標(biāo),修改后的 Ingress 對(duì)象如下所示:

          apiVersion:?extensions/v1beta1
          kind:?Ingress
          metadata:
          ??name:?todo
          ??namespace:?default
          ??annotations:
          ????kubernetes.io/ingress.class:?"nginx"
          ????nginx.ingress.kubernetes.io/rewrite-target:?/$2
          spec:
          ??rules:
          ??-?host:?todo.qikqiak.com
          ????http:
          ??????paths:
          ??????-?backend:
          ??????????serviceName:?todo
          ??????????servicePort:?3000
          ????????path:?/app(/|$)(.*)

          更新后,我們可以遇見(jiàn)到直接訪問(wèn)域名肯定是不行了,因?yàn)槲覀儧](méi)有匹配 / 的 path 路徑:

          ingress nginx rewrite 404

          但是我們帶上 app 的前綴再去訪問(wèn):

          ingress nginx rewrite 1

          我們可以看到已經(jīng)可以訪問(wèn)到頁(yè)面內(nèi)容了,這是因?yàn)槲覀冊(cè)?path 中通過(guò)正則表達(dá)式 /app(/|$)(.*) 將匹配的路徑設(shè)置成了 rewrite-target 的目標(biāo)路徑了,所以我們?cè)L問(wèn) todo.qikqiak.com/app 的時(shí)候?qū)嶋H上相當(dāng)于訪問(wèn)的就是后端服務(wù)的 / 路徑,但是我們也可以發(fā)現(xiàn)現(xiàn)在頁(yè)面的樣式?jīng)]有了:

          ingress nginx rewrite 2

          這是因?yàn)閼?yīng)用的靜態(tài)資源路徑是在 /stylesheets 路徑下面的,現(xiàn)在我們做了 url rewrite 過(guò)后,要正常訪問(wèn)也需要帶上前綴才可以:http://todo.qikqiak.com/stylesheets/screen.css,對(duì)于圖片或者其他靜態(tài)資源也是如此,當(dāng)然我們?nèi)ジ捻?yè)面引入靜態(tài)資源的方式為相對(duì)路徑也是可以的,但是畢竟要修改代碼,這個(gè)時(shí)候我們可以借助 ingress-nginx 中的 configuration-snippet 來(lái)對(duì)靜態(tài)資源做一次跳轉(zhuǎn),如下所示:

          apiVersion:?extensions/v1beta1
          kind:?Ingress
          metadata:
          ??name:?todo
          ??namespace:?default
          ??annotations:
          ????kubernetes.io/ingress.class:?"nginx"
          ????nginx.ingress.kubernetes.io/rewrite-target:?/$2
          ????nginx.ingress.kubernetes.io/configuration-snippet:?|
          ??????rewrite?^/stylesheets/(.*)$?/app/stylesheets/$1?redirect;??#?添加?/app?前綴
          ??????rewrite?^/images/(.*)$?/app/images/$1?redirect;??#?添加?/app?前綴
          spec:
          ??rules:
          ??-?host:?todo.qikqiak.com
          ????http:
          ??????paths:
          ??????-?backend:
          ??????????serviceName:?todo
          ??????????servicePort:?3000
          ????????path:?/app(/|$)(.*)

          更新 Ingress 對(duì)象后,這個(gè)時(shí)候我們刷新頁(yè)面可以看到已經(jīng)正常了:

          ingress nginx rewrite 3

          要解決我們?cè)L問(wèn)主域名出現(xiàn) 404 的問(wèn)題,我們可以給應(yīng)用設(shè)置一個(gè) app-root 的注解,這樣當(dāng)我們?cè)L問(wèn)主域名的時(shí)候會(huì)自動(dòng)跳轉(zhuǎn)到我們指定的 app-root 目錄下面,如下所示:

          apiVersion:?extensions/v1beta1
          kind:?Ingress
          metadata:
          ??name:?todo
          ??namespace:?default
          ??annotations:
          ????kubernetes.io/ingress.class:?"nginx"
          ????nginx.ingress.kubernetes.io/app-root:?/app/
          ????nginx.ingress.kubernetes.io/rewrite-target:?/$2
          ????nginx.ingress.kubernetes.io/configuration-snippet:?|
          ??????rewrite?^/stylesheets/(.*)$?/app/stylesheets/$1?redirect;??#?添加?/app?前綴
          ??????rewrite?^/images/(.*)$?/app/images/$1?redirect;??#?添加?/app?前綴
          spec:
          ??rules:
          ??-?host:?todo.qikqiak.com
          ????http:
          ??????paths:
          ??????-?backend:
          ??????????serviceName:?todo
          ??????????servicePort:?3000
          ????????path:?/app(/|$)(.*)

          這個(gè)時(shí)候我們更新應(yīng)用后訪問(wèn)主域名 http://todo.qikqiak.com 就會(huì)自動(dòng)跳轉(zhuǎn)到 http://todo.qikqiak.com/app/ 路徑下面去了。但是還有一個(gè)問(wèn)題是我們的 path 路徑其實(shí)也匹配了 /app 這樣的路徑,可能我們更加希望我們的應(yīng)用在最后添加一個(gè) / 這樣的 slash,同樣我們可以通過(guò) configuration-snippet 配置來(lái)完成,如下 Ingress 對(duì)象:

          apiVersion:?extensions/v1beta1
          kind:?Ingress
          metadata:
          ??name:?todo
          ??namespace:?default
          ??annotations:
          ????kubernetes.io/ingress.class:?"nginx"
          ????nginx.ingress.kubernetes.io/app-root:?/app/
          ????nginx.ingress.kubernetes.io/rewrite-target:?/$2
          ????nginx.ingress.kubernetes.io/configuration-snippet:?|
          ??????rewrite?^(/app)$?$1/?redirect;
          ??????rewrite?^/stylesheets/(.*)$?/app/stylesheets/$1?redirect;
          ??????rewrite?^/images/(.*)$?/app/images/$1?redirect;
          spec:
          ??rules:
          ??-?host:?todo.qikqiak.com
          ????http:
          ??????paths:
          ??????-?backend:
          ??????????serviceName:?todo
          ??????????servicePort:?3000
          ????????path:?/app(/|$)(.*)

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

          Basic Auth

          同樣我們還可以在 Ingress Controller 上面配置一些基本的 Auth 認(rèn)證,比如 Basic Auth,可以用 htpasswd 生成一個(gè)密碼文件來(lái)驗(yàn)證身份驗(yàn)證。

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

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

          ??kubectl?create?secret?generic?basic-auth?--from-file=auth
          secret/basic-auth?created
          ??kubectl?get?secret?basic-auth?-o?yaml
          apiVersion:?v1
          data:
          ??auth:?Zm9vOiRhcHIxJFNjcVhZcFN6JDc4Nm5ISFNaeDdwN2VscDM2WUo0YS8K
          kind:?Secret
          metadata:
          ??creationTimestamp:?"2019-12-08T06:40:39Z"
          ??name:?basic-auth
          ??namespace:?default
          ??resourceVersion:?"9197951"
          ??selfLink:?/api/v1/namespaces/default/secrets/basic-auth
          ??uid:?6b2aa299-b511-412e-85ea-d0e91e578af0
          type:?Opaque

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

          apiVersion:?extensions/v1beta1
          kind:?Ingress
          metadata:
          ??name:?ingress-with-auth
          ??annotations:
          ????#?認(rèn)證類(lèi)型
          ????nginx.ingress.kubernetes.io/auth-type:?basic
          ????#?包含?user/password?定義的?secret?對(duì)象名
          ????nginx.ingress.kubernetes.io/auth-secret:?basic-auth
          ????#?要顯示的帶有適當(dāng)上下文的消息,說(shuō)明需要身份驗(yàn)證的原因
          ????nginx.ingress.kubernetes.io/auth-realm:?'Authentication?Required?-?foo'
          spec:
          ??rules:
          ??-?host:?foo.bar.com
          ????http:
          ??????paths:
          ??????-?path:?/
          ????????backend:
          ??????????serviceName:?my-nginx
          ??????????servicePort:?80

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

          ??curl?-v?http://k8s.qikqiak.com?-H?'Host:?foo.bar.com'
          *?Rebuilt?URL?to:?http://k8s.qikqiak.com/
          *???Trying?123.59.188.12...
          *?TCP_NODELAY?set
          *?Connected?to?k8s.qikqiak.com?(123.59.188.12)?port?80?(#0)
          >?GET?/?HTTP/1.1
          >?Host:?foo.bar.com
          >?User-Agent:?curl/7.54.0
          >?Accept:?*/*
          >
          <

          401?Authorization?Required

          401?Authorization?Required



          openresty/1.15.8.2



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

          ??curl?-v?http://k8s.qikqiak.com?-H?'Host:?foo.bar.com'?-u?'foo:foo'
          *?Rebuilt?URL?to:?http://k8s.qikqiak.com/
          *???Trying?123.59.188.12...
          *?TCP_NODELAY?set
          *?Connected?to?k8s.qikqiak.com?(123.59.188.12)?port?80?(#0)
          *?Server?auth?using?Basic?with?user?'foo'
          >?GET?/?HTTP/1.1
          >?Host:?foo.bar.com
          >?Authorization:?Basic?Zm9vOmZvbw==
          >?User-Agent:?curl/7.54.0
          >?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.




          可以看到已經(jīng)認(rèn)證成功了。當(dāng)然出來(lái) Basic Auth 這一種簡(jiǎn)單的認(rèn)證方式之外,NGINX Ingress Controller 還支持一些其他高級(jí)的認(rèn)證,比如 OAUTH 認(rèn)證之類(lèi)的。

          灰度發(fā)布

          在日常工作中我們經(jīng)常需要對(duì)服務(wù)進(jìn)行版本更新升級(jí),所以我們經(jīng)常會(huì)使用到滾動(dòng)升級(jí)、藍(lán)綠發(fā)布、灰度發(fā)布等不同的發(fā)布操作。而 ingress-nginx 支持通過(guò) Annotations 配置來(lái)實(shí)現(xiàn)不同場(chǎng)景下的灰度發(fā)布和測(cè)試,可以滿(mǎn)足金絲雀發(fā)布、藍(lán)綠部署與 A/B 測(cè)試等業(yè)務(wù)場(chǎng)景。ingress-nginx 的 Annotations 支持以下 4 種 Canary 規(guī)則:

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

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

          總的來(lái)說(shuō)可以把以上的四個(gè) annotation 規(guī)則劃分為以下兩類(lèi):

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

          • 基于用戶(hù)請(qǐng)求的 Canary 規(guī)則

          下面我們通過(guò)一個(gè)示例應(yīng)用來(lái)對(duì)灰度發(fā)布功能進(jìn)行說(shuō)明。

          第一步. 部署 Production 應(yīng)用

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

          #?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)建一個(gè)用于 production 環(huán)境訪問(wèn)的 Ingress 資源對(duì)象:

          #?production-ingress.yaml
          apiVersion:?extensions/v1beta1
          kind:?Ingress
          metadata:
          ??name:?production
          ??annotations:
          ????kubernetes.io/ingress.class:?nginx
          spec:
          ??rules:
          ??-?host:?echo.qikqiak.com
          ????http:
          ??????paths:
          ??????-?backend:
          ??????????serviceName:?production
          ??????????servicePort:?80

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

          ??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

          應(yīng)用部署成功后,將域名 echo.qikqiak.com 映射到 master1 節(jié)點(diǎn)(ingress-nginx 所在的節(jié)點(diǎn))的外網(wǎng) IP,然后即可正常訪問(wèn)應(yīng)用了:

          ??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)建一個(gè) Canary 版本的應(yīng)用。

          #?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

          接下來(lái)就可以通過(guò)配置 Annotation 規(guī)則進(jìn)行流量切分了。

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

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

          創(chuàng)建一個(gè)基于權(quán)重的 Canary 版本的應(yīng)用路由 Ingress 對(duì)象。

          #?canary-ingress.yaml
          apiVersion:?extensions/v1beta1
          kind:?Ingress
          metadata:
          ??name:?canary
          ??annotations:
          ????kubernetes.io/ingress.class:?nginx?
          ????nginx.ingress.kubernetes.io/canary:?"true"???#?要開(kāi)啟灰度發(fā)布機(jī)制,首先需要啟用?Canary
          ????nginx.ingress.kubernetes.io/canary-weight:?"30"??#?分配30%流量到當(dāng)前Canary版本
          spec:
          ??rules:
          ??-?host:?echo.qikqiak.com
          ????http:
          ??????paths:
          ??????-?backend:
          ??????????serviceName:?canary
          ??????????servicePort:?80

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

          ??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 版本應(yīng)用創(chuàng)建成功后,接下來(lái)我們?cè)诿钚薪K端中來(lái)不斷訪問(wèn)這個(gè)應(yī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 版本應(yīng)用分配了 30% 左右權(quán)重的流量,所以上面我們?cè)L問(wèn)10次有3次訪問(wèn)到了 Canary 版本的應(yīng)用,符合我們的預(yù)期。

          2. 基于 Request Header: 基于 Request Header 進(jìn)行流量切分的典型應(yīng)用場(chǎng)景即灰度發(fā)布或 A/B 測(cè)試場(chǎng)景。

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

          annotations:
          ??kubernetes.io/ingress.class:?nginx?
          ??nginx.ingress.kubernetes.io/canary:?"true"???#?要開(kāi)啟灰度發(fā)布機(jī)制,首先需要啟用?Canary
          ??nginx.ingress.kubernetes.io/canary-by-header:?canary??#?基于header的流量切分
          ??nginx.ingress.kubernetes.io/canary-weight:?"30"??#?會(huì)被忽略,因?yàn)榕渲昧?canary-by-headerCanary版本

          更新上面的 Ingress 資源對(duì)象后,我們?cè)谡?qǐng)求中加入不同的 Header 值,再次訪問(wèn)應(yīng)用的域名。

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

          ??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

          這里我們?cè)谡?qǐng)求的時(shí)候設(shè)置了 canary: never 這個(gè) Header 值,所以請(qǐng)求沒(méi)有發(fā)送到 Canary 應(yīng)用中去。如果設(shè)置為其他值呢:

          ??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

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

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

          annotations:
          ??kubernetes.io/ingress.class:?nginx?
          ??nginx.ingress.kubernetes.io/canary:?"true"???#?要開(kāi)啟灰度發(fā)布機(jī)制,首先需要啟用?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%流量到當(dāng)前Canary版本

          同樣更新 Ingress 對(duì)象后,重新訪問(wèn)應(yīng)用,當(dāng) Request Header 滿(mǎn)足 canary: user-value時(shí),所有請(qǐng)求就會(huì)被路由到 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ī)則類(lèi)似。例如在 A/B 測(cè)試場(chǎng)景下,需要讓地域?yàn)楸本┑挠脩?hù)訪問(wèn) Canary 版本。那么當(dāng) cookie 的 annotation 設(shè)置為 nginx.ingress.kubernetes.io/canary-by-cookie: "users_from_Beijing",此時(shí)后臺(tái)可對(duì)登錄的用戶(hù)請(qǐng)求進(jìn)行檢查,如果該用戶(hù)訪問(wèn)源來(lái)自北京則設(shè)置 cookie users_from_Beijing 的值為 always,這樣就可以確保北京的用戶(hù)僅訪問(wèn) Canary 版本。

          同樣我們更新 Canary 版本的 Ingress 資源對(duì)象,采用基于 Cookie 來(lái)進(jìn)行流量切分,

          annotations:
          ??kubernetes.io/ingress.class:?nginx?
          ??nginx.ingress.kubernetes.io/canary:?"true"???#?要開(kāi)啟灰度發(fā)布機(jī)制,首先需要啟用?Canary
          ??nginx.ingress.kubernetes.io/canary-by-cookie:?"users_from_Beijing"??#?基于?cookie
          ??nginx.ingress.kubernetes.io/canary-weight:?"30"??#?會(huì)被忽略,因?yàn)榕渲昧?canary-by-cookie

          更新上面的 Ingress 資源對(duì)象后,我們?cè)谡?qǐng)求中設(shè)置一個(gè) users_from_Beijing=always 的 Cookie 值,再次訪問(wèn)應(yīng)用的域名。

          ??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

          我們可以看到應(yīng)用都被路由到了 Canary 版本的應(yīng)用中去了,如果我們將這個(gè) Cookie 值設(shè)置為 never,則不會(huì)路由到 Canary 應(yīng)用中。

          HTTPS

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

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

          然后通過(guò) Secret 對(duì)象來(lái)引用證書(shū)文件:

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

          這個(gè)時(shí)候我們就可以創(chuàng)建一個(gè) HTTPS 訪問(wèn)應(yīng)用的:

          apiVersion:?extensions/v1beta1
          kind:?Ingress
          metadata:
          ??name:?ingress-with-auth
          ??annotations:
          ????#?認(rèn)證類(lèi)型
          ????nginx.ingress.kubernetes.io/auth-type:?basic
          ????#?包含?user/password?定義的?secret?對(duì)象名
          ????nginx.ingress.kubernetes.io/auth-secret:?basic-auth
          ????#?要顯示的帶有適當(dāng)上下文的消息,說(shuō)明需要身份驗(yàn)證的原因
          ????nginx.ingress.kubernetes.io/auth-realm:?'Authentication?Required?-?foo'
          spec:
          ??rules:
          ??-?host:?foo.bar.com
          ????http:
          ??????paths:
          ??????-?path:?/
          ????????backend:
          ??????????serviceName:?my-nginx
          ??????????servicePort:?80
          ??tls:
          ??-?hosts:
          ????-?foo.bar.com
          ????secretName:?foo-tls

          除了自簽名證書(shū)或者購(gòu)買(mǎi)正規(guī)機(jī)構(gòu)的 CA 證書(shū)之外,我們還可以通過(guò) letsencrypt 來(lái)自動(dòng)生成合法的證書(shū)。

          CertManager 自動(dòng) HTTPS

          安裝配置

          cert-manager 是一個(gè)云原生證書(shū)管理開(kāi)源項(xiàng)目,用于在 Kubernetes 集群中提供 HTTPS 證書(shū)并自動(dòng)續(xù)期,支持 Let's Encrypt/HashiCorp/Vault 這些免費(fèi)證書(shū)的簽發(fā)。在 Kubernetes 中,可以通過(guò) Kubernetes Ingress 和 Let's Encrypt 實(shí)現(xiàn)外部服務(wù)的自動(dòng)化 HTTPS。

          cert-manager 架構(gòu)

          上面是官方給出的架構(gòu)圖,可以看到 cert-manager 在 Kubernetes 中定義了兩個(gè)自定義類(lèi)型資源:Issuer(ClusterIssuer)Certificate

          • 其中 Issuer 代表的是證書(shū)頒發(fā)者,可以定義各種提供者的證書(shū)頒發(fā)者,當(dāng)前支持基于 Let's Encrypt/HashiCorp/Vault 和 CA 的證書(shū)頒發(fā)者,還可以定義不同環(huán)境下的證書(shū)頒發(fā)者。
          • Certificate 代表的是生成證書(shū)的請(qǐng)求,一般其中存入生成證書(shū)的元信息,如域名等等。

          一旦在 Kubernetes 中定義了上述兩類(lèi)資源,部署的 cert-manager 則會(huì)根據(jù) IssuerCertificate 生成 TLS 證書(shū),并將證書(shū)保存進(jìn) Kubernetes 的 Secret 資源中,然后在 Ingress 資源中就可以引用到這些生成的 Secret 資源作為 TLS 證書(shū)使用,對(duì)于已經(jīng)生成的證書(shū),還會(huì)定期檢查證書(shū)的有效期,如即將超過(guò)有效期,還會(huì)自動(dòng)續(xù)期。

          要在 Kubernetes 集群上安裝 cert-manager 也非常簡(jiǎn)單,官方提供了一個(gè)單一的資源清單文件,包含了所有的資源對(duì)象,所以直接安裝即可:

          #?Kubernetes?1.16+
          ??kubectl?apply?-f?https://github.com/jetstack/cert-manager/releases/download/v1.1.0/cert-manager.yaml
          #?Kubernetes?<1.16
          ??kubectl?apply?--validate=false?-f?https://github.com/jetstack/cert-manager/releases/download/v1.1.0/cert-manager-legacy.yaml

          上面的命令會(huì)創(chuàng)建一個(gè)名為 cert-manager 的命名空間,安裝大量的 CRD 以及 AdmissionWebhook 對(duì)象,可以通過(guò)如下命令來(lái)查看是否安裝成功:

          ??kubectl?get?pods?-n?cert-manager
          NAME??????????????????????????????????????READY???STATUS????RESTARTS???AGE
          cert-manager-5597cff495-q6rzh?????????????1/1?????Running???0??????????5m31s
          cert-manager-cainjector-bd5f9c764-5sc7d???1/1?????Running???0??????????5m31s
          cert-manager-webhook-5f57f59fbc-mvcq4?????1/1?????Running???0??????????5m30s

          正常情況下可以看到 cert-manager、cert-manager-cainjector 以及 cert-manager-webhook 這幾個(gè) Pod 處于 Running 狀態(tài)。我們可以通過(guò)下面的測(cè)試來(lái)驗(yàn)證下是否可以簽發(fā)基本的證書(shū)類(lèi)型,創(chuàng)建一個(gè) Issuer 資源對(duì)象來(lái)測(cè)試 webhook 工作是否正常(在開(kāi)始簽發(fā)證書(shū)之前,必須在群集中至少配置一個(gè) Issuer 或 ClusterIssuer 資源):

          ??cat?<?>?test-selfsigned.yaml
          apiVersion:?v1
          kind:?Namespace
          metadata:
          ??name:?cert-manager-test
          ---
          apiVersion:?cert-manager.io/v1
          kind:?Issuer
          metadata:
          ??name:?test-selfsigned
          ??namespace:?cert-manager-test
          spec:
          ??selfSigned:?{}??#?配置自簽名的證書(shū)機(jī)構(gòu)類(lèi)型
          ---
          apiVersion:?cert-manager.io/v1
          kind:?Certificate
          metadata:
          ??name:?selfsigned-cert
          ??namespace:?cert-manager-test
          spec:
          ??dnsNames:
          ??-?example.com
          ??secretName:?selfsigned-cert-tls
          ??issuerRef:
          ????name:?test-selfsigned
          EOF

          這里我們創(chuàng)建了一個(gè)名為 cert-manager-test 的命名空間,創(chuàng)建了一個(gè)自簽名的 Issuer 證書(shū)頒發(fā)機(jī)構(gòu),然后使用這個(gè) Issuer 來(lái)創(chuàng)建一個(gè)證書(shū)請(qǐng)求的 Certificate 對(duì)象,直接創(chuàng)建上面的資源清單即可:

          ??kubectl?apply?-f?test-selfsigned.yaml
          namespace/cert-manager-test?created
          issuer.cert-manager.io/test-selfsigned?created
          certificate.cert-manager.io/selfsigned-cert?created

          創(chuàng)建完成后可以檢查新創(chuàng)建的證書(shū)狀態(tài),在 cert-manager 處理證書(shū)請(qǐng)求之前,可能需要稍微等幾秒:

          ??kubectl?describe?certificate?-n?cert-manager-test
          Name:?????????selfsigned-cert
          Namespace:????cert-manager-test
          ......
          Spec:
          ??Dns?Names:
          ????example.com
          ??Issuer?Ref:
          ????Name:???????test-selfsigned
          ??Secret?Name:??selfsigned-cert-tls
          Status:
          ??Conditions:
          ????Last?Transition?Time:??2020-12-12T03:29:07Z
          ????Message:???????????????Certificate?is?up?to?date?and?has?not?expired
          ????Reason:????????????????Ready
          ????Status:????????????????True
          ????Type:??????????????????Ready
          ??Not?After:???????????????2021-03-12T03:29:06Z
          ??Not?Before:??????????????2020-12-12T03:29:06Z
          ??Renewal?Time:????????????2021-02-10T03:29:06Z
          ??Revision:????????????????1
          Events:
          ??Type????Reason?????Age???From??????????Message
          ??----????------?????----??----??????????-------
          ??Normal??Issuing????6s????cert-manager??Issuing?certificate?as?Secret?does?not?exist
          ??Normal??Generated??6s????cert-manager??Stored?new?private?key?in?temporary?Secret?resource?"selfsigned-cert-sppz7"
          ??Normal??Requested??6s????cert-manager??Created?new?CertificateRequest?resource?"selfsigned-cert-z4nvl"
          ??Normal??Issuing????5s????cert-manager??The?certificate?has?been?successfully?issued

          從上面的 Events 事件中我們可以證書(shū)已經(jīng)成功簽發(fā)了,生成的證書(shū)存放在一個(gè)名為 selfsigned-cert-tls 的 Secret 對(duì)象下面:

          ??kubectl?get?secret?-n?cert-manager-test????????????????????????????
          NAME??????????????????TYPE??????????????????????????????????DATA???AGE
          default-token-t928x???kubernetes.io/service-account-token???3??????64s
          selfsigned-cert-tls???kubernetes.io/tls?????????????????????3??????63s
          ??kubectl?get?secret?-n?cert-manager-test?selfsigned-cert-tls?-o?yaml
          apiVersion:?v1
          data:
          ??ca.crt:?......
          ??tls.crt:?......
          ??tls.key:?......
          kind:?Secret
          ......
          ??name:?selfsigned-cert-tls
          ??namespace:?cert-manager-test
          ??resourceVersion:?"13461084"
          ??selfLink:?/api/v1/namespaces/cert-manager-test/secrets/selfsigned-cert-tls
          ??uid:?42e456dc-6d34-4269-b207-f1f3bd50db8b
          type:?kubernetes.io/tls

          到這里證明我們的 cert-manager 已經(jīng)安裝成功了。我們需要注意的是 cert-manager 的功能非常強(qiáng)大,不只是可以支持 ACME 類(lèi)型的證書(shū)簽發(fā),還支持其他眾多的類(lèi)型,比如 SelfSigned(自簽名)、CA、Vault、Venafi、External、ACME,只是我們一般主要是使用 ACME 來(lái)幫我們生成自動(dòng)化的證書(shū)。

          下面我們就來(lái)使用 cert-manager 結(jié)合 ingress-nginx 為 Kubernetes 應(yīng)用自動(dòng)簽發(fā) Let's Encrypt 類(lèi)型的 HTTPS 證書(shū)。

          自動(dòng)化 HTTPS

          Let's Encrypt 使用 ACME 協(xié)議來(lái)校驗(yàn)域名是否真的屬于你,校驗(yàn)成功后就可以自動(dòng)頒發(fā)免費(fèi)證書(shū),證書(shū)有效期只有 90 天,在到期前需要再校驗(yàn)一次來(lái)實(shí)現(xiàn)續(xù)期,而 cert-manager 是可以自動(dòng)續(xù)期的,所以事實(shí)上并不用擔(dān)心證書(shū)過(guò)期的問(wèn)題。目前主要有 HTTP 和 DNS 兩種校驗(yàn)方式。

          HTTP-01 校驗(yàn)

          HTTP-01 的校驗(yàn)是通過(guò)給你域名指向的 HTTP 服務(wù)增加一個(gè)臨時(shí) location,在校驗(yàn)的時(shí)候 Let's Encrypt 會(huì)發(fā)送 http 請(qǐng)求到 http:///.well-known/acme-challenge/,其中 YOUR_DOMAIN 就是被校驗(yàn)的域名,TOKEN 是 cert-manager 生成的一個(gè)路徑,它通過(guò)修改 Ingress 規(guī)則來(lái)增加這個(gè)臨時(shí)校驗(yàn)路徑并指向提供 TOKEN 的服務(wù)。Let's Encrypt 會(huì)對(duì)比 TOKEN 是否符合預(yù)期,校驗(yàn)成功后就會(huì)頒發(fā)證書(shū)了,不過(guò)這種方法不支持泛域名證書(shū)。

          使用 HTTP 校驗(yàn)這種方式,首先需要將域名解析配置好,也就是需要保證 ACME 服務(wù)端可以正常訪問(wèn)到你的 HTTP 服務(wù)。這里我們以上面的 TODO 應(yīng)用為例,我們已經(jīng)將 todo.qikqiak.com 域名做好了正確的解析。

          由于 Let's Encrypt 的生產(chǎn)環(huán)境有著嚴(yán)格的接口調(diào)用限制,所以一般我們需要先在 staging 環(huán)境測(cè)試通過(guò)后,再切換到生產(chǎn)環(huán)境。首先我們創(chuàng)建一個(gè)全局范圍 staging 環(huán)境使用的 HTTP-01 校驗(yàn)方式的證書(shū)頒發(fā)機(jī)構(gòu):

          ??cat?<apiVersion:?cert-manager.io/v1
          kind:?ClusterIssuer
          metadata:
          ??name:?letsencrypt-staging-http01
          spec:
          ??acme:
          ????#?ACME?服務(wù)端地址
          ????server:?https://acme-staging-v02.api.letsencrypt.org/directory
          ????#?用于?ACME?注冊(cè)的郵箱
          ????email:[email protected]
          ????#?用于存放?ACME?帳號(hào)?private?key?的?secret
          ????privateKeySecretRef:
          ??????name:?letsencrypt-staging-http01
          ????solvers:
          ????-?http01:?#?ACME?HTTP-01?類(lèi)型
          ????????ingress:
          ??????????class:?nginx??#?指定ingress的名稱(chēng)
          EOF

          同樣再創(chuàng)建一個(gè)用于生產(chǎn)環(huán)境使用的 ClusterIssuer 對(duì)象:

          ??cat?<apiVersion:?cert-manager.io/v1
          kind:?ClusterIssuer
          metadata:
          ??name:?letsencrypt-http01
          spec:
          ??acme:
          ????server:?https://acme-v02.api.letsencrypt.org/directory
          ????email:[email protected]
          ????privateKeySecretRef:
          ??????name:?letsencrypt-http01
          ????solvers:
          ????-?http01:?
          ????????ingress:
          ??????????class:?nginx
          EOF

          創(chuàng)建完成后可以看到兩個(gè) ClusterIssuer 對(duì)象:

          ??kubectl?get?clusterissuer
          NAME?????????????????????????READY???AGE
          letsencrypt-http01???????????True????17s
          letsencrypt-staging-http01???True????3m12s

          有了 Issuer/ClusterIssuer 證書(shū)頒發(fā)機(jī)構(gòu),接下來(lái)我們就可以生成免費(fèi)證書(shū)了,cert-manager 給我們提供了 Certificate 這個(gè)用于生成證書(shū)的自定義資源對(duì)象,不過(guò)這個(gè)對(duì)象需要在一個(gè)具體的命名空間下使用,證書(shū)最終會(huì)在這個(gè)命名空間下以 Secret 的資源對(duì)象存儲(chǔ)。我們這里是要結(jié)合 ingress-nginx 一起使用,實(shí)際上我們只需要修改 Ingress 對(duì)象,添加上 cert-manager 的相關(guān)注解即可,不需要手動(dòng)創(chuàng)建 Certificate 對(duì)象了,修改上面的 todo 應(yīng)用的 Ingress 資源對(duì)象,如下所示:

          ??cat?<apiVersion:?extensions/v1beta1
          kind:?Ingress
          metadata:
          ??name:?todo
          ??annotations:
          ????kubernetes.io/ingress.class:?"nginx"
          ????cert-manager.io/cluster-issuer:?"letsencrypt-staging-http01"??#?使用哪個(gè)issuer
          spec:
          ??tls:
          ??-?hosts:
          ????-?todo.qikqiak.com?????#?TLS?域名
          ????secretName:?todo-tls???#?用于存儲(chǔ)證書(shū)的?Secret?對(duì)象名字?
          ??rules:
          ??-?host:?todo.qikqiak.com
          ????http:
          ??????paths:
          ??????-?path:?/
          ????????backend:
          ??????????serviceName:?todo
          ??????????servicePort:?3000
          EOF

          更新了上面的 Ingress 對(duì)象后,正常就會(huì)自動(dòng)為我們創(chuàng)建一個(gè) Certificate 對(duì)象:

          ??kubectl?get?certificate??????????????????????????????
          NAME???????READY???SECRET?????AGE
          todo-tls???False???todo-tls???34s

          在校驗(yàn)過(guò)程中會(huì)自動(dòng)創(chuàng)建一個(gè) Ingress 對(duì)象用于 ACME 服務(wù)端訪問(wèn):

          ??kubectl?get?ingress?????
          NAME????????????????????????CLASS????HOSTS????????????????ADDRESS????????PORTS?????AGE
          cm-acme-http-solver-tgwlb??????todo.qikqiak.com?????10.151.30.11???80????????25s
          my-nginx???????????????????????ngdemo.qikqiak.com???10.151.30.11???80????????23h
          todo???????????????????????????todo.qikqiak.com?????10.151.30.11???80,?443???33s

          校驗(yàn)成功后會(huì)將證書(shū)保存到 todo-tls 的 Secret 對(duì)象中:

          ??kubectl?get?certificate?????????????????????????
          NAME???????READY???SECRET?????AGE
          todo-tls???True????todo-tls???21m
          ??kubectl?get?secret?????????????????????????????????????????????????
          NAME??????????????????????????TYPE??????????????????????????????????DATA???AGE
          default-token-hpd7s???????????kubernetes.io/service-account-token???3??????55d
          todo-tls??????????????????????kubernetes.io/tls?????????????????????2??????20m
          ???kubectl?describe?certificate?todo-tls?
          Name:?????????todo-tls
          Namespace:????default
          ......
          Events:
          ??Type????Reason?????Age???From??????????Message
          ??----????------?????----??----??????????-------
          ??Normal??Issuing????22m???cert-manager??Issuing?certificate?as?Secret?does?not?exist
          ??Normal??Generated??22m???cert-manager??Stored?new?private?key?in?temporary?Secret?resource?"todo-tls-tr4pq"
          ??Normal??Requested??22m???cert-manager??Created?new?CertificateRequest?resource?"todo-tls-2gchg"
          ??Normal??Issuing????21m???cert-manager??The?certificate?has?been?successfully?issued

          證書(shū)自動(dòng)獲取成功后,現(xiàn)在就可以講 ClusterIssuer 替換成生產(chǎn)環(huán)境的了:

          ??cat?<apiVersion:?extensions/v1beta1
          kind:?Ingress
          metadata:
          ??name:?todo
          ??annotations:
          ????kubernetes.io/ingress.class:?"nginx"
          ????cert-manager.io/cluster-issuer:?"letsencrypt-http01"??#?使用生產(chǎn)環(huán)境的issuer
          spec:
          ??tls:
          ??-?hosts:
          ????-?todo.qikqiak.com?????#?TLS?域名
          ????secretName:?todo-tls???#?用于存儲(chǔ)證書(shū)的?Secret?對(duì)象名字?
          ??rules:
          ??-?host:?todo.qikqiak.com
          ????http:
          ??????paths:
          ??????-?path:?/
          ????????backend:
          ??????????serviceName:?todo
          ??????????servicePort:?3000
          EOF
          ??kubectl?get?certificate?????????????????????????
          NAME???????READY???SECRET?????AGE
          todo-tls???True????todo-tls???25m

          校驗(yàn)成功后就可以自動(dòng)獲取真正的 HTTPS 證書(shū)了,現(xiàn)在在瀏覽器中訪問(wèn) https://todo.qikqiak.com 就可以看到證書(shū)是有效的了。

          DNS-01 校驗(yàn)

          DNS-01 的校驗(yàn)是通過(guò) DNS 提供商的 API 拿到你的 DNS 控制權(quán)限, 在 Let's Encrypt 為 cert-manager 提供 TOKEN 后,cert-manager 將創(chuàng)建從該 TOKEN 和你的帳戶(hù)密鑰派生的 TXT 記錄,并將該記錄放在 _acme-challenge.。然后 Let's Encrypt 將向 DNS 系統(tǒng)查詢(xún)?cè)撚涗?,如果找到匹配?xiàng),就可以頒發(fā)證書(shū),這種方法是支持泛域名證書(shū)的。(不知道是不是公眾帳號(hào) bug 了,后面內(nèi)容添加不上了,提示內(nèi)容太多)

          參考鏈接

          • https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/
          • https://v2-1.docs.kubesphere.io/docs/zh-CN/quick-start/ingress-canary/
          • https://cert-manager.io/docs/tutorials/acme/ingress/


          另外我們平臺(tái)的雙12課程優(yōu)惠活動(dòng)正在進(jìn)行中,今天最后一天優(yōu)惠,年底最后一次超車(chē)計(jì)劃,還不快上車(chē)嗎?點(diǎn)擊即刻參與~



          ?點(diǎn)擊屏末?|??|?即刻學(xué)習(xí)

          瀏覽 60
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  午夜亚洲| 色色色综合 | 清纯唯美亚洲第一页麻豆豆花 | 爱搞视频在线播放 | 性色在线 |