21. 入口流量

出于简单性和可组合性的原因,Linkerd 不提供内置 ingress。 相反,Linkerd 旨在与现有的 Kubernetes ingress 解决方案配合使用。

结合 Linkerd 和您的 ingress 解决方案需要两件事:

  1. 配置您的 ingress 以支持 Linkerd
  2. 将您的 ingress pod 网格化,以便它们安装 Linkerd proxy

将您的 ingress pod 网格化将允许 Linkerd 在流量进入集群内部时提供 L7 指标和 mTLS 等功能。 (有关如何对 ingress 进行网格化的说明,请参阅添加您的服务。)

请注意,某些 ingress 选项需要在 “ingress” 模式下进行网格划分。请参阅下面的详细信息。

Linkerd 使用的常见 ingress 选项包括:

有关使用特定 ingress 的快速入门指南,请访问该 ingress 的部分。 如果您的 ingress 不在该列表中,请不要害怕 - 它可能无论如何都有效。 请参阅下面的 Ingress 详细信息

Ambassador (aka Emissary)

Ambassador 可以正常 mesh。配置 Ambassador / Emissary 的示例清单如下:

apiVersion: v1
kind: Service
metadata:
  name: web-ambassador
  namespace: emojivoto
  annotations:
    getambassador.io/config: |
      ---
      apiVersion: getambassador.io/v2
      kind: Mapping
      name: web-ambassador-mapping
      service: http://web-svc.emojivoto.svc.cluster.local:80
      host: example.com
      prefix: /      
spec:
  selector:
    app: web-svc
  ports:
  - name: http
    port: 80
    targetPort: http

如需更详细的指南,我们建议阅读 使用 Linkerd service mesh 安装 Emissary ingress

Nginx

Nginx 可以正常 mesh, 但是 nginx.ingress.kubernetes.io/service-upstream annotation 要设置为 true。 无需进一步配置。

# apiVersion: networking.k8s.io/v1beta1 # for k8s < v1.19
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: emojivoto-web-ingress
  namespace: emojivoto
  annotations:
    nginx.ingress.kubernetes.io/service-upstream: true
spec:
  ingressClassName: nginx
  defaultBackend:
    service:
      name: web-svc
      port:
        number: 80

Traefik

Traefik 应该在启用 ingress mode 的情况下进行网格化, 即使用 linkerd.io/inject: ingress annotation 而不是默认 enabled

1.x2.x 版本的 Traefik 说明有所不同。

Traefik 1.x

使用 Traefik 1.x 作为 Linkerd 入口的最简单方法是使用 ingress.kubernetes.io/custom-request-headers 像这样:

# apiVersion: networking.k8s.io/v1beta1 # for k8s < v1.19
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
  namespace: emojivoto
  annotations:
    ingress.kubernetes.io/custom-request-headers: l5d-dst-override:web-svc.emojivoto.svc.cluster.local:80
spec:
  ingressClassName: traefik
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: 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 服务 FQDN (web-svc.emojivoto.svc.cluster.local) 目标 servicePort

要对此进行测试,您需要获取控制器的外部 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 2.x

Traefik 2.x 通过名为 IngressRoute 的 自定义资源定义 (CRD) 添加了对基于路径的请求路由的支持。

如果您选择使用 IngressRoute 而不是默认的 Kubernetes Ingress 资源, 那么您还需要使用 Traefik中间件 自定义资源定义来添加 l5d-dst-override header

下面的 YAML 使用 Traefik CRDemojivoto 应用程序产生相同的结果,如上所述。

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

GCE ingress 应该在启用 ingress mode 的情况下进行网格化, 即使用 linkerd.io/inject: ingress annotation 而不是默认 enabled

此示例展示了如何将 Google Cloud 静态外部 IP 地址TLSGoogle 管理的证书 结合使用。

# apiVersion: networking.k8s.io/v1beta1 # for k8s < v1.19
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
  namespace: emojivoto
  annotations:
    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:
  ingressClassName: gce
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: 80

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

托管证书的提供大约需要 30-60 分钟,但 ingress 的状态应在几分钟内正常。 一旦提供了托管证书,ingress 应该对 Internet 可见。

Gloo

Gloo 应该在启用 ingress mode 的情况下进行网格化, 即使用 linkerd.io/inject: ingress annotation 而不是默认 enabled

Gloo v0.13.20 开始,GlooLinkerd 进行了原生集成, 因此会自动添加所需的 Linkerd header。 假设您将 Gloo 安装到默认位置,您可以通过运行以下命令启用原生集成:

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

