天天看點

服務網格GRPC協定多種程式設計語言實踐.3.GRPC協定示例的容器實踐

1 容器資源

本篇使用上一篇分發的鏡像,在阿裡雲容器服務(ACK)上部署。

4個版本的client通過調用變量

GRPC_SERVER

定義的服務

grpc-server-svc.grpc-best.svc.cluster.local

,均勻地路由到4個版本的server上。與此同時,我們通過配置

istio-ingressgateway

Gateway

可以将外部請求按負載均衡政策路由到4個版本的grpc server上。

示例完整的拓撲如下圖所示。

服務網格GRPC協定多種程式設計語言實踐.3.GRPC協定示例的容器實踐

grpc-server-svc

本系列的示例隻有一個命名為

grpc-server-svc

的grpc類型的Service。grpc類型的服務,

spec.ports.name

的值需要以

grpc

開頭。

apiVersion: v1
kind: Service
metadata:
  namespace: grpc-best
  name: grpc-server-svc
  labels:
    app: grpc-server-svc
spec:
  ports:
    - port: 9996
      name: grpc-port
  selector:
    app: grpc-server-deploy           

server deployment

完整的deployment詳見kube/deployment目錄,這裡以node server的deployment檔案

grpc-server-node.yaml

為例,對服務端進行說明。

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: grpc-best
  name: grpc-server-node
  labels:
    app: grpc-server-deploy
    version: v3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grpc-server-deploy
      version: v3
  template:
    metadata:
      labels:
        app: grpc-server-deploy
        version: v3
    spec:
      serviceAccountName: grpc-best-sa
      containers:
        - name: grpc-server-deploy
          image: registry.cn-beijing.aliyuncs.com/asm_repo/grpc_server_node:1.0.0
          imagePullPolicy: Always
          ports:
            - containerPort: 9996
              name: grpc-port           

服務端的4個deployment都需要定義

app

标簽的值為

grpc-server-deploy

,以比對

grpc-server-svc

selector

。每種語言的

version

标簽要各部相同。

client deployment

用戶端和服務端有兩處不同。

  • 服務端啟動後會持續運作,而用戶端完成請求後就會結束程序,是以,需要實作一種死循環的方式保持用戶端容器不自己退出。
  • 需要定義變量

    GRPC_SERVER

    的值,在用戶端容器啟動時傳遞給grpc client。

這裡以go client的deployment檔案

grpc-client-go.yaml

為例,對用戶端進行說明。

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: grpc-best
  name: grpc-client-go
  labels:
    app: grpc-client-go
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grpc-client-go
  template:
    metadata:
      labels:
        app: grpc-client-go
    spec:
      serviceAccountName: grpc-best-sa
      containers:
        - name: grpc-client-go
          image: registry.cn-beijing.aliyuncs.com/asm_repo/grpc_client_go:1.0.0
          command: ["/bin/sleep", "3650d"]
          env:
            - name: GRPC_SERVER
              value: "grpc-server-svc.grpc-best.svc.cluster.local"
          imagePullPolicy: Always           

其中,

command: ["/bin/sleep", "3650d"]

是定義

grpc_client_go

啟動後執行的指令,通過長久地

sleep

的方式保持用戶端容器運作。

env

中定義了

GRPC_SERVER

變量,值為

grpc-server-svc.grpc-best.svc.cluster.local

2 部署

首先在ACK執行個體中建立名稱為

grpc-best

的命名空間,然後為該命名空間啟用自動注入sidecar。

alias k="kubectl --kubeconfig $USER_CONFIG"
k create ns grpc-best
k label ns grpc-best istio-injection=enabled           

執行如下指令部署ServiceAccount、Service,及8個Deployment。

k apply -f grpc-sa.yaml
k apply -f grpc-svc.yaml
k apply -f deployment/grpc-server-java.yaml
k apply -f deployment/grpc-server-python.yaml
k apply -f deployment/grpc-server-go.yaml
k apply -f deployment/grpc-server-node.yaml
k apply -f deployment/grpc-client-java.yaml
k apply -f deployment/grpc-client-python.yaml
k apply -f deployment/grpc-client-go.yaml
k apply -f deployment/grpc-client-node.yaml           

3 從POD側驗證

kube驗證包括兩側,一側是從client容器請求grpc server service,另一側是從本地請求

ingressgateway

。這裡示範從client容器請求4個server容器的過程。

首先通過如下指令,擷取4個client容器的名稱。

client_java_pod=$(k get pod -l app=grpc-client-java -n grpc-best -o jsonpath={.items..metadata.name})
client_go_pod=$(k get pod -l app=grpc-client-go -n grpc-best -o jsonpath={.items..metadata.name})
client_node_pod=$(k get pod -l app=grpc-client-node -n grpc-best -o jsonpath={.items..metadata.name})
client_python_pod=$(k get pod -l app=grpc-client-python -n grpc-best -o jsonpath={.items..metadata.name})           

然後通過如下指令,在client容器中執行對grpc server service的請求。

k exec "$client_java_pod" -c grpc-client-java -n grpc-best -- java -jar /grpc-client.jar

k exec "$client_go_pod" -c grpc-client-go -n grpc-best -- ./grpc-client

k exec "$client_node_pod" -c grpc-client-node -n grpc-best -- node proto_client.js
  
k exec "$client_python_pod" -c grpc-client-python -n grpc-best -- sh /grpc-client/start_client.sh           

最後我們以node client為例,通過一個循環,驗證grpc server service的負載均衡。

for ((i = 1; i <= 100; i++)); do
  k exec "$client_node_pod" -c grpc-client-node -n grpc-best -- node kube_client.js > kube_result
done
sort kube_result | grep -v "^[[:space:]]*$" | uniq -c | sort -nrk1           

輸出如下,均勻路由4個版本的服務,符合預期。

26 Talk:PYTHON
  25 Talk:NODEJS
  25 Talk:GOLANG
  24 Talk:JAVA           

4 從本地驗證

接下來,我們再來驗證從本地請求

istio-ingressgateway

。進入服務網格(ASM)執行個體,定義GRPC服務的

Gateway

,将如下内容複制到頁面。

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  namespace: grpc-best
  name: grpc-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 9996
        name: grpc
        protocol: GRPC
      hosts:
        - "*"           

使用如下指令擷取

istio-ingressgateway

的IP。

alias k="kubectl --kubeconfig $USER_CONFIG"
INGRESS_IP=$(k -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')           

使用如下指令驗證grpc server service的負載均衡。

docker run -d --name grpc_client_node -e GRPC_SERVER="${INGRESS_IP}" registry.cn-beijing.aliyuncs.com/asm_repo/grpc_client_node:1.0.0 /bin/sleep 3650d
client_node_container=$(docker ps -q)

docker exec -e GRPC_SERVER="${INGRESS_IP}" -it "$client_node_container" node kube_client.js

for ((i = 1; i <= 100; i++)); do
  docker exec -e GRPC_SERVER="${INGRESS_IP}" -it "$client_node_container" node kube_client.js >> kube_result
done
sort kube_result | grep -v "^[[:space:]]*$" | uniq -c | sort -nrk1