shell函数
1、分别在服务器和客户端上创建www用户
useradd www id wwww
- 所有的web服务,都应该使用普通用户,所有的web服务都不应该监听80端口,除非负载均衡。8080
- 普通用户能启动80端口吗?通过和科技,比如给命令设置suid
- 生产指定uid
2、保证www用户登录其他的节点都不要输入密码
服务器端:
[root@node1 ~]# useradd www [root@node1 ~]# id www [root@node1 ~]# passwd www [root@node1 ~]# su www [root@node1 ~]# cd /home/www/ [www@node1 ~]$ ssh-copy-id -i .ssh/id_rsa.pub www@172.16.14.116 [www@node1 ~]$ ssh 172.16.14.116 Last failed login: Sat Jan 13 09:56:41 CST 2018 from 172.16.14.115 on ssh:notty There were 3 failed login attempts since the last successful login. Last login: Sat Jan 13 09:23:02 2018
客户端:
[root@node2 ~]# useradd www [root@node2 ~]# id www [root@node2 ~]# passwd www [root@node2 ~]# su www [root@node2 ~]# cd /home/www/ [www@node2 ~]$ ssh-copy-id -i .ssh/id_rsa.pub www@172.16.14.115 [www@node2 ~]$ ssh 172.16.14.115 Last failed login: Sat Jan 13 09:56:41 CST 2018 from 172.16.14.115 on ssh:notty There were 3 failed login attempts since the last successful login. Last login: Sat Jan 13 09:23:02 2018
3、写一个复杂的脚本
先把框架写出来,使用echo来测试框架的流程是否正确
#!/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/" TMP_DIR="/deploy/config" 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_get; sleep 2; } code_build(){ echo code_build; sleep 2; } code_config(){ echo code_config; sleep 2; } code_tar(){ echo code_tar; sleep 2; } code_scp(){ echo code_scp; sleep 1; } cluster_node_remove(){ echo cluster_node_remove; sleep 1; } code_deploy(){ echo code_deploy; } config_diff(){ echo config__diff; } code_test(){ echo code_test; } cluster_node_in(){ echo cluster_node_in; } main(){ if [ -f $LOCK_FILE ];then echo "Deploy is running"&& exit; fi DEPLOY_METHOD=$1 case $DEPLOY_METHOD in deploy) 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 }
4、什么也没提示?在末尾添加 man $1
main(){ DEPLOY_METHOD=$1 case $DEPLOY_METHOD in deploy) shell_lock; ;; rollback) shell_lock; ;; *) usage; esac } main $1
本节小结:
1、凡是不记录日志的脚本就是耍流氓
2、这个脚本能不能多个人同时执行?
1、最好不要,但是运维团队有很多人,我如何知道别人有没有执行?
答:我写一个锁文件
1、锁文件放那?
答:放在/tmp/deploy.lock" 因为放在下www没有权限
2、系统的锁文件放哪里?
/var/run/lock
3、看不出来?
答:sleep60秒
4、不是脚本的$1匙函数的$1
5、在两台电脑上都要用到所以定义为变量
2、功能实现
1、日志函数
#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") .... writelog(){ LOGINFO=$1 echo "${CDATE} ${CTIME}: ${SHELL_NAME}: ${LOGINFO}" >> ${SHELL_LOG} }
1、希望在很多地方记录日志
echo一行,写到一个文件里,记日志还要记时间
方法1:写一个日志的函数,每次调用这个函数
方法2:在每一个函数里写一个echo,然后写在那个位置,还要记时间
2、日志函数的好处?
- 这个函数可以复制,以后写别的脚本直接改改就可以
- 每一个函数里都写一个函数
3、shell是如何解析的?
从上倒下逐行执行
4、遇到函数怎么办?
先加载不执行
5、日志的内容从哪来?
从参数来:$1
6、脚本名称:
当前日期+脚本名称+日志内容
难保你以后会写在一起所以要区分开
7、时间是不是不能变?
我就不需要它变:
1、打包的时候不能变,包里有有日期和时间包名不能变
2、打包如何命名?
是scp时间不对,包就找不着了
LOG_DATE='date "+%Y-%m-%d"' LOG_TIME='date "+%H-%M-%S"'
- 一个是让执行 记日志用的
- 一个不让执行 做别的用处
- 已经执行了,在后面就不变了
2、get代码函数
#Code Env PRO_NAME="web-demo" CODE_DIR="/deploy/code/web-demo" CONFIG_DIR="/deploy/config/web-demo" TMP_DIR="/deploy/tmp" LOCK_FILE="/tmp/deploy.lock" ....... code_get(){ writelog "code_get"; cd $CODE_DIR && echo "git pull" cp -r ${CODE_DIR} ${TMP_DIR}/ API_VERL=$(git show |grep commit | cut -d ' ' -f2) API_VER=$(echo ${API_VERL:0:6})
1、代码应该放在那?
放在CODE_DIR="/deploy/code/web-demo"目录下
2、配置文件能直接放CODE_DIR这吗?
不能,专门用于git更新的目录
如果你把文件拷贝到这里,所有的包里面都有这个文件
一不小心多放了一个,那个可不会pull
3、怎样区分是仓库的还是我copy过来的?
也能区分 看git状态,本地状态 正常区分不了
更新完之后copy走,放着也行出故障了你就知道是什么意思了!
4、复制到哪?
TMP_DIR
5、为什么对web-demo要重命名?
- 复制过去要重命名
- 打包的时候还要重命名
- 每次都覆盖那就乱了
6、要怎样重命名?
时间+版本号?
1、svn怎样获取版本号?
2、git如何获取版本号?
API_VERL=$(git show |grep commit | cut -d ' ' -f2)
3、配置文件函数
#Code Env PRO_NAME="web-demo" CODE_DIR="/deploy/code/web-demo" CONFIG_DIR="/deploy/config/web-demo" TMP_DIR="/deploy/tmp" LOCK_FILE="/tmp/deploy.lock" ...... code_config(){ writelog "code_config" /bin/cp -r ${CONFIG_DIR}/base/* ${TMP_DIR}/"${PRO_NAME}" PKG_NAME="${PKG_NAME}"_"$API_VER"_"${CDATE}-${CTIME}" cd ${TMP_DIR} && mv ${PKG_NAME} ${PKG_NAME}} }
1、我是哪个项目的配置文件?
CONFIG_DIR="/deploy/config/web-demo"
2、为什么加/bin/cp -r?
/bin/cp -r ${CONFIG_DIR}/base/* ${TMP_DIR}/"${PRO_NAME}"
1、有可能我文件下还有目录呢!
2、我拷贝的那个目录下有那个配置文件
有一测试有权限,犯二提交了一个相同的配置文件 你没有覆盖连到测试库了
大家打开的都是测试的库
开发可以错,测试可以错,运维不可以错 为什么你上线的时候也没发现?
每一个小细节都是有意义不是瞎写
3、复制和打包可以放在一个里面,为什么把包名做成一个变量?
- 很多地方都用到
- 包名很长
- 包名本身也包含变量
4、为什么要全写成变量
因为不只为这一个脚本,写别的脚本改改就可以啦!
5、为什么tmp需要定期进行清理?
部署几个月可以,时间久磁盘就满了
有时间了就好删除了,解决了各种方式
只有版本号你怎样删?把15年的全删了
4、打包函数
code_tar(){ writelog "code_tar" cd ${TMP_DIR} && tar czf ${PKG_NAME}.tar.gz ${PKG_NAME} writelog "${PKG_NAME}.tar.gz" }
1、为什么要写&&?
函数和函数之间可不知道上一级目录是什么!!!
不单独搞一行,如果目录不存在进去了可能不是你想要的
5、scp到目标服务器
code_scp(){ writelog "code_scp" for node in $PRE_LIST;do for node in $GROUP1_LIST;do scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot/ done }
1、统一用一个包的好处?
完全可以写一个for循环
我要加机器 在列表里加一行
减机器 在列表里减去一行
标准化的好处
2、为什么不能直接写在/opt?
- 没有权限
- 在opt创建一个/opt/webroot/复制到这
6、部署函数
group1_deploy(){ writelog "remove from cluster" for node in $GROUP1_LIST;do ssh $node "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" ssh $node "rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" done scp ${CONFIG_DIR}/other/192.168.56.12.crontab.xml 192.168.56.12:/webroot/web-demo/crontab.xml }
1、项目之间应该保持独立才对
2、你的目录放在那?
所有生产的web服务器的家目录都写在/webroot的项目名称下
3、为什么先创建软链接然后在复制差异文件?
路径写的少,要不然你写到解压后的路径下
如果没有生成我就不复制
生产部署的时候,没部署成功结果scp复制过去了
4、第一次手动创建一个因为 没有会报错。
su -www cd /webroot/ touch web-demo 用salt就要先touch文件
5、&&不能去掉,因为以后部署时候我要先删除才能软链接
6、一个软连接连一毫秒都花不了
3、脚本扩展
1、每个节点上各装一个apache
yum install httpd -y
2、修改配置文件以下两处
vim /etc/httpd/conf/httpd.conf
1、测试函数
url_test(){ URL=$1 curl -s --head $URL |grep '200 ok' if [ $? -ne 0 ];then shell_unlock; echo "test error" && exit; fi }
1、测试一能访问就加入集群不能访问就移除集群
2、部署一个测一个通了才能加到集群里
生产是一个组一个组测试
并行和串行相结合
每一个组一个预生产节点
直接部署第二个节点
2、主函数
main(){ if [ -f $LOCK_FILE ]; then echo "Deploy is running" && exit; fi DEPLOY_METHOD=$1 ROLLBACK_VER=$2 case $DEPLOY_METHOD in deploy) shell_lock; code_get; code_build; code_config; code_tar; code_scp; pre_deploy; pre_test; group1_deploy; group1_test; shell_unlock; ;; rollback) shell_lock; rollback $ROLLBACK_VER; shell_unlock; ;; *) usage; esac } main $1 $2
1、先判断是否有文件,存在说明有人在执行直接退出
2、你是要部署还是要回滚,要是是部署先锁住脚本
从git上获取文件
进行编译
复制配置文件进去
打包并重命名
scp到所有机器(不分组)
晚上要做一个不算停机维护,所有机器都需要同时重启
涉及到数据一致性
组一部署集群
测试组一集群
4、秒级回滚
在某个地方记住上一个版本是啥,部署把版本写在一个文件里(紧急回滚的一个函数),然后读这个文件
rollback(){ if [ -z $1 ];then shell_unlock; echo "please input rollback version" && exit; fi case $1 in list) ls -l /opt/webroot/*.tar.gz ;; *) rollback_fun $1 esac }
-
部署还是回滚$1,回滚到那个版本是$2
-
传list的我就列出来,不传我就回滚
-
我可以只部署预生产,我部署机肯定有我其他的节点没有
rollback_fun(){ for node in $ROLLBACK_LIST;do ssh $node "rm -f /webroot/web-demo && ln -s /opt/webroot/$1 /webroot/web-demo" done
1、如果list存在我就执行,不存在就结束for循环
2、远程ssh执行命令,引起来才能当成一个,因为中间还有空格
3、脚本的$2传到回滚函数里就是$1
5、gitlab部署和回滚
安装gitlab私有仓库,地址见运维社区gitlab
1、登陆修改root密码
2、备份:每天备份每小时也行
越频繁越好
分布式每个人的本地都有
6、完整脚本构造
#!/bin/bash #Dir List mkdir -p /deploy/code/web-demo mkdir -p /deploy/config/web-demo/base mkdir -p /deploy/config/web-demo/other mkdir -p /deploy/tar mkdir -p /deploy/tmp mkdir -p /opt/webroot mkdir /webroot chown -R www.www /deploy chown -R www.www /opt/webroot chown -R www.www /webroot #Node List PRE_LIST="192.168.56.11" GROUP1_LIST="192.168.56.12" ROLLBACK_LIST="192.168.56.11 192.168.56.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") #Shell Env SHELL_NAME="deploy_all.sh" SHELL_DIR="/home/www/" SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log" #Code Env PRO_NAME="web-demo" CODE_DIR="/deploy/code/web-demo" CONFIG_DIR="/deploy/config/web-demo" TMP_DIR="/deploy/tmp" LOCK_FILE="/tmp/deploy.lock" usage(){ echo $"Usage: $0{deploy|rollback[ list|version ]}" } writelog(){ LOGINFO=$1 echo "${CDATE} ${CTIME}: ${SHELL_NAME}: ${LOGINFO}" >> ${SHELL_LOG} } shell_lock(){ touch ${LOCK_FILE} } url_test(){ URL=$1 curl -s --head $URL |grep '200 ok' if [ $? -ne 0 ];then shell_unlock; echo "test error" && exit; fi } shell_unlock(){ rm -f ${LOCK_FILE} } code_get(){ writelog "code_get"; cd $CODE_DIR && echo "git pull" cp -r ${CODE_DIR} ${TMP_DIR}/ API_VERL=$(git show |grep commit | cut -d ' ' -f2) API_VER=$(echo ${API_VERL:0:6}) } code_build(){ echo code_Build } code_config(){ writelog "code_config" /bin/cp -r ${CONFIG_DIR}/base/* ${TMP_DIR}/"${PRO_NAME}" PKG_NAME="${PKG_NAME}"_"$API_VER"_"${CDATE}-${CTIME}" cd ${TMP_DIR} && mv ${PKG_NAME} ${PKG_NAME}} } code_tar(){ writelog "code_tar" cd ${TMP_DIR} && tar czf ${PKG_NAME}.tar.gz ${PKG_NAME} writelog "${PKG_NAME}.tar.gz" } code_scp(){ writelog "code_scp" for node in $PRE_LIST;do for node in $GROUP1_LIST;do scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot/ done } pre_deploy(){ writelog "remove from cluster" ssh $PRE_LIST "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" ssh $PRE_LIST "rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" } pre_test(){ url_test "http://${PRE_LIST}/index.html" echo "add to cluster" } group1_deploy(){ writelog "remove from cluster" for node in $GROUP1_LIST;do ssh $node "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" ssh $node "rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" done scp ${CONFIG_DIR}/other/192.168.56.12.crontab.xml 192.168.56.12:/webroot/web-demo/crontab.xml } group1_test(){ url_test "http://192.168.56.12/index.html" echo "add to cluster" } rollback_fun(){ for node in $ROLLBACK_LIST;do ssh $node "rm -f /webroot/web-demo && ln -s /opt/webroot/$1 /webroot/web-demo" done } rollback(){ if [ -z $1 ];then shell_unlock; echo "please input rollback version" && exit; fi case $1 in list) ls -l /opt/webroot/*.tar.gz ;; *) rollback_fun $1 esac } main(){ if [ -f $LOCK_FILE ]; then echo "Deploy is running" && exit; fi DEPLOY_METHOD=$1 ROLLBACK_VER=$2 case $DEPLOY_METHOD in deploy) shell_lock; code_get; code_build; code_config; code_tar; code_scp; pre_deploy; pre_test; group1_deploy; group1_test; shell_unlock; ;; rollback) shell_lock; rollback $ROLLBACK_VER; shell_unlock; ;; *) usage; esac } main $1 $2
转载地址:https://github.com/unixhot/deploy-shell