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
作者:罗阿红