首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Linkerd 2.10(Step by Step)—Ingress 流量

Linkerd 2.10(Step by Step)—Ingress 流量

作者头像
为少
发布2021-07-07 11:13:41
发布2021-07-07 11:13:41
1.5K00
代码可运行
举报
文章被收录于专栏:黑客下午茶黑客下午茶
运行总次数:0
代码可运行

Linkerd 2.10 系列

Linkerd 2.10 中文手册持续修正更新中:

  • https://linkerd.hacker-linner.com

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

默认模式

当 ingress controller 注入 linkerd.io/inject: enabled annotation 时, 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 标志来完成。

代码语言:javascript
代码运行次数:0
运行
复制
kubectl get deployment <ingress-controller> -n <ingress-namespace> -o yaml | linkerd inject --ingress - | kubectl apply -f -

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

代码语言:javascript
代码运行次数:0
运行
复制
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 为例

示例入口定义是:

代码语言:javascript
代码运行次数:0
运行
复制
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 是:

代码语言:javascript
代码运行次数:0
运行
复制
    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, 则还需要添加以下代码段。

代码语言:javascript
代码运行次数:0
运行
复制
    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 将忽略任何不需要的指令。

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

代码语言:javascript
代码运行次数:0
运行
复制
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 地址:

代码语言:javascript
代码运行次数:0
运行
复制
kubectl get svc --all-namespaces \
  -l app=nginx-ingress,component=controller \
  -o=custom-columns=EXTERNAL-IP:.status.loadBalancer.ingress[0].ip

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

代码语言:javascript
代码运行次数:0
运行
复制
curl -H "Host: example.com" http://external-ip

如果您使用默认后端,则需要为该后端创建入口定义 以确保设置了 l5d-dst-override header。例如:

代码语言:javascript
代码运行次数:0
运行
复制
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,如下所示:

代码语言:javascript
代码运行次数:0
运行
复制
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 是:

代码语言:javascript
代码运行次数:0
运行
复制
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 地址:

代码语言:javascript
代码运行次数:0
运行
复制
kubectl get svc --all-namespaces \
  -l app=traefik \
  -o='custom-columns=EXTERNAL-IP:.status.loadBalancer.ingress[0].ip'

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

代码语言:javascript
代码运行次数:0
运行
复制
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 应用程序生成相同的结果,如上所述。

代码语言:javascript
代码运行次数:0
运行
复制
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 一起使用。

示例入口定义是:

代码语言:javascript
代码运行次数:0
运行
复制
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。示例服务定义是:

代码语言:javascript
代码运行次数:0
运行
复制
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 是:

代码语言:javascript
代码运行次数:0
运行
复制
      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 地址:

代码语言:javascript
代码运行次数:0
运行
复制
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:

代码语言:javascript
代码运行次数:0
运行
复制
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 安装到默认位置,您可以通过运行以下命令启用本机集成:

代码语言:javascript
代码运行次数:0
运行
复制
kubectl patch settings -n gloo-system default \
  -p '{"spec":{"linkerd":true}}' --type=merge

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

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

代码语言:javascript
代码运行次数:0
运行
复制
glooctl add route --path-prefix=/ --dest-name booksapp-webapp-7000
手动的

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

代码语言:javascript
代码运行次数:0
运行
复制
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 是:

代码语言:javascript
代码运行次数:0
运行
复制
      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:

代码语言:javascript
代码运行次数:0
运行
复制
glooctl proxy URL

这将返回类似于:

代码语言:javascript
代码运行次数:0
运行
复制
$ 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 安装:

代码语言:javascript
代码运行次数:0
运行
复制
linkerd inject https://projectcontour.io/quickstart/contour.yaml | kubectl apply -f -

Envoy 不会自动挂载 service account token。要解决此问题,您需要设置 automountServiceAccountToken: true。您可以选择创建一个专用 service account 以避免使用 default

代码语言:javascript
代码运行次数:0
运行
复制
# 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

代码语言:javascript
代码运行次数:0
运行
复制
linkerd inject https://projectcontour.io/examples/kuard.yaml | kubectl apply -f -

要将外部流量路由到您的服务,您需要提供一个 HTTPProxy

代码语言:javascript
代码运行次数:0
运行
复制
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

代码语言:javascript
代码运行次数:0
运行
复制
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
代码语言:javascript
代码运行次数:0
运行
复制
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 部署进行以下更改:

代码语言:javascript
代码运行次数:0
运行
复制
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
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 黑客下午茶 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Linkerd 2.10 系列
  • 默认模式
  • 代理 Ingress Mode
    • Nginx
    • Traefik
      • Traefik 2.x
    • GCE
    • Ambassador
    • Gloo
      • 自动的
      • 手动的
      • Test
    • Contour
    • Kong
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档