运维

5-4 持续集成与持续部署

2020-04-15  本文已影响0人  ioufev

5-4 持续集成与持续部署

课程介绍

那些大厂们,天天DevOps、持续集成的?到底在讲些什么?这堂课来给你揭开持续集成与持续部署的面纱!!没有什么难的,盘它!

传统的开发过程中的坑:

image.png

你有没有想过/用过?当你哪一天...

持续集成解决了什么问题?

课程的主要内容:

环境准备:

持续集成

核心概念

集成,就是一些孤立的事物或元素通过某种方式集中在一起,产生联系,从而构成一个有机整体的过程。知识经济的社会,集成已经成了很重要的一个名词。各行各业基本都会用到集成。比如汽车行业,那么复杂的一台跑车愣是通过一大堆零件组装起来。对于这些传统行业,它们在研发成功以后,可以通过流水线的方法批量生产进行集成。而在软件行业中,集成并不是一个简单的“搬箱子”的过程。因为软件工业是一个知识生产活动,其内在逻辑非常复杂,需求又很难一次性确定,完成的产品与最初的设计往往相差很远。敏捷宣言中就有一条是说响应变化重于遵循计划。而且由于软件行业的迅猛发展,软件变的越来越复杂,单靠个人是根本无法完成。大型软件为了重用及解耦,往往还需要分成好几个模块,这样集成就成了软件开发中不可或缺的一部分。

持续,不言而喻,就是指长期的对项目代码进行集成。

持续集成

持续集成(英文:Continuous Integration,简称CI)

在软件工程中,持续集成是指将所有开发者工作副本每天多次合并到主干的做法。

Grady Booch 在1991年的 Booch method 中首次命名并提出了 CI 的概念,尽管在当时他并不主张每天多次集成。而 XP(Extreme programming,极限编程)采用了 CI 的概念,并提倡每天不止一次集成。

在《持续集成》一书中,对持续集成的定义如下:持续集成是一种软件开发实践。在持续集成中,团队成员频繁集成他们的工作成果,一般每人每天至少集成一次,也可以多次。每次集成会经过自动构建(包括自动测试)的检验,以尽快发现集成错误。自从在团队中引入这样的实践之后,Martin Fowler发现这种方法可以显著减少集成引起的问题,并可以加快团队合作软件开发的速度。

image.png

持续集成强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起。

对于一天需要集成多少次数,并没有一个明确的定义。一般就是按照自己项目的实际需要来设置一定的频率,少则可能几次,多则可能达几十次。可以设置按照代码的变更来触发集成,或者设置一个固定时间周期来集成,也可以手工点击集成的按钮来“一键集成”。

持续交付

持续交付(英文:Continuous Delivery,简称CD)

完成 CI 中构建及单元测试和集成测试的自动化流程后,持续交付可自动将已验证的代码发布到存储库。为了实现高效的持续交付流程,务必要确保 CI 已内置于开发管道。持续交付的目标是拥有一个可随时部署到生产环境的代码库。

image.png

在持续交付中,每个阶段(从代码更改的合并,到生产就绪型构建版本的交付)都涉及测试自动化和代码发布自动化。在流程结束时,运维团队可以快速、轻松地将应用部署到生产环境中。

比如,我们完成单元测试后,可以把代码部署到连接数据库的 Staging 环境中更多的测试。如果代码没有问题,可以继续手动部署到生产环境中。

持续部署

持续部署(英文:Continuous Deployment,简称CD)

对于一个成熟的 CI/CD 管道来说,最后的阶段是持续部署。作为持续交付——自动将生产就绪型构建版本发布到代码存储库——的延伸,持续部署可以自动将应用发布到生产环境。由于在生产之前的管道阶段没有手动门控,因此持续部署在很大程度上都得依赖精心设计的测试自动化。

image.png

实际上,持续部署意味着开发人员对应用的更改在编写后的几分钟内就能生效(假设它通过了自动化测试)。这更加便于持续接收和整合用户反馈。总而言之,所有这些 CI/CD 的关联步骤都有助于降低应用的部署风险,因此更便于以小件的方式(而非一次性)发布对应用的更改。不过,由于还需要编写自动化测试以适应 CI/CD 管道中的各种测试和发布阶段,因此前期投资还是会很大。

持续部署则是在持续交付的基础上,把部署到生产环境的过程自动化

持续集成组成要素

一个最小化的持续集成系统需要包含以下几个要素:

  1. 版本管理系统:项目的源代码需要托管到适合的版本管理系统中,一般我们使用git作为版本控制库,版本管理软件可以使用github、gitlab、stash等。
  2. 构建脚本&工具:每个项目都需要有构建脚本来实现对整个项目的自动化构建。比如Java的项目就可以使用gradle作为构建工具。通过构建工具实现对编译、静态扫描、运行测试、样式检查、打包、发布等活动串起来,可以通过命令行自动执行。
  3. CI服务器:CI服务器可以检测项目中的代码变动,并及时的通过构建机器运行构建脚本,并将集成结果通过某种方式反馈给团队成员。

应用场景

工作流

