基于容器服务的持续集成与云端交付(四)- 多种发布方式

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 前言 哲学有各种各样的流派,百家争鸣,但是只有一个哲学问题是严肃的,那就是生与死。而云端交付过程中也只有三个问题是严肃的。 如何重建你的系统 How to recreate your system? 如何安全地部署你的系统 How to safely change your system? 部署后的问题监控与解决 When something has gone wrong? 在前面的文章中,我们讲述了什么是云端交付,如何搭建从零搭建一个持续交付系统,而今天我们要谈的是如何安全的部署你的系统,部署这个名词包含了很多的含义,最简单的解释就是如何让你的程序运行在最终的环境上。

前言

哲学有各种各样的流派,百家争鸣,但是只有一个哲学问题是严肃的,那就是生与死。而云端交付过程中也只有三个问题是严肃的。

  1. 如何重建你的系统 How to recreate your system?
  2. 如何安全地部署你的系统 How to safely change your system?
  3. 部署后的问题监控与解决 When something has gone wrong?

在前面的文章中,我们讲述了什么是云端交付,如何搭建从零搭建一个持续交付系统,而今天我们要谈的是如何安全的部署你的系统,部署这个名词包含了很多的含义,最简单的解释就是如何让你的程序运行在最终的环境上。但是部署的方式上面有非常多的最佳实践。接下来我们来讨论下常见的几种发布方式,以及如何利用容器发布实现最常用的零宕机发布方式蓝绿发布。

发布策略

常见的发布策略有蓝绿发布、金丝雀发布(灰度发布)、ABTest,在国内的开发者中,对这几个概念有独立的理解。蓝绿发布通常被大家成为热部署;金丝雀发布在国内的名头完全被他的变种发布方式盖过了,主要是灰度发布与ABTtest,下面我们来详细的为大家解释一下他们之间的异同。

蓝绿发布

在发布的过程中用户无感知服务的重启,通常情况下是通过新旧版本并存的方式实现,也就是说在发布的流程中,新的版本和旧的版本是相互热备的,通过切换路由权重的方式(非0即100)实现不同的应用的上线或者下线。


08e4195eec87b02f2afe7f2fa43ec555127f2100


22c0f969a692ff28a501a8c8585f25108f6a92e0


5d079141ee10164a538c5cb14e999d0202cd4bba

金丝雀发布

通过在线上运行的服务中,新加入少量的新版本的服务,然后从这少量的新版本中快速获得反馈,根据反馈决定最后的交付形态。

灰度发布

灰度发布是通过切换线上并存版本之间的路由权重,逐步从一个版本切换为另一个版本的过程。虽然马丁·扶老耳朵大人认为灰度发布与金丝雀发布是等同的,但是在具体的操作和目的上面个还是有些许差别的。金丝雀发布更倾向于获取快速的反馈,而灰度发布更倾向于从一个版本到另一个版本平稳的切换。


90c8d36866b247d2edd9502b33ae9980038a55df


e0c63b94b936587a6b7fc60ace6b06fedf81b201


5a9ca9875ef60c6435ff938519c54691ff407fff

ABTest

ABTest和灰度发布非常像,但是从发布的目的上,可以简单的区分灰度发布与ABTest,ABTest侧重的是从A版本或者B版本之间的差异,并根据这个结果进行决策。最终选择一个版本进行部署。因此和灰度发布相比,ABTest更倾向于去决策,和金丝雀发布相比,ABTest在权重和流量的切换上更灵活。


ac8b1d89edd8904d1225ccff1706037b068516dc

阿里云容器服务实现蓝绿发布

下面我们通过一个简单的例子来演示蓝绿发布的流程。假设我们要进行蓝绿发布的应用是一个nginx的静态页面,初始的应用模板如下

nginx-v1:
  image: 'registry.aliyuncs.com/ringtail/nginx:1.0'
  labels:
    aliyun.routing.port_80: nginx
  restart: always

