Linkerd 2.10(Step by Step)—多集群通信

546 阅读11分钟

Linkerd 2.10 系列

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

本指南将引导您安装和配置 Linkerd,以便两个集群可以与托管在两个集群上的服务通信。 在本指南结束时,您将了解如何在不同集群上的服务之间分配流量。

您将:

  1. 安装 Linkerd,在具有共享信任锚(shared trust anchor)的两个集群上。
  2. 准备集群。
  3. 链接集群。
  4. 安装 demo。
  5. 暴露 demo services, 以控制可见性。
  6. 验证集群的安全性。
  7. 拆分流量,将从源集群 (west) 上的 pod 的流量拆分到目标集群 (east)。

前提条件

  • 两个集群。我们将在本指南中将它们称为 eastwest。 在您浏览本指南时,请跟随 博客文章! 为开发执行此操作的最简单方法是在您的笔记本电脑上本地运行一个 kindk3d 集群, 并在云提供商(例如 AKS) 上远程运行一个集群。
  • 这些集群中的每一个都应配置为 kubectl contexts。 我们建议您使用 eastwest的名称, 以便您可以按照本指南进行操作。 使用 kubectl rename contexts 很容易,所以不要觉得你需要永远保持这种命名方式。
  • 两个集群上的提升权限。我们将创建服务帐户并授予扩展权限, 因此您需要能够在测试集群上执行此操作。
  • 应安装 Linkerd 的 viz 扩展,以便运行 stat 命令、 查看 Grafana 或 Linkerd 仪表板并 运行 linkerd multicluster gateways 命令。
  • 支持 east 集群中的 LoadBalancer 类型的服务。 查看集群提供商的文档或查看 inlets。 这是 west 集群将用于通过网关与 east 通信的内容。

安装 Linkerd

28-1.png

Linkerd 需要在所有相互通信的集群中的安装之间存在共享 trust anchor。 这用于加密集群之间的流量并授权到达网关的请求,以便您的集群不对公共互联网开放。 我们需要生成凭据并将它们用作 install 命令的配置,而不是让 linkerd 生成所有内容。

我们喜欢使用 step CLI 来生成这些证书。 如果您更喜欢 openssl,请随意使用它! 要使用 step 生成信任锚,您可以运行:

step certificate create root.linkerd.cluster.local root.crt root.key \
  --profile root-ca --no-password --insecure

该证书将构成所有集群之间的共同信任基础。 每个代理都将获得此证书的副本,并使用它来验证从对等方收到的证书, 作为 mTLS 握手的一部分。有了共同的信任基础, 我们现在需要生成一个证书,可以在每个集群中使用该证书向代理颁发证书。

我们生成的信任锚是一个自签名证书,可用于创建新证书(证书颁发机构)。 要使用信任锚生成 issuer credentials,请运行:

step certificate create identity.linkerd.cluster.local issuer.crt issuer.key \
  --profile intermediate-ca --not-after 8760h --no-password --insecure \
  --ca root.crt --ca-key root.key

集群中的 identity 服务将使用您在此处生成的证书(certificate)和 密钥(key)来生成每个单独代理使用的证书。 虽然我们将在本指南的每个集群上使用相同的颁发者凭据, 但最好为每个集群使用不同的颁发者凭据。

有了有效的信任锚(trust anchor)和发行人凭据(issuer credentials), 我们现在就可以在您的 westeast 集群上安装 Linkerd。

linkerd install \
  --identity-trust-anchors-file root.crt \
  --identity-issuer-certificate-file issuer.crt \
  --identity-issuer-key-file issuer.key \
  | tee \
    >(kubectl --context=west apply -f -) \
    >(kubectl --context=east apply -f -)

install 的输出将应用于每个集群并出现! 您可以使用 check 来验证一切是否成功。

for ctx in west east; do
  echo "Checking cluster: ${ctx} .........\n"
  linkerd --context=${ctx} check || break
  echo "-------------\n"
