非容器应用与K8s工作负载的服务网格化实践-4 基于ASM的POD和VM互访实践-GRPC协议篇

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 为了实现高可用,非容器应用通常有一套服务注册和发现的机制。相对而言,kubernetes容器服务为POD提供了统一的基于dns的注册和发现机制。对于http协议的非容器应用的迁移,因为都是基于dns机制,切换成本交底。而对于使用非http协议的非容器应用,服务注册和发现这个技术点为迁移带来了额外的困难。如何从非容器的注册和发现大脑最终迁移到kubernetes的注册和发现大脑,目前尚没有广泛认可的方案。目前常见的讨论是双脑方案,就是让非容器应用在启动时同时向两套大脑注册,并从两套中发现依赖服务,然后逐步实现向kubernetes大脑过度。这套方案的优点是可以通过随时摆动来保证可用性。

为了实现高可用,非容器应用通常有一套服务注册和发现的机制。相对而言,kubernetes容器服务为POD提供了统一的基于dns的注册和发现机制。对于http协议的非容器应用的迁移,因为都是基于dns机制,切换成本交底。而对于使用非http协议的非容器应用,服务注册和发现这个技术点为迁移带来了额外的困难。

如何从非容器的注册和发现大脑最终迁移到kubernetes的注册和发现大脑,目前尚没有广泛认可的方案。目前常见的讨论是双脑方案,就是让非容器应用在启动时同时向两套大脑注册,并从两套中发现依赖服务,然后逐步实现向kubernetes大脑过度。这套方案的优点是可以通过随时摆动来保证可用性。

我个人比较倾向于彻底的kubernetes一脑模式。相比多脑,一脑的复杂度会极大下降。遗留大脑集群保持现状,kubernetes大脑集群使用新的方案。这样可以将服务发现和网格化解耦为两个独立的问题。借助服务网格的蓝绿部署/流量转移,可以将验证完毕依赖关系的集群逐步放行并最终替换遗留大脑集群。这个方案最有挑战的地方是如何在不改变非容器应用代码的前提下,将其底层协议替换。如果可以替换为grpc,那么就可以按照本篇的实践实现网格化。目前这个想法还很不成熟,期待交流。

1 POD和VM互访

路由规则

服务网格的流量转移是一脑方案的核心。首先需要明确的是,网格化的服务链路都会经过sidecar,sidecar内部(envoy)实现了对grpc的负载均衡,grpc协议的上游服务通过长链接和下游服务各个节点保持连接,在不配置流量转移的情况下,上游请求会均匀地路由到下游各个节点。

与http协议通过path配置流量转移类似,grpc的配置是通过service/method或者service.method来定义匹配规则的。grpc的路由配置示意如下。

spec:
  hosts:
    - hello2-svc
  http:
    - name: grpc-hello-route
      match:
        - uri:
            prefix: /org.feuyeux.grpc.Greeter/SayHello
      route:
        - destination:
            host: hello2-svc
            subset: v1
          weight: 30
        - destination:
            host: hello2-svc
            subset: v2
          weight: 60
        - destination:
            host: hello2-svc
            subset: v3
          weight: 10

搭建实验环境

本篇示例实验与前一篇相仿,不再冗述重复部分。我们希望路由到hello2 en/fr/es的流量比例为:30%:60%:10%。

示例(grpc_reciprocal_demo)包含如下元素:

  • hello1 deployment(镜像grpc_springboot_v1)
  • hello3 deployment(镜像grpc_springboot_v1)
  • hello2 docker containers(镜像grpc_springboot_v1/grpc_springboot_v2/grpc_springboot_v3)
  • 入口网关:istio-ingressgateway
  • 入口流量配置:gateway/virtualservice
  • hello1流量配置:hello1 service
  • hello2流量配置:hello2 service/hello2 virtualservice/hello2 destinationrule
  • hello3流量配置:hello3 service
  • hello2 serviceentry/hello2 workloadentry

