Linkerd 2.10(Step by Step)—Ingress 流量
Linkerd 2.10 中文手冊(cè)持續(xù)修正更新中:
- https://linkerd.hacker-linner.com
從 Linkerd 2.9 版開(kāi)始,有兩種方式可以讓 Linkerd 代理 與您的 Ingress Controller 一起運(yùn)行。
默認(rèn)模式
當(dāng) ingress controller 注入 linkerd.io/inject: enabled annotation 時(shí), Linkerd 代理將遵守 ingress controller 做出的負(fù)載平衡決策, 而不是應(yīng)用自己的 EWMA 負(fù)載平衡。這也意味著 Linkerd 代理不會(huì)為此流量使用服務(wù)配置文件(Service Profiles), 因此不會(huì)公開(kāi)每個(gè)路由的指標(biāo)(per-route metrics)或進(jìn)行流量拆分(traffic splitting)。
如果您的 Ingress controller 注入沒(méi)有特定于 Ingress 的額外配置, Linkerd 代理將在默認(rèn)模式下運(yùn)行。
代理 Ingress Mode
如果您需要 Linkerd 功能,如服務(wù)配置文件(Service Profiles)、流量拆分(Traffic Splits)等, 則需要進(jìn)行額外的配置才能使 Ingress 控制器的 Linkerd 代理在入口模式下運(yùn)行。這會(huì)導(dǎo)致 Linkerd 根據(jù)其 :authority、Host 或 l5d-dst-override headers 而不是原始目的地來(lái)路由請(qǐng)求,這允許 Linkerd 執(zhí)行自己的負(fù)載平衡 并使用服務(wù)配置文件(Service Profiles)來(lái)公開(kāi)每個(gè)路由的指標(biāo)并啟用流量拆分(traffic splitting)。
通過(guò)在 Ingress Controller 的 Pod Spec 中添加以下注釋, 即 linkerd.io/inject: ingress,可以使 Ingress 控制器 deployment 的代理 在 ingress 模式下運(yùn)行。
同樣可以通過(guò)在注入命令中使用 --ingress 標(biāo)志來(lái)完成。
- kubectl get deployment <ingress-controller> -n <ingress-namespace> -o yaml | linkerd inject --ingress - | kubectl apply -f -
這可以通過(guò)檢查 Ingress 控制器的 pod 是否具有相關(guān)的 annotation 集來(lái)驗(yàn)證。
- kubectl describe pod/<ingress-pod> | grep "linkerd.io/inject: ingress"
對(duì)于 ingress,大多數(shù)控制器默認(rèn)情況下不會(huì)將傳入 header (example.com) 重寫 為內(nèi)部服務(wù)名稱(example.default.svc.cluster.local)。在這種情況下,當(dāng) Linkerd 收到傳出請(qǐng)求時(shí),它認(rèn)為該請(qǐng)求的目的地 是 example.com 而不是 example.default.svc.cluster.local。這會(huì)造成一個(gè)非常令人沮喪的無(wú)限循環(huán)!
幸運(yùn)的是,許多入口控制器允許您修改 Host header 或向傳出請(qǐng)求添加自定義標(biāo)頭。以下是常見(jiàn)入口控制器的一些說(shuō)明:
- Nginx
- Traefik
- GCE
- Ambassador
- Gloo
- Contour
- Kong
如果您的 ingress controller 正在終止 HTTPS, Linkerd 將只為傳入請(qǐng)求提供 TCP 統(tǒng)計(jì)信息, 因?yàn)榇砜吹降乃辛髁慷际羌用艿?。它將提供從控制器到后端服?wù)的傳出請(qǐng)求的完整統(tǒng)計(jì)信息, 因?yàn)檫@是從控制器到 Linkerd 的純文本。
如果請(qǐng)求在注入您的 ingress controller 后遇到 2-3 秒的延遲, 這可能是因?yàn)?type: LoadBalancer 的服務(wù)隱藏了客戶端源 IP。您可以通過(guò)在入口的服務(wù)定義中設(shè)置 externalTrafficPolicy: Local 來(lái)解決此問(wèn)題。
雖然 Kubernetes Ingress API 定義允許 backend 的 servicePort 是字符串值, 但 Linkerd 只能使用數(shù)字 servicePort 值。如果遇到字符串值,Linkerd 將默認(rèn)使用端口 80。
Nginx
這里以 emojivoto 為例
示例入口定義是:
- apiVersion: extensions/v1beta1
- kind: Ingress
- metadata:
- name: web-ingress
- namespace: emojivoto
- annotations:
- kubernetes.io/ingress.class: "nginx"
- nginx.ingress.kubernetes.io/configuration-snippet: |
- proxy_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
- grpc_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
- spec:
- rules:
- - host: example.com
- http:
- paths:
- - backend:
- serviceName: web-svc
- servicePort: 80
這里的重要 annotation 是:
- nginx.ingress.kubernetes.io/configuration-snippet: |
- proxy_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
- grpc_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
如果您使用的是 auth-url, 則還需要添加以下代碼段。
- nginx.ingress.kubernetes.io/auth-snippet: |
- proxy_set_header l5d-dst-override authn-name.authn-namespace.svc.cluster.local:authn-port;
- grpc_set_header l5d-dst-override authn-name.authn-namespace.svc.cluster.local:authn-port;
這個(gè)例子結(jié)合了 NGINX 用于代理 HTTP 和 gRPC 流量的兩個(gè)指令。實(shí)際上,根據(jù)服務(wù)使用的協(xié)議,只需要設(shè)置 proxy_set_header 或 grpc_set_header 指令, 但是 NGINX 將忽略任何不需要的指令。
此示例入口定義為具有使用不同端口的多個(gè)端點(diǎn)的應(yīng)用程序使用單個(gè)入口。
- apiVersion: extensions/v1beta1
- kind: Ingress
- metadata:
- name: web-ingress
- namespace: emojivoto
- annotations:
- kubernetes.io/ingress.class: "nginx"
- nginx.ingress.kubernetes.io/configuration-snippet: |
- proxy_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
- grpc_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
- spec:
- rules:
- - host: example.com
- http:
- paths:
- - path: /
- backend:
- serviceName: web-svc
- servicePort: 80
- - path: /another-endpoint
- backend:
- serviceName: another-svc
- servicePort: 8080
Nginx 將添加一個(gè) l5d-dst-override header 來(lái) 指示 Linkerd 請(qǐng)求的目的地是什么服務(wù)。您需要同時(shí)包含 Kubernetes service FQDN (web-svc.emojivoto.svc.cluster.local) 和目標(biāo) servicePort。
要對(duì)此進(jìn)行測(cè)試,您需要獲取控制器的外部 IP 地址。如果您通過(guò) helm 安裝了 nginx-ingress,則可以通過(guò)運(yùn)行以下命令獲取該 IP 地址:
- kubectl get svc --all-namespaces \
- -l app=nginx-ingress,component=controller \
- -o=custom-columns=EXTERNAL-IP:.status.loadBalancer.ingress[0].ip
然后你可以通過(guò) curl 使用這個(gè) IP:
- curl -H "Host: example.com" http://external-ip
如果您使用默認(rèn)后端,則需要為該后端創(chuàng)建入口定義 以確保設(shè)置了 l5d-dst-override header。例如:
- apiVersion: extensions/v1beta1
- kind: Ingress
- metadata:
- name: default-ingress
- namespace: backends
- annotations:
- kubernetes.io/ingress.class: "nginx"
- nginx.ingress.kubernetes.io/configuration-snippet: |
- proxy_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
- grpc_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
- spec:
- backend:
- serviceName: default-backend
- servicePort: 80
Traefik
這里以 emojivoto 為例,看一下 getting started 以復(fù)習(xí)如何安裝它。
使用 Traefik 作為 Linkerd ingress 的最簡(jiǎn)單方法是使用 ingress.kubernetes.io/custom-request-headers 配置 Kubernetes Ingress resource,如下所示:
- apiVersion: extensions/v1beta1
- kind: Ingress
- metadata:
- name: web-ingress
- namespace: emojivoto
- annotations:
- kubernetes.io/ingress.class: "traefik"
- ingress.kubernetes.io/custom-request-headers: l5d-dst-override:web-svc.emojivoto.svc.cluster.local:80
- spec:
- rules:
- - host: example.com
- http:
- paths:
- - backend:
- serviceName: web-svc
- servicePort: 80
這里的重要 annotation 是:
- ingress.kubernetes.io/custom-request-headers: l5d-dst-override:web-svc.emojivoto.svc.cluster.local:80
Traefik 將添加一個(gè) l5d-dst-override header 來(lái)指示 Linkerd 請(qǐng)求的目的地是什么服務(wù)。您需要同時(shí)包含 Kubernetes service FQDN (web-svc.emojivoto.svc.cluster.local) 和目標(biāo) servicePort。有關(guān)更多信息,請(qǐng)參閱 Traefik 網(wǎng)站。
要對(duì)此進(jìn)行測(cè)試,您需要獲取控制器的外部 IP 地址。如果您通過(guò) helm 安裝了 Traefik,則可以通過(guò)運(yùn)行以下命令獲取該 IP 地址:
- kubectl get svc --all-namespaces \
- -l app=traefik \
- -o='custom-columns=EXTERNAL-IP:.status.loadBalancer.ingress[0].ip'
然后你可以通過(guò) curl 使用這個(gè) IP:
- curl -H "Host: example.com" http://external-ip
如果您使用 Traefik 的 service weights,此解決方案將不起作用, 因?yàn)?Linkerd 將始終向 l5d-dst-override 中的服務(wù)名稱發(fā)送請(qǐng)求。一種解決方法是使用 traefik.frontend.passHostHeader: "false" 代替。請(qǐng)注意,如果您使用 TLS,Traefik 和后端服務(wù)之間的連接將不會(huì)被加密。有一個(gè)open issue 可以跟蹤此問(wèn)題的解決方案。
Traefik 2.x
Traefik 2.x 通過(guò)名為 IngressRoute 的 Custom Resource Definition (CRD) 添加了 對(duì)基于路徑(path)的請(qǐng)求路由的支持。
如果您選擇使用 IngressRoute 而不是默認(rèn)的 Kubernetes Ingress resource, 那么您還需要使用 Traefik 的 Middleware Custom Resource Definition 來(lái)添加 l5d-dst-override header。
下面的 YAML 使用 Traefik CRD 為 emojivoto 應(yīng)用程序生成相同的結(jié)果,如上所述。
- apiVersion: traefik.containo.us/v1alpha1
- kind: Middleware
- metadata:
- name: l5d-header-middleware
- namespace: traefik
- spec:
- headers:
- customRequestHeaders:
- l5d-dst-override: "web-svc.emojivoto.svc.cluster.local:80"
- ---
- apiVersion: traefik.containo.us/v1alpha1
- kind: IngressRoute
- metadata:
- annotations:
- kubernetes.io/ingress.class: traefik
- creationTimestamp: null
- name: emojivoto-web-ingress-route
- namespace: emojivoto
- spec:
- entryPoints: []
- routes:
- - kind: Rule
- match: PathPrefix(`/`)
- priority: 0
- middlewares:
- - name: l5d-header-middleware
- services:
- - kind: Service
- name: web-svc
- port: 80
GCE
這個(gè)例子和 Traefik 類似,也以 emojivoto 為例。查看 getting started 以復(fù)習(xí)如何安裝它。
除了在 Traefik 示例中找到的自定義 headers 之外, 它還展示了如何將 Google Cloud Static External IP Address 和 TLS 與 Google-managed certificate 一起使用。
示例入口定義是:
- apiVersion: extensions/v1beta1
- kind: Ingress
- metadata:
- name: web-ingress
- namespace: emojivoto
- annotations:
- kubernetes.io/ingress.class: "gce"
- ingress.kubernetes.io/custom-request-headers: "l5d-dst-override: web-svc.emojivoto.svc.cluster.local:80"
- ingress.gcp.kubernetes.io/pre-shared-cert: "managed-cert-name"
- kubernetes.io/ingress.global-static-ip-name: "static-ip-name"
- spec:
- rules:
- - host: example.com
- http:
- paths:
- - backend:
- serviceName: web-svc
- servicePort: 80
要使用此示例定義,請(qǐng)將 managed-cert-name 和 static-ip-name 替換為您項(xiàng)目中定義的短名稱(n.b. 使用 IP 地址的名稱,而不是地址本身)。
托管證書將需要大約 30-60 分鐘來(lái)提供,但 ingress 的狀態(tài)應(yīng)該在幾分鐘內(nèi)是健康的。提供托管證書后,ingress 應(yīng)該對(duì) Internet 可見(jiàn)。
Ambassador
這里以 emojivoto 為例, 看一下 getting started 以復(fù)習(xí)如何安裝它。
Ambassador 不使用 Ingress 資源,而是依賴 Service。示例服務(wù)定義是:
- apiVersion: v1
- kind: Service
- metadata:
- name: web-ambassador
- namespace: emojivoto
- annotations:
- getambassador.io/config: |
- ---
- apiVersion: ambassador/v1
- kind: Mapping
- name: web-ambassador-mapping
- service: http://web-svc.emojivoto.svc.cluster.local:80
- host: example.com
- prefix: /
- add_linkerd_headers: true
- spec:
- selector:
- app: web-svc
- ports:
- - name: http
- port: 80
- targetPort: http
這里的重要 annotation 是:
- add_linkerd_headers: true
Ambassador 將添加一個(gè) l5d-dst-override header 來(lái)指示 Linkerd 的請(qǐng)求是為什么服務(wù)。這將包含 Kubernetes service FQDN (web-svc.emojivoto.svc.cluster.local) 和 目標(biāo) servicePort。
要使其全局化,請(qǐng)將 add_linkerd_headers 添加到您的 Module 配置中。
要對(duì)此進(jìn)行測(cè)試,您需要獲取控制器的外部 IP 地址。如果您通過(guò) helm 安裝了 Ambassador,則可以通過(guò)運(yùn)行以下命令獲取該 IP 地址:
- kubectl get svc --all-namespaces \
- -l "app.kubernetes.io/name=ambassador" \
- -o='custom-columns=EXTERNAL-IP:.status.loadBalancer.ingress[0].ip'
如果您已經(jīng)安裝了管理界面,這將返回兩個(gè) IP,其中之一是
然后你可以通過(guò) curl 使用這個(gè) IP:
- curl -H "Host: example.com" http://external-ip
您還可以在此處 從 Buoyant 的人們那里找到有關(guān)將 Linkerd 與 Emissary Ingress(又名Ambassador)結(jié)合使用的更詳細(xì)指南。
Gloo
這里以 books 為例,查看 Demo: Books 了解如何運(yùn)行它。
如果您使用 Gateway method(gloo install gateway)安裝了 Gloo, 那么您將需要一個(gè) VirtualService 才能將流量路由到您的 Books 應(yīng)用程序。
要將 Gloo 與 Linkerd 一起使用,您可以選擇兩個(gè)選項(xiàng)之一。
自動(dòng)的
從 Gloo v0.13.20 開(kāi)始,Gloo 與 Linkerd 進(jìn)行了原生集成, 因此會(huì)自動(dòng)添加所需的 Linkerd header。
假設(shè)您將 gloo 安裝到默認(rèn)位置,您可以通過(guò)運(yùn)行以下命令啟用本機(jī)集成:
- kubectl patch settings -n gloo-system default \
- -p '{"spec":{"linkerd":true}}' --type=merge
Gloo 現(xiàn)在會(huì)自動(dòng)向上游的每個(gè) kubernetes 添加 l5d-dst-override header。
現(xiàn)在只需添加一條到上游 books app 的路由:
- glooctl add route --path-prefix=/ --dest-name booksapp-webapp-7000
手動(dòng)的
如本文檔開(kāi)頭所述,您需要指示 Gloo 添加一個(gè) header,以允許 Linkerd 識(shí)別將流量發(fā)送到何處。
- apiVersion: gateway.solo.io/v1
- kind: VirtualService
- metadata:
- name: books
- namespace: gloo-system
- spec:
- virtualHost:
- domains:
- - '*'
- name: gloo-system.books
- routes:
- - matcher:
- prefix: /
- routeAction:
- single:
- upstream:
- name: booksapp-webapp-7000
- namespace: gloo-system
- routePlugins:
- transformations:
- requestTransformation:
- transformationTemplate:
- headers:
- l5d-dst-override:
- text: webapp.booksapp.svc.cluster.local:7000
- passthrough: {}
這里的重要 annotation 是:
- routePlugins:
- transformations:
- requestTransformation:
- transformationTemplate:
- headers:
- l5d-dst-override:
- text: webapp.booksapp.svc.cluster.local:7000
- passthrough: {}
使用 Gloo 中內(nèi)置的內(nèi)容轉(zhuǎn)換引擎,您可以指示它添加所需的 l5d-dst-override header, 該 header 在上面的示例中指向服務(wù)的 FDQN 和端口:webapp.booksapp.svc.cluster.local:7000
Test
為了輕松測(cè)試這一點(diǎn),您可以通過(guò)運(yùn)行以下命令獲取 Gloo 代理的 URL:
- glooctl proxy URL
這將返回類似于:
- $ glooctl proxy url
- http://192.168.99.132:30969
對(duì)于上面的示例 VirtualService,它偵聽(tīng)任何域(domain)和路徑(path), 在瀏覽器中訪問(wèn)代理 URL (http://192.168.99.132:30969) 應(yīng)該會(huì)打開(kāi) Books 應(yīng)用程序。
Contour
Contour 不支持自動(dòng)設(shè)置 l5d-dst-override header。以下示例使用 Contour getting started 來(lái)演示如何手動(dòng)設(shè)置所需的 header:
首先,將 Linkerd 注入您的 Contour 安裝:
- linkerd inject https://projectcontour.io/quickstart/contour.yaml | kubectl apply -f -
Envoy 不會(huì)自動(dòng)掛載 service account token。要解決此問(wèn)題,您需要設(shè)置 automountServiceAccountToken: true。您可以選擇創(chuàng)建一個(gè)專用 service account 以避免使用 default。
- # create a service account (optional)
- kubectl apply -f - << EOF
- apiVersion: v1
- kind: ServiceAccount
- metadata:
- name: envoy
- namespace: projectcontour
- EOF
- # add service account to envoy (optional)
- kubectl patch daemonset envoy -n projectcontour --type json -p='[{"op": "add", "path": "/spec/template/spec/serviceAccount", "value": "envoy"}]'
- # auto mount the service account token (required)
- kubectl patch daemonset envoy -n projectcontour --type json -p='[{"op": "replace", "path": "/spec/template/spec/automountServiceAccountToken", "value": true}]'
驗(yàn)證您的 Contour 和 Envoy 安裝有一個(gè)正在運(yùn)行的 Linkerd sidecar。
接下來(lái)我們將部署一個(gè) demo service:
- linkerd inject https://projectcontour.io/examples/kuard.yaml | kubectl apply -f -
要將外部流量路由到您的服務(wù),您需要提供一個(gè) HTTPProxy:
- apiVersion: projectcontour.io/v1
- kind: HTTPProxy
- metadata:
- name: kuard
- namespace: default
- spec:
- routes:
- - requestHeadersPolicy:
- set:
- - name: l5d-dst-override
- value: kuard.default.svc.cluster.local:80
- services:
- - name: kuard
- namespace: default
- port: 80
- virtualhost:
- fqdn: 127.0.0.1.xip.io
請(qǐng)注意,l5d-dst-override header 顯式設(shè)置為目標(biāo) service。
最后,您可以測(cè)試您的 working service mesh :
- kubectl port-forward svc/envoy -n projectcontour 3200:80
- http://127.0.0.1.xip.io:3200
如果您將 Contour 與 flagger 一起使用, l5d-dst-override 請(qǐng)求頭將自動(dòng)設(shè)置。
Kong
Kong 不自動(dòng)支持標(biāo)頭 l5d-dst-override。本文檔將使用以下元素:
- Kong
- Emojivoto
在安裝 Emojivoto demo 應(yīng)用程序之前,請(qǐng)?jiān)谀募荷习惭b Linkerd 和 Kong。記得在注入 Kong 部署時(shí)使用 上面 提到的 --ingress 標(biāo)志(或注解)!
我們還需要聲明這些對(duì)象:
- KongPlugin,Kong 提供的 CRD
- Ingress
- apiVersion: configuration.konghq.com/v1
- kind: KongPlugin
- metadata:
- name: set-l5d-header
- namespace: emojivoto
- plugin: request-transformer
- config:
- add:
- headers:
- - l5d-dst-override:$(headers.host).svc.cluster.local
- ---
- apiVersion: extensions/v1beta1
- kind: Ingress
- metadata:
- name: web-ingress
- namespace: emojivoto
- annotations:
- kubernetes.io/ingress.class: "kong"
- konghq.com/plugins: set-l5d-header
- spec:
- rules:
- - http:
- paths:
- - path: /api/vote
- backend:
- serviceName: web-svc
- servicePort: http
- - path: /api/list
- backend:
- serviceName: web-svc
- servicePort: http
我們?cè)?KongPlugin 中明確設(shè)置了 l5d-dst-override。使用 templates as values, 我們可以使用來(lái)自請(qǐng)求的 host header,并基于此設(shè)置 l5d-dst-override 值。
最后,讓我們安裝 Emojivoto,以便它的 deploy/vote-bot 以 ingress 為目標(biāo), 并包含 web-svc.emojivoto 服務(wù)的 host header。
在應(yīng)用注入的(injected) Emojivoto 應(yīng)用程序之前,對(duì) vote-bot 部署進(jìn)行以下更改:
- env:
- # Target the Kong ingress instead of the Emojivoto web service
- - name: WEB_HOST
- value: kong-proxy.kong:80
- # Override the host header on requests so that it can be used to set the l5d-dst-override header
- - name: HOST_OVERRIDE
- value: web-svc.emojivoto
【編輯推薦】