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