与前一篇http所用示例类似,grpc示例使用的镜像为grpc_springboot-{version},是一个基于springboot开发的grpc服务(源代码在这里)。每个实例可以通过环境变量GRPC_HELLO_BACKEND定义下游服务。

启动hello2应用

通过如下命令分别在3个ecs节点上启动hello2的 docker container

#ssh1.sh
docker run \
--rm \
--network host \
--name http_v1 \
-e GRPC_HELLO_BACKEND=hello3-svc.grpc-reciprocal-hello.svc.cluster.local \
registry.cn-beijing.aliyuncs.com/asm_repo/grpc_springboot_v1:1.0.0
#ssh2.sh
docker run \
--rm \
--network host \
--name http_v2 \
-e GRPC_HELLO_BACKEND=hello3-svc.grpc-reciprocal-hello.svc.cluster.local \
registry.cn-beijing.aliyuncs.com/asm_repo/grpc_springboot_v2:1.0.0
#ssh3.sh
docker run \
--rm \
--network host \
--name http_v3 \
-e GRPC_HELLO_BACKEND=hello3-svc.grpc-reciprocal-hello.svc.cluster.local \
registry.cn-beijing.aliyuncs.com/asm_repo/grpc_springboot_v3:1.0.0

其他部分的搭建与前篇类似,可以参考前篇和本篇示例脚本,余文不在冗述。

grpcurl

相对于http的验证工具curl,我们使用grpcurl对grpc服务进行验证。

当grpc服务提供反射protocolbuf能力时,可以使用如下命令进行请求验证:

k exec "$hello1_pod" -c hello-v1-deploy -n grpc-reciprocal-hello \
  -- grpcurl -plaintext -d '{"name":"eric"}' \
  hello3-svc.grpc-reciprocal-hello.svc.cluster.local:7001 org.feuyeux.grpc.Greeter/SayHello | jq -r '.reply'
  
Hello eric(172.18.1.10)

如果上述命令返回错误,说明grpc服务无法反射protocolbuf,需要在执行grpccurl时,通过-import-path-proto参数提供proto文件。示意如下。

k exec "$hello1_pod" -c hello-v1-deploy -n grpc-reciprocal-hello -- \
grpcurl -plaintext -d '{"name":"eric"}' \
-import-path /opt -proto hello.proto \
hello3-svc.grpc-reciprocal-hello.svc.cluster.local:7001 org.feuyeux.grpc.Greeter/SayHello | jq -r '.reply'

Hello eric(172.18.1.10)

KUBE验证-POD和VM互访

初步掌握grpccurl命令后,我们验证基于grpc协议的POD和VM互访。请求从hello1 POD发向hello2 service,然后路由到各VM中的hello2 app,再由hello2 app请求到hello3 POD。

for i in {1..6}; do
  k exec "$hello1_pod" -c hello-v1-deploy -n grpc-reciprocal-hello \
    -- grpcurl -plaintext -d '{"name":"eric"}' localhost:7001 org.feuyeux.grpc.Greeter/SayHello | jq -r '.reply'
done
Hello eric(172.18.1.11)<-Hola eric(192.168.0.172)<-Hello eric(172.18.1.10)
Hello eric(172.18.1.11)<-Bonjour eric(192.168.0.171)<-Hello eric(172.18.1.10)
Hello eric(172.18.1.11)<-Hello eric(192.168.0.170)<-Hello eric(172.18.1.10)
...

MESH验证-全链路流量转移

最后部署gateway/virtualservice/destinationrule进行端到端验证。