传统的工作流

参与人员:开发、项目经理、测试

主要流程:

这也是传统的瀑布式开发模型,请参考:软件开发模式对比(瀑布、迭代、螺旋、敏捷)

带来的问题:

  1. 重复性劳动,无效的等待变多

    重复的进行发布部署。

    流程上:有可能开发在等集成其他人的模块;测试人员在等待开发人员修复 Bug;产品经理在等待新版本上线好给客户做演示;项目经理在等待其他人提交代码。不管怎么样,等待意味低效。

    自动化部署工作可以解放了集成、测试、部署等重复性劳动,而且机器集成的频率明显可以比手工的高很多。

  2. 很晚才发现缺陷,并且难以修复

    实践证明,缺陷发现的越晚,需要修复的时间和精力也就越大。从上一个可工作的软件到发现缺陷之间可能存在很多次提交,而要从这些提交中找出问题并修复的成本会很大,因为开发人员需要回忆每个提交的上下文来评估影响点。

  3. 低品质的软件,软件交付时机无法保障

    由于集成时每次包含的代码很多,所以大家的关注点主要都是如何保证编译通过、自动化测试通过,而往往很容易忽略代码是否遵守了编码规范、是否包含有重复代码、是否有重构的空间等问题。而这些问题又反过来会影响今后的开发和集成,久而久之集成变得越来越困难,软件的质量可想而知。

  4. 项目缺少可见性

    某些项目,程序会经常需要变更,特别是敏捷开发的实践者。由于产品经理在与客户交流过程中,往往实际的软件就是最好的原型,所以软件会被当作原型作为跟客户交流的工具。当然,客户最希望的当然是客户的想法能够马上反映到原型上,这会导致程序会经常被修改的。那么也就意味着“分配 Bug -> 修改 Bug -> 集成代码 -> 部署到测试服务器上 -> 集成测试”工作无形又爆增了。

常见的工作流

image.png

该系统的各个组成部分是按如下顺序来发挥作用的:

  1. 开发者检入代码到源代码仓库。

  2. CI系统会为每一个项目创建了一个单独的工作区。当预设或请求一次新的构建时,它将把源代码仓库的源码存放到对应的工作区。

  3. CI系统会在对应的工作区内执行构建过程。

  4. 配置如果存在)构建完成后,CI系统会在一个新的构件中执行定义的一套测试。完成后触发通知(Email,RSS等等)给相关的当事人。

  5. 配置如果存在)如果构建成功,这个构件会被打包并转移到一个部署目标(如应用服务器)或存储为软件仓库中的一个新版本。软件仓库可以是CI系统的一部分,也可以是一个外部的仓库,诸如一个文件服务器或者像Java.net、SourceForge之类的网站。

  6. CI系统通常会根据请求发起相应的操作,诸如即时构建、生成报告,或者检索一些构建好的构件。

“You build it, you run it”,这是 Amazon 一年可以完成 5000 万次部署,平均每个工程师每天部署超过 50 次的核心秘籍。

解决的问题

常见问题

  1. 思维转变后,新技术抵触

    • 无法接受新事物:不管怎么样,求稳心态的人还是多。总是有人认为老的技术代表稳定,新的事物往往会带来问题。
    • 认为手工集成也没有多少工作量:不是所有的人都参与到了整个持续集成的环节,所以没有办法认识到问题全貌。

    针对这个问题,可以通过设置一定的持续集成技术培训、宣讲得到改观

  2. 管理层的抵触

    • 培训持续集成需要投入资金啊,没钱。
    • 持续集成服务器要增加软硬件成本啊,没钱。
    • 开发人员领了那么高的工资,多干活多加班应该啊。

    针对这一点,可以从开发人员的成本和持续集成的投入(软硬件)的成本上两者做下估算。

    硬件参考:

    Jenkins主服务器一般2C4G,slave服务器根据生产需要进行选购。

    git服务器一般2C4G(10人团队)

    Docker服务器8C32G(Rancher + harbor)

  3. 生产环境的复杂

    • 比如部署的生成环境是在政务外网,无法从互联网直接访问等。
    • 构建效率低下,任务多

    目前,这个是最麻烦的,还在研究中。初步设想是让政务外网开辟一个白名单,给持续集成服务器设置一个单独的通道。只是思路,未验证。

最佳实践

实施持续集成的开发人员可以尽早并经常提交。这允许他们尽早发现冲突。并且,如果存在任何问题,则使用较小的提交可以更轻松地对代码进行故障排除。每天或甚至更频繁地提交软件对于持续集成是必要的,但还不够。

要成功使用持续集成,团队必须:

效率工具对比

image.png

点击查看效率工具

1. Jenkins

Jenkins,原名Hudson,2011年改为现在的名字,它 是一个开源的实现持续集成的软件工具。官方网站:http://jenkins-ci.org/

Jenkins 能实时监控集成中存在的错误,提供详细的日志文件和提醒功能,还能用图表的形式形象地展示项目构建的趋势和稳定性

Jenkins特点:

Jenkins优点:

Jenkins缺点:

