Kubernetes 的 service mesh – 第六部分:轻松预发布微服务

简介: 概述 在将新代码发布到生产环境之前, 预发布操作是构建一个可靠的、低宕机时间的软件系统的关键组成部分。但是,在微服务体系下,由于拆分出来的许许多多的微服务之间的依赖关系随着微服务数量成指数倍增长,从而增加了预发布操作的复杂性。

概述

在将新代码发布到生产环境之前, 预发布操作是构建一个可靠的、低宕机时间的软件系统的关键组成部分。但是,在微服务体系下,由于拆分出来的许许多多的微服务之间的依赖关系随着微服务数量成指数倍增长,从而增加了预发布操作的复杂性。在这篇文章里,我们将为您介绍 linkerd 的最强大的功能之一,单个请求路由(per-request routing),通过它,您将可以非常轻松的处理这个问题。


注意:这是关于Linkerd、Kubernetes和service mesh的系列文章其中一篇,其余部分包括:

  1. Kubernetes的service mesh – 第一部分:Service的重要指标
  2. Kubernetes的service mesh – 第二部分:以DaemonSet方式运行linkerd
  3. Kubernetes的service mesh – 第三部分:将一切加密
  4. Kubernetes的service mesh – 第四部分:通过流量切换持续部署
  5. Kubernetes的service mesh – 第五部分:DogFood环境,Ingress和Edge路由
  6. Staging microservices without the tears
  7. Distributed tracing made easy
  8. Linkerd as an ingress controller
  9. gRPC for fun and profit
  10. The Service Mesh API
  11. Egress
  12. Retry budgets, deadline propagation, and failing gracefully
  13. Autoscaling by top-line metrics

Linkerd 是云原生应用的一种服务网格(service mesh)。它作为对应用透明的网络代理层通过封装服务间的调用为应用提供如:低延迟负载均衡(latency-aware load balancing)、链接重试(retry budgets)及终止(deadlines)、熔断机制(circuit breaking)等特性来提高应用的适应性(application resilience)。

除了能够提高应用的适应性,linkerd 也能够提供强大的路由语言来改变服务在运行时请求流的方式。这篇文章我们将为您展示 linkerd 如何做到这一点,不仅仅是全局范围,更精细到每一个基础请求。也将为您展示每一个请求路由如何被用来创建临时的预发布环境,从而允许在生产环境上下文中测试新代码而不用真正将其发布到生产环境里。最后,将为您介绍(in contrast to staging with a dedicated staging environment)临时的预发布环境如何做到既不需要与其他团队的协调工作,也不需要花费时间精力来同时保持多个部署环境。

为什么要预发布

为什么预发布如此重要?在现代软件开发当中,代码需要经过一系列预先设计好的实践路线来保证正确性:代码走查(code review),单元测试(unit tests),集成测试(integration tests)等等。经过这些流程之后,需要开始估算代码的表现了:新代码运行的速度如何?高负载下的表现如何?在运行时与其他服务以及相关依赖的交互表现如何?

预发布系统就可以回答这些问题。预发布的基本原则就是越接近生产环境,系统就越切实可行。因此,就像测试环节中的 mocks 和 stub 一样,对于预发布,我们期望能够运行真实的服务。最好的预发布环境就是和生产环境完全一样。

为什么微服务的预发布很难

如果你的应用由许多微服务构成,那么微服务之间的通信交互就会变成像端到端应用行为一样的重要组成部分。其实,应用拆分的越细,那么在运行时应用之间的交互就会越复杂,而此时应用的表现已经不仅仅是每个微服务自己的问题了,很大程度上取决于微服务之间的交互。

实际上,增加微服务的数量不仅仅增加了正确预发布的重要性,也同时增加了实现这一点的难度。我们来看几个常用的预发布方法,以及为什么在微服务环境下这些方法都会变得比较困难。

预发布的常规方法是共享预发布集群,而在这个集群里,除了你的预发布服务之外其他人的预发布服务也在这里。这种方式的弊端就是没有隔离。如下图展示,如果 Alex 把他的服务发布了上去但是出了点问题,整个链条中就很难判断出问题源的所在–因为问题可能出现在 Alex、Alice 或者 Bob 的服务上,又或者干脆就是数据库里的数据有问题。这样预发布环境与生产环境的同步就会非常困难,尤其是当服务、团队以及发行版本数量庞大的时候。

另一种共享环境称为“私人”或者单个开发者的预发布集群,可以解决隔离的问题。在这个例子中,每一个开发者可以根据需要来操作预发布集群。预发布一个服务需要同时预发布这个服务的上游以及下游服务也包括相关的依赖,从而可以保证预发布的有效性。(比如,在下图中,Alex 必须先发布 Web FE 和 API 服务来保证他的 Foo 服务可以正常运行。)然而,根据需要来维护以及部署部分应用拓扑结构会非常复杂,尤其是当应用拓扑结构非常大而且服务又有独立的部署模型。

