笔者Q:552408925、572891887
架构师群:471443208
bjstack运维社区:524721466
有任何疑问请加群互动,或上社区发帖bjstack运维社区 bjstack.com
1.1早期手动部署代码
1.纯手动scp上传代码。 2.纯手动登陆,git pull 或者svn update。 3.纯手动xftp上传代码。 4.开发发送压缩包,rz上传,解压部署代码。 缺点: 1.全程运维参与,占用大量时间。 2.如果节点多,上线速度慢。 3.人为失误多,目录管理混乱。 4.回滚不及时,或者难以回退。
1.2设计自动部署代码
流程设计,确定目标.
1.2.1自动部署环境
1.开发环境 开发者本地有自己的环境,运维配置公共开发环境,大家可共用的服务。例如:开发数据库MySQL,redis,Memcached等 2.测试环境 功能测试以及性能测试。 3.预生产环境 生产环境集群中的某一个节点,并且连接生产库。(不对外,不做破坏型操作。) 4.灰度环境 根据不同的区域进行划分分。(生产环境) 5.生产环境 对用户提供服务的环境。 预生产环境由来: 1.数据库不一致,测试环境和生产环境数据库是不一样的。 2.使用生产环境的联调接口;例如:支付接口。(电商业务)
1.2.1自动部署规划
1.已经有一个可以上线的代码在git仓库。 2.我们现在要做10个集群节点的一键部署,秒级回滚。 3.所有的web服务,都应该使用普通用户。(强烈建议) 4.所有的web服务都不应该监听80端口,除了负载均衡。 5.那我们如何设计一套生产自动化部署系统。 1.规划。 2.实现。 3.总结和扩展。(PDCA方法论) 4.生产环境应用。
实现思路:
1.代码放置位置 Git(首先)、Svn 2.获取最新代码 1.git pull获取最新分支(更新非常频繁,没有特别严格的项目管理团队。) 2.git tag 获取指定标签版本(更新没有那么频繁,有一定的项目管理的团队。) 3.git commit获取指定版本号 3.差异解决 1.各个节点之间差异 2.代码仓库和实际的差异。配置文件是否放在代码仓库中。(配置单独进行存放,config.example )短信接口,支付,等敏感信息不让所有开发知道 3.统一的.集群有10个节点。(Job节点 crontab.xml 配置文件不一样) 4.项目名称如何设计。 项目名称_环境名称_版本_分支_时间_某开发提交 测试: rainbow_test_v1.1.1_dev_2016-08-11_12:12_xuliangwei 生产: rainbow_pro_v1.1.1_master_2016-08-11_11:11_xuliangwei 5.如何更新。 php,tomcat需要重启,重新软链接。 6.如何测试。 测试(关键的页面,API,后台等) 测试一个预生产环境,通过则继续部署,如果失败,退出部署操作。 7.记录日志。 可以部署统计。 成功多少次。 失败多少次。 回滚多少次。 8.多人同时执行脚本。 防止多人操作导致重复上线失败。通过lock锁对文件进行控制。 9.串行,并行。 机器少的情况串行感觉不出什么。如果机器过多则会很慢。 分组部署并行部署,以及分组测试。 测试一个预生产环境,通过则继续部署,如果失败,退出部署操作。 10.部署服务器双机。 防止部署系统down机,部署机代码丢失,误操作。 11.如何执行。 1.shell执行 2.web界面点击(自定义或jenkins) 12.如何实现正常回退,以及紧急回退(回滚的必要性)。 通过软链接的方式来实现代码秒级别回退。
1.2.1自动部署难点
在大公司推进自动化部署上线,是有许多的难点,根据个人公司的不同,来选择不同的方法来进行推进。 自动化推进难点: 1.能力(个人能力,团队能力) 2.责任(责任能否承担,敢于承担责任) 3.公司流程、人员、组织架构。 可通过如下方法推进: 1.目标化沟通。 2.责任划分 3.ITIL 4.项目管理:PMBOOK
1.3自动部署实践
整个集群自动化部署流程设计如下:
1.获取最新代码 2.编译(可选) 3.配置文件(软连接或者拷贝)。 4.打包(tar,加速传输) 5.文件分发(Scp Rsync Salt)(不需要密码验证) 6.将目标服务器移除集群(注释配置文件) 7.解压 8.防止webroot站点目录 9.scp差异文件(可能有一个节点配置文件不一样) 10.重启Web服务 11.测试
1.4正常回退实践
1.列出回滚版本 2.目标服务器移除集群 3.执行回滚 4.重启并测试 5.加入集群
1.5紧急回退实践
1.列出回滚版本(ls -l或find查出对应的历史版本)。 2.执行回滚操作(删除软链接,重建软链接)。 3.重启对应服务。
1.6自动部署采坑
自动化部署php环境或者java环境的过程中,那么你一定遇到了如下的问题。
1.如何应用到你的生产环境。
2.回退到“上一个”“正常”版本。
3.自动部署软连接的坑。
1.PHP如果开启Opcache,需要重启PHP,或者清理opcache
2.Java Tomcat是必须要重启,最好每次清理work,tmp缓存目录。
自动化系统构建实践-运维体系
1.1环境准备
首先在执行脚本前,先做好初始化环境,最好是通过saltstack来完成。我这里没有那么多机器,就先用两台演示。
linux-node1 192.168.90.201
linux-node2 192.168.90.202
1.创建普通用户
useradd xuliangwei passwd xuliangwei
2.配置密钥
[[email protected] ~]# su - xuliangwei #切换至普通用户 [[email protected] ~]$ ssh-keygen -t dsa #生成密钥 Generating public/private dsa key pair. Enter file in which to save the key (/home/xuliangwei/.ssh/id_dsa): #默认回车一路 /home/xuliangwei/.ssh/id_dsa already exists. Overwrite (y/n)? y Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/xuliangwei/.ssh/id_dsa. #这是钥匙 Your public key has been saved in /home/xuliangwei/.ssh/id_dsa.pub. #这是锁 The key fingerprint is: 39:6f:d8:42:61:d7:c3:f9:4b:e7:fb:b0:af:52:cd:59 [email protected] The key‘s randomart image is: +--[ DSA 1024]----+ | | | o . | | o . = | | . + o E| | S oo+| | . = ..=o| | o + .o .| | o . o.| | .o++| +-----------------+ [[email protected] ~]$ ssh-copy-id -i ~/.ssh/id_dsa.pub [email protected] #公钥分发给其他服务器 [email protected]‘s password: Now try logging into the machine, with "ssh ‘[email protected]‘", and check in: .ssh/authorized_keys to make sure we haven‘t added extra keys that you weren‘t expecting. [[email protected] ~]$ ssh -p22 [email protected] #使用xuliangwei用户登录node2节点服务器 Last login: Wed Aug 10 17:59:02 2016 from 192.168.90.201 [[email protected] ~]$ #成功登录
3.创建相关目录
mkdir /deploy/ mkdir -p /deploy/code/rainbow_pro mkdir -p /deploy/source/rainbow_pro mkdir -p /deploy/config/rainbow_pro/config mkdir -p /deploy/config/rainbow_pro/admin_config mkdir -p /deploy/tmp mkdir -p /home/xuliangwei/webroot chown -R www:www /deploy chown -R www:www /home/xuliangwei/webroot
4.配置Nginx
user xuliangwei; #指定用户 root /home/xuliangwei/webroot/rainbow_pro; #指定项目路径
5.配置好git环境
1.[centos7部署gitlab][https://about.gitlab.com/downloads/#centos7] 2.克隆项目可参考 [git远程仓库创建与建立][http://www.bjstack.com/thread-25-1-1.html] 3.最终效果如下: [[email protected] ~]$ ll /deploy/source/rainbow_pro/ 总用量 4 -rw-rw-r-- 1 xuliangwei xuliangwei 34 8月 12 18:05 index.html
1.2剖析脚本 配合上文来进行
[[email protected] ~]$ cat deploy.sh #!/bin/bash # useradd xuliangwei && sshkey需认证 # Nginx 权限必须让xuliangwei用户可访问 # Dir List # mkdir -p /deploy/code/rainbow_pro # web code的仓库 # mkdir -p /deploy/source/rainbow_pro #存放git源码仓库 # mkdir -p /deploy/config/rainbow_pro/config #存放config信息 # mkdir -p /deploy/config/rainbow_pro/admin_config #存放后台config信息 # mkdir -p /deploy/tmp # Web Root Dir # mkdir -p /home/xuliangwei/webroot # chown web # chown -R www:www /deploy # chown -R www:www /home/xuliangwei/webroot # Code Env PRO_NAME="rainbow_pro" CODE_DIR="/deploy/code/$PRO_NAME" SOURCE_DIR="/deploy/source/$PRO_NAME" CONFIG_DIR="/deploy/config/$PRO_NAME" WEB_DIR="/home/xuliangwei/webroot" TMP_DIR="/deploy/tmp" # Node List PRE_LIST="192.168.90.201" GROUP1_LIST="192.168.90.202" ROLLBACK_LIST="192.168.90.201 192.168.90.202" # Date/Time Veriables CTIME=$(date "+%F-%H-%M") # Shell Env SHELL_NAME="deploy.sh" SHELL_DIR="/home/xuliangwei/webroot" # Log LOG_FILE="${SHELL_DIR}/${SHELL_NAME}".log LOCK_FILE="/tmp/deploy.lock" # Lock shell_lock(){ touch ${LOCK_FILE} } shell_unlock(){ rm -f ${LOCK_FILE} } # URL Test url_test(){ URL=$1 curl -s --head $URL |egrep ‘200|301|302‘ if [ $? -ne 0 ];then shell_unlock; echo "test error" && exit; fi } # log writelog(){ LOGINFO=$1 echo "${CTIME}: ${SHELL_NAME} : ${LOGINFO}" >> ${LOG_FILE} } code_get(){ writelog "code_get" cd $SOURCE_DIR && git pull GIT_CID=$(git log|awk ‘NR==1{print $2}‘|cut -c 1-6) PKG_VER="${CTIME}_${GIT_CID}" PKG_NAME="${PRO_NAME}_${PKG_VER}" cp -r ${SOURCE_DIR} ${TMP_DIR}/${PKG_NAME} } code_bulid(){ echo code_bulid #由于php没有编译过程 } code_config(){ writelog "code_config" /bin/cp -r ${CONFIG_DIR}/config.php ${TMP_DIR}/${PKG_NAME}/config.php } code_tar(){ writelog "code_tar" cd ${TMP_DIR} && tar czf ${PKG_NAME}_tar.gz ${PKG_NAME} --exclude=.git --exclude=.gitignore writelog "${PKG_NAME}_tar.gz" } code_scp(){ writelog "code_scp" for node in $PRE_LIST;do scp ${TMP_DIR}/${PKG_NAME}_tar.gz $node:${TMP_DIR}/ done for node in $GROUP1_LIST;do scp ${TMP_DIR}/${PKG_NAME}_tar.gz $node:${TMP_DIR}/ done } pre_deploy(){ writelog "remove from cluster" ssh $PRE_LIST "cd ${TMP_DIR} && tar xf ${PKG_NAME}_tar.gz -C ${CODE_DIR}/" ssh $PRE_LIST "rm -f $WEB_DIR/${PRO_NAME} && ln -s ${CODE_DIR}/${PKG_NAME} $WEB_DIR/${PRO_NAME}" } pre_test(){ url_test "http://${PRE_LIST}/index.html" echo "Rre add to cluster" } group1_deploy(){ writelog "remove from cluster" for node in $GROUP1_LIST;do ssh $node "cd ${TMP_DIR} && tar xf ${PKG_NAME}_tar.gz -C ${CODE_DIR}/" ssh $node "rm -f $WEB_DIR/${PRO_NAME} && ln -s ${CODE_DIR}/${PKG_NAME} $WEB_DIR/${PRO_NAME}" done #scp ${CONFIG_DIR}/other/192.168.90.201.crontab.xml 192.168.90.201:/$WEB_DIR/${PRO_NAME}/crontab.xml 额外不一样的配置可能需要用到 } group1_test(){ url_test "http://${GROUP1_LIST}/index.html" echo "group1_node add to cluster" } code_reload(){ systemctl restart php-fpm #重启php清楚opcode缓存 } rollback_list(){ for node in $GROUP1_LIST;do ssh $node ls -l "$WEB_DIR" && ssh $node find "$CODE_DIR/" -maxdepth 1 -mtime -2|sed 1d|awk -F ‘/‘ ‘{print $5}‘ #find "$CODE_DIR" -type d -name "$PRO_NAME*" -mtime +30|xargs rm -fr done } rollback_fun(){ if [ -z $ROOLBACK ];then shell_unlock; echo "Please input rollback version" && exit; else for node in $ROLLBACK_LIST;do ssh $node rm -f $WEB_DIR/${PRO_NAME} && ssh $node ln -s ${CODE_DIR}/$ROOLBACK $WEB_DIR/${PRO_NAME} done fi } main(){ if [ -f "$LOCK_FILE" ];then echo "Deploy is Running" && exit; fi DEPLOY_METHOD="$1" ROOLBACK="$2" case $DEPLOY_METHOD in deploy) shell_lock; code_get; code_bulid; code_config; code_tar; code_scp; pre_deploy; pre_test; group1_deploy; group1_test; # group2_deploy; # group2_test; shell_unlock; ;; list) rollback_list; ;; rollback) shell_lock; rollback_fun $ROLLBACK; shell_unlock; ;; *) echo "$Usage:$0 [ deploy | list | rollback ]" esac } main "$1" "$2"
执行上线:
[[email protected] ~]$ sh deploy.sh deploy Already up-to-date. code_bulid rainbow_pro_2016-08-12-21-16_46236b_tar.gz 100% 6016KB 5.9MB/s 00:00 rainbow_pro_2016-08-12-21-16_46236b_tar.gz 100% 6016KB 5.9MB/s 00:00 rainbow_pro_2016-08-12-21-16_46236b_tar.gz 100% 6016KB 5.9MB/s 00:00 HTTP/1.1 200 OK Rre add to cluster HTTP/1.1 200 OK HTTP/1.1 200 OK group1_node add to cluster php-fpm restart
查看当前版本
[[email protected] ~]$ sh deploy.sh list 总用量 16 lrwxrwxrwx 1 xuliangwei xuliangwei 60 8月 12 21:16 rainbow_pro -> /deploy/code/rainbow_pro/rainbow_pro_2016-08-12-21-16_46236b rainbow_pro_2016-08-12-19-24_46236b rainbow_pro_2016-08-12-21-16_46236b 总用量 0 lrwxrwxrwx 1 xuliangwei xuliangwei 60 8月 12 21:16 rainbow_pro -> /deploy/code/rainbow_pro/rainbow_pro_2016-08-12-21-16_46236b rainbow_pro_2016-08-12-19-24_46236b rainbow_pro_2016-08-12-21-16_46236b
执行回滚操作
[[email protected] ~]$ sh deploy.sh rollback #直接执行是不允许的 Please input rollback version [[email protected] ~]$ sh deploy.sh rollback rainbow_pro_2016-08-12-19-24_46236b #这个操作一定要配合list来做。 查看已经回退到19点的版本 [[email protected] ~]$ sh deploy.sh list 总用量 16 -rw-rw-r-- 1 xuliangwei xuliangwei 14224 8月 12 21:16 deploy.sh.log lrwxrwxrwx 1 xuliangwei xuliangwei 60 8月 12 21:18 rainbow_pro -> /deploy/code/rainbow_pro/rainbow_pro_2016-08-12-19-24_46236b rainbow_pro_2016-08-12-19-24_46236b rainbow_pro_2016-08-12-21-16_46236b 总用量 0 lrwxrwxrwx 1 xuliangwei xuliangwei 60 8月 12 21:18 rainbow_pro -> /deploy/code/rainbow_pro/rainbow_pro_2016-08-12-19-24_46236b rainbow_pro_2016-08-12-19-24_46236b rainbow_pro_2016-08-12-21-16_46236b
查看日志:
[[email protected] ~]$ cat webroot/deploy.sh.log 2016-08-12-21-35: deploy.sh : code_get 2016-08-12-21-35: deploy.sh : code_config 2016-08-12-21-35: deploy.sh : code_tar 2016-08-12-21-35: deploy.sh : rainbow_pro_2016-08-12-21-35_46236b_tar.gz 2016-08-12-21-35: deploy.sh : code_scp 2016-08-12-21-35: deploy.sh : remove from cluster 2016-08-12-21-35: deploy.sh : remove from cluster
1.3脚本其他功能
当然此脚本功能不仅仅如此,可以通过git分支,git tag包等方式来上线,这些根据贵公司的具体业务来进行调整,也可以自己开发一个web界面来调用此脚本,这样就可以将上线工作交给开发,当然也可以使用开源jenkins来实现。
1.4后期更新
(如上脚本)+gitlab+jenkins+Sonar 构建自动化部署代码,并代码发布前质量管理
笔者Q:552408925、572891887
架构师群:471443208
bjstack运维社区:524721466
有任何疑问请加群互动,或上社区发帖[bjstack运维社区][http://bjstack.com]