蓝绿、A/B和金丝雀部署
—— 《DevOps with OpenShif》第3章 节选
蓝绿部署
蓝绿部署策略,通过确保在部署期间有两个版本的应用栈可用,从而最大限度地减少新旧版本应用切换时间(图3-3)。我们可以利用服务与路由之间的关联,轻松地在两个正在运行的应用堆栈之间切换,因此应用版本回滚简单快捷。
图3-3 蓝绿部署
我们将蓝、绿应用栈都部署到同一个OpenShift项目(bluegreen)当中,并把路由指向蓝应用栈提供的服务(图3-4):
$ oc new-project bluegreen --display-name="Blue Green Deployments" --description="Blue Green Deployments"
$ oc new-app https://github.com/devops-with-openshift/bluegreen#master --name=blue
$ oc expose service blue --name=bluegreen
$ oc new-app https://github.com/devops-with-openshift/bluegreen#green --name=green
【译者】:
上面这几条命令,创建了一个名称为bluegreen的项目;以源码的master分支部署一套应用栈,名称为blue,并定义名为bluegreen的路由指向此应用所对应的服务;再以源码的green分支部署另一套应用栈,名称为green
图3-4 在原文中是当作初始路由指向蓝应用栈服务时部署展现图,其实这已经是路由从蓝切绿之后的部署展现图
图3-4 绿部署
使用web界面或命令行,可以很轻松地在蓝、绿应用服务间切换路由指向:
# switch service to green
$ oc patch route/bluegreen -p '{"spec":{"to":{"name":"green"}}}'
# switch back to blue again
$ oc patch route/bluegreen -p '{"spec":{"to":{"name":"blue"}}}'
在无状态应用架构中,蓝绿部署相当容易实现,因为不用担心:
- 在原蓝色应用堆栈中有长事务在运行
- 数据需要随应用一起移植或回滚
【译者】:
oc expose service blue --name=bluegreen
命令产生路由配置用Yaml来表示的关键大致如下:
apiVersion: route.openshift.io/v1
kind: Route
name: bluegreen
namespace: bluegreen
spec:
host: bluegreen-bluegreen.192.168.42.65.nip.io
port:
targetPort: 8080-tcp
to:
kind: Service
name: blue
weight: 100
oc patch route/bluegreen -p '{"spec":{"to":{"name":"green"}}}'
命令,就是将配置中to
小节中的name
(服务名称)改成green,也就是将整个外部入口的流量全部路由到绿应用栈对应的服务:
apiVersion: route.openshift.io/v1
kind: Route
name: bluegreen
namespace: bluegreen
spec:
host: bluegreen-bluegreen.192.168.42.65.nip.io
port:
targetPort: 8080-tcp
to:
kind: Service
name: green
weight: 100
A/B部署
A/B部署得名于将应用功能新版本做为整体部署一部分、与旧版本并存线上进行测试的能力。通过这种方式,可以创建一个假定,执行A/B部署,测试假定是正确还是错误,以及回滚到初始应用部署(A)还是继续新版本应用部署(B)。
一个很好的例子,就是对销售网站或移动应用进行更改。 将一定比例的流量引导至新版本,并按版本计算销售量(根据访问者数量计算转化率)。 最后,根据哪个转换率较高,来决定应用版本是回滚还是继续部署新版本(图3-5)。
图3-5 A/B测试
我们可以利用OpenShift路由层来实现A/B部署(图3-6)。
图3-6 A/B部署
让我们先创建应用‘Cat of the Day’,做为A版本:
$ oc new-project cotd --display-name='A/B Deployment Example' --description='A/B Deployment Example'
$ oc new-app --name='cats' -l name='cats' php:5.6~https://github.com/devops-with-openshift/cotd.git -e SELECTOR=cats
$ oc expose service cats --name=cats -l name='cats'
再创建应用‘City of the Day’,做为B版本:
$ oc new-app --name='city' -l name='city' php:5.6~https://github.com/devops-with-openshift/cotd.git -e SELECTOR=cities
$ oc expose service city --name=city -l name='city'
我们还需要使用annotation
(注解)来覆盖修改HAProxy的默认负载均衡模式,从least connection
(最小连接数)改为round-robin
(轮询)模式,并在命令route-backends
中指定路由权重:
$ oc expose service cats --name='ab' -l name='ab'
$ oc annotate route/ab haproxy.router.openshift.io/balance=roundrobin
$ oc set route-backends ab cats=100 city=0
【译者】:
此时,系统里是存在三条路由的,cats
路由到A/Cats应用,city
路由到B/City应用,ab
根据权重随机路由到A/B应用:
若浏览器访问ab路由对外的端点,将会看到Cats版本的页面内容。让我们再使用OpenShiftset route-backends
命令调整路由权重,使得10%的流量转到City版本。 通过curl
命令模拟10次web页面点击,输出结果显示了HTML页面的图像位置,可以看到10次中有1次去了City版本(记得按照您的实际环境情况来替换URL里主机名称):
$ oc set route-backends ab --adjust city=+10%
$ for i in {1..10}; do curl -s http://ab-cotd.192.168.137.3.xip.io/item.php | grep data/images | awk '{print $5}'; done
data/images/cats/auckland.jpg
data/images/cats/perth.jpg
data/images/cats/christchurch.jpg
data/images/cats/hobart.jpg
data/images/cats/canberra.jpg
data/images/cats/melbourne.jpg
data/images/cats/canberra.jpg
data/images/cats/christchurch.jpg
data/images/cities/hobart.jpg
data/images/cats/sydney.jpg
【译者】:
执行完命令oc set route-backends ab --adjust city=+10%
后,路由ab
的整体情况如下图:
HAProxy的默认配置使用客户端cookie来支持会话粘连(sticky sessions)。如果使用curl
命令模拟(指定–cookie选项)支持cookie的浏览器,由于会话粘连行为,只会看到cates或city。
过段时间后,我们通过两个应用日志中记录的用户反馈,来衡量cities或cats哪个更受喜爱。可使用oc logs -f <name of pod>
命令来查看各个应用的日志:
$ oc logs -f $(oc get pods -l name=cats -o name) | grep COTD
...
{"auckland" : "4"}
$ oc logs -f $(oc get pods -l name=city -o name) | grep COTD
...
{"sydney" : "3"}, {"wellington" : "5"}
如果我们高兴地看到用户更加喜爱cities多一些,即可路由所有流量到B/city版本应用(图3-7):
$ oc set route-backends ab cats=0 city=100
当我们在web界面查看流量统计条时,就能看到:
图3-7 所有流量流向(B)cities
当然,在生产环境,我们更偏向于自动化地进行衡量,并通过API调用设置路由权重。
金丝雀部署
金丝雀部署是一种类似于A/B部署的技术,可将变更缓慢地向部分用户推出,然后再将其推出到整个基础架构,并提供给所有人使用。
如果查看一下A/B部署的例子,可以看到有三条路由被暴露:
$ oc get routes
NAME HOST/PORT PATH SERVICES PORT TERMINATION
ab ab-cotd.192.168.137.3.xip.io cats(100%),city(0%) 8080-tcp
cats cats-cotd.192.168.137.3.xip.io cats 8080-tcp
city city-cotd.192.168.137.3.xip.io city 8080-tcp
我们可使用这些路由来制定金丝雀部署的策略:
- 一个简单的策略是针对随机抽样用户来使用新版本 —— 这是A/B部署策略
- 将新版本提供给内部测试人员,直接把他们流量导入City路由,以进行测试
- 在OpenShift里创建一个测试项目做为金丝雀,在测试通过之后再发布
- 更复杂的方法是根据用户的个人资料和其他人口统计资料选择用户。
做为集群管理员,也可以使用类似于客户化HAProxy路由模板配置的高级技术。
按照文档,可利用客户化访问控制列表来限制对金丝雀路由的访问。您 现在不需要执行此操作,这里是haproxy-config.template示例的一部分,它阻止不在我们子网中的用户访问City路由:
frontend public
# Custom acl
# block users not in 192.168.137.0/24 network from accessing city host
acl network_allowed src 192.168.137.0/24
acl host_city hdr(host) -i city-cotd.192.168.137.3.xip.io
acl restricted_page path_beg /
http-request deny if restricted_page host_city !network_allowed