2. Travis CI

Travis CI是一个托管的持续集成服务,用于构建和测试在GitHub上托管的软件项目。

Travis CI is a hosted continuous integration service used to build and test software projects hosted at GitHub

Travis CI的特点:

Travis CI优点:

Travis CI缺点:

3. Circle CI

在GitHub或Bitbucket上的软件存储库被授权并作为项目添加到circleci.com之后,每个代码更改都会在干净的容器或VM中触发自动化测试。

CircleCI在2017年被Forrester评为持续集成领导者,并被命名为多个最佳DevOps工具列表。CircleCI成立于2011年,总部位于旧金山,拥有全球性的远程员工队伍,由Scale Venture Partners,DFJ,Baseline Ventures,Top Tier Capital,Industry Ventures,Heavybit和Harrison Metal Capital提供风险投资。

Circle CI的特点:

CircleCI优点:

CircleCI缺点:

总结一下:

分类 Jenkins Travis CI Circle CI
本地部署 支持 不支持 支持
REST API 支持 支持 支持
配置 复杂,高度可配置 YAML文件 YAML文件
按需安装
跨平台支持 Linux + MacOS Linux + MacOS(付费)
多服务器 按需
快速构建 手动配置复杂 快(需要写配置文件) 最快
基本环境 Java 云环境 云环境
费用 免费 特定免费(69$/c) 特定免费(50$/c)

Travis CI的价格(非常感人):

image.png

CirCle CI的价格:

image.png

其他的一些持续集成的工具:CruiseControl,TeamCity,Continuum等

Jenkins

使用简介

Jenkins是开源CI&CD软件领导者, 提供超过1000个插件来支持构建、部署、自动化, 满足任何项目的需要。

image.png

相关概念:

image.png

Jenkins的界面

image.png

任务详情页面

image.png

Jenkins任务日志

安装方式

  1. 环境要求

    • 机器要求:
      • 256 MB 内存,建议大于 512 MB
      • 10 GB 的硬盘空间(用于 Jenkins 和 Docker 镜像)
    • 需要安装以下软件:
      • Java 8 ( JRE 或者 JDK 都可以)
      • Docker (导航到网站顶部的Get Docker链接以访问适合您平台的Docker下载)
  2. 常规安装

    • 安装JDK

      官方地址

      下载对应的操作系统的JDK,然后解压进行安装。以Linux为例:

      下载最新版本,上传到Linux服务器

      # 上传到 /opt/jdk8目录下
      
      # tar解压JDK安装包
      mkdir -p /opt/jdk8
      tar zxvf jdk-8u211-linux-x64.tar.gz -C /opt/jdk8 --strip-components 1
      
      # vi /etc/profile
      export JAVA_HOME=/opt/jdk8
      export JRE_HOME=${JAVA_HOME}/jre
      export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
      export PATH=${JAVA_HOME}/bin:$PATH
      
    • 安装Jenkins

      下载Jenkins最新的war包:Latest

      mkdir -p /opt/jenkins && cd /opt/jenkins
      
      wget -O /opt/jenkins/jenkins.war http://mirrors.jenkins.io/war-stable/latest/jenkins.war
      
      java -jar jenkins.war --httpPort=8080
      

      就嗯可以打开,http://localhost:8080

      注意一段这样的话:

      *************************************************************
      *************************************************************
      *************************************************************
      
      Jenkins initial setup is required. An admin user has been created and a password generated.
      Please use the following password to proceed to installation:
      
      63196690ae7d47c49506480ee0e1af4a
      
      This may also be found at: /root/.jenkins/secrets/initialAdminPassword
      
      *************************************************************
      *************************************************************
      *************************************************************
      

      这里的63196690ae7d47c49506480ee0e1af4a就是初始的安装的管理员密码。

  3. 使用Docker安装

    • 安装Docker

      # From https://get.docker.com:
      curl -fsSL https://get.docker.com -o get-docker.sh
      sh get-docker.sh
      
      #From https://test.docker.com:
      curl -fsSL https://test.docker.com -o test-docker.sh
      sh test-docker.sh
      
      # From the source repo (This will install latest from the test channel):
      sh install.sh
      
    • 配置Docker镜像加速,使用阿里云容器加速服务

      左侧的加速器帮助页面就会显示为你独立分配的加速地址

      例如:
      公网Mirror:[系统分配前缀].mirror.aliyuncs.com
      

      使用配置文件 /etc/docker/daemon.json(没有时新建该文件)

      {
          "registry-mirrors": ["<your accelerate address>"]
      }
      

      重启Docker Daemon就可以了

      systemctl daemon-reload
      systemctl restart docker
      

      docker ps 查看容器运行状态

      docker logs 容器ID/容器名称 查看管理员初始密码

    • 安装Docker-compose.yml文件(可选)

      安装方法:

      #下载
      sudo curl -L https://github.com/docker/compose/releases/download/1.20.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
      #安装
      chmod +x /usr/local/bin/docker-compose
      #查看版本
      docker-compose --version
      
  1. 配置Jenkins插件加速

    进入jenkins系统管理->插件管理中->高级选项卡->升级站点,使用清华源:

    https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/current/update-center.json
    
