北美KubeCon CloudNativeCon虚拟大会赞助商客座文章作者:Lin Sun,IBM高级技术人员
在今年8月的欧洲ServiceMeshCon会议上,来自Linkerd的William Morgan和我共同发表了篇题为service mesh is still hard的演讲。William详细介绍了对Linkerd的改进,而我介绍了对Istio的改进。很明显,这两个项目都在努力让用户更容易地采用服务网格(service mesh)。
服务网格已经比一、两年前成熟了很多,但是对于用户来说仍然很困难。服务网格有两种类型的技术角色,平台所有者(platform owner)和服务所有者(service owner)。平台所有者,也称为网格管理员,拥有服务平台,并为服务所有者定义采用服务网格的总体策略和实现。服务所有者在网格中拥有一个或多个服务。
平台所有者使用服务网格变得更加容易,因为这些项目正在实现简化网络配置、安全策略配置和整个网格可视化的方法。例如,在Istio中,平台所有者可以按照他们喜欢的范围设置Istio身份验证策略或授权策略。在将目标服务的实际路由行为和流量策略委托给服务所有者时,平台所有者可以在主机/端口/TLS相关设置上配置入口网关。实现经过良好测试的常见场景的服务所有者从Istio的可用性改进中获益,可以轻松地将其微服务装载到网格中。实现不太常见场景的服务所有者继续遇到陡峭的学习曲线。
我相信服务网还是很难,原因如下:
1. 缺乏关于是否需要服务网格的明确指导
在用户开始评估多个服务网格或深入到一个特定的服务网格之前,他们需要关于服务网格是否有用的指导。不幸的是,这并不是一个简单的是或不是的问题。有多个因素需要考虑:
- 你的工程组织里有多少人?
- 你有多少微服务?
- 这些微服务使用什么语言?
- 你有采用开源项目的经验吗?
- 你在哪些平台上运行你的服务?
- 你从服务网格需要什么功能?
- 对于一个给定的服务网格项目,这些特性是否稳定?
更复杂的是,对于不同的服务网格项目,答案可能是不同的。甚至在Istio 1.5之前的早期版本中,我们也采用了微服务来充分利用网格,但是我们决定将多个Istio控制面组件转换为一个独立的应用程序来降低操作的复杂性。对于这种情况,运行一个单体服务比运行4个或5个微服务更合理。
2. 你的服务可能会在射入边车后立即中断
去年感恩节,我试图帮助一个用户在网格运行一个Zookeeper服务,使用最新的Zookeeper Helm chart。Zookeeper作为Kubernetes StatefulSet运行。当我试图将Envoy边车(sidecar)代理注入到每个Zookeeper pod时,由于无法建立领导者和成员之间的沟通,Zookeeper pod无法运行并一直重启。默认情况下,Zookeeper监听pod的IP地址,以实现服务器之间的通信。然而,Istio和其他服务网格需要localhost(127.0.0.1)作为侦听的地址,这使得Zookeeper服务器无法彼此通信。
通过与上游社区的合作,我们为Zookeeper以及Casssandra、Elasticsearch、Redis和Apache NiFi添加了个配置应变方法。我确信还有其他应用程序与边车不兼容。如果你知道任何一些,请通知社区。
https://istio.io/latest/faq/applications/#zookeeper
3. 你的服务在开始或停止时可能有奇怪的行为
应用程序容器可能在边车之前启动,并导致应用程序失败。在停止时间也会发生类似的挑战,即边车可能会在应用程序容器之前停止。
Kubernetes缺乏声明容器依赖关系的标准方法。有个边车Kubernetes增强建议(KEP),但是它还没有在Kubernetes的版本中实现,需要一段时间才能稳定下来。现在,服务所有者可能会在启动或停止时观察到意外的行为。
https://github.com/kubernetes/enhancements/issues/753
为了帮助解决这个问题,Istio为平台所有者实现了个全局配置选项,可以延迟应用程序的启动,直到边车准备就绪。Istio很快也将允许服务所有者在pod级别上进行配置。
4. 服务零配置可以,零代码更改不可行
服务网格项目的主要目标之一是为服务所有者提供零配置。一些像Istio这样的项目已经添加了智能协议检测来帮助检测协议并简化网格的加载体验,然而,我们仍然建议用户在生产中显式声明协议。随着Kubernetes中添加了appProtocol设置,服务所有者现在有了种标准的方法来为运行在新的Kubernetes版本(例如1.19)中的Kubernetes服务配置应用程序协议。
https://kubernetes.io/docs/concepts/services-networking/service/#application-protocol
不幸的是,要充分利用服务网格的强大功能,零代码更改并不可行。
- 为了让服务所有者和平台所有者正确地观察服务跟踪,在服务之间传播跟踪头非常重要。
- 为了避免混淆和意外行为,重新检查服务代码中的重试和超时非常重要,以查看是否应该调整它们,并了解它们的行为与边车代理配置的重试和超时之间的关系。
- 为了让边车代理检查从应用程序容器发送的流量并智能地利用内容来做出决策,例如基于请求的路由或基于标头的授权,对于服务所有者而言,确保从源服务发送纯流量“plain traffic”到目标服务至关重要,并信任边车代理安全地升级连接。
5. 服务所有者需要了解客户端和服务端配置的细微差别
在使用服务网格之前,我不知道Envoy代理有这么多配置是与超时和重试有关。大多数用户都熟悉请求超时、空闲超时和重试次数,但有一些细微差别和复杂性:
- 当涉及到空闲超时时,HTTP协议下有个idle_timeout,它应用于HTTP连接管理器和上游集群HTTP连接。对于不存在上游或下游活动的流,可以使用stream_idle_timeout,甚至可以使用idle_timeout路由覆盖stream_idle_timeout。
- 自动重试也很复杂。重试不仅仅是重试的次数,而是允许的最大重试次数(可能不是实际的重试次数)。实际的重试数量取决于重试条件、路由请求超时和重试之间的间隔,这些必须在请求超时和重试的总体预算之内。
在非服务网格环境中,源和目标容器之间只有一个连接池,但在服务网格环境中,有三个连接池:
- 源容器到源边车代理
- 源边车代理到目标边车理
- 目标边车代理到目标容器
每个连接池都有自己的单独配置。Karl Stoney有个很棒的博客,解释了其中的复杂性,以及这三个连接池任何一个可能会出现错误,以及需要进行哪些检查才能修复它们。
https://karlstoney.com/2019/05/31/istio-503s-ucs-and-tcp-fun-times/
总结
我希望上述挑战能与你产生共鸣,无论你在何阶段采用服务网格。我期待着观察所有项目的创新,因为我们正努力使服务网格尽可能的无聊但有用。
点击【https://www.cncf.io/blog/2020/10/26/service-mesh-is-still-hard/】阅读网站原文。