k8s多集羣搭建istio共享控制平面(多網絡)及部署grpc服務分流實踐

個人博客原文:http://www.lampnick.com/php/913

本文目標

  • 部署一個多集羣的共享的istio服務網格
  • 部署一套基於grpc的服務
  • 對grpc服務進行流量管理

架構圖如下

istio灰度流程圖

前提條件

  • 兩個或多個kubernetes集羣,版本爲1.14,1.15,1.16,1.17
  • 有k8s管理員權限
  • 兩個k8s集羣(分別稱爲主集羣prod和私有集羣private),以下簡稱prod,private
  • 注意:主集羣prod必須要能訪問私有集羣private的Kubernetes API Server

開始配置集羣

安裝集羣1(主集羣prod)
  • 部署Istio
1. 下載istio發行版(https://storage.googleapis.com/istio-release/releases/1.4.3/istio-1.4.3-linux.tar.gz)
2.解壓
3.切換到istio-1.4.3目錄
4.部署
[root@master /root]# kubectl create ns istio-system
[root@master /root]# kubectl create  secret generic cacerts -n istio-system --from-file=samples/certs/ca-cert.pem --from-file=samples/certs/ca-key.pem --from-file=samples/certs/root-cert.pem --from-file=samples/certs/cert-chain.pem
[root@master /root]# istioctl manifest apply -f install/kubernetes/operator/examples/multicluster/values-istio-multicluster-primary.yaml
等待k8s中的Istio pods就緒:
[root@master /root]# kubectl get pods -nistio-system
NAME                                      READY   STATUS    RESTARTS   AGE
istio-citadel-856b4c8cbb-ch777            1/1     Running   0          4d3h
istio-galley-fd9694b9c-8nk58              2/2     Running   0          4d3h
istio-ingressgateway-66f89856c8-b4lhn     1/1     Running   0          4d3h
istio-pilot-5c68bb85df-rfssq              2/2     Running   0          4d3h
istio-policy-587798bdcc-dtrvh             2/2     Running   0          4d3h
istio-sidecar-injector-7dd87d7989-slnml   1/1     Running   0          4d3h
istio-telemetry-75c64d988b-mnnzn          2/2     Running   0          4d3h
prometheus-66c5887c86-jl46f               1/1     Running   0          4d3h
#注意網關地址設置爲 0.0.0.0。這些是臨時的佔位值,在後面集羣部署後,將被更新爲兩個集羣的網關公網IP。

  • 創建一個 ingress 網關訪問 private集羣的服務:
[root@master /root]# kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: cluster-aware-gateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 443
      name: tls
      protocol: TLS
    tls:
      mode: AUTO_PASSTHROUGH
    hosts:
    - "*.local"
EOF

本例 Gateway 配置 443 端口來將流經的入口流量導向請求 SNI 頭中指明的目標服務,其中 SNI 的頂級域名爲 local(譬如:Kubernetes DNS域名)。 從源至目標 sidecar,始終使用雙向 TLS 連接。

儘管應用於主集羣,該網關實例也會影響 private集羣,因爲兩個集羣通過同一個 Pilot 通信。

  • 確定主集羣的ingress IP和端口。
    • 按照確定ingress IP和端口中的說明,設置環境變量 INGRESS_HOST 及 SECURE_INGRESS_PORT。
    export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
    export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
    export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
    export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
    
    • 打印 INGRESS_HOST 及 SECURE_INGRESS_PORT:
    [root@master /root]# echo The ingress gateway of cluster1: address=$INGRESS_HOST, port=$SECURE_INGRESS_PORT
    The ingress gateway of cluster1: address=10.10.8.39, port=31216
    
    • 更新網格網絡配置中的網關地址。編輯 istio ConfigMap:
    [root@master /root]# kubectl edit cm -n istio-system istio
    第一個地方:
    120行 meshNetworks: |-
    121     # Network config
    122     networks:
    123       network1:
    124         endpoints:
    125         - fromRegistry: Kubernetes
    126         gateways:
    127         - address: 10.10.8.39
    128           port: 31216
    第二個地方:
    154行   meshNetworks:
    155       networks:
    156         network1:
    157           endpoints:
    158           - fromRegistry: Kubernetes
    159           gateways:
    160           - address: 10.10.8.39
    161             port: 31216
    
    將網關地址和 network1 的端口分別更新爲 cluster1 的 ingress 主機和端口,然後保存並退出。注意該地址在配置文件中出現兩次,第二次位於 values.yaml: 下方。 一旦保存,Pilot 將自動讀取更新後的網絡配置。
    • 輸出主集羣的網關地址(部署私有集羣private時會用):
    [root@master /root]# kubectl get svc --selector=app=istio-ingressgateway  -n istio-system -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}'
    10.10.8.39
    
    該命令將網關地址設置爲網關的公共 IP 並顯示。若負載均衡配置沒有設置 IP 地址,命令將執行失敗。DNS 域名支持尚未實現,亟待解決。如果沒有LoadBalancer,可參考這個文章 http://www.lampnick.com/php/910
安裝集羣2(私有集羣private)
  • 部署 Istio:
將主集羣下載的istio-1.4.3文件複製到這臺機器並解壓,進入istio-1.4.3目錄執行如下命令
[root@master ~]# export MASTER_GW_ADDR=10.10.8.39#主集羣獲取到的
[root@master ~]# kubectl create ns istio-system
[root@master ~]# kubectl create  secret generic cacerts -n istio-system --from-file=samples/certs/ca-cert.pem --from-file=samples/certs/ca-key.pem --from-file=samples/certs/root-cert.pem --from-file=samples/certs/cert-chain.pem
[root@master ~]# CLUSTER_NAME=$(kubectl config view --minify=true -o jsonpath='{.clusters[].name}')
[root@master ~]# istioctl manifest apply \
  --set profile=remote \
  --set values.global.mtls.enabled=true \
  --set values.gateways.enabled=true \
  --set values.security.selfSigned=false \
  --set values.global.createRemoteSvcEndpoints=true \
  --set values.global.remotePilotCreateSvcEndpoint=true \
  --set values.global.remotePilotAddress=${MASTER_GW_ADDR} \
  --set values.global.remotePolicyAddress=${MASTER_GW_ADDR} \
  --set values.global.remoteTelemetryAddress=${MASTER_GW_ADDR} \
  --set values.gateways.istio-ingressgateway.env.ISTIO_META_NETWORK="network2" \
  --set values.global.network="network2" \
  --set values.global.multiCluster.clusterName=${CLUSTER_NAME} \
  --set autoInjection.enabled=true

等待 cluster2 中的 Istio pods 就緒,istio-ingressgateway 除外。

[root@master ~]# kubectl get pods -n istio-system -l istio!=ingressgateway
NAME                                      READY   STATUS    RESTARTS   AGE
istio-citadel-64d4866c95-tnjtf            1/1     Running   0          4d
istio-sidecar-injector-75ff97b4d8-5tf4j   1/1     Running   0          4d

istio-ingressgateway目前無法就緒,直到在主集羣prod的Istio控制面板中配置好 watch private cluster。

  • 確定集羣的ingress IP和端口。
    • 按照確定ingress IP和端口中的說明,設置環境變量 INGRESS_HOST 及 SECURE_INGRESS_PORT。
      export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
      export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
      export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
      export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
      
      • 打印 INGRESS_HOST 及 SECURE_INGRESS_PORT:
      [root@master ~]# echo The ingress gateway of cluster1: address=$INGRESS_HOST, port=$SECURE_INGRESS_PORT
      The ingress gateway of cluster1: address=10.5.24.224, port=32483
      
  • 在主集羣中更新網格網絡配置中的網關地址。編輯 istio ConfigMap:
特別注意:這一步是在主集羣prod中執行
[root@master /root]# kubectl edit cm -n istio-system istio
第一個地方:
129行     network2:
130         endpoints:
131         - fromRegistry: n2-k8s-config
132         gateways:
133         - address: 10.5.24.224
134           port: 32483
第二個地方:
162行      network2:
163           endpoints:
164           - fromRegistry: n2-k8s-config
165           gateways:
166           - address: 10.5.24.224
167             port: 32483

將 network2 的網關地址和端口分別更新爲 private集羣 的 ingress 主機和端口,然後保存並退出。注意該地址在配置文件中出現兩次,第二次位於 values.yaml: 下方。一旦保存,Pilot 將自動讀取更新後的網絡配置。

  • 準備環境變量,構建服務賬戶 istio-reader-service-account 的配置文件 n2-k8s-config:
CLUSTER_NAME=$(kubectl config view --minify=true -o jsonpath='{.clusters[].name}')
SERVER=$(kubectl config view --minify=true -o jsonpath='{.clusters[].cluster.server}')
SECRET_NAME=$(kubectl get sa istio-reader-service-account -n istio-system -o jsonpath='{.secrets[].name}')
CA_DATA=$(kubectl get secret ${SECRET_NAME} -n istio-system -o jsonpath="{.data['ca\.crt']}")
TOKEN=$(kubectl get secret ${SECRET_NAME} -n istio-system -o jsonpath="{.data['token']}" | base64 --decode)
  • 在工作目錄中創建文件n2-k8s-config
cat <<EOF > n2-k8s-config
apiVersion: v1
kind: Config
clusters:
  - cluster:
      certificate-authority-data: ${CA_DATA}
      server: ${SERVER}
    name: ${CLUSTER_NAME}
contexts:
  - context:
      cluster: ${CLUSTER_NAME}
      user: ${CLUSTER_NAME}
    name: ${CLUSTER_NAME}
current-context: ${CLUSTER_NAME}
users:
  - name: ${CLUSTER_NAME}
    user:
      token: ${TOKEN}
EOF
  • 將上面創建的n2-k8s-config複製到主集羣prod
在主集羣prod上監聽私有集羣private
  • 執行下面命令,添加並標記私有集羣private的secret。 執行完這些命令,主集羣prod中的Istio Pilot將開始 watching私有集羣private 的服務和實例,如同對待主集羣prod一樣。
[root@master /root]# kubectl create secret generic n2-k8s-secret --from-file n2-k8s-config -n istio-system
[root@master /root]# kubectl label secret n2-k8s-secret istio/multiCluster=true -n istio-system
  • 等待私有集羣private中的istio-ingressgateway就緒:
[root@master ~]# kubectl get pods -n istio-system -l istio=ingressgateway
NAME                                    READY   STATUS    RESTARTS   AGE
istio-ingressgateway-5fb99d5694-dpqc5   1/1     Running   0          4d

現在,主集羣prod和私有集羣private均已安裝完成,可以部署gRPC服務。

  • 參考文檔
    • https://istio.io/docs/setup/install/multicluster/shared-gateways/

部署grpc服務及實現根據header進行分流

主集羣prod上執行應用如下yaml
  • kubectl apply -f .
-rw-r--r-- 1 root root  940 Feb 26 20:05 mycaller-deploy.yaml
-rw-r--r-- 1 root root  275 Feb 27 18:09 mycaller-destinationrule.yaml
-rw-r--r-- 1 root root  228 Feb 28 10:28 mycaller-service.yaml
-rw-r--r-- 1 root root  215 Feb 27 18:09 mycaller-virtualservice.yaml
-rw-r--r-- 1 root root 1.1K Feb 28 15:53 myresponser-deploy-v1.yaml
-rw-r--r-- 1 root root  284 Feb 28 12:12 myresponser-destinationrule-v1-v2.yaml
-rw-r--r-- 1 root root  237 Feb 28 16:09 myresponser-service.yaml
-rw-r--r-- 1 root root  262 Feb 28 12:44 myresponser-virtualservice-type-all-v2.yaml
-rw-r--r-- 1 root root  406 Mar  2 10:57 myresponser-virtualservice-type-v1-v2.yaml
-rw-r--r-- 1 root root 1.6K Feb 28 09:27 sleep.yaml
私有集羣private上執行應用如下yaml
  • kubectl apply -f .
-rw-r--r-- 1 root root 1048 Feb 28 16:04 myresponser-deploy-v2.yaml
-rw-r--r-- 1 root root  237 Feb 28 16:10 myresponser-service.yaml
效果如下


[root@master /root]# kubectl exec -it -c sleep $(kubectl get pod  -l app=sleep -o jsonpath='{.items[0].metadata.name}') -- curl "mycaller.default:59130/testCaller/GetHello?type=1&orgcode=private&port=53605"
{"res":"[2020-03-03 09:09:59] responser version:private, hostname:myresponser-v2-67d7f6d7f4-6fctl, req:1, orgcode:private"}

[root@master /root]# kubectl exec -it -c sleep $(kubectl get pod  -l app=sleep -o jsonpath='{.items[0].metadata.name}') -- curl "mycaller.default:59130/testCaller/GetHello?type=1&orgcode=private&port=53605"
{"res":"[2020-03-03 09:10:04] responser version:private, hostname:myresponser-v2-67d7f6d7f4-6fctl, req:1, orgcode:private"}

[root@master /root]# kubectl exec -it -c sleep $(kubectl get pod  -l app=sleep -o jsonpath='{.items[0].metadata.name}') -- curl "mycaller.default:59130/testCaller/GetHello?type=1&orgcode=private&port=53605"
{"res":"[2020-03-03 09:10:07] responser version:private, hostname:myresponser-v2-67d7f6d7f4-6fctl, req:1, orgcode:private"}

[root@master /root]# kubectl exec -it -c sleep $(kubectl get pod  -l app=sleep -o jsonpath='{.items[0].metadata.name}') -- curl "mycaller.default:59130/testCaller/GetHello?type=1&orgcode=&port=53605"
{"res":"[2020-03-03 09:10:16] responser version:prod, hostname:myresponser-v1-6b9f79c64d-fwl79, req:1, orgcode:prod"}

[root@master /root]# kubectl exec -it -c sleep $(kubectl get pod  -l app=sleep -o jsonpath='{.items[0].metadata.name}') -- curl "mycaller.default:59130/testCaller/GetHello?type=1&orgcode=ttt&port=53605"
{"res":"[2020-03-03 09:10:23] responser version:prod, hostname:myresponser-v1-6b9f79c64d-fwl79, req:1, orgcode:ttt"}

[root@master /root]# kubectl exec -it -c sleep $(kubectl get pod  -l app=sleep -o jsonpath='{.items[0].metadata.name}') -- curl "mycaller.default:59130/testCaller/GetHello?type=1&orgcode=prod&port=53605"
{"res":"[2020-03-03 09:10:30] responser version:prod, hostname:myresponser-v1-6b9f79c64d-fwl79, req:1, orgcode:prod"}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章