上面说的是一种极其简单的部署新代码到生产环境并且有问题时可以回滚的方式。当然了,这种方式很有风险,而且不能处理部分应用类型,比如:金融事务。虽然还有很多其他的部署方法,但是本文我们将介绍一种直接的、轻松的方式。

一种更好的方式

使用 Linkerd 创建临时的预发布环境,就可以很好的避免以上提到的弊端。实际上,在 Twitter 里 Finagle 路由层作为linkerd 的底层, 他的主要动机就是解决这个问题。

我们来看一下 Alex 的 Foo 服务。如果,我们不另外部署一个隔离的环境,而是仅仅使用 Foo 的预发布版本替代 Foo 的生产版本,然后通过一个特殊的请求来访问它呢?针对生产环境,这将能够确保 Foo 的预发布版本的安全性,而且除了 Foo 预发布版本之外也不需要部署其他的任何东西。这就是临时预发布环境的本质。而此时,开发者身上的任务一下就轻松了:Alex 只需要预发布他的新代码,然后在 ingress 请求的 header 上设置一个标记就可以了,就这么简单!

Linkered 的单个请求路由可以帮助我们实现这种方式。通过 linkerd 的请求代理,可以给特定的请求上设置一个 l5d-dtab 的 header 。这个 header 可以允许你设置路由规则(叫做 in Finagle parlance, Dtabs)。比如,dtab 规则 /s/foo => /srv/alex-foo 可以覆盖 Foo 服务生产环境的规则。给单个请求添加这个可以使得请求直接到达 Alex 的 Foo 服务,也仅仅作用与这一个请求。Linkerd 可以拦截这个规则,所以生产环境里任何使用 Alex 的 Foo 服务的地方都可以正确的处理。

试一下这个功能吧

Service Mesh for Kubernetes 系列文章的读者应该已经知道我们有一个 demo our dogfood blog post。我们部署过一个 world-v2 服务,并且可以通过设置重定向路由规则发送单个的 dogfood 请求。现在我们可以使用相同机制来做些别的事情:创建一个临时的预发布环境。

部署一个服务的两个版本,再使用 linkerd 的路由功能在部署到生产环境之前来测试新服务。我们先部署 hello 和 world-v1 服务来作为我们的生产环境服务,然后再创建一个临时的预发布环境来测试 world 服务的新版本 world-v2。

第一步:部署LINKERD和HELLO-WORLD服务

我们使用前一篇文章里部署的 hello world 服务。它由 hello 服务调用 world 服务组成。这些应用通过 Kubernetes downward API 提供的根据 nodeName 来找到 Linkerd 。如果你不确定你的集群是否支持 nodeName, 你可以运行如下命令:

kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/node-name-test.yml

然后查看一下日志:

kubectl logs node-name-test

如果你看到了 ip 就表示成功了。然后再通过如下命令部署 hello world 应用:

kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world.yml

如果你看到了 “server can’t find …” 错误,那就部署 hello-world 的 legacy 版本,这个版本依赖 hostIP 而不是 nodeName:

kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world-legacy.yml

然后我们来部署生产环境(linkerd 和 hellow 以及 world 服务):

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd-ingress.yml

再来部署 linkerd 和预发布版本的服务 world-v2 ,这个服务会返回 “earth” 而不是 “world”。

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd-ingress.yml
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/world-v2.yml

第二步:在临时预发布环境里使用单个请求覆盖

现在,我们运行了 world-v2 服务,来测试一下是否通了。我们期望的是请求到达的是 `world-v2` 而不是 `world-v1`。首先,先运行一个没有更改的请求,这个请求会走默认的路径。(你可能需要等待 l5d 的 external IP 出现):

$ INGRESS_LB=$(kubectl get svc l5d -o jsonpath="{.status.loadBalancer.ingress[0].*}")
$ curl -H "Host: www.hello.world" $INGRESS_LB
Hello (10.196.2.232) world (10.196.2.233)!!

如果外部负载均衡不起作用,可以使用 hostIP:

INGRESS_LB=$(kubectl get po -l app=l5d -o jsonpath="{.items[0].status.hostIP}"):$(kubectl get svc l5d -o 'jsonpath={.spec.ports[0].nodePort}')
$ curl -H "Host: www.hello.world" $INGRESS_LB
Hello (10.196.2.232) world (10.196.2.233)!!

如我们所料,返回了 `Hello (……) World (…..)`,这说明走的是生产环境。

那如何来请求预发布环境呢?我们需要做的就是发送给一个带有覆盖 header 的请求到生产环境中去,它就会访问到 `world-v2` 服务!由于 header 的设置,请求会走 `/srv/world-v2` 而不是 `/host/world`。

$ curl -H "Host: www.hello.world" -H "l5d-dtab: /host/world => /srv/world-v2;" $INGRESS_LB
Hello (10.196.2.232) earth (10.196.2.234)!!

我们看到了 “earch” 而不是 “world”! 这个请求已经成功的到达了 world-v2 服务,而且是在生产环境里,并且没有任何代码变更或者额外的部署工作。就是这样,预发布就变的 so easy 了。