image.png image.png

关于官方所有的镜像列表:

http://mirrors.jenkins-ci.org/status.html

  1. 环境配置

    • Jenkins 的URL路径
    • 全局工具的配置:Docker, JDK(JAVA)...
  2. 用户权限配置

    • 矩阵权限的配置
    • 添加管理员用户所有的权限
    • 添加Authorize Project插件,并且在系统管理中进行配置。配置逻辑,就给用户当前项目的矩阵权限!
  3. 与gitlab进行联接

    • 设置一个SSH Key,方便Jenkins去拉取Gitlab中的项目
    • GItlab项目中去配置SSH Key的Deploy权限。Settings -> Repository -> Deploy keys -> Public Deploy Keys
    • Jenkins添加SSH的私钥

    这样就完成了Jenkins可以访问gitlab的联接的过程。

    Jenkins层面,需要去安装Gitlab相关插件。

插件介绍

​ 该插件可以读取和解析测试框架输出的报告,并且在 Jenkins 上绘制性能和稳定性相关的图表。Performance Plugin 支持的测试框架有 JUnit、JMeter, Twitter 的 Lago 和 Taurus。下图是该插件输出的示例图:

image.png

https://plugins.jenkins.io/performance

​ Gitlab Merge Request Builder Plugin 可以方便的自动发起代码审查,它在创建 pull request 的时候,会自动带上关联任务的运行结果,以方便代码审查着确认改动的正确性。

​ 同时,这款插件还支持自动合并,既在代码审查通过后自动合并该 pull request 内容。

https://github.com/timols/jenkins-gitlab-merge-request-builder-plugin

​ JIRA Plugin 可以让 Jenkins 任务和 JIRA 集成起来,这样项目管理者可以通过 JIRA 了解项目进度,开发者也可以通过该插件直接更改 JIRA 上的 issue 状态。

https://plugins.jenkins.io/jira

​ 和最近大热的容器编排框架 Kubernetes 集成当然不能落下了。另外,Jenkins 对执行机的管理一直比较弱,无法做到快速的扩容和缩容。Kubernetes Plugin 通过引入 Kubernetes 的容器编排能力,让 Jenkins 执行机运行在 Kubernetes 环境中。

https://github.com/jenkinsci/kubernetes-plugin

​ 对一个系统的持续集成会包含很多个方面,如果将它们都杂糅在一个 Jenkins 任务中,会提高排查成本,也不利于整个持续集成的运作。Build Pipeline plugin 可以让项目管理员针对系统持续集成步骤设置一系列关联的任务,任务之间可以设置不同的触发条件,以确认何时需要人工介入。该插件可以让整个持续集成流程变得非常直观:

image.png

https://github.com/jenkinsci/build-pipeline-plugin

配置自动化任务

两种执行方法:

  1. 配置自由风格的项目
  2. 配置Pipeline使用Jenkinsfile

需要注意的地方

其他的一些用法:

把构建、打包的工作放在Docker容器里面,用于应对不同的开发环境需求(node8,node10等)

前端项目中的应用

插件推荐:

Jenkins发布到Nginx Docker容器:

# !bin/bash
node -v
cnpm install
npm run build
ls -la
if [ "$(docker inspect -f '{{.State.Running}}' nginx)" = "true" ]; then
    docker stop nginx && docker rm nginx;
fi

docker run -itd --name nginx -v `pwd`/dist:/usr/share/nginx/html -p 20000:80 nginx

Pipleline演示:

pipeline {
  agent {
    docker {
      image 'node:10'
      args '-p 20000:8080'
    }

  }
  stages {
    stage('Build') {
      steps {
        sh 'yarn install'
      }
    }
    stage('Deploy') {
      steps {
        sh './scripts/deploy.sh'
        input 'Finished using the web site? (Click "Proceed" to continue)'
        sh './scripts/kill.sh'
      }
    }
  }
}

deploy.sh文件

#!/usr/bin/env sh
set -x
npm run serve &
sleep 1
echo $! > .pidfile
set +x

echo 'Now...'
echo 'Visit http://localhost:8080 to see your Node.js/Vue application in action.'

set命令用法:

set指令能设置所使用shell的执行方式,可依照不同的需求来做设置
 -a  标示已修改的变量,以供输出至环境变量。
 -b  使被中止的后台程序立刻回报执行状态。
 -C  转向所产生的文件无法覆盖已存在的文件。
 -d  Shell预设会用杂凑表记忆使用过的指令,以加速指令的执行。使用-d参数可取消。
 -e  若指令传回值不等于0,则立即退出shell。  
 -f   取消使用通配符。
 -h  自动记录函数的所在位置。
 -H Shell  可利用"!"加<指令编号>的方式来执行history中记录的指令。
 -k  指令所给的参数都会被视为此指令的环境变量。
 -l  记录for循环的变量名称。
 -m  使用监视模式。
 -n  只读取指令,而不实际执行。
 -p  启动优先顺序模式。
 -P  启动-P参数后,执行指令时,会以实际的文件或目录来取代符号连接。
 -t  执行完随后的指令,即退出shell。
 -u  当执行时使用到未定义过的变量,则显示错误信息。
 -v  显示shell所读取的输入值。
 -x  执行指令后,会先显示该指令及所下的参数。

