亚马逊AWS官方博客

通过Istio在Amazon EKS上实现灰度发布

在微服务架构下,服务越来越多,版本更新频繁,如何能够在不影响已上线业务的情况下进行升级,需要运维团队有灰度发布的能力,通过灰度发布来说实现业务从老版本到新版本的平滑过渡,尽可能避免升级过程中出现的问题对客户造成影响。

在本篇博客中,将介绍如何通过Istio在Amazon EKS上实现灰度发布。

 

灰度发布:又称金丝雀发布,是指在黑与白之间,能够平滑过渡的一种发布方式。在其上可以进行A/B testing,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。

Istio:是一种开源服务网格,是一种现代化的服务网络层,它提供一种透明、独立于语言的方法,实现应用网络功能自动化。Istio采用sidecar对应用流量进行了转发,通过Pilot下发路由规则,可以在不修改应用程序的前提下实现应用的灰度发布。借助 Istio可以保护、连接和监控微服务,可帮助组织在任何位置运行基于微服务的分布式应用,从而更快捷安全地实现企业应用现代化改造。

Amazon EKS: Amazon Elastic Kubernetes Service (Amazon EKS) 是一项托管 Kubernetes 服务,让您能够轻松在 AWS 上和本地运行 Kubernetes。Amazon EKS 经认证与 Kubernetes 一致,因此运行于上游 Kubernetes 的现有应用程序可与 Amazon EKS 兼容。Amazon EKS 可自动管理负责安排容器、管理应用程序可用性、存储集群数据和其他关键任务的 Kubernetes 控制平面节点的可用性和可扩展性。

为了演示灰度发布,我们以Istio官方提供的Bookinfo应用为例 :设置一个 EKS 集群、安装 Istio、部署bookinfo应用、使用istio实现灰度发布。

Bookinfo应用可分为四个单独的微服务: ·

  • productpage 这个微服务会调用details和reviews两个微服务,用来生成页面。
  • details 这个微服务中包含了书籍的信息。
  • reviews 这个微服务中包含了书籍相关的评论。它还会调用ratings微服务。
  • 这个微服务中包含了由书籍评价组成的评级信息。

reviews微服务有 3 个版本:

  • v1 版本不会调用ratings服务。
  • v2 版本会调用ratings服务,并使用 1 到 5 个黑色星形图标来显示评分信息。
  • v3 版本会调用ratings服务,并使用 1 到 5 个红色星形图标来显示评分信息。

下图展示了这个应用的端到端架构。

环境准备

1.安装AWS CLI(以Linux为例)

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
export PATH=/usr/local/bin/aws/:$PATH

其他类型操作系统安装AWS CLI请参考:安装AWS CLI

2.配置AWS Configuration

aws configure

参考样例:

$ aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: us-west-1
Default output format [None]: json

部署 EKS 集群

1.安装eksctl

eksctl是一个简单的 CLI 工具,用于在 Amazon EKS上创建和管理集群。

# 下载、安装eksctl
curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin
# 查看eksctl版本信息
eksctl version

2.安装kubectl

Kubectl 是 Kubernetes 的命令行配置工具,可与 Kubernetes API 服务器进行通信,使用 kubectl 可以创建、检查、更新和删除 Kubernetes 对象。

# 下载安装kubectl
curl -LO --silent https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
chmod 775 ./kubectl
sudo mv ./kubectl /usr/local/bin
# 查看kubectl版本信息
kubectl version --short

3.创建EKS集群

通过eksctl在us-west-1创建EKS集群,包含2个节点,节点类型是c5.large。

eksctl create cluster \
--name ekslab \
--version=1.21 \
--region us-west-1 \
--node-type=c5.large \
--nodes=2 \
--nodes-min=1 \
--nodes-max=4 \
--managed

看到如下输出内容时,EKS集群创建完成。

4.检查所有namespaces中的pod和节点的状态,确保所有namespaces中的pod都是Running,节点状态是Ready。

kubectl get nodes -o wide
kubectl get pods --all-namespaces

设置 Istio

1.安装Istio

Istio提供了一个二进制文件istioctl用于设置Istio并与Istio交互,下载安装Istio,并将istioctl工具添加到用户的PATH环境变量中。

# 下载安装Istio,进入安装目录并设置环境变量
curl -L https://istio.io/downloadIstio | sh -
cd istio-1.13.3
export PATH=$PWD/bin:$PATH

通过运行istioctl x precheck预检查命令确认EKS环境是否正常;

# 环境预检查
istioctl x precheck

为istio安装demo profile,包含Istio-core,Istiod,Egress gateway,Ingress gateway等插件。

istioctl install --set profile=demo -y

为default namespaces中设置istio-injection=enabled标签,开启sidercar自动注入。

kubectl label namespace default istio-injection=enabled

查看istio对应的namespaces和pods是否已经正常创建,并检查状态是否为Running。

2. 部署bookinfo应用:使用kubectl部署bookinfo应用。

kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml

检查services和pods状态,确认已经启动成功。

kubectl get svc
kubectl get pods

在ratings pod中调用productpage,验证bookinfo应用是否正常,当输出”<title>Simple Bookstor App</title>”时说明应用正常。

kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"

3. 部署Backinfo-Gateway

Bookinfo服务已经启动并在运行中,需要部署istio Gateway从外部访问Bookinfo应用。创建Gateway和Virtual Service等用户自定义资源(CRDs),然后访问应用程序

# 为应用程序定义入口网关
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
# 确认网关创建完成,且与bookinfo关联
kubectl get gateway
kubectl get virtualservice

确认Node Port使用的Ingress IP和端口,并设置Gateway_URL。

export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
export INGRESS_HOST=*url_of_load_balancer*
export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
# 获取外部访问地址
echo $GATEWAY_URL

通过浏览器访问productpage页面,刷新页面,如果看到reviews星级发生变化,说明已经成功部署了istio的demo。

4. 部署istio附加组件,如kiali dashboard、grafana、prometheus和jager,通过kubectl apply示例中addons目录下所有的文件。

kubectl apply -f samples/addons

5. 配置Kiali

Kiali是一个基于服务网格的istio管理控制台,它提供了一些列的仪表盘和可观测能力,展示整个网格的网络拓扑和服务的健康状况。默认情况下,Kiali通过Cluster IP暴露服务,如果需要从外部访问kiali的控制台页面,需要将默认配置spec.type:ClusterIp 修改为LoadBalancer。

# 编辑kiali
kubectl edit svc kiali -n istio-system

配置生效后,查看kiali的访问地址和端口。

kubectl get svc kiali -n istio-system

在浏览器中访问Kiali,默认端口是20001

在Graph页面也看到调用关系。

6. 配置Grafana

修改grafana的Service配置,使用LoadBalancer的方式提供对外访问。

配置生效后,查看grafana的访问地址和端口。

在浏览器中访问grafana dashboard,默认端口是3000

用Istio实现灰度发布

采用Istio实现灰度发布,可以通过定制路由规则将特定的流量导入新版本服务中,可以最小化升级中出现的故障对用户的影响,同时存在新老版本服务时,还可根据应用压力对不同版本的服务进行独立的缩扩容。实现灰度发布前,我们先熟悉一下虚拟服务(VirtualService)和目标规则(destination rule)这两个概念。

虚拟服务(Vistrual Service)是 Istio 重要的资源对象,作用是将流量路由到网格中的服务,支持基于权重、http header条件等优先级的路由,颗粒度更加精细。

目标规则(Destination Rule)是 Istio 重要的资源对象,不能独自使用,必须跟 Virtual Service 共同发挥作用,作用是将流量标记分组并路由到具体服务。

下面我们通过4个任务模拟实现基于权重路由的灰度发布:

任务1:流量全部发送到reviews v1版本

任务2:90%流量发送到reviews v1版本,%10流量发送到reviews v2版本

任务3:50%流量发送到reviews v1版本,50%流量发送到reviews v3版本

任务4:流量全部发送到review v3版本

检查pods和服务的状态

kubectl get pods
kubectl get svc

任务1

执行以下命令,将流量全部发送到reviews v1版本

kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml

yaml文件内容如下:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: productpage
spec:
hosts:
- productpage
http:
- route:
- destination:
host: productpage
subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- route:
- destination:
host: ratings
subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: details
spec:
hosts:
- details
http:
- route:
- destination:
host: details
subset: v1
---

在Kiali中查看服务拓扑图如下:

任务2

执行如下命令,将90%的流量发送到reviews v1版本,另外10%的流量发送到reviews v2版本:

kubectl apply -f virtual-service-reviews-90-10.yaml

yaml文件内容如下:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 90
- destination:
host: reviews
subset: v2
weight: 10

在Kiali中查看服务拓扑图如下:

任务3

执行如下命令,将50%的流量发送到reviews v1版本,另外50%流量发送到reviews v3版本

kubectl apply -f virtual-service-reviews-50-v3.yaml

yaml文件内容如下:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 50
- destination:
host: reviews
subset: v3
weight: 50

在Kiali中查看服务拓扑图如下:

任务4

运行如下命令,将流量全部发送到reviews v3版本。

kubectl apply -f virtual-service-reviews-v3.yaml

yaml文件内容如下:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v3

在Kiali中查看服务拓扑图如下:

清理环境

1.卸载istio&bookinfo

# 卸载addons
cd /data/istio-1.13.3
kubectl delete -f samples/addons
# 卸载bookinfo
kubectl delete -n istio-demo -f samples/bookinfo/platform/kube/bookinfo.yaml
kubectl delete -n istio-demo -f samples/bookinfo/networking/bookinfo-gateway.yaml
# 卸载istio
istioctl manifest generate --set profile=demo | kubectl delete --ignore-not-found=true -f -

2.删除EKS集群

eksctl delete cluster --name=eks-lab

参考资料:

istio参考文档:https://istio.io/latest/docs/setup/getting-started/

kubectl参考文档:https://kubernetes.io/docs/reference/kubectl/

eksctl参考文档:https://eksctl.io/introduction/

本篇作者

张世浩

亚马逊云科技解决方案架构师,负责企业客户的解决方案咨询与架构设计优化,现致力于容器和IoT相关领域的研究。