自动化部署shell01
自动化部署--shell脚本--1
传统部署方式
1、纯手工scp
2、纯手工登录git pull 、svn update
3、纯手工xftp往上拉
4、开发给打一个压缩包,rz上去。解压
传统部署缺点:
1、全程运维参与,占用大量时间
2、上线速度慢。
3、认为失误多。管理混乱
4、回滚慢,不及时
新项目上线,规划排在第一位
一般银行都不提供测试接口。比如一些电商公司测试的话,经常把商品调节成1分,只能特定账号能看到。
环境的规划
1、开发环境-开发者本地有自己的环境,然后运维需要设置的开发环境,放的是大家共用的服务。如开发数据库mysql,其它:redis、Memcached。
2、测试环境:功能测试环境和性能测试环境
3、预生产环境:一般可以用生产环境中的某个节点担任
4、生产环境:直接对用户提供服务的环境
预生产环境产生的原因:
1、数据库不一致:测试环境和生产环境数据库肯定不一样的。
2、使用生产环境的联调接口。例如,支付接口
预生产环境--生产环境--灰度发布
灰度发布:
阿里云产品上线,都是一个区一个区上的。肯定不是一下子都上的
qq弹窗:恭喜你获得某某版本资格,请下载新版本享用,你就是小白鼠,这个也是一种灰度发布
规划
已经有一个可以上线的代码在代码仓库。我们如何设计一套生产自动化部署系统。
1、规划
2、实现
3、总结和扩展。PDCA
4、在生产环境应用
自动化部署系统的规划
需求:
1个集群有10个节点。一键部署这10个节点。
2、一键回滚到任意版本
3、一键回滚到上个版本
部署:
1、代码放在哪里:svn,git
2、获取什么版本代码?
svn+git直接拉去某个分支
svn:指定版本号
git:指定tag
3、差异解决:
(1)、各个节点直接差异:
(2)、代码仓库和实际的差异。配置文件是否在代码仓库中
(3)、配置文件未必一样:crontab.xml预生产节点
4、如何更新。java tomcat。需要重启。
5、测试。
6、串行和并行 分组部署
7如何执行。(1)shell执行。(2)web界面
关于配置文件存放:
配置文件放代码仓库里,岂不是所有开发都能连数据库了。
因此配置文件不能放git里。
有的人把配置文件放某个分支里。让一些人没法看到
我觉得可以单独有个放配置文件的git
腾讯蓝鲸:我帮你做个平台,你写个脚本,我帮你发布到某个机器上,你通过平台帮你执行
一些公司现在的运维,不管任何发布,都是做好界面,让项目负责人去通过界面管理
关于差异文件:
可能有些节点有特殊的差异性文件
自动化部署流程设计
自动化部署实战-shell函数
环境准备
系统版本
[root@linux-node1 ~]# cat /etc/redhat-release CentOS Linux release 7.1.1503 (Core) [root@linux-node1 ~]# uname -rm 3.10.0-229.el7.x86_64 x86_64 [root@linux-node1 ~]#
主机名和IP
node1 [root@linux-node1 ~]# hostname linux-node1.nmap.com [root@linux-node1 ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.56.11 linux-node1 linux-node1.nmap.com 192.168.56.12 linux-node2 linux-node2.nmap.com [root@linux-node1 ~]# node2 [root@linux-node2 ~]# hostname linux-node2.nmap.com [root@linux-node2 ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.56.11 linux-node1 linux-node1.nmap.com 192.168.56.12 linux-node2 linux-node2.nmap.com [root@linux-node2 ~]#
两台web服务器,node1和node2作为两个web服务器,同时node1也作为部署分发服务器,去管理2个node节点上的web包
两个节点添加普通用户www,作为web服务器管理用户。
[root@linux-node1 scripts]# useradd -u 1001 www [root@linux-node1 scripts]# id www uid=1001(www) gid=1001(www) groups=1001(www) [root@linux-node1 scripts]# [root@linux-node2 ~]# useradd -u 1001 www [root@linux-node2 ~]# id www uid=1001(www) gid=1001(www) groups=1001(www) [root@linux-node2 ~]#
配置www用户登录其他机器不用密码。密钥认证。以后www用户作为管理其它机器的用户
[root@linux-node1 .ssh]# su - www [www@linux-node1 ~]$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/www/.ssh/id_rsa): Created directory '/home/www/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/www/.ssh/id_rsa. Your public key has been saved in /home/www/.ssh/id_rsa.pub. The key fingerprint is: 70:37:ff:d0:17:e0:74:1d:c9:04:28:bb:de:ec:1f:7f www@linux-node1.nmap.com The key's randomart p_w_picpath is: +--[ RSA 2048]----+ | .++++| | . .o oo.| | . . = . . | | o o o . .| | S . o . .| | . o . | | . o .. | | . o o E| | .... ..| +-----------------+ [www@linux-node1 ~]$
查看公钥
[www@linux-node1 ~]$ cd .ssh/ [www@linux-node1 .ssh]$ ll total 8 -rw------- 1 www www 1679 Apr 5 03:41 id_rsa -rw-r--r-- 1 www www 406 Apr 5 03:41 id_rsa.pub [www@linux-node1 .ssh]$ cat id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDcZh8EEk2/rS6B/tLHnRpZGrGIJYFHg7zRFvuT3N9jvOFhYJdWv+8WSQuT0pvxNM4eR0N5Ma9wVvKPo/lVjCaFK+M0dENJVhi6m9OKMtoo2u jvvuyinNPP4pyoK6ggG5jOlEkHoLcbWCRG/j3pN1rZYV+1twET9xi2IA4UQkgPvKKYWjq7NUR0v5BWsgEQt7VvjcLWTlltTVeGb3FDVKIjDnioIBmLmVwJS64N+GGgAj5YQ+bKHTwY anEMD39JGKxo0RXTZB5sa734yfNjc3hTZXB4RCcGdzgcMJs/Rt5VeZ277zF86xr4Hd5cioAbV6Y1RvELjmpvrqUUz3tcaKId www@linux-node1.nmap.com [www@linux-node1 .ssh]$
node2也添加node1的公钥
改成600权限才能正常登录
[www@linux-node2 ~]$ cd .ssh/ [www@linux-node2 .ssh]$ vim authorized_keys [www@linux-node2 .ssh]$ cat authorized_keys ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDcZh8EEk2/rS6B/tLHnRpZGrGIJYFHg7zRFvuT3N9jvOFhYJdWv+8WSQuT0pvxNM4eR0N5Ma9wVvKPo/lVjCaFK+M0dENJVhi6m9OKMtoo2u jvvuyinNPP4pyoK6ggG5jOlEkHoLcbWCRG/j3pN1rZYV+1twET9xi2IA4UQkgPvKKYWjq7NUR0v5BWsgEQt7VvjcLWTlltTVeGb3FDVKIjDnioIBmLmVwJS64N+GGgAj5YQ+bKHTwY anEMD39JGKxo0RXTZB5sa734yfNjc3hTZXB4RCcGdzgcMJs/Rt5VeZ277zF86xr4Hd5cioAbV6Y1RvELjmpvrqUUz3tcaKId www@linux-node1.nmap.com [www@linux-node2 .ssh]$ chmod 600 authorized_keys [www@linux-node2 .ssh]$
登录测试--成功
[www@linux-node1 .ssh]$ ssh 192.168.58.12 Last login: Mon Apr 10 00:31:23 2017 from 192.168.58.11 [www@linux-node2 ~]$
让node1的www用户ssh自己也不需要输入密码。
node1添加公钥
本地也放自己的密钥,这样可以假装模拟成3台机器。2个ssh免密钥的机器
node1同时作为部署机
[www@linux-node1 .ssh]$ ll total 12 -rw------- 1 www www 1679 Apr 5 03:41 id_rsa -rw-r--r-- 1 www www 406 Apr 5 03:41 id_rsa.pub -rw-r--r-- 1 www www 175 Apr 5 03:43 known_hosts [www@linux-node1 .ssh]$ vim authorized_keys [www@linux-node1 .ssh]$ chmod 600 authorized_keys [www@linux-node1 .ssh]$ ssh 192.168.58.11 The authenticity of host '192.168.58.11 (192.168.58.11)' can't be established. ECDSA key fingerprint is 8b:4e:2f:cd:37:89:02:60:3c:99:9f:c6:7a:5a:29:14. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.58.11' (ECDSA) to the list of known hosts. Last login: Wed Apr 5 03:40:47 2017 [www@linux-node1 ~]$ exit logout Connection to 192.168.58.11 closed. [www@linux-node1 .ssh]$ ssh 192.168.58.11 Last login: Wed Apr 5 03:46:21 2017 from 192.168.58.11 [www@linux-node1 ~]$
开始写自动化部署脚本
根据上面的流程图,先把大体框架写出来
先把框架写出来,然后每个函数里写echo
看看脚本执行流程是否有问题
code_diff 拷贝差异部署文件
这是面向过程的一种开发方式
[root@linux-node1 ~]# mkdir /scripts -p [root@linux-node1 ~]# cd /scripts/ [root@linux-node1 scripts]# vim deploy.sh [root@linux-node1 scripts]# chmod +x deploy.sh [root@linux-node1 scripts]# ./deploy.sh Usage: ./deploy.sh [ deploy | rollback ] [root@linux-node1 scripts]# cat deploy.sh #!/bin/bash#Shell Env SHELL_NAME="deploy.sh" SHELL_DIR="/home/www" SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"#Code Env CODE_DIR="/deploy/code/deploy" CONFIG_DIR="/deploy/config" TMP_DIR="/deploy/tmp" TAR_DIR="/deploy/tar"usage(){echo $"Usage: $0 [ deploy | rollback ]" }code_get(){echo code_get }code_build(){echo code_build }code_config(){echo code_config }code_tar(){echo code_tar }code_scp(){echo code_scp }cluster_node_remove(){echo cluster_node_remove }code_deploy(){echo code_deploy }config_diff(){echo config_diff }code_test(){echo code_test }cluster_node_in(){echo cluster_node_in }rollback(){echo rollback }main(){case $1 indeploy)code_get;code_build;code_config;code_tar;code_scp;cluster_node_remove;code_deploy;config_diff;code_test;cluster_node_in;;;rollback)rollback;;;*)usage;esac} main $1 [root@linux-node1 scripts]#
最末尾还要加个main,否则无法执行
脚本再优化下
尽量不要让$1来回传,否则可能会乱
main(){DEPLOY_METHOD=$1case $DEPLOY_METHOD indeploy)code_get;code_build;code_config;code_tar;code_scp;cluster_node_remove;code_deploy;config_diff;code_test;cluster_node_in;;;
继续完善脚本--添加日志和锁
1、凡是不记录日志的脚本就是刷流氓,执行到哪一步失败的啊?
2、脚本是否可以多个人一起执行?(最好不要多个人一起执行)不允许多人执行的话可以上锁
一般锁文件放下面目录下
[root@linux-node1 ~]# cd /var/run/lock/ [root@linux-node1 lock]# ls iscsi lockdev lvm ppp subsys [root@linux-node1 lock]#
我们可以单独添加个目录,给它用,因为权限问题,需要授权改变属组,我们使用tmp目录
主函数执行之前,应该先判断锁文件是否存在,执行的时候也应该生成这个lock文件
既然2个地方用到了它,是否可以把它制作成变量
新的脚本如下,主要添加了锁的功能
[root@linux-node1 scripts]# cat deploy.sh #!/bin/bash#Shell Env SHELL_NAME="deploy.sh" SHELL_DIR="/home/www" SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"#Code Env CODE_DIR="/deploy/code/deploy" CONFIG_DIR="/deploy/config" TMP_DIR="/deploy/tmp" TAR_DIR="/deploy/tar" LOCK_FILE="/tmp/deploy.lock"usage(){echo $"Usage: $0 [ deploy | rollback ]" }shell_lock(){touch ${LOCK_FILE} } shell_unlock(){rm -f ${LOCK_FILE} }code_get(){echo code_getsleep 60; }code_build(){echo code_build }code_config(){echo code_config }code_tar(){echo code_tar }code_scp(){echo code_scp }cluster_node_remove(){echo cluster_node_remove }code_deploy(){echo code_deploy }config_diff(){echo config_diff }code_test(){echo code_test }cluster_node_in(){echo cluster_node_in }rollback(){echo rollback }main(){if [ -f ${LOCK_FILE} ];thenecho "Deploy is running" && exit;fiDEPLOY_METHOD=$1case $DEPLOY_METHOD indeploy)shell_lock;code_get;code_build;code_config;code_tar;code_scp;cluster_node_remove;code_deploy;config_diff;code_test;cluster_node_in;shell_unlock;;;rollback)shell_lock;rollback;shell_unlock;;;*)usage;esac} main $1 [root@linux-node1 scripts]#
先执行下检查语法错误
[root@linux-node1 scripts]# ./deploy.sh deploy code_get code_build code_config code_tar code_scp cluster_node_remove code_deploy config_diff code_test cluster_node_in [root@linux-node1 scripts]# ./deploy.sh rollback rollback
加个sleep测试下锁的功能
给一个函数加下sleep 测试下执行中,另外的人是否可以执行这个脚本
code_get(){echo code_getsleep 60; }
运行脚本
[root@linux-node1 scripts]# ./deploy.sh deploy code_get
新打开一个窗口执行测试
正常情况下一个窗口执行部署,再开一个窗口肯定执行不了
[root@linux-node1 scripts]# ./deploy.sh deploy Deploy is running [root@linux-node1 scripts]# ./deploy.sh deploy Deploy is running [root@linux-node1 scripts]# ./deploy.sh rollback Deploy is running [root@linux-node1 scripts]#
增加日志功能
其实就是echo一行到日志文件中,每个函数写加echo 写到日志里,这样比较low
能不能写个日志函数,加时间戳。以后日志函数可以复制到其它脚本里
[www@linux-node1 scripts]$ date "+%Y-%m-%d" 2017-04-23 [www@linux-node1 scripts]$ date "+%H-%M-%S" 22-10-34 [www@linux-node1 scripts]$
脚本默认从上到下执行,遇到函数先加载,但是不执行
继续优化下。如下
#!/bin/bash# Date/Time Veriables CDATE=$(date "+%Y-%m-%d") CTIME=$(date "+%H-%M-%S")#Shell Env SHELL_NAME="deploy.sh" SHELL_DIR="/home/www" SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"#Code Env CODE_DIR="/deploy/code/deploy" CONFIG_DIR="/deploy/config" TMP_DIR="/deploy/tmp" TAR_DIR="/deploy/tar" LOCK_FILE="/tmp/deploy.lock"
还不能这么写,不然以后的时间都是一样的
可以改成这样,它不会执行
#!/bin/bash# Date/Time Veriables CDATE='date "+%Y-%m-%d"' CTIME='date "+%H-%M-%S"'#Shell Env SHELL_NAME="deploy.sh" SHELL_DIR="/home/www" SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"#Code Env CODE_DIR="/deploy/code/deploy" CONFIG_DIR="/deploy/config" TMP_DIR="/deploy/tmp" TAR_DIR="/deploy/tar" LOCK_FILE="/tmp/deploy.lock"
打包的时候,也用到时间戳命名了。还得用一个固定不变的时间用于打包
因为解压的时候,scp的时候用必须知道确定的包名字。
这里用到了2个时间,log-date是让它不执行的,cdate是让它执行的
#!/bin/bash# Date/Time Veriables LOG_DATE='date "+%Y-%m-%d"' LOG_TIME='date "+%H-%M-%S"'CDATE=$(date "+%Y-%m-%d") CTIME=$(date "+%H-%M-%S")#Shell Env SHELL_NAME="deploy.sh" SHELL_DIR="/home/www" SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"#Code Env CODE_DIR="/deploy/code/deploy" CONFIG_DIR="/deploy/config" TMP_DIR="/deploy/tmp" TAR_DIR="/deploy/tar"
自己先测试下
[root@linux-node1 ~]# LOG_DATE='date "+%Y-%m-%d"' [root@linux-node1 ~]# LOG_TIME='date "+%H-%M-%S"' [root@linux-node1 ~]# echo $LOG_DATE date "+%Y-%m-%d" [root@linux-node1 ~]# echo $LOG_TIME date "+%H-%M-%S" [root@linux-node1 ~]#
eval的用法
[root@linux-node1 ~]# eval $LOG_TIME 22-21-05 [root@linux-node1 ~]# eval $LOG_DATE 2017-04-23 [root@linux-node1 ~]#
怎么可以让它在一行呢。暂时没找到办法(倒是可以单独定义一个时间变量)
[root@linux-node1 ~]# eval $LOG_DATE && eval $LOG_TIME 2017-04-23 22-22-48 [root@linux-node1 ~]#
单独定义一个时间变量(这里用不到,但是可以实现)
[root@linux-node1 ~]# D_T='date "+%Y-%m-%d-%H-%M-%S"' [root@linux-node1 ~]# echo $D_T date "+%Y-%m-%d-%H-%M-%S" [root@linux-node1 ~]# eval $D_T 2017-04-26-19-33-01 [root@linux-node1 ~]#
编写记录日志函数
usage(){echo $"Usage: $0 [ deploy | rollback ]" }writelog(){LOGINFO=$1echo "${CDATE} ${CTIME}: ${SHELL_NAME} : ${LOGINFO}" >> ${SHELL_LOG} }shell_lock(){touch ${LOCK_FILE} }shell_unlock(){rm -f ${LOCK_FILE} }
这样code_get函数就记录日志了
shell_lock(){touch ${LOCK_FILE} }shell_unlock(){rm -f ${LOCK_FILE} }code_get(){writelog code_get; }code_build(){echo code_build }
规范点,加上双引号,分号可要可不要,写上不会报错
shell_unlock(){rm -f ${LOCK_FILE} }code_get(){writelog "code_get"; }code_build(){echo code_build }
获取代码
把代码放哪里?
为什么创建这些目录,写着写着你就知道了
[root@linux-node1 scripts]# mkdir /deploy/config -p [root@linux-node1 scripts]# mkdir /deploy/tmp -p [root@linux-node1 scripts]# mkdir /deploy/tar -p [root@linux-node1 scripts]# mkdir /deploy/code -p [root@linux-node1 scripts]# cd /deploy/ [root@linux-node1 deploy]# ll total 0 drwxr-xr-x 2 root root 6 Apr 23 22:37 code drwxr-xr-x 2 root root 6 Apr 23 22:37 config drwxr-xr-x 2 root root 6 Apr 23 22:37 tar drwxr-xr-x 2 root root 6 Apr 23 22:37 tmp [root@linux-node1 deploy]#
最终目录建立成这种
[root@linux-node1 deploy]# cd code/ [root@linux-node1 code]# mkdir web-demo -p [root@linux-node1 code]# cd .. [root@linux-node1 deploy]# tree . ├── code │ └── web-demo ├── config ├── tar └── tmp5 directories, 0 files [root@linux-node1 deploy]#
修改脚本
#Shell Env SHELL_NAME="deploy.sh" SHELL_DIR="/home/www" SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log"#Code Env CODE_DIR="/deploy/code/web-demo" CONFIG_DIR="/deploy/config" TMP_DIR="/deploy/tmp" TAR_DIR="/deploy/tar" LOCK_FILE="/tmp/deploy.lock"usage(){echo $"Usage: $0 [ deploy | rollback ]" }
有的不需要编译,拉下代码之后,可以先把配置文件放进去
code_get(){writelog "code_get";cd $CODE_DIR && git pull }
配置文件不要放这个目录下,这个目录只用来更新---git pull.你不好判断配置文件是仓库里面的,还是你专门下载下来的(最佳实践)
规划的时候,只让这里目录执行git pull
下面这个目录用于整合配置文件。
TMP_DIR="/deploy/tmp"
继续优化获取代码的函数
code_get(){writelog "code_get";cd $CODE_DIR && git pullcp -r ${CODE_DIR} ${TMP_DIR}/ }
配置操作的函数时候,觉得不合适,应该区分项目,标准化。比如web-demo可以理解为一个项目包名字
#Code Env CODE_DIR="/deploy/code/web-demo" CONFIG_DIR="/deploy/config/web-demo" TMP_DIR="/deploy/tmp" TAR_DIR="/deploy/tar" LOCK_FILE="/tmp/deploy.lock"
目录新建
[root@linux-node1 scripts]# cd /deploy/ [root@linux-node1 deploy]# cd config/ [root@linux-node1 config]# mkdir web-demo [root@linux-node1 config]# cd .. [root@linux-node1 deploy]# tree . ├── code │ └── web-demo ├── config │ └── web-demo ├── tar └── tmp6 directories, 0 files [root@linux-node1 deploy]#
模拟下,在里面写上hehe
[root@linux-node1 deploy]# cd config/ [root@linux-node1 config]# cd web-demo/ [root@linux-node1 web-demo]# vim config.ini [root@linux-node1 web-demo]# cat config.ini hehe [root@linux-node1 web-demo]#
因为web-demo项目出现频繁,把它弄成变量
#Code Env PRO_NAME="web-demo" CODE_DIR="/deploy/code/web-demo" CONFIG_DIR="/deploy/config/web-demo" TMP_DIR="/deploy/tmp" TAR_DIR="/deploy/tar" LOCK_FILE="/tmp/deploy.lock"
调整下脚本,优化code_config函数
code_get(){writelog "code_get";cd $CODE_DIR && git pullcp -r ${CODE_DIR} ${TMP_DIR}/ }code_build(){echo code_build }code_config(){echo code_config/bin/cp -r $CONFIG_DIR/* $TMP_DIR/$PRO_NAME }
规范下,给变量加大括号
code_get(){writelog "code_get";cd $CODE_DIR && git pullcp -r ${CODE_DIR} ${TMP_DIR}/ }code_build(){echo code_build }code_config(){echo code_config/bin/cp -r ${CONFIG_DIR}/* ${TMP_DIR}/"${PRO_NAME}" }
注意是/bin/cp ,这样原先有配置文件,这里可以直接替换了
如果开发把配置文件打包进去了。连接的是测试的库,假如你部署生产环境了,连接测试的库。出了问题,谁背黑锅
运维是最后一道防线。开发和测试没遇到。你背黑锅
该给包重命名了
code_config(){echo code_config/bin/cp -r ${CONFIG_DIR}/* ${TMP_DIR}/"${PRO_NAME}"PKG_NAME="${PRO_NAME}"_"${API_VER}"-"${CDATE}-${CTIME}" }
继续优化
code_config(){echo code_config/bin/cp -r ${CONFIG_DIR}/* ${TMP_DIR}/"${PRO_NAME}"PKG_NAME="${PRO_NAME}"_"${API_VER}"-"${CDATE}-${CTIME}"cd ${TMP_DIR} && mv ${PRO_NAME} ${PKG_NAME} }
添加版本号,先随便定义个版本
code_get(){writelog "code_get";cd $CODE_DIR && git pullcp -r ${CODE_DIR} ${TMP_DIR}/API_VER="123" }
现在没有git pull 假装以echo 代替git pull
code_get(){writelog "code_get";cd $CODE_DIR && echo "git pull"cp -r ${CODE_DIR} ${TMP_DIR}/API_VER="123" }
属组授权
[root@linux-node1 scripts]# chown -R www:www /deploy/ [root@linux-node1 scripts]#
内容为hehe,生成代码(页面)
[root@linux-node1 scripts]# cd /deploy/code/web-demo/ [root@linux-node1 web-demo]# echo hehe>>index.html [root@linux-node1 web-demo]# cat index.html hehe [root@linux-node1 web-demo]#
文件和目录结构如下
[root@linux-node1 deploy]# tree . ├── code │ └── web-demo │ └── index.html ├── config │ └── web-demo │ └── config.ini ├── tar └── tmp6 directories, 2 files [root@linux-node1 deploy]#
以www用户测试脚本
[root@linux-node1 deploy]# cd /scripts/ [root@linux-node1 scripts]# chown -R www:www /scripts/deploy.sh [root@linux-node1 scripts]# ll total 12 -rw-r--r-- 1 root root 234 Apr 3 23:51 cobbler_list.py -rw-r--r-- 1 root root 1533 Apr 4 00:01 cobbler_system_api.py -rwxr-xr-x 1 www www 1929 Apr 23 23:04 deploy.sh [root@linux-node1 scripts]# su - www Last login: Sun Apr 23 22:06:44 CST 2017 on pts/0 [www@linux-node1 scripts]$ ./deploy.sh deploy git pull code_build code_config code_tar code_scp cluster_node_remove code_deploy config_diff code_test cluster_node_in [www@linux-node1 scripts]$
测试结果
[www@linux-node1 scripts]$ tree /deploy/ /deploy/ ├── code │ └── web-demo │ └── index.html ├── config │ └── web-demo │ └── config.ini ├── tar └── tmp├── web-demo_123-2017-04-23-23-12-15│ ├── config.ini│ └── index.html└── web-demo_123-2017-04-23-23-13-20├── config.ini└── index.html8 directories, 6 files [www@linux-node1 scripts]$
版本和时间之间改成下划线
code_config(){echo code_config/bin/cp -r ${CONFIG_DIR}/* ${TMP_DIR}/"${PRO_NAME}"PKG_NAME="${PRO_NAME}"_"${API_VER}"_"${CDATE}-${CTIME}"cd ${TMP_DIR} && mv ${PRO_NAME} ${PKG_NAME} }
再次执行
[www@linux-node1 scripts]$ ./deploy.sh deploy git pull code_build code_config code_tar code_scp cluster_node_remove code_deploy config_diff code_test cluster_node_in [www@linux-node1 scripts]$ tree /deploy/ /deploy/ ├── code │ └── web-demo │ └── index.html ├── config │ └── web-demo │ └── config.ini ├── tar └── tmp├── web-demo_123-2017-04-23-23-12-15│ ├── config.ini│ └── index.html├── web-demo_123-2017-04-23-23-13-20│ ├── config.ini│ └── index.html└── web-demo_123_2017-04-23-23-17-20├── config.ini└── index.html9 directories, 8 files [www@linux-node1 scripts]$
可以看到tmp目录需要定期清理
给下面2个函数加写日志功能
code_config(){writelog "code_config"/bin/cp -r ${CONFIG_DIR}/* ${TMP_DIR}/"${PRO_NAME}"PKG_NAME="${PRO_NAME}"_"${API_VER}"_"${CDATE}-${CTIME}"cd ${TMP_DIR} && mv ${PRO_NAME} ${PKG_NAME} }code_tar(){writelog "code_tar" }
打包,记录日志
code_tar(){writelog "code_tar"cd ${TMP_DIR} && tar cfz ${PKG_NAME}.tar.gz ${PKG_NAME}writelog "${PKG_NAME}.tar.gz" }
再次测试脚本
[www@linux-node1 scripts]$ ./deploy.sh deploy git pull code_build code_scp cluster_node_remove code_deploy config_diff code_test cluster_node_in [www@linux-node1 scripts]$ tree /deploy/ /deploy/ ├── code │ └── web-demo │ └── index.html ├── config │ └── web-demo │ └── config.ini ├── tar └── tmp├── web-demo_123-2017-04-23-23-12-15│ ├── config.ini│ └── index.html├── web-demo_123-2017-04-23-23-13-20│ ├── config.ini│ └── index.html├── web-demo_123_2017-04-23-23-17-20│ ├── config.ini│ └── index.html├── web-demo_123_2017-04-23-23-22-09│ ├── config.ini│ └── index.html└── web-demo_123_2017-04-23-23-22-09.tar.gz10 directories, 11 files [www@linux-node1 scripts]$
准备拷贝到目标服务器
前4步都完毕,开始第五步--拷贝到目标服务器
遍历节点
[www@linux-node1 scripts]$ node_list="192.168.58.11 192.168.58.12" [www@linux-node1 scripts]$ for node in $node_list;do echo $node;done 192.168.58.11 192.168.58.12 [www@linux-node1 scripts]$
脚本里添加node_list
#!/bin/bash#Node List NODE_LIST="192.168.58.11 192.168.58.12"# Date/Time Veriables LOG_DATE='date "+%Y-%m-%d"' LOG_TIME='date "+%H-%M-%S"'CDATE=$(date "+%Y-%m-%d") CTIME=$(date "+%H-%M-%S")
分发到目标节点
code_scp(){echo code_scpfor node in $NODE_LIST;doscp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot/done }
2台机器建立webroot
[root@linux-node1 scripts]# mkdir /opt/webroot -p [root@linux-node1 scripts]# chown -R www:www /opt/webroot [root@linux-node1 scripts]# [root@linux-node2 ~]# mkdir /opt/webroot -p [root@linux-node2 ~]# chown -R www:www /opt/webroot [root@linux-node2 ~]#
完善拷贝函数
code_scp(){echo code_scpfor node in $NODE_LIST;doscp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot/done }
再次部署测试下
[www@linux-node1 scripts]$ ./deploy.sh deploy git pull code_build code_scp web-demo_123_2017-04-23-23-33-50.tar.gz 100% 204 0.2KB/s 00:00 web-demo_123_2017-04-23-23-33-50.tar.gz 100% 204 0.2KB/s 00:00 cluster_node_remove code_deploy config_diff code_test cluster_node_in [www@linux-node1 scripts]$
检查
[www@linux-node1 scripts]$ tree /opt/webroot/ /opt/webroot/ └── web-demo_123_2017-04-23-23-33-50.tar.gz0 directories, 1 file [www@linux-node1 scripts]$ [root@linux-node2 ~]# tree /opt/webroot/ /opt/webroot/ └── web-demo_123_2017-04-23-23-33-50.tar.gz0 directories, 1 file [root@linux-node2 ~]#
该第6步了,写个日志代替
cluster_node_remove(){ writelog "cluster_node_remove" }
解压完毕,拷贝差异文件。你要把差异文件单独放一个目录下。不要和配置文件放一起
修改上面,上面是相同配置目录文件
code_config(){writelog "code_config"/bin/cp -r ${CONFIG_DIR}/* ${TMP_DIR}/"${PRO_NAME}"PKG_NAME="${PRO_NAME}"_"${API_VER}"_"${CDATE}-${CTIME}"cd ${TMP_DIR} && mv ${PRO_NAME} ${PKG_NAME} }
改成如下
code_config(){writelog "code_config"/bin/cp -r ${CONFIG_DIR}/base/* ${TMP_DIR}/"${PRO_NAME}"PKG_NAME="${PRO_NAME}"_"${API_VER}"_"${CDATE}-${CTIME}"cd ${TMP_DIR} && mv ${PRO_NAME} ${PKG_NAME} }
创建配置文件目录,base存放相同的配置,other存放差异配置
[www@linux-node1 scripts]$ cd /deploy/config/web-demo/ [www@linux-node1 web-demo]$ mkdir base [www@linux-node1 web-demo]$ mkdir other [www@linux-node1 web-demo]$ ll total 4 drwxrwxr-x 2 www www 6 Apr 23 23:38 base -rw-r--r-- 1 www www 5 Apr 23 22:46 config.ini drwxrwxr-x 2 www www 6 Apr 23 23:38 other [www@linux-node1 web-demo]$
调整下配置文件所在目录
[www@linux-node1 web-demo]$ mv config.ini base/ [www@linux-node1 web-demo]$ cd other/ [www@linux-node1 other]$ echo 192.168.58.12-config >>192.168.58.12.crontab.xml [www@linux-node1 other]$ ll total 4 -rw-rw-r-- 1 www www 21 Apr 23 23:39 192.168.58.12.crontab.xml [www@linux-node1 other]$
拷贝差异文件到目标服务器的目标目录
code_deploy(){echo code_deploycd /opt/webroot/ && tar xfz ${PKG_NAME}.tar.gz }config_diff(){echo config_diffscp ${CONFIG_DIR}/other/192.168.58.12.crontab.xml 192.168.58.12:/opt/webroot/${PKG_NAME} }
再次测试
[www@linux-node1 scripts]$ ./deploy.sh deploy git pull code_build code_scp web-demo_123_2017-04-23-23-43-48.tar.gz 100% 204 0.2KB/s 00:00 web-demo_123_2017-04-23-23-43-48.tar.gz 100% 204 0.2KB/s 00:00 code_deploy config_diff 192.168.58.12.crontab.xml 100% 21 0.0KB/s 00:00 code_test cluster_node_in [www@linux-node1 scripts]$
上面还有不足的地方,scp到目标服务器并解压,应该使用ssh远程执行、。上面脚本远程node2上解压是失败的
脚本再次改造下,把部署的函数和差异配置合并到一起
cluster_node_remove(){writelog "cluster_node_remove" }code_deploy(){echo code_deployfor node in $NODE_LIST;dossh $node "cd /opt/webroot/ && tar xfz ${PKG_NAME}.tar.gz"donescp ${CONFIG_DIR}/other/192.168.58.12.crontab.xml 192.168.58.12:/opt/webroot/${PKG_NAME}/crontab.xml }code_test(){echo code_test }
创建webroot
[root@linux-node1 ~]# mkdir /webroot [root@linux-node1 ~]# chown -R www:www /webroot [root@linux-node1 ~]# [root@linux-node2 ~]# mkdir /webroot [root@linux-node2 ~]# chown -R www:www /webroot [root@linux-node2 ~]#
再次对部署函数优化,添加使用软链接参数(这个是秒级回滚的关键)
cluster_node_remove(){writelog "cluster_node_remove" }code_deploy(){echo code_deployfor node in $NODE_LIST;dossh $node "cd /opt/webroot/ && tar xfz ${PKG_NAME}.tar.gz"donescp ${CONFIG_DIR}/other/192.168.58.12.crontab.xml 192.168.58.12:/opt/webroot/${PKG_NAME}/crontab.xmlln -s /opt/webroot/${PKG_NAME} /webroot/web-demo }code_test(){echo code_test }
再次对脚本优化
cluster_node_remove(){writelog "cluster_node_remove" }code_deploy(){echo code_deployfor node in $NODE_LIST;dossh $node "cd /opt/webroot/ && tar xfz ${PKG_NAME}.tar.gz"donescp ${CONFIG_DIR}/other/192.168.58.12.crontab.xml 192.168.58.12:/opt/webroot/${PKG_NAME}/crontab.xmlrm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo }code_test(){echo code_test }
自动化部署的精髓,创建软链接
对脚本优化,每个服务器要执行相同的操作,因此放在循环里
cluster_node_remove(){writelog "cluster_node_remove" }code_deploy(){echo code_deployfor node in $NODE_LIST;dossh $node "cd /opt/webroot/ && tar xfz ${PKG_NAME}.tar.gz"rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demodonescp ${CONFIG_DIR}/other/192.168.58.12.crontab.xml 192.168.58.12:/opt/webroot/${PKG_NAME}/crontab.xml }code_test(){echo code_test }
拷贝差异文件应该创建软链接之后拷贝,其实就是路径写的少点
cluster_node_remove(){writelog "cluster_node_remove" }code_deploy(){echo code_deployfor node in $NODE_LIST;dossh $node "cd /opt/webroot/ && tar xfz ${PKG_NAME}.tar.gz"rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demodonescp ${CONFIG_DIR}/other/192.168.58.12.crontab.xml 192.168.58.12:/webroot/web-demo/crontab.xml }code_test(){echo code_test }
第一次没软链接,会报错。需要先手动创建个软连接,或者先创建web-demo目录
其实我觉的完全可以在上面脚本里加入mkdir /webroot/web-demo -p 这样永远不会错
[www@linux-node1 scripts]$ cd /webroot/ [www@linux-node1 webroot]$ mkdir web-demo -p [www@linux-node1 webroot]$ [root@linux-node2 webroot]# mkdir web-demo -p [root@linux-node2 webroot]#
再次执行部署脚本。node1完成了
继续优化脚本,rm -rf 这里要写为-rf
cluster_node_remove(){writelog "cluster_node_remove" }code_deploy(){echo code_deployfor node in $NODE_LIST;dossh $node "cd /opt/webroot/ && tar xfz ${PKG_NAME}.tar.gz"ssh $node "rm -rf /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo"donescp ${CONFIG_DIR}/other/192.168.58.12.crontab.xml 192.168.58.12:/webroot/web-demo/crontab.xml }code_test(){echo code_test }
测试脚本
[www@linux-node1 scripts]$ ./deploy.sh deploy git pull code_build code_scp web-demo_123_2017-04-24-00-01-24.tar.gz 100% 204 0.2KB/s 00:00 web-demo_123_2017-04-24-00-01-24.tar.gz 100% 204 0.2KB/s 00:00 code_deploy 192.168.58.12.crontab.xml 100% 21 0.0KB/s 00:00 ./deploy.sh: line 113: config_diff: command not found code_test cluster_node_in [www@linux-node1 scripts]$
主函数里,删除这个 config_diff
继续测试和检查
测试 [www@linux-node1 scripts]$ ./deploy.sh deploy git pull code_build code_scp web-demo_123_2017-04-24-00-02-44.tar.gz 100% 205 0.2KB/s 00:00 web-demo_123_2017-04-24-00-02-44.tar.gz 100% 205 0.2KB/s 00:00 code_deploy 192.168.58.12.crontab.xml 100% 21 0.0KB/s 00:00 code_test cluster_node_in [www@linux-node1 scripts]$ 检查 [www@linux-node1 scripts]$ ll /webroot/ total 0 lrwxrwxrwx 1 www www 45 Apr 24 00:02 web-demo -> /opt/webroot/web-demo_123_2017-04-24-00-02-44 [www@linux-node1 scripts]$ [root@linux-node2 webroot]# ll /webroot/ total 0 lrwxrwxrwx 1 www www 45 Apr 24 00:02 web-demo -> /opt/webroot/web-demo_123_2017-04-24-00-02-44 [root@linux-node2 webroot]#
模拟版本更新,把版本写成456
code_get(){writelog "code_get";cd $CODE_DIR && echo "git pull"cp -r ${CODE_DIR} ${TMP_DIR}/API_VER="456" }
继续测试
[www@linux-node1 scripts]$ ./deploy.sh deploy git pull code_build code_scp web-demo_456_2017-04-24-00-04-05.tar.gz 100% 204 0.2KB/s 00:00 web-demo_456_2017-04-24-00-04-05.tar.gz 100% 204 0.2KB/s 00:00 code_deploy 192.168.58.12.crontab.xml 100% 21 0.0KB/s 00:00 code_test cluster_node_in [www@linux-node1 scripts]$ ll /webroot/ total 0 lrwxrwxrwx 1 www www 45 Apr 24 00:04 web-demo -> /opt/webroot/web-demo_456_2017-04-24-00-04-05 [www@linux-node1 scripts]$
检查
链接 到了新的版本
转载于:https://blog.51cto.com/zengwj1949/1982313
自动化部署shell01相关推荐
- Jenkins 流水线 获取git 分支列表_jenkins的安装和配置 自动化部署 码云 gitee
目前项目使用的jenkins 自动化部署的还是比较多的 ,所以趁着脑瓜子还清醒,来写一下如何使用 jenkins 使用码云更新代码后,重新构建就是最新的代码,费话不多少了 直接上货, 首先要做一下准备 ...
- Azure自动化部署运维浅谈
本次来谈一谈如何在Azure中实现一些简单的自动化运维的需求,一般来讲自动化运维我们通过很多第三方的工具平台实现,比较流行的目前有很多,比如老牌的chef, puppet,新兴的PowerShell ...
- 公有云环境下应用程序的自动化部署与水平扩展问题
先介绍了一下公有云计算环境下的一些特点,再根据这些特点探讨一下作为云计算用户而言,如何对应用程序做好自动化部署和水平扩展(弹性计算)的问题.阅读本文需要有一定的云计算知识.开发运维知识. 公有云环境的 ...
- 一套基础自动化部署搭建过程
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:LoyaltyLu segmentfault.com/a/1 ...
- 20分钟一键自动化部署10台集群规模实战(隆重分享)
特别隆重分享此内容给所有关心,支持老男孩的所有朋友和学员! 博文内容介绍: 本视频精彩纷呈,无比震撼,不看会后悔,特别是初中级运维,会感受很多! 本内容来自老男孩教育,20期学生的期中架构实战分享讲解 ...
- springboot 使用Jenkins实现自动化部署
springboot 使用Jenkins实现自动化部署 简介 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持 ...
- Jenkins 自动化部署上线
Jenkins 自动化部署上线 Jenkins 自动化部署上线 由于51cto格式问题,可以直接访问https://www.abcdocker.com/abcdocker/3174 查看原文 [TOC ...
- Devstack 多节点自动化部署
本文为minxihou的翻译文章,转载请注明出处Bob Hou: http://blog.csdn.net/minxihou JmilkFan:minxihou的技术博文方向是 算法&Open ...
- Python—自动化部署工具:Fabric
Fabric是python编写的一款自动化部署工具 Fabric依赖paramiko进行SSH交互,某种意义上Fabric是对paramiko的封装,封装完成后,不需要像使用paramiko一样处理S ...
最新文章
- LeetCode简单题之检查字符串是否为数组前缀
- maven的pom.xml中profiles的作用
- .NET6之MiniAPI(十五):跨域CORS(下)
- (转)在编写Spring框架的配置文件时,标签无提示符的解决办法
- 数据可视化 —— 数据流图(Data Flow Diagram)
- java类中代码执行顺序
- 用 Python 自制成语接龙小游戏!
- Eclipse 中设置编辑器字体,包括 Java 编辑器,XML 编辑器和 Property 编辑器的字体都可以设置
- php查看版本命令,如何查看php版本?查看php版本的详细步骤分享
- 通过FTP从服务器上下载文件
- MongoTemplate地理位置查询(标准)
- 虚拟机克隆的服务器怎么改mac地址,Centos6克隆虚拟机改IP和mac地址
- openoffice 中文乱码问题
- matlab处理声音报告,基于MATLAB的语音信号分析与处理的实验报告.doc
- html5个人影集,全屏的个人影集展示网页模板
- 关于cmake与make
- (个人翻译)Scrivener交互式手册中文版FowWindows 03基础操作
- 【已解决】Nginx基于多端口、多域名配置
- IP地址详解(扫盲篇)
- 计算机应用基础本科试题及答案,计算机应用基础课程(本科)网考模拟试题