CI/CD入门(二)

CI/CD入门(二)

1、代码上线方案

1.1 早期手动部署代码

  • 纯手动Scp、Rsync上传代码。
  • 纯手动登陆,Git pull 或者 Svn update。
  • 纯手动xftp、ftp、filezilla上传代码。
  • 开发发送压缩包,rz上传,解压部署代码。

缺点:

  • 全程运维参与,占用大量时间。
  • 如果节点多,上线速度慢。
  • 人为失误多,目录管理混乱。
  • 回滚不及时,或者难以回退。

上线方案示意图:

1190037-20171201192743261-564020995-1581427002308.png-106kB

1.2 合理化上线方案

  • 开发人员(rd)需在个人电脑搭建LAMP环境测试开发好的网站代码,并且在办公室或 IDC机房的测试环境测试通过,最好有专职测试人员(ts)。
  • 程序代码上线要规定时间,例如:三天上线一次,如网站需经常更新可每天下午 20 点上线,这个看网站业务性质而定,原则就是影响用户体验最小。
  • 代码上线之前需备份,网站程序出了问题方便回退,另外,从上线技巧上讲,上传代码时尽可能先传到服务器网站临时目录,传完整后一步mv过去,或者通过In做软链接— 线上更新代码的思路。如果严格更新,把应用服务器从集群节点平滑下线,然后更新。
  • 尽量由运维人员管理上线,对于代码的功能性,开发人员更在意,而对于代码的性能优化和上线后服务器的稳定,运维更在意服务器的稳定,因此,如果网站宕机问题归运维管,就要让运维上线,这样更规范科学。否则,开发随意更新,出了问题运维负责,这样就错了,运维永远无法抬头。
    web代码规范化上线流程图

1190037-20171201192752386-122301749-1581427002308.png-66kB

1.3 大型企业上线制度和流程

JAVA代码环境上线时,有数台机器同时需要更新或者分批更新

  • 本地开发人员取svn代码。当天上线提交到trunk,否则,长期项目单开分支开发,然后在合并主线(trunk)
  • 办公内网开发测试时,由开发人员或配置管理员通过部署平台jenkins实现统一部署,(即在部署平台上控制开发机器从svn取代码,编译,打包,发布到开发机,包名如idc_dep.war).
  • 开发人员通知或和测试人员一起测试程序,没有问题后,由配置管理员打上新的tag标记。这里要注意,不同环境的配置文件是随代码同时发布的。
  • 配置管理员,根据上一步的tag标记,checkout出上线代码,并配置好IDC测试环境的所有配置,执行编译,打包(mvn,ant)(php不需要打包),然后发布到IDC内的统一分发服务器。
  • 配置管理员或SA上线人员,把分发的程序代码内容推送到相关测试服务器(包名如idc_test.war),然后通知开发及测试人员进行测试。如果有问题向上回退,继续修改。
  • 如果IDC测试没有问题,继续打好tag标记,此时,配置管理员,根据上步的tag标记,checkout出测试好的代码,并配置好IDC正式环境的所有配置,执行编译,打包(mvn,ant)(php不需要打包),然后发布到IDC内的统一分发服务器主机,准备批量发布。
  • 配置管理员或SA上线人员,把分发的内容推送到相关正式服务器(包名如idc_product.war),然后通知开发及测试人员进行测试。如果有问题直接发布回滚指令。

IDC正式上线的过程对于JAVA程序,可以是AB组分组上线的思路,即平滑下线一半的服务器,然后发布更新代码,重启测试,无问题后,挂上更新后的服务器,同时再平滑下线另一半的服务器,然后发布更新代码测试(或者直接发布后,重启,挂上线)

1.4 php程序代码上线的具体方案

对于PHP上线方法:发布代码时(也需要测试流程)可以直接发布到正式线临时目录 ,然后mv或更改link的方式发布到正式上线目录 ,不需要重启http服务。这是新朗,赶集的上线方案。

1.5 Java程序代码上线的具体方案

对于java上线方法:较大公司需要分组平滑上线(如从负载均衡器上摘掉一半的服务器),发布代码后,重启服务器测试,没问题后,挂上上好线的一半,再下另外一半。如果前端有DNS智能解析,上线还可以分地区上线若干服务器,逐渐普及到全国的服务器,这个被称为“灰度发布”,在后面门户网站上线的知识里我们在讲解。

1.6 代码上线解决方案注意事项