done

准备集群

28-2.png

为了在集群之间路由流量,Linkerd 利用了 Kubernetes services, 因此您的应用程序代码无需更改,也无需学习任何新内容。 这需要一个网关组件,将传入请求路由到正确的内部服务。 网关将通过 LoadBalancer 类型的 Service 暴露给公共互联网。 仅允许通过 Linkerd 的 mTLS(具有共享信任锚)验证的请求通过此网关。

要在 westeast 上安装多集群组件,您可以运行:

for ctx in west east; do
  echo "Installing on cluster: ${ctx} ........."
  linkerd --context=${ctx} multicluster install | \
    kubectl --context=${ctx} apply -f - || break
  echo "-------------\n"
done

28-3.png

网关安装在 linkerd-multicluster 命名空间中, 是一个简单的 NGINX proxy, 它已经注入了 Linkerd 代理。 在入站端,Linkerd 负责验证连接是否 使用了作为信任锚一部分的 TLS 证书。 NGINX 接收请求并将其转发到 Linkerd 代理的出站端。 此时,Linkerd 代理像数据平面中的任何其他代理一样运行, 并将请求转发到正确的服务。通过运行以下命令确保网关成功启动:

for ctx in west east; do
  echo "Checking gateway on cluster: ${ctx} ........."
  kubectl --context=${ctx} -n linkerd-multicluster \
    rollout status deploy/linkerd-gateway || break
  echo "-------------\n"
done

通过运行以下命令仔细检查负载均衡器是否能够分配公共 IP 地址:

for ctx in west east; do
  printf "Checking cluster: ${ctx} ........."
  while [ "$(kubectl --context=${ctx} -n linkerd-multicluster get service \
    -o 'custom-columns=:.status.loadBalancer.ingress[0].ip' \
    --no-headers)" = "<none>" ]; do
      printf '.'
      sleep 1
  done
  printf "\n"
done

每个集群现在都在运行多集群控制平面(multicluster control plane)并准备启动镜像服务。 我们现在想要将集群链接在一起!

链接集群

28-4.png

为了让 westeast 镜像服务,west 集群需要有凭据, 以便它可以监视要暴露的 east 服务。 毕竟,您不希望任何人能够内省集群上运行的内容! 凭据包括用于验证服务镜像的服务帐户以及 允许监视服务的 ClusterRoleClusterRoleBinding。 总的来说,服务镜像组件使用这些凭证来观察 east 或目标集群上的服务, 并从自身(west)添加/删除它们。 作为 linkerd multicluster install 的一部分添加了一个默认设置, 但是如果您想为每个集群拥有单独的凭据, 您可以运行 linkerd multicluster allow

下一步是将 west 链接到 east。 这将创建一个 credentials secret、Link resource 和 service-mirror controller。 凭证密钥包含一个 kubeconfig,可用于访问目标(east)集群的 Kubernetes API。 Link resource 是配置服务镜像的自定义资源, 包含网关地址(gateway address)、网关标识(gateway identity) 和在确定要镜像哪些服务时使用的标签选择器等内容。 服务镜像控制器(service-mirror controller)使用 Link 和 secret 在 目标集群上查找与给定标签选择器匹配的服务, 并将它们复制到源(本地)集群中。

要将 west 集群链接到 east 集群,请运行:

linkerd --context=east multicluster link --cluster-name east |
  kubectl --context=west apply -f -

Linkerd 将查看您当前的 east context, 提取包含服务器位置(server location)以及 CA 包的 cluster 配置。 然后它将获取 ServiceAccount token 并 将这些配置合并到一个 kubeconfig 的 secret 中。

再次运行 check 将确保服务镜像(service mirror)已经 发现了这个 secret 并且可以到达 east

linkerd --context=west multicluster check

此外,east 网关现在应该显示在列表中:

linkerd --context=west multicluster gateways