+<参数>  取消某个set曾启动的参数。

kill.sh文件:

#!/usr/bin/env sh

echo 'The following command terminates the "npm run serve" process using its PID'
echo '(written to ".pidfile"), all of which were conducted when "deloy.sh"'
echo 'was executed.'
set -x
kill $(cat .pidfile)

思路:

  1. 使用一台单独的Nginx服务器发布,使用Publish Over SSH插件上传
  2. 使用Docker在本地发布或者远程发布
  3. 使用Dockerfile进行镜像内的构建,使用docker镜像进行发布

TravisCI

使用简介

Travis CI 只支持 Github,不支持其他代码托管服务。这意味着,你必须满足以下条件,才能使用 Travis CI。

  • 拥有 GitHub 帐号
  • 该帐号下面有一个项目
  • 该项目里面有可运行的代码
  • 该项目还包含构建或测试脚本

Travis简单的使用步骤:

github授权及面板

首先,访问官方网站 travis-ci.org,点击右上角的个人头像,使用 Github 账户登入 Travis CI。

会进入到授权页面,这里跟微博、QQ是一回事,主要是读取你的用户信息。

image.png

这里第二步在,Dashboard这个选项卡中,点击Activate这个按钮

image.png

完了之后,Dashboard会列出所有Github中有.travis.yml配置文件的仓库:

image.png

Travis 会列出 Github 上面你的所有仓库,以及你所属于的组织。此时,选择你需要 Travis 帮你构建的仓库,打开仓库旁边的开关。一旦激活了一个仓库,Travis 会监听这个仓库的所有变化。

image.png image.png image.png

获取github的token

在settings->Developer settings->Personal access tokens->Generate new token

image.png

配置项目的.travis.yml文件

完整的生命周期,从开始到结束是下面的流程。

  1. before_install
  2. install
  3. before_script
  4. script
  5. aftersuccess or afterfailure
  6. [OPTIONAL] before_deploy
  7. [OPTIONAL] deploy
  8. [OPTIONAL] after_deploy
  9. after_script

参考资料:

配置Node.js应用

配置一个Vue实例并发布到github pages

.travis.yml文件:

language: node_js
node_js:
  - "10"

# Travis-CI Caching
cache:
  directories:
    - node_modules

# S: Build Lifecycle
install:
  - yarn install

before_script:

# 无其他依赖项所以执行npm run build 构建就行了
script:
  - npm run build

deploy:
    # 其他的一些配置项,可以参考:https://docs.travis-ci.com/user/deployment/pages/
  provider: pages
  skip_cleanup: true
  local_dir: dist/
  github_token: $GITHUB_TOKEN # Set in the settings page of your repository, as a secure variable
  keep_history: false
  on:
    branch: master

CircleCI

使用简介

  1. 注册 CircleCI

    打开 CircleCI 官方网站,使用您的GitHub帐户登录。

image.png

进行授权:

image.png
  1. 启动存储库

检查要在 CircleCI 上管理的存储库的开关按钮。

image.png
  1. 编写 config.yml

    version: 2
    jobs:
      build:
        docker:
          ...
        branches:
          ...
        steps:
          ...
         environment:
             ...
    

    官方参考文档:https://circleci.com/docs/2.0/configuration-reference/#version

来看一个完事版的配置

version: 2
jobs:
  build:
    docker:
      - image: ubuntu:14.04

      - image: mongo:2.6.8
        command: [mongod, --smallfiles]

      - image: postgres:9.4.1
        # some containers require setting environment variables
        environment:
          POSTGRES_USER: root

      - image: redis@sha256:54057dd7e125ca41afe526a877e8bd35ec2cdd33b9217e022ed37bdcf7d09673

      - image: rabbitmq:3.5.4

    environment:
      TEST_REPORTS: /tmp/test-reports

    working_directory: ~/my-project

    steps:
      - checkout

      - run:
          command: echo 127.0.0.1 devhost | sudo tee -a /etc/hosts

      # Create Postgres users and database
      # Note the YAML heredoc '|' for nicer formatting
      - run: |
          sudo -u root createuser -h localhost --superuser ubuntu &&
          sudo createdb -h localhost test_db

      - restore_cache:
          keys:
            - v1-my-project-{{ checksum "project.clj" }}
            - v1-my-project-

      - run:
          environment:
            SSH_TARGET: "localhost"
            TEST_ENV: "linux"
          command: |
            set -xu
            mkdir -p ${TEST_REPORTS}
            run-tests.sh
            cp out/tests/*.xml ${TEST_REPORTS}

      - run: |
          set -xu
          mkdir -p /tmp/artifacts
          create_jars.sh ${CIRCLE_BUILD_NUM}
          cp *.jar /tmp/artifacts

      - save_cache:
          key: v1-my-project-{{ checksum "project.clj" }}
          paths:
            - ~/.m2

      # Save artifacts
      - store_artifacts:
          path: /tmp/artifacts
          destination: build

      # Upload test results
      - store_test_results:
          path: /tmp/test-reports

  deploy-stage:
    docker:
      - image: ubuntu:14.04
    working_directory: /tmp/my-project
    steps:
      - run:
          name: Deploy if tests pass and branch is Staging
          command: ansible-playbook site.yml -i staging

  deploy-prod:
    docker:
      - image: ubuntu:14.04
    working_directory: /tmp/my-project
    steps:
      - run:
          name: Deploy if tests pass and branch is Master
          command: ansible-playbook site.yml -i production

workflows:
  version: 2
  build-deploy:
    jobs:
      - build:
          filters:
            branches:
              ignore:
                - develop
                - /feature-.*/
      - deploy-stage:
          requires:
            - build
          filters:
            branches:
              only: staging
      - deploy-prod:
          requires:
            - build
          filters:
            branches:
              only: master
  1. 设置/查看任务
