Linkerd 2.10(Step by Step)—Ingress 流量

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
简介: Linkerd 2.10(Step by Step)—Ingress 流量

Linkerd 2.9 版开始,有两种方式可以让 Linkerd 代理 与您的 Ingress Controller 一起运行。


默认模式



当 ingress controller 注入 linkerd.io/inject: enabledannotation 时, Linkerd 代理将遵守 ingress controller 做出的负载平衡决策, 而不是应用自己的 EWMA 负载平衡。这也意味着 Linkerd 代理不会为此流量使用服务配置文件(Service Profiles), 因此不会公开每个路由的指标(per-route metrics)或进行流量拆分(traffic splitting)。


如果您的 Ingress controller 注入没有特定于 Ingress 的额外配置, Linkerd 代理将在默认模式下运行。


代理 Ingress Mode



如果您需要 Linkerd 功能,如服务配置文件(Service Profiles)、流量拆分(Traffic Splits)等, 则需要进行额外的配置才能使 Ingress 控制器的 Linkerd 代理在入口模式下运行。这会导致 Linkerd 根据其 :authorityHostl5d-dst-override headers 而不是原始目的地来路由请求,这允许 Linkerd 执行自己的负载平衡 并使用服务配置文件(Service Profiles)来公开每个路由的指标并启用流量拆分(traffic splitting)。


通过在 Ingress Controller 的 Pod Spec 中添加以下注释, 即 linkerd.io/inject: ingress,可以使 Ingress 控制器 deployment 的代理 在 ingress 模式下运行。

同样可以通过在注入命令中使用 --ingress 标志来完成。


kubectl get deployment <ingress-controller> -n <ingress-namespace> -o yaml | linkerd inject --ingress - | kubectl apply -f -


这可以通过检查 Ingress 控制器的 pod 是否具有相关的 annotation 集来验证。


kubectl describe pod/<ingress-pod> | grep "linkerd.io/inject: ingress"


对于 ingress,大多数控制器默认情况下不会将传入 header (example.com) 重写 为内部服务名称(example.default.svc.cluster.local)。在这种情况下,当 Linkerd 收到传出请求时,它认为该请求的目的地 是 example.com 而不是 example.default.svc.cluster.local。这会造成一个非常令人沮丧的无限循环!

幸运的是,许多入口控制器允许您修改 Host header 或向传出请求添加自定义标头。以下是常见入口控制器的一些说明:


  • Nginx
  • Traefik
  • GCE
  • Ambassador
  • Gloo
  • Contour
  • Kong


如果您的 ingress controller 正在终止 HTTPS, Linkerd 将只为传入请求提供 TCP 统计信息, 因为代理看到的所有流量都是加密的。它将提供从控制器到后端服务的传出请求的完整统计信息, 因为这是从控制器到 Linkerd 的纯文本。


如果请求在注入您的 ingress controller 后遇到 2-3 秒的延迟, 这可能是因为 type: LoadBalancer 的服务隐藏了客户端源 IP。您可以通过在入口的服务定义中设置 externalTrafficPolicy: Local 来解决此问题。


虽然 Kubernetes Ingress API 定义允许 backendservicePort 是字符串值, 但 Linkerd 只能使用数字 servicePort 值。如果遇到字符串值,Linkerd 将默认使用端口 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;


这个例子结合了 NGINX 用于代理 HTTPgRPC 流量的两个指令。实际上,根据服务使用的协议,只需要设置 proxy_set_headergrpc_set_header 指令, 但是 NGINX 将忽略任何不需要的指令。


此示例入口定义为具有使用不同端口的多个端点的应用程序使用单个入口。


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 将添加一个 l5d-dst-override header 来 指示 Linkerd 请求的目的地是什么服务。您需要同时包含 Kubernetes service FQDN (web-svc.emojivoto.svc.cluster.local) 和目标 servicePort


要对此进行测试,您需要获取控制器的外部 IP 地址。如果您通过 helm 安装了 nginx-ingress,则可以通过运行以下命令获取该 IP 地址:


kubectl get svc --all-namespaces \
  -l app=nginx-ingress,component=controller \
  -o=custom-columns=EXTERNAL-IP:.status.loadBalancer.ingress[0].ip


然后你可以通过 curl 使用这个 IP:


curl -H "Host: example.com" http://external-ip


如果您使用默认后端,则需要为该后端创建入口定义 以确保设置了 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 以复习如何安装它。