link 假设两个集群将使用与您在本地使用的配置相同的配置相互连接。 如果不是这种情况,您将需要为 link 使用 --api-server-address 标志。

安装测试服务

28-5.png

是时候测试这一切了! 第一步是添加一些我们可以镜像的服务。 要将这些添加到两个集群,您可以运行:

for ctx in west east; do
  echo "Adding test services on cluster: ${ctx} ........."
  kubectl --context=${ctx} apply \
    -k "github.com/linkerd/website/multicluster/${ctx}/"
  kubectl --context=${ctx} -n test \
    rollout status deploy/podinfo || break
  echo "-------------\n"
done

您现在将拥有一个 test 命名空间,在每个集群中运行两个部署 - frontend 和 podinfo。 podinfo 在每个集群中的配置略有不同,具有不同的名称和颜色,以便我们可以知道请求的去向。

要立即从 west 集群中查看它的样子,您可以运行:

kubectl --context=west -n test port-forward svc/frontend 8080

28-6.gif

通过 http://localhost:8080 提供的 podinfo 登录页面, 您现在可以看到它在 west 集群中的外观。 或者,运行 curl http://localhost:8080 将返回一个类似于以下内容的 JSON 响应:

{
  "hostname": "podinfo-5c8cf55777-zbfls",
  "version": "4.0.2",
  "revision": "b4138fdb4dce7b34b6fc46069f70bb295aa8963c",
  "color": "#6c757d",
  "logo": "https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif",
  "message": "greetings from west",
  "goos": "linux",
  "goarch": "amd64",
  "runtime": "go1.14.3",
  "num_goroutine": "8",
  "num_cpu": "4"
}

请注意,message 引用了 west 集群名称。

暴露 services

为确保敏感服务(sensitive services)不被镜像并且 集群性能受到服务的创建或删除的影响,我们要求显式暴露服务。 出于本指南的目的,我们将把 podinfo 服务从 east 集群导出到 west 集群。 为此,我们必须首先导出 east 集群中的 podinfo 服务。 你可以通过添加 mirror.linkerd.io/exported 标签来做到这一点:

kubectl --context=east label svc -n test podinfo mirror.linkerd.io/exported=true

您可以通过在 linkerd multicluster link 命令上使用 --selector 标志或 通过编辑由 linkerd multicluster link 命令创建 的 Link resource 来配置不同的标签选择器。

查看服务镜像控制器(service mirror controller)刚刚创建的服务!

kubectl --context=west -n test get svc podinfo-east

architecture 中,您会记得服务镜像(service mirror)组件所做的不仅仅是移动服务。 它还管理镜像服务上的端点。 要验证设置是否正确,您可以检查 west 的端点并验证它们 是否与 east 网关的公共 IP 地址匹配。

kubectl --context=west -n test get endpoints podinfo-east \
  -o 'custom-columns=ENDPOINT_IP:.subsets[*].addresses[*].ip'
kubectl --context=east -n linkerd-multicluster get svc linkerd-gateway \
  -o "custom-columns=GATEWAY_IP:.status.loadBalancer.ingress[*].ip"

此时,我们可以从 west 集群中访问 east 中的 podinfo 服务。 这需要对客户端进行网格化,因此让我们从前端 pod 中运行 curl

kubectl --context=west -n test exec -c nginx -it \
  $(kubectl --context=west -n test get po -l app=frontend \
    --no-headers -o custom-columns=:.metadata.name) \
  -- /bin/sh -c "apk add curl && curl http://podinfo-east:9898"

你会看到 greeting from east 的消息! 来自在 west 运行的 frontend pod 的请求被透明地转发到 east。 假设您仍然在上一步进行端口转发, 您也可以从浏览器访问 http://localhost:8080/east。 刷新几次,您也可以从 linkerd viz stat 中获取指标。

linkerd --context=west -n test viz stat --from deploy/frontend svc

我们还提供了一个 grafana 仪表板来了解这里发生的事情。 您可以通过运行 linkerd --context=west viz dashboard 并转到 http://localhost:50750/grafana/ 来访问它。