部署后会有“Welcome to nginx”的成功页面提示。如果用户想变更配置, 可以在操作面板上选择“变更配置”,进入信息修改阶段,选择变更的发布策略与新版本服务的配置。


b2c3264b5f55e9d7248f1476d1f16e4e19f076df
nginx-v2:
  image: 'registry.aliyuncs.com/ringtail/nginx:2.0'
  labels:
    aliyun.routing.coexist: true
    aliyun.routing.port_80: nginx
  restart: always

在蓝绿发布中,新版本与旧版本不能共用同一个名字;如果共享同一个路由地址,那么需要添加aliyun.routing.coexist的label,这个label的含义是,当前的服务与其他服务共享路由地址,在蓝绿发布的场景中,为了保证应用的零宕机切换,新版本的服务的路由权重默认为0,需要通过路由管理页面进行调整,方可进行流量切换。

在进行发布的过程中,会经历两个状态,一个是蓝绿发布中,一个是蓝绿发布待确认。“蓝绿发布中”表示,新版本的服务尚未启动完成;而“蓝绿发布待确认”表示新版本的服务已经启动完成,此时需要进行发布确认或者发布回滚方可进行下一次发布。其中,新版本的应用和旧版本的应用并存,前者用绿色标明,后者用蓝色标明。如果一个服务在前后两个版本中都存在且没有变化,那么会使用黄色标记,表示这个应用在蓝绿发布中不会出现任何变化。


dbd3a39ebe4b94f2e7029de5e5980f512f1c66b0

选择“路由列表”之后再点击“设置服务权重”,调整与之对应的路由权重。如图所示,旧版本服务的权重为100,新版本服务的权重为0;下面我们将旧版本服务的权重调整为0,新版本服务的权重调整为100。


66e195c726713a4e79211889f56c0a2a5d58e993


fed3fae35900b872264b6d28771b4d14d6c504da

由于默认路由服务是进行会话保持的,您可以打开一个新的浏览器窗口,访问新的版本,结果如下。


092be26066d208c877d808a360911fe00f60c1c2

当整个发布流程验证完毕后,需要进行发布确认,方可进行下一次发布。

点击发布确认后,查看应用的详情,可以看到应用的服务列表已经更新了,旧的服务已经完全下线删除了。


6cddaf9185d1a2411ad3812c17a7716361f79fc7

复杂拓扑下的蓝绿发布

场景分析

大于大多数场景而言,对客户提供服务的软件的形态有三种。一种是前端类服务,用户可以直接或者间接通过网页、接口调用使用该服务提供的能力;一种是后端类服务,用户无法直接使用该服务提供的功能,该服务主要的使用者是其他服务,并通过其他服务最终将处理后的结果反馈给用户;第三种是调度任务类服务,即不被用户使用也不被其他服务调用,它的生命周期只存在在一个任务的执行生命周期中,通常任务的执行周期完毕,服务的生命周期就停止,通常为无状态资源密集性服务。

对于上述三种场景,以路由权重切换为主要实现方式的发布策略例如蓝绿发布、A/BTest等通常情况下比较适用于前端类服务与后端类服务。下面我们用一个简单的例子来拆解下如何使用阿里云容器服务来实现这两类服务的蓝绿发布。

在上一篇发布策略的文章中,有的开发者会问我的应用的拓扑关系不是单体的,不能通过单一容器级别的路由权重切换解决。在此要明确的一件事情,蓝绿发布是一种发布策略,部署的最小维度是容器,而发布的最小维度是应用。蓝绿发布的原理是老的应用的版本不变,新的应用版本进行部署,如果新版本与老版本之间应用的名字以及相关的配置没有改变,那么会认为这个应用是新老版本中共用的,无需变更;需要进行变更的应用通过名字的不同进行区分。简单的来讲,蓝绿发布是一个应用级别的更新操作,你可以对一个服务进行两个版本之间的切换,服务是一个逻辑的概念,而不是容器这样一个实体的概念,蓝绿发布可以做复杂拓扑的应用更新操作。