image.png

配置Node.js应用

.circleci/config.yml配置文件

version: 2
jobs:
  build:
    docker:
      - image: circleci/node:10
    branches:
      only:
        - master
    steps:
      - add_ssh_keys:
          fingerprints:
            - "c5:20:8e:79:81:19:fd:c1:6c:c4:fb:41:58:92:9d:4f"
      - checkout
      - restore_cache:
          keys:
            # fallback to using the latest cache if no exact match is found
            - dependencies-
      - run:
          name: Install
          command: yarn install
      - save_cache:
          paths:
            - node_modules
          key: dependencies-
      - run:
          name: build github pages
          command: yarn build
      - run:
          name: Prepare shell commands
          command: chmod +x scripts/deploy.sh
      - run:
          name: Run deploy scripts
          command: ./scripts/deploy.sh

这里以发布到github page为示例:

deploy.sh文件的内容:

#!/bin/sh
# ideas used from https://gist.github.com/motemen/8595451

# Based on https://github.com/eldarlabs/ghpages-deploy-script/blob/master/scripts/deploy-ghpages.sh
# Used with their MIT license https://github.com/eldarlabs/ghpages-deploy-script/blob/master/LICENSE

# abort the script if there is a non-zero error
set -e

# show where we are on the machine
pwd
remote=$(git config remote.origin.url)

echo 'remote is: '$remote

# make a directory to put the gp-pages branch
mkdir gh-pages-branch
cd gh-pages-branch
# now lets setup a new repo so we can update the gh-pages branch
git config --global user.email "$GH_EMAIL" > /dev/null 2>&1
git config --global user.name "$GH_NAME" > /dev/null 2>&1
git init
git remote add --fetch origin "$remote"

echo 'email is: '$GH_EMAIL
echo 'name is: '$GH_NAME
echo 'sitesource is: '$siteSource

# switch into the the gh-pages branch
if git rev-parse --verify origin/gh-pages > /dev/null 2>&1
then
    git checkout gh-pages
    # delete any old site as we are going to replace it
    # Note: this explodes if there aren't any, so moving it here for now
    git rm -rf .
else
    git checkout --orphan gh-pages
fi

# copy over or recompile the new site
cp -a "../${siteSource}/." .

ls -la

# stage any changes and new files
git add -A
# now commit, ignoring branch gh-pages doesn't seem to work, so trying skip
git commit --allow-empty -m "Deploy to GitHub pages [ci skip]"
# and push, but send any output to /dev/null to hide anything sensitive
git push --force --quiet origin gh-pages
# go back to where we started and remove the gh-pages git repo we made and used
# for deployment
cd ..
rm -rf gh-pages-branch

echo "Finished Deployment!"

说明:

>/dev/null 2>&1的含义

文件描述符

当执行shell命令时,会默认打开3个文件,每个文件有对应的文件描述符来方便我们使用:

类型 文件描述符 默认情况 对应文件句柄位置
标准输入(standard input) 0 从键盘获得输入 /proc/slef/fd/0
标准输出(standard output) 1 输出到屏幕(即控制台) /proc/slef/fd/1
错误输出(error output) 2 输出到屏幕(即控制台) /proc/slef/fd/2

> 代表重定向到哪里?

例如:echo "123" > /home/123.txt
1 表示stdout标准输出,系统默认值是1,所以>/dev/null等同于1>/dev/null
2 表示stderr标准错误
& 表示等同于的意思,2>&1,表示2的输出重定向等同于1

参考资料:

Shell脚本———— /dev/null 2>&1详解

shell中>/dev/null 2>&1

Linux Shell 1>/dev/null 2>&1 含义

扩展知识

