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