试驾 Open Service Mesh
上周微软发布了全新的服务网格(Service Mesh)轻量级解决方案:Open Service Mesh(简称 OSM),OSM 是 Service Mesh Interface(SMI)规范的一个实现,同样使用 Envoy 作为 sidecar 代理。对于一些初学者来说,这些概念可能比较陌生,下面我们从头开始来介绍下服务网格。
什么是服务网格?
我记得第一次听说服务网格的时候,是在一个”Introduction to Istio and onto 1.0“ 的 meetup 上,来自 Google 的 Dan Curuli 介绍了Istio 和它所解决的问题,从那以后服务网格和 Istio 越来越受欢迎。
那么什么是服务网格呢?服务网格是一种基础设施组件,有助于管理服务间的通信。换句话说,它是一种透明的技术,它将服务间通信的某些逻辑从你的应用代码中剥离出来,转移到了服务网格中。一个很好的例子就是我们调用 API 时的重试逻辑,如果没有服务网格,我们就必须把这些逻辑写到应用代码中去,但是有了服务网格过后,我们就可以将重试逻辑转移到网格中来,利用网格中的重试策略来实现这个功能(参考 Istio 中的示例)。
服务网格通常使用在 Kubernetes 环境下,虽然也可以在非 Kubernetes 环境中使用。在 Kubernetes 集群中,服务网格通常使用 sidecar 模式来实现,sidecar 是一个伴生容器,被添加到应用程序的 Pod 中去,以实现服务网格中的额外功能。
这个 sidecar 容器可以是很多种容器,不过作为 sidecar 使用 Envoy 是一个非常流行的代理,Istio 就是使用的这个 sidecar(OSM 也是使用的 Envoy)。Envoy 最初是由 Lyft 开发的代理工具,在功能上与 Nginx 或者 HAProxy 比较类似,但是 Envoy 有一些明显的优势,包括高性能处理和集中式配置管理系统。当然 Envoy 并不是唯一可以使用的 sidecar,你也可以使用 Nginx,通常情况下,每个服务网格都会有一个默认的 sidecar 代理。
目前最流行的服务网格实现要数 Istio 了,Istio 最初是由 Google、IBM 和 Lyft 共同创建的项目,虽然它是目前最流行的服务网格,但是最近在开源社区也引起了一些小骚动,因为 Google 将 Istio 捐献给了一个新的基金会:Open Usage Commons,而不是将 Istio 捐献给 CNCF 基金会。当然 Istio 也不是唯一的服务网格,其他流行的网格包括 Linkerd、Consul、Maesh 等。
服务网格领域目前仍然还处于早期阶段,每种服务网格都有自己的优势和劣势。但是从一个网格切换到另一个网格并不是很直接,有一定成本,这是因为每个网格都有自己的配置语言语法,这就是 SMI 规范视图解决的问题。
SMI 规范
Serivce Mesh Interface(SMI)规范是运行在 Kubernetes 上的服务网格的标准接口。如果你熟悉 Kubernetes 中的 Ingress 资源,SMI 对于服务网格,就类似于 Ingress 对于反向代理,它是一种配置多个后端实现的标准化方式。这样做的好处是,你不必学习特定实现的具体内容,就可以简单使用 SMI 规范来配置你的服务网格了。
微软最初在2019年5月创建了 SMI 规范,并在2020年4月将该规范捐献给了 CNCF 基金会。到目前为止,已经有4个服务网格实现了 SMI 规范:
Istio ( 通过适配器 )
Linkerd
Consul Connect ( 通过适配器 )
Maesh
当然现在又有一个新的服务网格实现实现了 SMI 规范,那就是 OSM。
Open Service Mesh
Open Service Mesh(OSM)是一个新的服务网格,同样使用 Envoy 作为 sidecar 代理,并使用 SMI 规范进行配置。虽然这个服务网格才刚刚推出,但是已经实现了一些功能(摘自 OSM 官网:https://openservicemesh.io/):
轻松、透明地配置应用的流量移动
通过启用 mTLS 确保端到端服务间的通信安全
定义并执行精细的服务访问控制策略
可观测性和应用指标,用于服务调试和监控
通过可插拔的接口与外部证书管理服务/解决方案集成
可以启用自动注入 Envoy sidecar 代理,将应用程序纳入到网格
足够灵活,可以通过 SMI 和 Envoy XDS API 来处理简单和复杂的各种场景
接下来我们就去 Kubernetes 集群中来安装体验下 OSM。
使用 OSM
我将在 Azure 中的现有集群上安装 OSM,OSM 需要一个 v1.15.0 版本或以上的 Kubernetes 集群。
然后下载 OSM 二进制文件,这里我们下载 GitHub 上的最新版本 v0.2.0:
wget https://github.com/openservicemesh/osm/releases/download/v0.2.0/osm-v0.2.0-linux-amd64.tar.gz
tar -xvzf osm-v0.2.0-linux-amd64.tar.gz
sudo mv linux-amd64/osm /usr/local/bin/osm
rm -rf linux-amd64
然后直接执行 osm install
命令安装 OSM 即可,安装结果如下图所示:
当安装完 OSM 过后,我们就可以来探索下如何使用了~
OSM 演示应用程序
基本设置
OSM 团队为我们提供了一个非常友好的完整演示应用程序,这里我们将创建几个 namespace 并部署几个应用。
首先将 OSM 的代码仓库 Clone 到本地:
git clone https://github.com/openservicemesh/osm.git
cd osm
接下来我们创建4个 namespace,并将这4个 namespace 加入到 OSM 中:
for i in bookstore bookbuyer bookthief bookwarehouse; do kubectl create ns $i; done
for i in bookstore bookbuyer bookthief bookwarehouse; do osm namespace add $i; done
然后部署4个应用程序,它们的配置在目录 docs/example/manifests/apps/
中:
我们可以看到有4个应用的 YAML 资源清单文件,还有一个 traffic-split.yaml
的文件,这个文件中就包含了服务网格的配置,文件内容如下所示:
apiVersion: split.smi-spec.io/v1alpha2
kind: TrafficSplit
metadata:
name: bookstore-split
namespace: bookstore
spec:
service: bookstore.bookstore #
. backends:
service: bookstore-v1
weight: 100
这就是 SMI 配置,并没有 OSM 的特殊配置,因为 OSM 是遵循 SMI 规范的,我们直接部署这个示例应用,看看会发生什么。
kubectl create -f docs/example/manifests/apps/
可以看到会部署一堆资源对象,部署完成后我们可以通过设置端口转发来查看应用程序:
cp .env.example .env
./scripts/port-forward-all.sh
这会在本地开启如下几个端点绑定在应用程序上:
http://localhost:8080 – Bookbuyer
http://localhost:8081 – bookstore-v1
http://localhost:8083 – bookthief
可以默认访问服务的样子如下所示:
允许请求
正常情况下,如果服务之间能够互相通信,我们就可以看到页面上的计数器会增加。但是现在这三个服务之间不允许有任何流量,意味着没有 book 会被 buy 或者 stolen,我们可以通过应用访问控制策略来修改。在上面仓库代码的 docs/example/manifests/access/
目录下面就有一个策略文件,内容如下所示:
kind: TrafficTarget
apiVersion: access.smi-spec.io/v1alpha2
metadata:
name: bookstore-v1
namespace: bookstore
spec:
destination:
kind: ServiceAccount
name: bookstore-v1
namespace: bookstore
rules:
kind: HTTPRouteGroup
name: bookstore-service-routes
matches:
buy-a-book
books-bought
sources:
kind: ServiceAccount
name: bookbuyer
namespace: bookbuyer
#- kind: ServiceAccount
#name: bookthief
#namespace: bookthief
---
apiVersion: specs.smi-spec.io/v1alpha3
kind: HTTPRouteGroup
metadata:
name: bookstore-service-routes
namespace: bookstore
spec:
matches:
name: books-bought
pathRegex: /books-bought
methods:
GET
headers:
host: "bookstore.bookstore"
"user-agent": ".*-http-client/*.*"
"client-app": "bookbuyer"
name: buy-a-book
pathRegex: ".*a-book.*new"
methods:
GET
headers:
host: "bookstore.bookstore"
首先,bookthief 这个 ServiceAccount 被注释掉了,意味着这个 sa 下面的应用不能访问其他服务
然后,可以看到我们创建了两个对象:
TrafficTarget
与HTTPRouteGroup
。HTTPRouteGroup
用于描述 HTTP/1 和 HTTP/2 的流量,它枚举了可以通过应用程序进行服务的路由。TrafficTarget
将一组流量定义(规则)与服务关联起来,服务和一组 Pods 进行关联。在我们这个示例,可以看到:
现在的源只是 bookbuyer 这个 ServiceAccount,而不是 thief(被注释掉了)。
我们创建了一个通往目标 bookstore-v1 的
TrafficGroup
匹配了两个HTTPRouteGroup
。
下面我们直接创建 HTTPRouteGroups
来查看流量请求:
kubectl create -f docs/example/manifests/access/
一旦创建了访问策略,我们就会看到计数器递增,这意味着书籍正在被买进或卖出,但没有被盗。
接下来我们启用 book thief,将上面文件docs/example/manifests/access/traffic-access.yaml
中的注释取消掉:
kind: TrafficTarget
apiVersion: access.smi-spec.io/v1alpha2
metadata:
name: bookstore-v1
namespace: bookstore
spec:
destination:
kind: ServiceAccount
name: bookstore-v1
namespace: bookstore
rules:
kind: HTTPRouteGroup
name: bookstore-service-routes
matches:
buy-a-book
books-bought
sources:
kind: ServiceAccount
name: bookbuyer
namespace: bookbuyer
kind: ServiceAccount
name: bookthief
namespace: bookthief
重新更新我们的资源清单:
kubectl apply -f docs/example/manifests/access/traffic-access.yaml
现在我们再去访问我们的应用,就可以看到在 bookthief 中也有变化了。
我们来快速回顾下上面我们做的事情:
在集群中安装了 OSM
创建了4个命名空间,并将这些命名空间加入到 OSM 网格中
创建了一个应用程序,看到流量默认被阻止
使用
TrafficTarget
和HTTPRouteGroup
对象创建了一个流量策略,以允许特定的流量在我们的网格中流动
下面我们将创建一个新版本的 bookstore(bookstore-v2),我们将能够将流量从一个服务引导到另一个服务。
流量分流
在本节中,我们将部署一个新版本的 bookstore,然后慢慢将所有流量导向它,首先,让我们部署第二版本的 bookstore:
kubectl apply -f docs/example/manifests/bookstore-v2/
在我们进行端口转发的终端窗口中,我们需要停掉脚本,然后再次启动该脚本,就可以转发到第二版本的 bookstore 应用了。
当我们访问应用的时候可以看到计数器增加了,但是第二家书店没有卖出任何副本,这是因为 TrafficSplit
被配置为将 100% 的流量导入到了主要的书店。我们可以通过检查该对象来验证这一点。
kubectl get trafficsplit bookstore-split -n bookstore
我们可以通过部署 docs/example/manifests/split-v2/traffic-split-v2.yaml
文件将流量重定向到 v2 版本的书店,我们先来查看该文件的内容。
apiVersion: split.smi-spec.io/v1alpha2
kind: TrafficSplit
metadata:
name: bookstore-split
namespace: bookstore
spec:
service: bookstore.bookstore #
. backends:
service: bookstore-v1
weight: 0
service: bookstore-v2
weight: 100
我们可以看到上面定义将100%的流量重定向到了 v2,我们直接应用上面的对象:
kubectl apply -f docs/example/manifests/split-v2/traffic-split-v2.yaml
然后我们再去访问应用可以发现只有 v2 版本的书店计数器在增加了:
我们也可以按照权重来拆分流量,比如 50/50 拆分,直接修改上面的资源对象:
kubectl edit trafficsplit bookstore-split -n bookstore
编辑后,现在我们可以看到两个版本的书店的计数器都在增加了,而且增长的速度差不多。
同样我们来回顾下这里我们做了些什么操作:
新建了一个新版本的 bookstore 应用
先把 100% 的流量发送到新书店,只能看到 bookstore-v2 应用有流量
然后我们做了 50/50% 的流量拆分,我们看到两个 bookstores 应用都收到了比例大致相等的流量。
最后,我们来看看 OSM 内置的一些监控。
流量监控
OSM 预安装了 Prometheus、Grafana 和 Zipkin,这些工具允许我们创建关于应用的流量图表(prometheus/grafana)和进行分布式追踪(Zipkin)。
要访问 Grafana,我们可以在浏览器中打开 localhost:3000,默认使用 admin/admin 进行登录,在Grafna 中,打开 dashboard 的管理视图:
我们来看下服务到服务的数据平面指标数据:
同样我们可以配置这个 dashboard,让我们看到不同系统/服务之间的流量。如果我们将其配置为监控 bookbuyer 和 bookstore-v1 之间的流量,我们就会清楚地看到哪里有 100% 的流量,哪里有 50% 的流量。此外,这个默认的 dashboard 还向我们展示了请求延迟和其他的一些指标,同样我们也可以自由配置自己的相关指标。
我们可以清楚地看到流量从 buyer 到 bookstore-v1 的转变,先是 100%,然后是 0%,然后是 50%。
关于 OSM 更多高级的用法可以去官方文档(https://openservicemesh.io/)上了解更多信息。
K8S进阶训练营,点击下方图片了解详情