DEMO

下面我们通过一个拓扑结构复杂一点的例子来讲述蓝绿发布。应用的拓扑结构如下:


e26fe16bb8d8b2253196424e97c50d2fd5b2c521

serviceB会调用serviceA,这两个都是python构建的,代码如下:

serviceA通过接口返回数据“world!”

from flask import Flask
app = Flask(__name__)

@app.route('/')
def world():
  return 'world!'

if __name__ == '__main__':
  app.run(port=5000,debug=True,host='0.0.0.0')

serviceB调用serviceA的接口,并将返回的数据字段前面添加“Hello ”

from flask import Flask
import requests
import os

dep_endpoint = os.getenv('dep_endpoint');

app = Flask(__name__)

@app.route('/')
def hello():
  msg = requests.get(dep_endpoint);
  return 'Hello ' + msg.text;

if __name__ == '__main__':
  app.run(port=5001,debug=True,host='0.0.0.0')

传统应用之间的调用方式可以是通过配置IP地址或者域名来调用,也可以通过服务注册中心中的地址的方式调用,但是对于一个无状态的多实例的服务,常见的做法是使用客户端的负载均衡器或者服务器的服务均衡器端点来实现。在容器服务中使用的方式是使用服务器端的负载均衡端点的方式,提供内部调用的路由端点,来实现后端服务的负载均衡。大致的调用方式如下。

serviceA-v1:
  image: 'registry-internal.cn-hangzhou.aliyuncs.com/ringtail/demo-service-a:1.0'
  labels:
    aliyun.scale: 3
    aliyun.routing.port_5000: servicea.local
serviceB-v1:
  image: 'registry-internal.cn-hangzhou.aliyuncs.com/ringtail/demo-service-b:1.0'
  environment:
    - 'dep_endpoint=http://servicea.local'
  labels:
    aliyun.scale: 2
    aliyun.routing.port_5001: serviceb
  external_links:
    - "servicea.local"

serviceB通过external_links的方式将serviceA的内部路由端点引入,在环境变量中将

dep_endpoint=http://servicea.local,使用servicea.local作为调用的地址。

访问serviceB的对外访问地址,可以得到:


18b2375693f7771cd5a6f7113a39aa384727a69d

我们最开始基本结构的应用就已经部署完毕了,下面开始进行不同服务的蓝绿发布。

前端服务的蓝绿发布

首先我们先看如果做前端服务的蓝绿发布,也就是说要对serviceB进行蓝绿发布的流程。大致的结构图如下。


3b7bbcf6708ca3f40f40586e744cee137e53f023

在这个应用中前端服务的蓝绿发布,也就是对serviceB进行蓝绿发布,下面我们修改serviceB的代码

from flask import Flask
import requests
import os

dep_endpoint = os.getenv('dep_endpoint');

app = Flask(__name__)

@app.route('/')
def hello():
  msg = requests.get(dep_endpoint);
  return 'Welcome to the ' + msg.text; //ץද"Hello " => "Welcome to the "
  
if __name__ == '__main__':
      app.run(port=5001,debug=True,host='0.0.0.0')

修改编排模板,进行蓝绿发布

serviceA-v1:
  image: 'registry-internal.cn-hangzhou.aliyuncs.com/ringtail/demo-service-a:1.0'
  labels:
    aliyun.scale: 3
    aliyun.routing.port_5000: servicea.local
serviceB-v2:
  image: 'registry-internal.cn-hangzhou.aliyuncs.com/ringtail/demo-service-b:2.0'
  environment:
    - 'dep_endpoint=http://servicea.local'
  labels:
    aliyun.scale: 2
    aliyun.routing.port_5001: serviceb
  external_links:
    - "servicea.local"

进行蓝绿发布更新后,可以看到更新后的服务列表,其中黄色的serviceA-v1表示当前的应用在蓝绿发布的过程中不会产生变化,serviceB-v1为老版本,serviceB-v2为新版本