上线的流程里,办公室测试环境-->IDC测试环境-->正式生产环境,所有环境中的所有软件均应版本统一,其次尽量单一,否则将后患无穷,开发测试成功,IDC测试就可能有问题(如:操作系统,web服务器,jdk,php,tomcat,resin等版本)

  • 开发团队小组办公内部测试环境测试(该测试环境属于开发小组维护,或定时自动更新代码),代码有问题返回给某开发人员重新开发。
  • 有专门的测试工程师,程序有问题直接返回给开发人员(此时返回的一般为程序的BUG,称为BUG库),无问题进行IDC测试
  • IDC测试由测试人员和运维人员参与,叫IDCtest,进行程序的压力测试,有问题直接返回给开发人员,无问题进行线上环境上线。
  • 数台服务器代码分发上线方案举例(JAVA程序)
    • A:假设同业务服务器有6台,将服务器分为A,B两组,A组三台,B组三台,先对A组进行从负载均衡器上平滑下线,B组正常提供服务,避免服务器因上线影响业务。
    • B:下线过程是通过脚本将A组服务器从RS池(LVS,NGINX,HAPROXY,F5等均有平滑方案)中踢出,避免负裁均衡器将请求发送给A组服务器(此时的时间应该为网站流量少时,一般为晚上)
    • C:将代码分发到A组服务器的站点目录下,对A组服务器上线并重启服务,并由专业的测试人员进行访问测试,测试成功后,挂上A组的服务器,同时下线B组服务器,B组代码上线操作测试等和A组相同,期间也要观察上线提供服务的服务器状况,有问题及时回滚。
  • 如果是PHP程序,则上线可以简单化,直接将上线代码(最好全量)发布到所有上线服务器的特定目录后,分发完成后,一次性mv或ln到站点目录,当然测试也是少不了的。测试除了人员测试外,还有各种测试脚本测试各个相关业务接口。

2、理解持续集成、持续交付、持续部署

软件开发的连续方法基于自动执行脚本,以最大限度地减少在开发应用程序时引入错误的可能性。从新代码的开发到部署,它们需要较少的人为干预甚至根本不需要干预。它涉及在每次小迭代中不断构建,测试和部署代码更改,从而减少基于有缺陷或失败的先前版本开发新代码的机会。有三种主要方法,分别为持续集成、持续交付、持续部署,每种方法都根据最适合您的策略进行应用。

1352872-20180728202111287-1863851599.png-34.7kB

2.1 持续集成

代码合并,构建,部署,测试都在一起,不断地执行这个过程,并对结果反馈

持续集成(英语:Continuous integration,缩写为 CI),一种软件工程流程,将所有工程师对于软件的工作复本,每天集成数次到共用主线(mainline)上。

这个名称最早由葛来迪·布区(Grady Booch)在他的布区方法中提出,但是他并没有提到要每天集成数次。之后成为极限编程(extreme programming,缩写为XP)的一部分。在测试驱动开发(TDD)的作法中,通常还会搭配自动单元测试。

持续集成的提出,主要是为了解决软件进行系统集成时面临的各项问题,极限编程称这些问题为集成地狱(integration hell)。

1190037-20171201191840448-1304029709.png-52.1kB

持续集成主要是强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起。简单来讲就是:频繁地(一天多次)将代码集成到主干。

持续集成的目的

  • 及早发现集成错误且由于修订的内容较小所以易于追踪,这可以节省项目的时间与成本。
  • 避免发布日期的前一分钟发生混乱,当每个人都会尝试为他们所造成的那一点点不兼容的版本做检查。
  • 当单元测试失或发生错误,若开发人员需要在不除错的情况下还原代码库到一个没有问题的状态,只需要放弃一小部分的更改 (因为集成的次数频繁)。
  • 让 "最新" 的程序可保持可用的状态供测试、展示或发布用。
  • 频繁的提交代码会促使开发人员创建模块化,低复杂性的代码。
  • 防止分支大幅偏离主干。如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。

2.2 持续交付

部署到测试环境、预生产环境

持续交付(英语:Continuous delivery,缩写为 CD),是一种软件工程手法,让软件产品的产出过程在一个短周期内完成,以保证软件可以稳定、持续的保持在随时可以释出的状况。

它的目标在于让软件的建置、测试与释出变得更快以及更频繁。这种方式可以减少软件开发的成本与时间,减少风险。

1190037-20171201191850511-1013536040.png-93.9kB

持续交付在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境的「类生产环境」(production-like environments)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的Staging 环境中更多的测试。如果代码没有问题,可以继续手动部署到生产环境中。