Gloo 现在会自动将 l5d-dst-override header 添加到每个 Kubernetes upstream

现在只需添加一条到 upstream 的路由,例如:

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

Contour

Contour 应该在启用 ingress mode 情况下进行网格划分, 即使用 linkerd.io/inject: ingress annotation 而不是默认 enabled

以下示例使用 Contour 入门文档 来演示如何手动设置所需的 header

ContourEnvoy DaemonSet 不会自动挂载 service account token, 这是 Linkerd proxyPod 之间执行 mTLS 所必需的。 所以首先我们需要安装未注入的 Contour, 使用 automountServiceAccountToken: true 修补 DaemonSet,然后注入它。 您可以选择创建一个专用服务帐户以避免使用默认服务帐户。

# install Contour
kubectl apply -f https://projectcontour.io/quickstart/contour.yaml

# 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}]'

# inject linkerd first into the DaemonSet
kubectl -n projectcontour get daemonset -oyaml | linkerd inject - | kubectl apply -f -

# inject linkerd into the Deployment
kubectl -n projectcontour get deployment -oyaml | linkerd inject - | kubectl apply -f -

验证您的 ContourEnvoy 安装有一个正在运行的 Linkerd sidecar

接下来我们将部署一个 demo 服务:

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
      port: 80
  virtualhost:
    fqdn: 127.0.0.1.nip.io

请注意 l5d-dst-override header 明确设置为目标 service

最后,您可以测试您的工作服务网格:

kubectl port-forward svc/envoy -n projectcontour 3200:80
http://127.0.0.1.nip.io:3200

Kong

Kong 应该在启用 ingress mode 的情况下进行网格化, 即使用 linkerd.io/inject: ingress annotation 而不是默认 enabled

此示例将使用以下元素:

在安装 emojivoto 之前,请在您的集群上安装 LinkerdKong。 注入 Kong 部署时,使用 --ingress flag(或 annotation)。

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

  • KongPluginKong 提供的 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: networking.k8s.io/v1beta1 # for k8s < v1.19
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: web-ingress
    namespace: emojivoto
    annotations:
    konghq.com/plugins: set-l5d-header
    spec:
    ingressClassName: kong
    rules:
    - http:
      paths:
      - path: /api/vote
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: http
      - path: /api/list
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              name: http

这里我们在 KongPlugin 中明确设置了 l5d-dst-override。 使用模板作为值, 我们可以使用来自请求的 host header 并基于此设置 l5d-dst-override 值。

最后,安装 emojivoto,使其 deploy/vote-botingress 为目标, 并包含 web-svc.emojivoto 服务的 host header 值。

在应用注入的 emojivoto 应用程序之前,对 vote-bot Deployment 进行以下更改:

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

Haproxy

Haproxy 应该在启用 ingress mode 的情况下进行网格化,即使用 linkerd.io/inject: ingress annotation 而不是默认的 enabled

使用 Haproxy 作为 Linkerd ingress 的最简单方法是 使用 haproxy.org/request-set-header annotation 配置 Kubernetes Ingress 资源,如下所示:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
  namespace: emojivoto
  annotations:
    kubernetes.io/ingress.class: haproxy
    haproxy.org/request-set-header: |
            l5d-dst-override web-svc.emojivoto.svc.cluster.local:80
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: 80

不幸的是,目前不支持通过使用服务名称命名空间端口作为变量在全局配置映射中动态执行此操作。 这也意味着,您不能在入口清单中组合多个服务入口规则, 因为每个服务入口规则都需要自己的 haproxy.org/request-set-header annotation 和硬编码值。

Ingress 详细信息

在本节中,我们将介绍 Linkerd 如何与 ingress controller 交互。

通常,Linkerd 可以与任何 ingress controller 一起使用。 为了让 Linkerd 正确应用基于路由的指标流量拆分等功能, Linkerd 需要 Kubernetes ServiceIP/port。 但是,默认情况下,许多 ingress 会进行自己的端点选择并传递目标 PodIP/port,而不是整个 Service

因此,将 ingressLinkerd 结合采用以下两种形式之一:

  1. 配置 ingress 以传递 ServiceIPport 作为目的地,即跳过其自己的端点选择。 (例如,参见上面的 Nginx。)

  2. 如果这不可能,则配置 ingress 以在 header (例如 l5d-dst-overrideHost:authority)中传递 Service IP/port, 并在 ingress 模式下配置 Linkerd。在这种模式下,它将改为从这些 header 之一读取。

形式 #2 中最常见的方法是使用显式 l5d-dst-override header