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

  • 2021 年 6 月 21 日
  • 筆記

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
    在您瀏覽本指南時,請跟隨
    博客文章
    為開發執行此操作的最簡單方法是在您的筆記本電腦上本地運行一個
    kind
    k3d 集群,
    並在雲提供商(例如 AKS
    上遠程運行一個集群。
  • 這些集群中的每一個都應配置為 kubectl
    contexts
    我們建議您使用 eastwest的名稱,
    以便您可以按照本指南進行操作。
    使用 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),
我們現在就可以在您的 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

準備集群

為了在集群之間路由流量,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

網關安裝在 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)並準備啟動鏡像服務。
我們現在想要將集群鏈接在一起!

鏈接集群

為了讓 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 標誌。

安裝測試服務

是時候測試這一切了!
第一步是添加一些我們可以鏡像的服務。
要將這些添加到兩個集群,您可以運行:

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

通過 //localhost:8080 提供的 podinfo 登錄頁面,
您現在可以看到它在 west 集群中的外觀。
或者,運行 curl //localhost:8080 將返回一個類似於以下內容的 JSON 響應:

{
  "hostname": "podinfo-5c8cf55777-zbfls",
  "version": "4.0.2",
  "revision": "b4138fdb4dce7b34b6fc46069f70bb295aa8963c",
  "color": "#6c757d",
  "logo": "//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 //podinfo-east:9898"

你會看到 greeting from east 的消息!
來自在 west 運行的 frontend pod 的請求被透明地轉發到 east
假設您仍然在上一步進行端口轉發,
您也可以從瀏覽器訪問 //localhost:8080/east
刷新幾次,您也可以從 linkerd viz stat 中獲取指標。

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

我們還提供了一個 grafana 儀錶板來了解這裡發生的事情。
您可以通過運行 linkerd --context=west viz dashboard
並轉到
//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 適用於具體資源,並且不能同時看到兩個集群,
因此目前無法顯示 eastwest 中 pod 之間的邊緣。
這就是我們在這裡使用 tap 來驗證 mTLS 的原因。

除了確保您的所有請求都被加密之外,阻止任意請求進入您的集群也很重要。
我們通過驗證請求來自網格中的客戶端來做到這一點。
為了進行這種驗證,我們依賴集群之間的共享信任錨。
要查看當客戶端在網格之外時會發生什麼,您可以運行:

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

流量拆分

讓服務自動出現在集群中並能夠明確地處理它們是非常有用的,
但是這僅涵蓋操作多個集群的一個用例。
多集群的另一個場景是故障轉移。
在故障轉移場景中,您沒有時間更新配置。
相反,您需要能夠不理會應用程序,而只需更改路由即可。
如果這聽起來很像我們進行 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
則可以將瀏覽器發送到 //localhost:8080
刷新頁面應該顯示兩個集群。
或者,對於命令行方法,curl localhost:8080
給你一條來自 westeast 的問候消息。

您還可以通過指標觀察發生的情況。要查看事物的源頭(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
我是為少
微信:uuhells123
公眾號:黑客下午茶
加我微信(互相學習交流),關注公眾號(獲取更多學習資料~)