28-7.png

安全

默认情况下,请求将通过公共互联网。 Linkerd 跨集群扩展其自动 mTLS, 以确保通过公共互联网进行的通信是加密的。 但是,要快速检查,您可以运行:

linkerd --context=west -n test viz tap deploy/frontend | \
  grep "$(kubectl --context=east -n linkerd-multicluster get svc linkerd-gateway \
    -o "custom-columns=GATEWAY_IP:.status.loadBalancer.ingress[*].ip")"

tls=true 告诉你请求正在被加密!

由于 linkerd edge 适用于具体资源,并且不能同时看到两个集群, 因此目前无法显示 eastwest 中 pod 之间的边缘。 这就是我们在这里使用 tap 来验证 mTLS 的原因。

除了确保您的所有请求都被加密之外,阻止任意请求进入您的集群也很重要。 我们通过验证请求来自网格中的客户端来做到这一点。 为了进行这种验证,我们依赖集群之间的共享信任锚。 要查看当客户端在网格之外时会发生什么,您可以运行:

kubectl --context=west -n test run -it --rm --image=alpine:3 test -- \
  /bin/sh -c "apk add curl && curl -vv http://podinfo-east:9898"

流量拆分

28-8.png

让服务自动出现在集群中并能够明确地处理它们是非常有用的, 但是这仅涵盖操作多个集群的一个用例。 多集群的另一个场景是故障转移。 在故障转移场景中,您没有时间更新配置。 相反,您需要能够不理会应用程序,而只需更改路由即可。 如果这听起来很像我们进行 canary 部署的方式,那么您是对的!

TrafficSplit 允许我们定义多个服务之间的权重并在它们之间拆分流量。 在故障转移场景中,您希望缓慢执行此操作,以确保不会因为 增加的延迟而使其他集群过载或跳闸任何 SLO。 为了让这一切都适用于我们的场景, 让我们在 westeast 中的 podinfo 服务之间进行拆分。 要配置它,您将运行:

cat <<EOF | kubectl --context=west apply -f -
apiVersion: split.smi-spec.io/v1alpha1
kind: TrafficSplit
metadata:
  name: podinfo
  namespace: test
spec:
  service: podinfo
  backends:
  - service: podinfo
    weight: 50
  - service: podinfo-east
    weight: 50
EOF

podinfo 的任何请求现在将有 50% 的时间转发到 podinfo-east 集群, 另外 50% 的时间会转发到本地 podinfo 服务。 发送到 podinfo-east 的请求最终会出现在 east 集群中, 因此我们现在已经有效地使从 westeast 的 50% 以上的流量失败了。

如果您仍在运行 port-forward, 则可以将浏览器发送到 http://localhost:8080。 刷新页面应该显示两个集群。 或者,对于命令行方法,curl localhost:8080 会 给你一条来自 westeast 的问候消息。

28-9.gif

您还可以通过指标观察发生的情况。要查看事物的源头(west),您可以运行:

linkerd --context=west -n test viz stat trafficsplit

也可以通过运行从目标(east)侧观察:

linkerd --context=east -n test viz stat \
  --from deploy/linkerd-gateway \
  --from-namespace linkerd-multicluster \
  deploy/podinfo

甚至还有一个仪表板! 运行 linkerd viz dashboard 并将浏览器发送到 localhost:50750

28-10.png

清理

要清理多集群控制平面,您可以运行:

for ctx in west east; do
  linkerd --context=${ctx} multicluster uninstall | kubectl --context=${ctx} delete -f -
done

如果您还想删除 Linkerd 安装,请运行:

for ctx in west east; do
  linkerd --context=${ctx} uninstall | kubectl --context=${ctx} delete -f -
done
我是为少
微信:uuhells123
公众号:黑客下午茶
加我微信(互相学习交流),关注公众号(获取更多学习资料~)