使用 Traefik 作为 Linkerd ingress 的最简单方法是使用

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 将添加一个 l5d-dst-override header 来指示 Linkerd 请求的目的地是什么服务。您需要同时包含 Kubernetes service FQDN (web-svc.emojivoto.svc.cluster.local) 和目标 servicePort。有关更多信息,请参阅 Traefik 网站。


要对此进行测试,您需要获取控制器的外部 IP 地址。如果您通过 helm 安装了 Traefik,则可以通过运行以下命令获取该 IP 地址:


kubectl get svc --all-namespaces \
  -l app=traefik \
  -o='custom-columns=EXTERNAL-IP:.status.loadBalancer.ingress[0].ip'


然后你可以通过 curl 使用这个 IP:


curl -H "Host: example.com" http://external-ip


如果您使用 Traefik 的 service weights,此解决方案将不起作用, 因为 Linkerd 将始终

l5d-dst-override 中的服务名称发送请求。一种解决方法是使用 traefik.frontend.passHostHeader: "false" 代替。请注意,如果您使用 TLS,Traefik 和后端服务之间的连接将不会被加密。有一个open issue 可以跟踪此问题的解决方案。


Traefik 2.x


Traefik 2.x 通过名为 IngressRoute 的 Custom Resource Definition (CRD) 添加了 对基于路径(path)的请求路由的支持。


如果您选择使用 IngressRoute 而不是默认的 Kubernetes Ingress resource, 那么您还需要使用 Traefik 的 Middleware Custom Resource Definition 来添加 l5d-dst-override header。


下面的 YAML 使用 Traefik CRD 为 emojivoto 应用程序生成相同的结果,如上所述。


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


这个例子和 Traefik 类似,也以 emojivoto 为例。查看 getting started 以复习如何安装它。


除了在 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


要使用此示例定义,请将 managed-cert-namestatic-ip-name 替换为您项目中定义的短名称(n.b. 使用 IP 地址的名称,而不是地址本身)。


托管证书将需要大约 30-60 分钟来提供,但 ingress 的状态应该在几分钟内是健康的。提供托管证书后,ingress 应该对 Internet 可见。


Ambassador


这里以 emojivoto 为例, 看一下 getting started 以复习如何安装它。

Ambassador 不使用 Ingress 资源,而是依赖 Service。示例服务定义是:


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 将添加一个 l5d-dst-override header 来指示 Linkerd 的请求是为什么服务。这将包含 Kubernetes service FQDN (web-svc.emojivoto.svc.cluster.local) 目标 servicePort

要使其全局化,请将 add_linkerd_headers 添加到您的 Module 配置中。


要对此进行测试,您需要获取控制器的外部 IP 地址。如果您通过 helm 安装了 Ambassador,则可以通过运行以下命令获取该 IP 地址:


kubectl get svc --all-namespaces \
  -l "app.kubernetes.io/name=ambassador" \
  -o='custom-columns=EXTERNAL-IP:.status.loadBalancer.ingress[0].ip'


如果您已经安装了管理界面,这将返回两个 IP,其中之一是 <none>。只需忽略那个并使用实际的 IP 地址。


然后你可以通过 curl 使用这个 IP:


curl -H "Host: example.com" http://external-ip


您还可以在此处 从 Buoyant 的人们那里找到有关将 Linkerd 与 Emissary Ingress(又名Ambassador)结合使用的更详细指南。


Gloo


这里以 books 为例,查看 Demo: Books 了解如何运行它。

如果您使用 Gateway methodgloo install gateway)安装了 Gloo, 那么您将需要一个 VirtualService 才能将流量路由到您的 Books 应用程序。

要将 GlooLinkerd 一起使用,您可以选择两个选项之一。


自动的


Gloo v0.13.20 开始,GlooLinkerd 进行了原生集成, 因此会自动添加所需的 Linkerd header


假设您将 gloo 安装到默认位置,您可以通过运行以下命令启用本机集成:


kubectl patch settings -n gloo-system default \
  -p '{"spec":{"linkerd":true}}' --type=merge


Gloo 现在会自动向上游的每个 kubernetes 添加 l5d-dst-override header。


现在只需添加一条到上游 books app 的路由:


glooctl add route --path-prefix=/ --dest-name booksapp-webapp-7000


手动的


如本文档开头所述,您需要指示 Gloo 添加一个 header,以允许 Linkerd 识别将流量发送到何处。


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 中内置的内容转换引擎,您可以指示它添加所需的 l5d-dst-override header, 该 header 在上面的示例中指向服务的 FDQN 和端口:webapp.booksapp.svc.cluster.local:7000


Test