自动化流程的发展趋势

  1. 集中化

    以集群为基础,服务采用Saas方式进行交付。所有折构建、测试、发布全集中进行管理。

  2. 微服务+无服务的应用模式

    应用程序执行环境的管理被新的编程模型和平台取代后,团队的交付生产率得到了进一步的提升。一方面它免去了很多环境管理的工作,包括设备、网络、主机以及对应的软件和配置工作,使得软件运行时环境更加稳定。另一方面,它大大降低了团队采用DevOps的技术门槛。

    无服务器风格的架构(Serverless architecture)把DevOps技术在微服务领域的应用推向极致。当应用程序执行环境的管理被新的编程模型和平台取代后,团队的交付生产率得到了进一步的提升。一方面它免去了很多环境管理的工作,包括设备、网络、主机以及对应的软件和配置工作,使得软件运行时环境更加稳定。另一方面,它大大降低了团队采用DevOps的技术门槛。

    在微服务端到端交付流程上,Netflix开源了自家的Spinnaker,Netflix作为微服务实践的先锋,不断推出新的开源工具来弥补社区中微服务技术和最佳实践的缺失。而Spring Cloud则为开发者提供了一系列工具,以便他们在所熟悉的Spring技术栈下使用这些服务协调技术(coordination techniques),如服务发现、负载均衡、熔断和健康检查。

  3. 人工智能领域的应用

    DevOps的最早实践来自于互联网企业的Web应用,相应的思想被引入企业级应用并促进了一系列工具的发展。在人工智能领域,TensorFlow就是这样一个例子,它可以有多种DevOps友好的安装和部署方式 ,例如采用Docker进行部署。

    随着Python在大数据、人工智能、区块链、微服务以及Docker中的发展,可以预见Python在日后的领域仍然会发挥重要的作用。

  4. 安全推动DevOps的发展

    全是DevOps永远绕不开的话题,也往往是新技术在传统行业(例如金融和电信)应用中的最大阻碍。一方面,组织结构的转型迫使企业要打破原先的部门墙,这意味着很多原先的控制流程不再适用。另一方面,由于大量的DevOps技术来源于开源社区,缺乏强大技术实力的企业在应用相关技术时不免会有所担忧。

  5. Windows平台下.net的技术潜力巨大

    长期以来,Windows和.NET平台下的DevOps一直都是一个被低估的领域。一方面,社区缺乏对 Windows Server平台的兴趣。另一方面,Windows Server却有接近90%的市场占用率,在Web服务器领域则有33.5%的市场占有率

  6. 非功能性自动化测试工具逐渐完善

    自动化测试水平往往是衡量DevOps技术能力高低的重要指标,尤其是针对生产环境应用程序的非功能性自动化测试工具。一直以来,技术雷达都在尝试从不同的角度宣扬自动化测试的重要性,从软件的开发阶段延展到了整个应用生命周期甚至整体IT资产的管理上。

复杂的DevOps相关工具

DevOps

Jenkins的一些应用场景

打包平台:

使用Jenkins搭建iOS/Android

测试平台:

jenkins + python + selenium

Jmeter+maven+Jenkins构建云性能测试平台

Jenkins+PMD构建自动化静态代码检测

使用jenkins+Emma统计

客户端单元测试覆盖率

Jenkins+Ant+Java+Junit+SVN执行junit单元测试

jenkins+ant+jmeter搭建持续集成的接口测试平台

自动部署:

Jenkins+GitLab+蒲公英+FTP

jenkins结合ansible用shell实现自动化部署和回滚

持续集成:

Tomcat+Sonar搭建持续集成环境

Maven+Nexus+Jenkins+git/SVN

Jenkins的Docker-compose.yml创建文件

version: '3'
services:
  jenkins:
    container_name: 'jenkins'
    image: jenkins/jenkins
    restart: always
    user: jenkins:<这里填Docker用户组的ID,见下面>
    ports:
    - "8080:8080"
    - "50000:50000"
    volumes:
    - /home/jenkins/data:/var/jenkins_home
    - /usr/bin/docker:/usr/bin/docker
    - /var/run/docker.sock:/var/run/docker.sock

上面的脚本使用注意:

  1. 创建本地jenkins数据目录

    mkdir -p /home/jenkins
    
  2. 查看docker用户组的ID

    cat /etc/group |grep docker
    
  3. 执行docker-compose up -d

gitlab的docker启动配置文件

项目地址:https://github.com/sameersbn/docker-gitlab

version: '2'