2.3 持续部署

将最终产品发布到生成环境,给用户使用

持续部署(英语:Continuous Deployment,缩写为 CD),是持续交付的下一步,指的是代码通过评审以后,自动部署到生产环境。

有时候,持续部署也与持续交付混淆。持续部署意味着所有的变更都会被自动部署到生产环境中。持续交付意味着所有的变更都可以被部署到生产环境中,但是出于业务考虑,可以选择不部署。如果要实施持续部署,必须先实施持续交付。

1190037-20171201191900433-349001067.png-92.4kB

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

3、Maven 私服 Nexus3

3.1 Maven和Nexus3 简介

Maven是一个采用纯Java编写的开源项目管理工具

采用一种被称之为Project Object Model(POM)概念来管理项目,所有的项目配置信息都被定义在一个叫做POM.xml的文件中, 通过该文件Maven可以管理项目的整个生命周期,包括清除、编译,测试,报告、打包、部署等等。

目前Apache下绝大多数项目都已经采用Maven进行管理. 而Maven本身还支持多种插件, 可以方便更灵活的控制项目, 开发人员的主要任务应该是关注商业逻辑并去实现它, 而不是把时间浪费在学习如何在不同的环境中去依赖jar包,项目部署等。

Maven和ant都是软件构建工具(软件管理工具),Maven比Ant更加强大,已经取代了ant,jar包的声明式依赖描述。Maven有jar包的仓库。

私服是架设在局域网的一种特殊的远程仓库,目的是代理远程仓库及部署第三方构件。有了私服之后,当 Maven 需要下载构件时,直接请求私服,私服上存在则下载到本地仓库;否则,私服请求外部的远程仓库,将构件下载到私服,再提供给本地仓库下载。

1167086-20180825103130887-988863302.jpg-24.6kB

公司如果没有maven私服,则需要用手动打jar包的方式添加依赖

3.2 安装 Maven

3.2.1 下载 maven

# 下载 maven
[root@maven ~]# wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz

# 解压安装
[root@maven ~]# tar xf apache-maven-3.8.8-bin.tar.gz -C /usr/local/
[root@maven ~]# mv /usr/local/apache-maven-3.8.8 /usr/local/maven

3.2.2 安装 java 环境

# 安装 java 环境
[root@maven ~]# tar xf jdk-8u171-linux-x64.tar.gz -C /usr/local/
[root@maven ~]# mv /usr/local/jdk1.8.0_171/ /usr/local/jdk

3.2.3 添加环境变量

# 添加环境变量
[root@maven ~]# cat >> /etc/profile << EOF
JAVA_HOME=/usr/local/jdk
export MAVEN_HOME=/usr/local/maven
export CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/lib/tools.jar:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$MAVEN_HOME/bin:$PATH
EOF

# 加载环境变量
[root@maven ~]# source /etc/profile

3.2.4 验证版本

[root@maven ~]# java -version
java version "1.8.0_171"
Java(TM) SE Runtime Environment (build 1.8.0_171-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)


[root@maven ~]# mvn -version
Apache Maven 3.8.8 (4c87b05d9aedce574290d1acc98575ed5eb6cd39)
Maven home: /usr/local/maven
Java version: 1.8.0_171, vendor: Oracle Corporation, runtime: /usr/local/jdk/jre
Default locale: zh_CN, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-1160.90.1.el7.x86_64", arch: "amd64", family: "unix"

3.3 安装 nexus3

3.3.1 下载

下载开源版 Nexus OSS

图片.png-183.3kB

3.3.2 安装nexus

# 解压
[root@maven ~]# tar xf nexus-3.58.1-02-unix.tar.gz -C /usr/local/
[root@maven ~]# mv /usr/local/nexus-3.58.1-02 /usr/local/nexus

# 启动
[root@maven ~]# cd /usr/local/nexus/bin/
[root@maven bin]# ./nexus start
WARNING: ************************************************************
WARNING: Detected execution as "root" user.  This is NOT recommended!
WARNING: ************************************************************
Starting nexus

看到如图所示内容表明我们已经启动成功了,游览器输入http://192.168.200.19:8081即可访问。

图片.png-102.2kB

登录 : 点击右上角的sign in登录,输入账户admin

# 密码
[root@maven bin]# cat /usr/local/sonatype-work/nexus3/admin.password 
9807551b-fed2-46f3-b500-74c785ce0ca7

图片.png-132.5kB

