定义
持续交付是开发人员,如何将一个好的点子,以最快的速度交付给用户的方法。
持续集成:开发反复提交-构建-测试的过程;
持续部署:可交付的产品快速且安全地交给用户使用的一套方法和系统;
通过统一标准、规范流程、工具化、自动化等的方式,影响着整个研发周期。
人(组织文化)+事(流程)+物(架构)。
DevOps是一种鼓励协作的研发文化,它的概念比持续交付更宽泛,持续交付是DevOps的一种工具和技术实现。
实践
拿Java中常用的maven来举例:
maven的原则:
最短路径优先,如果A依赖C,A依赖B,B依赖C,那么maven会使用A依赖的C的版本;
第一声明优先,如果A依赖B和C,B和C都依赖了D,那么maven会使用B依赖的版本。
实践:
- 不要在生产环境使用SNAPSHOT版本的包;
- 在父模块使用
dependencyManagment
来统一版本; - 对于一组依赖的控制,使用BOM来进行统一管理;
- 使用
properties
来减少重复劳动; - 不要在生产环境中使用
mvn install
命令,因为这个命令会导致真正需要的包被覆盖; - 禁止变更了代码不改版本号就上传到仓库。
集成分支上线后回滚,
1 | git fetch origin |
推动规范的完成:
- 代码以及依赖规范;
- 命名规范;
- 开发规范;
- 配置规范;
- 部署规范;
- 安全规范;
- 测试规范。
环境构建流水线:
可以通过OpenStack进行物理机和虚拟机的初始化工作,然后通过自动化的配置管理工具(Puppet、Chef、Ansible、SaltStack)安装一些基础软件,例如JDK和Tomcat等。如果采用资源池的方式,可以根据平时机器的使用情况预先分派一个资源池,省的从paas平台申请机器时还需要等待初始化。
云计算的三种模式:
- SaaS:软件即服务,提供用户所需要的一切应用;
- PaaS:平台即服务,提供了一个大的框架,包括中间件、操作系统、软件运行时环境等;
- Iaas:基础架构即服务,只提供网络,存储,虚拟化技术等底层,其他需要用户自助。
应用部署流水线:
- 单应用部署流水化;
- 应用部署并行;
- 流水线的容错机制:错误中断或者优先完成正常的,最后将错误的交给用户解决。
容器技术
统一了软件环境和软件代码。
- 交付结果一致;
- 交付自动化;
- 交付个性化;
- 交付版本控制。
构建提速
私有仓库
- createrepo:搭建CentOS的yum仓库;
- Nexus:Java的maven仓库;
- cnpm:NodeJS的npm仓库;
- pypiserver:Python的pip仓库;
- gitlab:代码仓库;
- Harbor:Docker镜像仓库。
Maven调优
- 合适堆内存;
-Dmaven.test.skip=true
跳过单元测试(-DskipTests
命令还会编译测试文件);- 构建过程异步检查和测试(Enforce检查,框架依赖检查,sona检查,单元测试,集成测试);
- 增量代码扫描;
- 发布阶段不使用snapshot版本的依赖;
- 使用
-T 2C
进行并行构建; -pl
参数局部构建;- 正确使用clean,在改了类型名或者删除了某些类的情况下可以使用该参数。
构建检测
maven enforcer
一款maven插件,使用如下:
1 | <build> |
通过继承pom的形式,定义公司或者bu的统一依赖管理。
参考携程的做法:
1 | corp pom |
对于一组依赖的控制,可以使用bom来统一管理依赖的公共组件。
参考enforcer插件的官网https://maven.apache.org/enforcer/enforcer-rules/index.html
以及扩展插件:http://www.mojohaus.org/extra-enforcer-rules/
CI工具
- Travis CI:基于Github的CI托管解决方案之一;
- Circle CI:基于Github,Bitbucket的云端持续集成方案;
- Jenkins CI:自动化驱动编译、测试、交付、部署。
容器镜像构建
- 选择合适的Base镜像
- 较少不必要的镜像层的产生
- 充分利用指令的缓存
Docker out Docker:在物理机上安装一个Docker daemon,所有的容器都在物理上运行;
Docker in Docker:在容器里安装一个Docker daemon,需要--privileged
参数取得真正的Root命令,docker官方提供了一个docker:dind镜像可以直接使用。
灰度发布
- 蓝绿发布:先增加一套新的集群,发布版本到新集群并验证,此时不介入外部流量,等验证通过以后再把流量引入新服务集群,等待一段时间没有异常以后,老版本服务集群下线。
- 滚动发布:从旧的集群中选出一批部署新应用,进行验证,验证完毕以后接入流量,然后依次重复部署;
- 金丝雀发布:从集群中挑选特定服务器或一小批符合条件的用户,对其进行版本更新验证,随后逐步更新。
发布系统
一张页面:展示尽可能详细和精准的数据和内容;
两个时态:
- 发布中:发布中内容,处理过程、结果、耗时、当前情况;
- 未发布时:历史发布进程,集群、服务器具体版本的情况;
两个按钮:
- 开始发布
- 中断发布
- 局部有错误时:中断或重试发布
- 发布被暂停时:中断或继续发布
三种发布结果:
- 成功
- 失败
- 中断
四类操作选择:
- 开始发布
- 停止发布
- 发布回退
- 发布重试
五个步骤:
- markdown-拉出集群,不接入新流量
- downland-下载代码包
- install-停止服务、替换代码、重启服务
- verify-启动检查、程序预热(异步)
- markup-拉回集群、接入流量
六个页面产物:
- 集群
- 示例
- 发布日志
- 发布历史
- 发布批次
- 发布操作
携程发布系统架构
Roll Engine:发布引擎,用于创建发布批次,按批次粒度实施部署策略,异步调用Salt Master服务,真正用于部署任务的是agent
监控
类型:
- 用户侧监控-访问速度和结果
- 网络监控-CDN与核心网络监控
- 业务监控-核心业务指标波动
- 应用监控-服务调用链、P99、错误量、JVM
- 系统监控-基础设置、虚拟机、操作系统
静态代码检查
SonarQube
提倡开发人员在开发环境中执行静态检查。
服务端环境:Sonar服务+CheckStyle插件
开发端环境:Idea-SonarLint插件
maven命令:mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.2:sonar -f ./pom.xml -Dsonar.host.url=sonar 服务器地址 -Dsonar.login= 账号名称 -Dsonar.password= 账号密码 -Dsonar.profile= 检查规则的集合 -Dsonar.global.exclusions= 排除哪些文件 -Dsonar.branch= 检查的分支
集成GitLab:在Merge Request中增加Sonar环节,包括检查状态和结果等。
破坏性测试
- 严格设计和执行破坏性测试的手段和过程;
- 权衡破坏性测试的量和度。
混沌工程
步骤:
- 正常系统行为的可测量数据-稳定态
- 对照组:假定对照组-实验组都是稳定态
- 引入真实世界变量-断网、磁盘损坏、服务器崩溃
- 对比对照组和实验组,找出系统弱点
高级原则:
- 真实场景
- 生产环境
- 自动化连续实现
- 最小爆破半径
Chaos Monkey
Netflix对于混沌工程的先驱实践,随机杀死一些服务制造混乱
测试
Mock
- 测试用例独立
- 提升测试执行速度
- 提高测试用例准备效率-无需考虑依赖端情况
基于对象和类的Mock:Mockito或者EasyMock,在运行时为每一个被Mock的对象或类动态生成一个代理对象适合DAO层数据库操作和复杂逻辑
基于微服务的Mock:Weir Mock和Mock Server,模拟API、http形式对象:
- 标记被代理的类或对象,或声明被代理的服务
- 通过Mock框架定制代理的行为
- 调用代理,从而获得预期的结果
回放
方案一:在统一的SLB上做统一的拦截和复制转发处理,容易产生生产链路的故障
方案二:在集群中新增一台服务器,启动一个软交换,由该软交换负责复制和转发用户请求
移动APP
静态检查
- Clang Static Analyzer:被Xcode集成
- OCLint
- Infer
Android热修复:
百川hHotFix、美团Robust、手机QQ空间、微信Thinker
IOS热修复:
- Rollout.io、JSPatch、DynamicCocoa,只针对IOS
- React Native(FaceBook)、Weex(Alibaba),跨平台热更新
- Wax、Hyrid,前者用Lua语言,比较适合游戏,Hybrid主要面向H5
Jenkins实践
Jenkins Pipeline:运行在Jenkins上的一个工作流框架,支持将原先运行在一个或多个节点的任务通过一个Groovy脚本串联起来,以实现之前单个任务难以完成的复杂工作流
- 安装Jenkins
- 配置Jenkins对GitLab的访问权限-配置Jenkins钥匙-凭据-系统-全局凭据-添加凭据,添加私钥
- 配置gitlab或者github的公钥
- 安装GitLab plugin
- 选择GitLab API Token,将GitLab的
/profile/personal_access_tokens
这个api生成的access token保存到GitLab API Token
创建Jenkins Pipeline任务:
GitLab项目-settings—>intergrations—>Merge request events
settings—>Merge Request—>Only allow Merge Requests to be merge if the pipeline succeeds
贴入代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26node {
def mvnHome
# 修改 Merge Request 的状态,并 checkout 代码
stage('Preparation') { // for display purposes
mvnHome = tool 'M3'
updateGitlabCommitStatus name: 'build', state: 'running'
checkout scm
}
# 执行 Maven 命令对项目编译和打包
stage('Build') {
echo 'Build Start'
// Run the maven build
sh "'${mvnHome}/bin/mvn' -Dmaven.test.skip=true clean package"
}
# 启动 sonar 检查,允许 junit 单元测试,获取编译产物,并更新 Merge request 的状态
stage('Results') {
// Run sonar
sh “'${mvnHome}/bin/mvn' org.sonarsource.scanner.maven:sonar-maven-plugin:3.2:sonar”
junit '**/target/surefire-reports/TEST-*.xml'
archive 'target/*.war'
updateGitlabCommitStatus name: 'build', state: 'success'
}
}对于Docker镜像,在上面的检查结束以后,还需要在检查以后安装Centos软件以及搭建Tomcat等容器运行环境。
对于IOS应用,需要指定应用在Mac Slave的Jenkins中进行编译构建。
企业级持续交付方案推荐:
代码管理:GitLab
构建打包:Jenkins
自动部署:Ansible
Web管理界面:Ansible Tower
交付平台:Spinnaker