services:
  redis:
    restart: always
    image: sameersbn/redis:4.0.9-1
    command:
    - --loglevel warning
    volumes:
    - /srv/docker/gitlab/redis:/var/lib/redis:Z

  postgresql:
    restart: always
    image: sameersbn/postgresql:10
    volumes:
    - /srv/docker/gitlab/postgresql:/var/lib/postgresql:Z
    environment:
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_NAME=gitlabhq_production
    - DB_EXTENSION=pg_trgm

  gitlab:
    restart: always
    image: sameersbn/gitlab:11.11.2
    depends_on:
    - redis
    - postgresql
    ports:
    - "10080:80"
    - "10022:22"
    volumes:
    - /srv/docker/gitlab/gitlab:/home/git/data:Z
    environment:
    - DEBUG=false

    - DB_ADAPTER=postgresql
    - DB_HOST=postgresql
    - DB_PORT=5432
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_NAME=gitlabhq_production

    - REDIS_HOST=redis
    - REDIS_PORT=6379

    - TZ=Asia/Kolkata
    - GITLAB_TIMEZONE=Kolkata

    - GITLAB_HTTPS=false
    - SSL_SELF_SIGNED=false

    # 这里修改成服务器的IP或者域名
    - GITLAB_HOST=localhost
    - GITLAB_PORT=10080
    - GITLAB_SSH_PORT=10022
    - GITLAB_RELATIVE_URL_ROOT=
    - GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_SECRET_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_OTP_KEY_BASE=long-and-random-alphanumeric-string

        # 这里给一个长度大于8的密码
    - GITLAB_ROOT_PASSWORD=12345678
    - GITLAB_ROOT_EMAIL=itheima@itcast.cn

    - GITLAB_NOTIFY_ON_BROKEN_BUILDS=true
    - GITLAB_NOTIFY_PUSHER=false

    - GITLAB_EMAIL=notifications@example.com
    - GITLAB_EMAIL_REPLY_TO=noreply@example.com
    - GITLAB_INCOMING_EMAIL_ADDRESS=reply@example.com

    - GITLAB_BACKUP_SCHEDULE=daily
    - GITLAB_BACKUP_TIME=01:00

    - SMTP_ENABLED=false
    - SMTP_DOMAIN=www.example.com
    - SMTP_HOST=smtp.gmail.com
    - SMTP_PORT=587
    - SMTP_USER=mailer@example.com
    - SMTP_PASS=password
    - SMTP_STARTTLS=true
    - SMTP_AUTHENTICATION=login

    - IMAP_ENABLED=false
    - IMAP_HOST=imap.gmail.com
    - IMAP_PORT=993
    - IMAP_USER=mailer@example.com
    - IMAP_PASS=password
    - IMAP_SSL=true
    - IMAP_STARTTLS=false

    - OAUTH_ENABLED=false
    - OAUTH_AUTO_SIGN_IN_WITH_PROVIDER=
    - OAUTH_ALLOW_SSO=
    - OAUTH_BLOCK_AUTO_CREATED_USERS=true
    - OAUTH_AUTO_LINK_LDAP_USER=false
    - OAUTH_AUTO_LINK_SAML_USER=false
    - OAUTH_EXTERNAL_PROVIDERS=

    - OAUTH_CAS3_LABEL=cas3
    - OAUTH_CAS3_SERVER=
    - OAUTH_CAS3_DISABLE_SSL_VERIFICATION=false
    - OAUTH_CAS3_LOGIN_URL=/cas/login
    - OAUTH_CAS3_VALIDATE_URL=/cas/p3/serviceValidate
    - OAUTH_CAS3_LOGOUT_URL=/cas/logout

    - OAUTH_GOOGLE_API_KEY=
    - OAUTH_GOOGLE_APP_SECRET=
    - OAUTH_GOOGLE_RESTRICT_DOMAIN=

    - OAUTH_FACEBOOK_API_KEY=
    - OAUTH_FACEBOOK_APP_SECRET=

    - OAUTH_TWITTER_API_KEY=
    - OAUTH_TWITTER_APP_SECRET=

    - OAUTH_GITHUB_API_KEY=
    - OAUTH_GITHUB_APP_SECRET=
    - OAUTH_GITHUB_URL=
    - OAUTH_GITHUB_VERIFY_SSL=

    - OAUTH_GITLAB_API_KEY=
    - OAUTH_GITLAB_APP_SECRET=

    - OAUTH_BITBUCKET_API_KEY=
    - OAUTH_BITBUCKET_APP_SECRET=

    - OAUTH_SAML_ASSERTION_CONSUMER_SERVICE_URL=
    - OAUTH_SAML_IDP_CERT_FINGERPRINT=
    - OAUTH_SAML_IDP_SSO_TARGET_URL=
    - OAUTH_SAML_ISSUER=
    - OAUTH_SAML_LABEL="Our SAML Provider"
    - OAUTH_SAML_NAME_IDENTIFIER_FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:transient
    - OAUTH_SAML_GROUPS_ATTRIBUTE=
    - OAUTH_SAML_EXTERNAL_GROUPS=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_EMAIL=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_NAME=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_USERNAME=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_FIRST_NAME=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_LAST_NAME=

    - OAUTH_CROWD_SERVER_URL=
    - OAUTH_CROWD_APP_NAME=
    - OAUTH_CROWD_APP_PASSWORD=

    - OAUTH_AUTH0_CLIENT_ID=
    - OAUTH_AUTH0_CLIENT_SECRET=
    - OAUTH_AUTH0_DOMAIN=

    - OAUTH_AZURE_API_KEY=
    - OAUTH_AZURE_API_SECRET=
    - OAUTH_AZURE_TENANT_ID=

原文链接:https://github.com/nordon-wang/markdowns/blob/master/%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90%E4%B8%8E%E6%8C%81%E7%BB%AD%E9%83%A8%E7%BD%B2/%E7%AC%94%E8%AE%B0.md

上一篇 下一篇

猜你喜欢

热点阅读