本指南将引导您安装和配置 Linkerd
,以便两个集群可以与托管在两个集群上的服务通信。在本指南结束时,您将了解如何在不同集群上的服务之间分配流量。
您将:
- 安装 Linkerd,在具有共享信任锚(
shared trust anchor
)的两个集群上。 - 准备集群。
- 链接集群。
- 安装 demo。
- 暴露 demo services, 以控制可见性。
- 验证集群的安全性。
- 拆分流量,将从源集群 (
west
) 上的 pod 的流量拆分到目标集群 (east
)。
前提条件
- 两个集群。我们将在本指南中将它们称为
east
和west
。在您浏览本指南时,请跟随 博客文章!为开发执行此操作的最简单方法是在您的笔记本电脑上本地运行一个 kind 或 k3d 集群, 并在云提供商(例如 AKS) 上远程运行一个集群。 - 这些集群中的每一个都应配置为
kubectl
contexts。我们建议您使用east
和west
的名称, 以便您可以按照本指南进行操作。使用kubectl
rename contexts 很容易,所以不要觉得你需要永远保持这种命名方式。 - 两个集群上的提升权限。我们将创建服务帐户并授予扩展权限, 因此您需要能够在测试集群上执行此操作。
- 应安装 Linkerd 的
viz
扩展,以便运行stat
命令、 查看 Grafana 或 Linkerd 仪表板并 运行linkerd multicluster gateways
命令。 - 支持
east
集群中的LoadBalancer
类型的服务。查看集群提供商的文档或查看 inlets。这是west
集群将用于通过网关与east
通信的内容。
安装 Linkerd
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), 我们现在就可以在您的 west
和 east
集群上安装 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
准备集群
为了在集群之间路由流量,Linkerd 利用了 Kubernetes services, 因此您的应用程序代码无需更改,也无需学习任何新内容。这需要一个网关组件,将传入请求路由到正确的内部服务。网关将通过 LoadBalancer
类型的 Service
暴露给公共互联网。仅允许通过 Linkerd 的 mTLS(具有共享信任锚)验证的请求通过此网关。
要在 west
和 east
上安装多集群组件,您可以运行:
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
网关安装在 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
)并准备启动镜像服务。我们现在想要将集群链接在一起!
链接集群
为了让 west
从 east
镜像服务,west
集群需要有凭据, 以便它可以监视要暴露的 east
服务。毕竟,您不希望任何人能够内省集群上运行的内容!凭据包括用于验证服务镜像的服务帐户以及 允许监视服务的 ClusterRole
和 ClusterRoleBinding
。总的来说,服务镜像组件使用这些凭证来观察 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
标志。
安装测试服务
是时候测试这一切了!第一步是添加一些我们可以镜像的服务。要将这些添加到两个集群,您可以运行:
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
通过 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/ 来访问它。
安全
默认情况下,请求将通过公共互联网。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
适用于具体资源,并且不能同时看到两个集群, 因此目前无法显示 east
和 west
中 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"
流量拆分
让服务自动出现在集群中并能够明确地处理它们是非常有用的, 但是这仅涵盖操作多个集群的一个用例。多集群的另一个场景是故障转移。在故障转移场景中,您没有时间更新配置。相反,您需要能够不理会应用程序,而只需更改路由即可。如果这听起来很像我们进行 canary 部署的方式,那么您是对的!
TrafficSplit
允许我们定义多个服务之间的权重并在它们之间拆分流量。在故障转移场景中,您希望缓慢执行此操作,以确保不会因为 增加的延迟而使其他集群过载或跳闸任何 SLO。为了让这一切都适用于我们的场景, 让我们在 west
和 east
中的 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
集群中, 因此我们现在已经有效地使从 west
到 east
的 50% 以上的流量失败了。
如果您仍在运行 port-forward
, 则可以将浏览器发送到 http://localhost:8080。刷新页面应该显示两个集群。或者,对于命令行方法,curl localhost:8080
会 给你一条来自 west
和 east
的问候消息。
您还可以通过指标观察发生的情况。要查看事物的源头(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。
清理
要清理多集群控制平面,您可以运行:
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