设置新密码:ywb971108

图片.png-138.3kB

禁用匿名模式

图片.png-183.4kB

3.4 仓库介绍

点击“设置-Repositories”,就可以看到仓库,分三种类型:

图片.png-209.5kB

  • proxy:是远程仓库的代理。比如说在nexus中配置了一个central repository的proxy,当用户向这个proxy请求一个artifact,这个proxy就会先在本地查找,如果找不到的话,就会从远程仓库下载,然后返回给用户,相当于起到一个中转的作用。    
  • Hosted:是宿主仓库,用户可以把自己的一些构件,deploy到hosted中,也可以手工上传构件到hosted里。比如说oracle的驱动程序,ojdbc6.jar,在central repository是获取不到的,就需要手工上传到hosted里,一般用来存放公司自己的jar包;
  • Group:是仓库组,在maven里没有这个概念,是nexus特有的。目的是将上述多个仓库聚合,对用户暴露统一的地址,这样用户就不需要在pom中配置多个地址,只要统一配置group的地址就可以了右边那个Repository Path可以点击进去,看到仓库中artifact列表。不过要注意浏览器缓存,当你的项目希望在多个repository使用资源时就不需要多次引用了,只需要引用一个group即可

  • maven-publicmaven-centralmaven-releasemaven-snapshot三个库的合集。
  • maven-release:用来存放release版本的jar包。
  • maven-snapshot:用来存放snapshot版本的jar包。

关于Maven的Snapshot版本与Release版本

  • Snapshot版本代表不稳定、尚处于开发中的版本
  • Release版本则代表稳定的版本
  • 什么情况下该用SNAPSHOT?
    协同开发时,如果A依赖构件B,由于B会更新,B应该使用SNAPSHOT来标识自己。这种做法的必要性可以反证如下:
    • 如果B不用SNAPSHOT,而是每次更新后都使用一个稳定的版本,那版本号就会升得太快,每天一升e68a84e8a2ade79fa5e9819331333363396362甚至每个小时一升,这就是对版本号的滥用。
    • 如果B不用SNAPSHOT, 但一直使用一个单一的Release版本号,那当B更新后,A可能并不会接受到更新。因为A所使用的repository一般不会频繁更新release版本的缓存(即本地repository),所以B以不换版本号的方式更新后,A在拿B时发现本地已有这个版本,就不会去远程Repository下载最新的B
  • 不用Release版本,在所有地方都用SNAPSHOT版本行不行?
    不行。正式环境中不得使用snapshot版本的库。 比如说,今天你依赖某个snapshot版本的第三方库成功构建了自己的应用,明天再构建时可能就会失败,因为今晚第三方可能已经更新了它的snapshot库。你再次构建时,Maven会去远程repository下载snapshot的最新版本,你构建时用的库就是新的jar文件了,这时正确性就很难保证了。

3.5 向 nexus3 私服上传 jar 包

3.5.1 准备环境

3.5.1.1 创建3rd_part

点击左侧的repository\repositories后,在右侧点击create repository

图片.png-197.8kB

然后选择maven2(hosted),填写如下

图片.png-175kB

图片.png-153.2kB

跳到首页后选择maven-public

图片.png-202.3kB

3rd_part移到member中,即将3rd_partmaven-public管理,点击save

图片.png-167.4kB

图片.png-154.5kB

图片.png-202.5kB

至此,创建仓库完成

3.5.1.2 创建 3rd_part 管理用户

创建用户: 用户名/密码-dev/dev123

图片.png-152.1kB

图片.png-110.6kB

图片.png-120.6kB

3.5.2 直接浏览器

使用dev/dev123登陆,点击upload

图片.png-106.9kB

填写上传jar包的信息后,点击upload

图片.png-189.7kB

图片.png-150.4kB

可以看到已经上传成功

图片.png-151.2kB

图片.png-136.5kB

4、常见错误

问题1:上传报错误码405,Failed to transfer file。

​ 解决:仔细查看报错信息就会发现,是上传的url错了,原因就是repository的地址写错了。

问题2:错误码401或者403

​ 解决:其实403错误就是“禁止访问”的含义,所以问题的根源肯定在授权上面。Maven在默认情况下会使用deployment帐号(默认密码deploy)登录的系统,但是关键的Nexus中Releases仓库默认的Deployment Policy是“Disable Redeploy”,所以无法部署的问题在这个地方,方法是将其修改为“Allow Redeploy”就可以了。401就是Maven settings.xml没有设置密码