7939953a0d6d6a8b19e9955c1be156da94acf80d

通过路由列表选择相应的权重管理,进行权重的调整,将serviceA-v1的权重调整为0,将serviceA-v2的权重调整为100,此时访问serviceB的网址可以发现。


<a href=https://yqfile.alicdn.com/83b14f2c118ca0812b33f35104fe5b0d04c2554a.png" >

验证完毕,点击确认发布完成,完成蓝绿发布。

后端服务的蓝绿发布

我们再看下如何做后端服务的蓝绿发布,也就是说对serviceA进行蓝绿发布。大致的结构图如下。


2703f2dbf237b3a36db30d3ab596b29ca815eb00

修改编排模板

serviceA-v2:
  image: 'registry-internal.cn-hangzhou.aliyuncs.com/ringtail/demo-service-a:2.0'
  labels:
    aliyun.scale: 3
    aliyun.routing.coexist: true
    aliyun.routing.port_5000: servicea.local
serviceB-v2:
  image: 'registry-internal.cn-hangzhou.aliyuncs.com/ringtail/demo-service-b:2.0'
  environment:
    - 'dep_endpoint=http://servicea.local'
  labels:
    aliyun.scale: 2
    aliyun.routing.coexist: true
    aliyun.routing.port_5001: serviceb
  external_links:
    - "servicea.local"

部署后的服务列表:


<a href=https://yqfile.alicdn.com/d7e3cd88f6e141ba5a932e77da4d7f7d7f2d0647.png" >

此时可以发现serviceB-v2在本次发布中不会进行变更,调整服务的权重


<a href=https://yqfile.alicdn.com/a47e7de9227a8cac1d2807158cc0497146c0f323.png" >

此时再访问serviceB的地址,可以得到如下的结果


280e2076dcd04aa275a92db71f6e6263e371dacf

总结

蓝绿发布是一种用于升级与更新的发布策略,对于增量升级有比较好的支持,但是对于涉及数据表结构变更等等不可逆转的升级,并不完全合适用蓝绿发布来实现,需要结合一些业务的逻辑以及数据迁移与回滚的策略才可以完全满足需求,希望给位开发者可以在自己的业务场景中,更灵活的使用和实现蓝绿发布。

附录

代码仓库地址:https://github.com/ringtail/BlueGreenDevelopment

个人简介

莫源,阿里云高级研发工程师。在加入阿里巴巴之前,先后在北京天方地圆科技有限公司、微软亚洲研究院任职。现主要负责阿里云容器服务产品的底层服务发现系统、集群管理系统的研发,从事容器的持续交付、持续集成的方案的设计与实现。在云计算、分布式系统、图像识别与虚拟现实方向有多年的开发经验。