为了轻松测试这一点,您可以通过运行以下命令获取 Gloo 代理的 URL:


glooctl proxy URL


这将返回类似于:


$ glooctl proxy url
http://192.168.99.132:30969


对于上面的示例 VirtualService,它侦听任何域(domain)和路径(path), 在浏览器中访问代理 URL (http://192.168.99.132:30969) 应该会打开 Books 应用程序。


Contour


Contour 不支持自动设置 l5d-dst-override header。以下示例使用 Contour getting started 来演示如何手动设置所需的 header:

首先,将 Linkerd 注入您的 Contour 安装:


linkerd inject https://projectcontour.io/quickstart/contour.yaml | kubectl apply -f -


Envoy 不会自动挂载 service account token。要解决此问题,您需要设置 automountServiceAccountToken: true。您可以选择创建一个专用 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}]'


验证您的 Contour 和 Envoy 安装有一个正在运行的 Linkerd sidecar

接下来我们将部署一个 demo service


linkerd inject https://projectcontour.io/examples/kuard.yaml | kubectl apply -f -


要将外部流量路由到您的服务,您需要提供一个 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


请注意,l5d-dst-override header 显式设置为目标 service

最后,您可以测试您的 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 请求头将自动设置。


Kong


Kong 不自动支持标头 l5d-dst-override。本文档将使用以下元素:


  • Kong
  • Emojivoto

在安装 Emojivoto demo 应用程序之前,请在您的集群上安装 Linkerd 和 Kong。记得在注入 Kong 部署时使用 上面 提到的 --ingress 标志(或注解)!

我们还需要声明这些对象:


  • 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


我们在 KongPlugin 中明确设置了 l5d-dst-override。使用 templates as values, 我们可以使用来自请求的 host header,并基于此设置 l5d-dst-override 值。

最后,让我们安装 Emojivoto,以便它的 deploy/vote-bot 以 ingress 为目标, 并包含 web-svc.emojivoto 服务的 host header。


在应用注入的(injected) Emojivoto 应用程序之前,对 vote-bot 部署进行以下更改:


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


相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
Prometheus Cloud Native 数据可视化
Linkerd 2.10(Step by Step)—4. 如何配置外部 Prometheus 实例
Linkerd 2.10(Step by Step)—4. 如何配置外部 Prometheus 实例
154 0
|
JSON Kubernetes 安全
Linkerd 2.10(Step by Step)—多集群通信
Linkerd 2.10(Step by Step)—多集群通信
289 0
Linkerd 2.10(Step by Step)—多集群通信
|
存储 数据可视化 应用服务中间件
Linkerd 2.10(Step by Step)—使用 Linkerd 进行分布式跟踪
Linkerd 2.10(Step by Step)—使用 Linkerd 进行分布式跟踪
254 0
Linkerd 2.10(Step by Step)—使用 Linkerd 进行分布式跟踪
|
JSON Kubernetes 监控
Linkerd 2.10(Step by Step)—2. 自动化的金丝雀发布
Linkerd 2.10(Step by Step)—2. 自动化的金丝雀发布
182 0
Linkerd 2.10(Step by Step)—2. 自动化的金丝雀发布
|
存储 Kubernetes API
Linkerd 2.10(Step by Step)—将 GitOps 与 Linkerd 和 Argo CD 结合使用
Linkerd 2.10(Step by Step)—将 GitOps 与 Linkerd 和 Argo CD 结合使用
662 0
Linkerd 2.10(Step by Step)—将 GitOps 与 Linkerd 和 Argo CD 结合使用
|
Kubernetes 关系型数据库 MySQL
Linkerd 2.10(Step by Step)—1. 将您的服务添加到 Linkerd
Linkerd 2.10(Step by Step)—1. 将您的服务添加到 Linkerd
161 0
|
Kubernetes Docker 容器
Linkerd 2.10(Step by Step)—安装 Linkerd
Linkerd 2.10(Step by Step)—安装 Linkerd
360 0
|
Kubernetes 安全 网络协议
Linkerd 2.10(Step by Step)—暴露 Dashboard
Linkerd 2.10(Step by Step)—暴露 Dashboard
236 0
|
Kubernetes Perl 容器
Linkerd 2.10(Step by Step)—优雅的 Pod 关闭
Linkerd 2.10(Step by Step)—优雅的 Pod 关闭
181 0
Linkerd 2.10(Step by Step)—使用 Kustomize 自定义 Linkerd 的配置
Linkerd 2.10(Step by Step)—使用 Kustomize 自定义 Linkerd 的配置
161 0

热门文章

最新文章