IP=$(k -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

for i in {1..100}; do
  resp=$(grpcurl -plaintext -d '{"name":"eric"}' "$IP":7004 org.feuyeux.grpc.Greeter/SayHello | jq -r '.reply')
  echo "$resp" >>test_traffic_shift_result
done

echo "expected 30%(Hello eric)-60%(Bonjour eric)-10%(Hola eric):"
sort test_traffic_shift_result | grep -v "^[[:space:]]*$"| uniq -c | sort -nrk1
  57 Hello eric(172.18.1.11)<-Bonjour eric(192.168.0.171)<-Hello eric(172.18.1.10)
  32 Hello eric(172.18.1.11)<-Hello eric(192.168.0.170)<-Hello eric(172.18.1.10)
  11 Hello eric(172.18.1.11)<-Hola eric(192.168.0.172)<-Hello eric(172.18.1.10)

2 grpc基准测试

ghz

ghz是grpc协议的基准测试工具,功能与http协议下的apache benchfortio类似。我们可以通过ghz对服务网格内的grpc服务进行测试和调参。ghz的基本用法示意如下。

hello1_pod=$(k get pod -l app=hello1-deploy -n grpc-reciprocal-hello -o jsonpath={.items..metadata.name})

k exec "$hello1_pod" -c hello-v1-deploy -n grpc-reciprocal-hello -- \
  ghz --insecure -d '{"name":"eric"}' \
  --proto /opt/hello.proto \
  --call org.feuyeux.grpc.Greeter/SayHello \
  -n 2000 \
  -c 20 \
  -q 500 \
  localhost:7001
  • -n参数用来指定请求数量
  • -c参数用来指定并发数量
  • -q参数用来指定QPS

测试结果示意如下。

Summary:
  Count:        2000
  Total:        5.60 s
  Slowest:      851.86 ms
  Fastest:      4.88 ms
  Average:      54.51 ms
  Requests/sec: 357.21

Response time histogram:
  4.883 [1]     |
  89.580 [1919] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
  174.278 [43]  |∎
  258.976 [3]   |
  343.673 [5]   |
  428.371 [2]   |
  513.068 [4]   |
  597.766 [3]   |
  682.464 [0]   |
  767.161 [7]   |
  851.859 [13]  |

Latency distribution:
  10 % in 24.37 ms 
  25 % in 31.71 ms 
  50 % in 41.98 ms 
  75 % in 53.87 ms 
  90 % in 70.67 ms 
  95 % in 83.83 ms 
  99 % in 683.16 ms 

Status code distribution:
  [OK]   2000 responses   

上述结果表示RT/latency基本(1919/2000)落在90ms以内,平均54.51 ms,95%的请求延迟在83.83 ms以内,99 %段的延迟在683.16 ms,存在长尾,需要进一步优化服务网格的配置以及服务源代码。

trafficPolicy

通过修改hello2的DestinationRule可以随时调整连接池配置。我们可以结合基准测试,不断调整配置找到最佳性能点。示意如下。

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: hello2-dr
  namespace: grpc-reciprocal-hello
spec:
  host: hello2-svc
  subsets:
    - labels:
        version: v1
      name: v1
    - labels:
        version: v2
      name: v2
    - labels:
        version: v3
      name: v3
  trafficPolicy:
    connectionPool:
      http:
        http1MaxPendingRequests: 20
        http2MaxRequests: 100
        maxRequestsPerConnection: 10
        maxRetries: 1
      tcp:
        connectTimeout: 10s
        maxConnections: 10

到此,POD和VM互访的grpc协议流量管理讲述完毕。

本篇示例完整演示了非容器应用网格化过程中的一个比较经典的场景。覆盖到从istio-ingressgateway到deployment、workloadentry等各种CRD的配置,较完整地展示了POD和VM互访中遇到的各技术点的配置。

接下来,我们在此基础上,验证下POD和VM作为同一service的混合流量,如何实现流量转移。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
1天前
|
Kubernetes 容器 Perl
在K8S中,如何查看Pod中某个容器日志?
在K8S中,如何查看Pod中某个容器日志?
|
1天前
|
Kubernetes 负载均衡 网络协议
在K8S中,Pod能否实现对容器健康检查,如果服务有异常,该如何处理?
在K8S中,Pod能否实现对容器健康检查,如果服务有异常,该如何处理?
|
1天前
|
Kubernetes 容器 Perl
在k8S中,如何向Pod中指定容器传递环境变量?有哪些方式?
在k8S中,如何向Pod中指定容器传递环境变量?有哪些方式?
|
1天前
|
Kubernetes 算法 容器
在k8S中,Pod的容器重启策略有哪些?
在k8S中,Pod的容器重启策略有哪些?
|
9天前
|
Docker 容器
Docker cp 将宿主机上的文件复制到容器中
Docker cp 将宿主机上的文件复制到容器中
11 0
|
4天前
|
JSON JavaScript 开发者
Composerize神器:自动化转换Docker运行命令至Compose配置,简化容器部署流程
【8月更文挑战第7天】Composerize神器:自动化转换Docker运行命令至Compose配置,简化容器部署流程
Composerize神器:自动化转换Docker运行命令至Compose配置,简化容器部署流程
|
1天前
|
缓存 开发者 Docker
Dockerfile是Docker容器化过程中的核心组件,它允许开发者以一种可重复、可移植的方式自动化地构建Docker镜像
【8月更文挑战第19天】Dockerfile是构建Docker镜像的脚本文件,含一系列指令定义镜像构建步骤。每条大写指令后跟至少一个参数,按序执行,每执行一条指令即生成新的镜像层。常用指令包括:FROM指定基础镜像;RUN执行构建命令;EXPOSE开放端口;CMD指定容器启动行为等。优化策略涉及减少镜像层数、选择轻量基础镜像、利用缓存及清理冗余文件。示例:基于Python应用的Dockerfile包括设置工作目录、复制文件、安装依赖等步骤。掌握Dockerfile有助于高效自动化构建镜像,加速应用部署。
|
6天前
|
监控 Ubuntu Docker
如何在Docker容器启动时自动运行脚本
【8月更文挑战第13天】在Docker容器启动时自动运行脚本可通过以下方式实现:1) 使用`ENTRYPOINT`或`CMD`指令在Dockerfile中直接指定启动脚本,如`ENTRYPOINT [&quot;/startup.sh&quot;]`;2) 启动容器时通过`--entrypoint`参数指定脚本路径;3) 利用supervisor等进程管理工具自动启动与监控脚本,确保其稳定运行。确保脚本具有执行权限并正确设置依赖资源路径。
|
15天前
|
Shell 云计算 Docker
零基础到容器技术大神,一键解锁Docker实战秘籍!从零搭建,见证你的技术飞跃,让代码在云端翩翩起舞!
【8月更文挑战第5天】在云计算与微服务当道的今天,容器技术如汹涌浪潮般席卷IT领域。对新手而言,它或许充满神秘,但无须担忧,让我们一同揭开它的面纱。容器是一种轻量级软件打包技术,允许应用及其依赖被打包,在独立的虚拟环境中运行。Docker作为容器界的明星,简化了容器的创建与管理。从安装Docker开始,运行首个容器,深入容器内部执行命令,直至构建自定义镜像,我们将逐步掌握这项关键技术。这不仅是一场技术之旅,更是思维方式的革新,让我们携手探索未来。
56 6
|
17天前
|
运维 Ubuntu Shell
Docker命令宝典:解锁容器化技术的无限可能,从镜像管理到容器操作,全面解析与实战指南!
【8月更文挑战第3天】Docker简化了应用的部署与运行,掌握其基本命令对开发者和运维人员至关重要。通过`docker images`可查看本地镜像;使用`docker pull`拉取如最新版Ubuntu镜像;`docker rmi`用于删除不再需要的镜像。运行容器可通过`docker run`命令,结合`-it`等选项提供交互式环境。`docker ps`显示运行中的容器,加上`-a`则列出所有容器。`docker stop`和`docker start`分别用于停止和重启容器,而`docker rm`则删除容器。
44 5

相关产品

  • 容器服务Kubernetes版
  • 推荐镜像

    更多