相关实践学习
巧用云服务器ECS制作节日贺卡
本场景带您体验如何在一台CentOS 7操作系统的ECS实例上,通过搭建web服务器,上传源码到web容器,制作节日贺卡网页。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
2月前
|
jenkins 持续交付 开发者
自动化部署:使用Jenkins和Docker实现持续集成与交付
【8月更文挑战第31天】本文旨在为读者揭示如何通过Jenkins和Docker实现自动化部署,从而加速软件开发流程。我们将从基础概念讲起,逐步深入到实际操作,确保即使是初学者也能跟上步伐。文章将提供详细的步骤说明和代码示例,帮助读者理解并应用这些工具来优化他们的工作流程。
|
2月前
|
消息中间件 弹性计算 Kubernetes
RabbitMQ与容器化技术的集成实践
【8月更文第28天】RabbitMQ 是一个开源消息代理和队列服务器,用于在分布式系统中存储、转发消息。随着微服务架构的普及,容器化技术(如 Docker 和 Kubernetes)成为了部署和管理应用程序的标准方式。本文将探讨如何使用 Docker 和 Kubernetes 在生产环境中部署和管理 RabbitMQ 服务,同时保证高可用性和弹性伸缩能力。
39 3
|
4月前
|
前端开发 安全 数据库
Web架构&前后端分离站&Docker容器站&集成软件站&建站分配
Web架构&前后端分离站&Docker容器站&集成软件站&建站分配
187 1
|
2月前
|
运维 安全 Cloud Native
"揭秘!Trivy——云原生时代的隐形安全侠,一键扫描,让容器镜像漏洞无所遁形,守护你的云端帝国坚不可摧!"
【8月更文挑战第14天】在云原生时代,容器技术如Docker与Kubernetes大放异彩,加速了应用部署。但容器化的普及也带来了安全挑战,尤其是镜像的安全性至关重要。Trivy,一款高效且轻量级的镜像安全扫描工具应运而生,成为开发者与运维人员的得力助手。它由Aqua Security开发,支持一键式全面扫描,能快速检测镜像中的漏洞与配置风险,并提供修复建议。Trivy采用Go语言编写,轻巧高效,支持多平台,并可轻松集成到CI/CD流程中,确保只有安全的镜像才能部署到生产环境。无论新手还是专家,Trivy都是构建安全可靠云环境的理想选择。
54 2
|
2月前
|
存储 安全 测试技术
持续集成、交付和部署简介
持续集成、交付和部署简介
37 1
|
2月前
|
开发者 持续交付 Android开发
Xamarin开发者的秘密武器:如何通过持续集成与持续部署(CI/CD)实现高效、高质量的软件交付
【8月更文挑战第31天】在当今追求高效、高质量软件交付的时代,Xamarin开发者需像大厨般迅速烹制数字化佳肴,而持续集成(CI)与持续部署(CD)则是关键工具。CI要求开发者频繁将代码集成到共享仓库,利用自动化工具如Azure Pipelines或Jenkins自动编译、测试代码,确保质量。CD在此基础上进一步实现自动化部署,简化从开发到生产的全过程。借助如Visual Studio App Center这样的工具,Xamarin项目得以快速构建、测试并部署至Android和iOS平台,显著提升开发效率和代码质量,助力团队乘风破浪,驶向成功的彼岸。
28 0
|
2月前
|
前端开发 Java UED
JSF遇上Material Design:一场视觉革命,如何让传统Java Web应用焕发新生?
【8月更文挑战第31天】在当前的Web开发领域,用户体验和界面美观性至关重要。Google推出的Material Design凭借其独特的动画、鲜艳的颜色和简洁的布局广受好评。将其应用于JavaServer Faces(JSF)项目,能显著提升应用的现代感和用户交互体验。本文介绍如何通过PrimeFaces等组件库在JSF应用中实现Material Design风格,包括添加依赖、使用组件及响应式布局等步骤,为用户提供美观且功能丰富的界面。
33 0
|
3月前
|
存储 Kubernetes 负载均衡
云端应用容器化管理:全面深入评测与分析
阿里云ACK测评:提供一键式容器应用部署,集成ALB实现高效交付,但一键部署有时故障且高级配置需专业知识。操作界面直观,文档全面但对Helm等进阶主题指导不足。适合已有Kubernetes基础的用户,对于新手可能挑战较大。推荐给寻求云上容器管理解决方案的企业。
云端应用容器化管理:全面深入评测与分析
|
2月前
|
Kubernetes 监控 Shell
在K8S中,我们公司用户反应pod连接数非常多,希望看一下这些连接都是什么信息?什么状态?怎么排查?容器里面没有集成bash环境、网络工具,怎么处理?
在K8S中,我们公司用户反应pod连接数非常多,希望看一下这些连接都是什么信息?什么状态?怎么排查?容器里面没有集成bash环境、网络工具,怎么处理?
|
2月前
|
测试技术 持续交付 数据库
容器镜像解析问题之区分单元测试和集成测试如何解决
容器镜像解析问题之区分单元测试和集成测试如何解决
15 0

相关产品

  • 容器计算服务
  • 下一篇
    无影云桌面