Linkerd 的 Dtabs 和 routing 的文档非常健全。在开发中,你可以使用 linkerd 的 “dtab playground” http://$INGRESS_LB:9990/delegator。By going to the “outgoing” router and testing a request name like /http/1.1/GET/world, you can see linkerd’s routing policy in action.

实践

在实践中,这种方式有一些需要注意的地方。首先,往生产环境的数据库里写东西时必须要小心。相同的 dtab 覆盖机制可以用来发送任何写预发布数据库的请求,或者在一些应用级别里直接 /dev/null。强烈建议,这些覆盖规则不能手动生成,以免发生不必要的错误,毕竟是在生产环境里!

其次,你的应用需要参考 linkerd’s context headers。

最后非常重要的一点,避免外界可以设置 l5d-dtab 请求头。setting up a dogfood environment in Kubernetes 这篇文章里我们阐述了一个 nginx 的 ingress 样例配置,可以有效的去掉不认识的请求头。

结尾

我们举例了如何通过 linkerd 设置单个请求路由规则来达到创建临时预发布环境的问题。通过这种方式,我们可以在生产环境里预发布服务,而不需要更改现有代码,也不需要其他额外的预发布环境资源(当然除了预发布服务自己),同时也不需要处理预发布与生产这两个平行环境。对于微服务众多的应用来说,这种方式提供了一种发布到生产环境之前的简单、高效的预发布方式。

本文转自kubernetes中文社区-Kubernetes 的 service mesh – 第六部分:轻松预发布微服务

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
运维 Kubernetes Docker
利用Docker和Kubernetes构建微服务架构
利用Docker和Kubernetes构建微服务架构
|
Kubernetes Cloud Native 持续交付
容器化、Kubernetes与微服务架构的融合
容器化、Kubernetes与微服务架构的融合
543 82
|
监控 持续交付 Docker
Docker容器化部署在微服务架构中的应用
Docker容器化部署在微服务架构中的应用
637 60
|
12月前
|
监控 Kubernetes Cloud Native
基于阿里云容器服务Kubernetes版(ACK)的微服务架构设计与实践
本文介绍了如何基于阿里云容器服务Kubernetes版(ACK)设计和实现微服务架构。首先概述了微服务架构的优势与挑战,如模块化、可扩展性及技术多样性。接着详细描述了ACK的核心功能,包括集群管理、应用管理、网络与安全、监控与日志等。在设计基于ACK的微服务架构时,需考虑服务拆分、通信、发现与负载均衡、配置管理、监控与日志以及CI/CD等方面。通过一个电商应用案例,展示了用户服务、商品服务、订单服务和支付服务的具体部署步骤。最后总结了ACK为微服务架构提供的强大支持,帮助应对各种挑战,构建高效可靠的云原生应用。
|
关系型数据库 MySQL Docker
《docker高级篇(大厂进阶):5.Docker-compose容器编排》包括是什么能干嘛去哪下、Compose核心概念、Compose使用三个步骤、Compose常用命令、Compose编排微服务
《docker高级篇(大厂进阶):5.Docker-compose容器编排》包括是什么能干嘛去哪下、Compose核心概念、Compose使用三个步骤、Compose常用命令、Compose编排微服务
755 24
|
12月前
|
监控 Cloud Native Java
基于阿里云容器服务(ACK)的微服务架构设计与实践
本文介绍如何利用阿里云容器服务Kubernetes版(ACK)构建高可用、可扩展的微服务架构。通过电商平台案例,展示基于Java(Spring Boot)、Docker、Nacos等技术的开发、容器化、部署流程,涵盖服务注册、API网关、监控日志及性能优化实践,帮助企业实现云原生转型。
|
12月前
|
运维 分布式计算 Kubernetes
ACK One多集群Service帮助大批量应用跨集群无缝迁移
ACK One多集群Service可以帮助您,在无需关注服务间的依赖,和最小化迁移风险的前提下,完成跨集群无缝迁移大批量应用。
|
关系型数据库 MySQL Docker
《docker高级篇(大厂进阶):5.Docker-compose容器编排》包括是什么能干嘛去哪下、Compose核心概念、Compose使用三个步骤、Compose常用命令、Compose编排微服务
《docker高级篇(大厂进阶):5.Docker-compose容器编排》包括是什么能干嘛去哪下、Compose核心概念、Compose使用三个步骤、Compose常用命令、Compose编排微服务
733 6
|
监控 持续交付 Docker
Docker 容器化部署在微服务架构中的应用有哪些?
Docker 容器化部署在微服务架构中的应用有哪些?
|
存储 监控 Docker
探索微服务架构下的容器化部署
本文旨在深入探讨微服务架构下容器化部署的关键技术与实践,通过分析Docker容器技术如何促进微服务的灵活部署和高效管理,揭示其在现代软件开发中的重要性。文章将重点讨论容器化技术的优势、面临的挑战以及最佳实践策略,为读者提供一套完整的理论与实践相结合的指导方案。

推荐镜像

更多