基于Istio的Kubernetes蓝绿发布
基于Istio的Kubernetes蓝绿发布
本文将向读者介绍如何在云效中发布基于Istio的应用程序,同时利用云效提供的蓝绿发布能力更安全的发布和验证应用。
本文采用Istio官方的Bookinfo实例程序,源码地址:https://gitee.com/moo/bookinfo.git
前提条件
在阿里云容器服务Kubernetes中创建集群,并导入到当前企业中
Kuberntes集群安装Istio组件
开通阿里云镜像仓库服务用于托管容器镜像
创建项目
在云效中我们采用项目的概念来管理一组相关的应用,并且对项目提供了如敏捷看板,测试,文档等服务。通过项目可以端到端的管理应用的整个交付周期:

这里我们为Bookinfo创建一个独立的项目,创建完成后就可以进入到该项目的主页:

创建应用
Bookinfo应用是一个典型的微服务应用程序,其主要结构如下所示:

该图来自于Istio 官方文档
Bookinfo示例程序组要由Productpage,Reviews,Details以及Ratings4个部分组成,同时使用了Python,Java,Ruby以及Node四种不同的技术栈。
创建Productpage应用
首先,我们在Bookinfo项目下创建应用productpage,如下所示:

由于示例应用源码是托管到码云(Gitee)中,我们需要完成码云授权,并关联已有源码:

关联已有代码后,我们需要为当前应用选择相应的应用模板,当前Productpage应用采用Python进行开发,并且使用Kubernetes进行部署:

在完成编程语言以及部署选项的设置后,用户需要定义应用时如何构建的,由于需要将应用部署到Kubernetes中,这里我们勾选Docker构建选项,并且定义了当前应用镜像发布的镜像仓库为rdc-samples/productpage。云效会自定在项目中生成productpage.release文件,该文件定义了Productpage是如何构建的:

下一步,预览并创建应用即可。

查看源码,可以看到云效自动创建的release文件:https://gitee.com/moo/bookinfo/blob/master/productpage.release:

由于Productpage应用是在项目的src/productpage路径下,这里需要手动修改productpage.release文件的内容,并制定Productpage应用的Dockerfile文件路径,完整配置如下所示:
# 构建源码语言类型
code.language=python2.7
# Docker镜像构建之后push的仓库地址
docker.file=src/productpage/Dockerfile
docker.repo=registry.cn-hangzhou.aliyuncs.com/rdc-samples/productpage
进入到productpage应用,可以看到在云效中应用会包含应用的发布流水线,配置管理,环境管理以及版本等能力:

进入到应用的发布页面可以看到云效为应用自动创建的持续交付流水线。触发流水线构建,在构建阶段云效会根据productpage.release文件定义的内容对项目进行打包以及镜像构建,并且将镜像推送到阿里云镜像仓库服务:

不过由于,我们还未进行日常,预发以及正式环境的部署配置,因此当流水线运行到日常部署阶段,会出现如下错误信息:

根据提示,我们进入到日常环境的部署配置页面,这里我们为日常环境创建了名为dev的命名空间,并且为该命名空间启用了Istio的自动注入能力:
kubectl create namespace dev
kubectl label namespace dev istio-injection=enabled
选择集群,命名空间并且新建productpage服务:

这里需要指定Productpage服务的端口以及相应的容器端口,在bookinfo中productpage应用监听的是9080端口,完成配置后如下所示,对于启用了Istio支持的集群,云效会自动打开蓝绿部署选项:

完成配置后,回到流水线页面重新触发日常环境部署动作,由于是第一次部署Productpage服务,云效会直接完成服务的初始化动作:

查看发布单,可以查看具体的资源信息,这里云效自动创建了productpage的Pod实例,并且可以看到自动注入的istio-proxy容器:

部署单发布完成后,查看当前集群dev命名空间下的所有资源如下所示:
$ kubectl -n dev get all --selector='app=productpage'
NAME READY STATUS RESTARTS AGE
pod/productpage-vuhpe-df8967b85-gw28g 2/2 Running 0 3m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/productpage ClusterIP 172.19.0.131 <none> 9080/TCP 54m
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/productpage-vuhpe 1 1 1 1 3m
NAME DESIRED CURRENT READY AGE
replicaset.apps/productpage-vuhpe-df8967b85 1 1 1 3m
云效会为应用版本创建相应的DestinationRules以及VirtualService资源,并且在第一次部署完成后自动将路由规则定向到当前部署版本。
查看DestinationRules如下所示:
#$ kubectl -n dev get destinationrules productpage -o yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
creationTimestamp: 2018-12-14T11:59:07Z
generation: 1
name: productpage
namespace: dev
resourceVersion: "341256082"
selfLink: /apis/networking.istio.io/v1alpha3/namespaces/dev/destinationrules/productpage
uid: a8fe5fc8-ff97-11e8-bbda-de3c7d18d080
spec:
host: productpage
subsets:
- labels:
version: vuhpe
name: vuhpe
查看VirtualService如下所示:
#$ kubectl -n dev get virtualservice productpage -o yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
creationTimestamp: 2018-12-14T11:59:07Z
generation: 1
name: productpage
namespace: dev
resourceVersion: "341256093"
selfLink: /apis/networking.istio.io/v1alpha3/namespaces/dev/virtualservices/productpage
uid: a90d8198-ff97-11e8-bbda-de3c7d18d080
spec:
hosts:
- productpage
http:
- route:
- destination:
host: productpage
subset: vuhpe
使用Istio Gateway访问应用
为了能够访问Productpage应用,用户需要在dev命名空间下部署Gateway资源如下所示:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
namespace: dev
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- '*'
port:
name: http
number: 80
protocol: HTTP
将以上内容保存到bookinfo-gateway.yaml中,并通过Kubectl在集群中创建:
$ kubectl -n dev create -f bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway created
创建完Gateway之后,需要手动绑定Productpage服务和Gateway绑定:
$ kubectl -n dev edit virtualservice productpage
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
creationTimestamp: 2018-12-14T11:59:07Z
generation: 1
name: productpage
namespace: dev
resourceVersion: "341256093"
selfLink: /apis/networking.istio.io/v1alpha3/namespaces/dev/virtualservices/productpage
uid: a90d8198-ff97-11e8-bbda-de3c7d18d080
spec:
# 添加gateways节点绑定bookinfo-gateway
gateways:
- bookinfo-gateway
hosts:
# 添加需要监听的域名
- productpage.yunxiao.com
- productpage
http:
- route:
- destination:
host: productpage
subset: vuhpe
在完成VirtualService完成Gateway绑定后,用户就可以通过集群的istio Gateway访问应用,可以通过以下命令获取Istio Gateway的外网地址:
$ 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=="http")].port}')
此时只需要在本地添加DNS设置,即可通过Gateway访问ProductPage应用:
182.92.244.178 productpage.yunxiao.com
打开浏览器访问https://productpage.yunxiao.com/productpage,如下所示:

不过由于目前我们只部署了Productpage应用,因此当前页面会提示“Error fetching product details!”和“Error fetching product reviews!”的错误信息。
使用蓝绿发布
在Productpage应用第一次发布时由于集群中并不存在任何资源,因此云效会直接创建资源并且将部署设置为成功。在第二次部署应用时,由于底层资源已存在,再次运行流水线,会触发正式的蓝绿部署流程。修改productpage.html文件如下所示:

并重新触发流水线,此时当进入到部署阶段后部署任务会进入等待状态:

点击查看发布单按钮,进入发布单页面,可以看到云效为当前服务创建了两个Deploymet版本:

在默认情况下,当前应用的所有流量依然全部指向旧版的应用实例,访https://productpage.yunxiao.com/productpage可以验证当前应用的流量情况:

在部署暂停时如果希望某些流量能够进入到新版应用,例如,某些特定的URL或者是HTTP Header中包含特定值的请求。那可以直接在发布单中编辑灰度规则即可。例如,我们希望所有/productpage的请求都直接进入新版,那如下所示,添加一条灰度规则即可:

预览生成的YAML并下发规则:

在灰度规则更新成功后,此时如果再次访问应用,那流量则会进入到新版的ProductPage中:

在确认新版应用能够按照预期工作后,在发布单点击继续按钮,即可完成本次发布过程。发布完成后云效会自动移除旧版应用实例,并且将所有流量规则指向新版本。

小结
在这部分中,我们完成了对bookinfo中productpage应用的发布,通过使用云效可以让用户几乎0成本的将应用接入到Istio模式,并且使用蓝绿部署模式安全的对软件进行升级和发布。