自動化部署基礎與shell腳本實現
關于自動化的基礎知識:
1.1:當前代碼部署的實現方式:
運維純手工scp到web服務器
純手工登錄git服務器執行git pull或svn服務器執行svn update更新代碼
通過xftp上傳代碼
開發打壓縮包上傳到服務器然后解壓
缺點:
1.需要運維全程參與,占用大量的工作時間
2.上線時間比較慢
3.人為造成的失誤較多,管理比較混亂
4.回滾復雜而且慢,還不及時
1.2:運行環境規劃:
開發環境:開發者本地有自己的環境,然后運維需要設置開發環境的公用服務,例如開發數據庫、redis、memcached等
測試環境:功能測試環境和性能測試環境
預生產環境:由生產環境集群中的某一個節點擔任測試,此節點只做測試不對外提供服務
生產環境:直接對外提供服務的環境
為什么有預生產環境?
可能是生產環境預測試環境的數據庫或數據庫版本不一樣導致語句出現問題
或者是生產環境調用的接口不一樣,例如支付接口在測試環境無法調用
1.3:設計一套生產環境的代碼自動化部署系統:
開發環境 --> 功能測試/性能測試 --> 預生產環境 --> 生產環境
1.4:總體規劃流程:
一個服務的集群節點數量,是一次部署還是分次部署
一鍵回滾到上個版本
一鍵回滾到任意版本
代碼保存在SVN還是Git
獲取指定分支或master的指定版本號的代碼,svn指定版本號,git指定tag標簽,或直接拉取某個分支
配置文件差異化,即測試環境和生產環境的配置文件不一樣,如IP不一樣或主機名不一樣或數據庫連接不一樣等等
代碼倉庫和實際的差異,即配置文件是否放在代碼倉庫中,如果保存在git則所有人都可以從配置文件看到數據庫用戶密碼等信息,可以使用單獨分支保存配置文件,或配置文件只在部署服務器的某個項目的目錄,比如是config.example
如何更新代碼,java tomcat需要重啟
測試部署后的web頁面是否可以正常訪問是否是想要的頁面
并行(saltstack)或并行(shell)的問題,涉及到分組部署重啟服務
如何執行,shell執行還是web執行
1.5:總體規劃如下:
獲取代碼(git pull拉取) --> 是否編譯(java需要編譯) --> 配置文件(統一和差異) --> 打包 --> scp到目標服務器(或者用saltstack) --> 將服務器移除集群 --> 解壓代碼包 --> 放置到目標目錄(如webroot) --> scp差異文件 --> 重啟服務(可選) --> 測試服務(訪問web或者post請求) --> 將節點重新加入集群
二:實現代碼自動化部署
2.1:通過shell腳本實現,shell腳本規劃如下:
2.1.1:各web服務器添加一個uid相同的普通用戶,而且所有的web服務都以此普通用戶啟動,默認情況下所有的wenb服務除了負載均衡之外都不能監聽80端口,比如可以監聽8008端口
2.1.2:部署服務器的用戶登錄其他服務器免密碼登錄,因此需要做秘鑰認證,在各主機執行以下命令:
# useradd www -u 1010
# su – www
$ ssh-keygen
#將部署機www用戶的公鑰復制到各web服務器的 /home/www/.ssh/authorized_keys或執行ssh-copy-id www@192.168.3.13
$ chmod 600 /home/www/.ssh/authorized_keys
2.1.3:測試部署服務器是否可以免秘鑰用www用戶登錄各個web服務器
2.2:編寫shell腳本:
2.2.1:完成框架編寫:
#!/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_get"sleep 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 "cluste_node_in"
}rollback(){echo "rollback"
}# 主函數
main(){ if [ -f $LOCK_FILE ];
then # 先判斷鎖文件在不在echo "Deploy is running" && exit
10; # 如果有鎖文件直接退出fi DEPLOY_METHOD=$
1 # 避免出錯誤將腳本的第一個參數作為變量case $DEPLOY_METHOD
indeploy) # 如果第一個參數是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) # 如果第一個參數是rollback就執行以下操作shell_lock; # 回滾之前也是先創建鎖文件rollback; # 執行完成刪除鎖文件shell_unlock;;;*
) # 其他輸入執行以下操作usage;esac
}
# 執行主函數并把第一個變量當參數
main $1 ?
2.2.2:完成腳本:實現代碼部署、測試、回滾等操作:
代碼回滾設計:
正常回滾是回滾已經在web服務器部署過的版本,因此就不需要獲取代碼打包和部署的過程了
列出回滾版本
將模板服務器移除集群
執行回滾
重啟和測試
將模板服務器加入集群
#!/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 /deploy/
tmp
# mkdir /deploy/
tar# chown -R www.www /
deploy
# chown -R www.www /
webroot
# chown -R www.www /opt/webroot/
# chown -R www.www /
webroot# 需要在客戶端節點做的操作
# mkdir /opt/
webroot
# mkdir /
webroot
# chown -R www.www /
webroot
# chown -R www.www /opt/webroot/
# chown -R www.www /
webroot
# [www@ ~]$
touch /webroot/web-
dem# Node List 服務器節點
PRE_LIST=
"192.168.3.12" # 預生產節點
GROUP1_LIST=
"192.168.3.12 192.168.3.13"
GROUP2_LIST=
"192.168.3.13"
ROLLBACK_LIST=
"192.168.3.12 192.168.3.13"# 日志日期和時間變量
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 代碼變量
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" # 鎖文件路徑usage(){ # 使用幫助函數echo $
"Usage: $0 [ deploy | rollback [ list | version ]"
}writelog(){ # 寫入日志的函數LOGINFO=$
1 # 將參數作為日志輸入echo "${CDATE} ${CTIME} : ${SEHLL_NAME} : ${LOGINFO}" >>
${SHELL_LOG}
}# 鎖函數
shell_lock(){touch ${LOCK_FILE}
}# 解鎖函數
shell_unlock(){rm -
f ${LOCK_FILE}
}# 獲取代碼的函數
code_get(){echo "code_get"writelog code_getcd $CODE_DIR &&
echo "git pull" # 進入到代碼目錄更新代碼,此處必須免密碼更新,此目錄僅用于代碼更新不能放其他任何文件cp -rf ${CODE_DIR} ${TMP_DIR}/ # 臨時保存代碼并重命名,包名為時間+
版本號,準備復制到web服務器API_VER=
"123" # 版本號
}code_build(){ # 代碼編譯函數echo code_build
}code_config(){ # 配置文件函數writelog code_config/bin/
cp -rf ${CONFIG_DIR}/base
/* ${TMP_DIR}/"${PRO_NAME}" # 將配置文件放在本機保存配置文件的臨時目錄,用于暫時保存代碼項目PKG_NAME="${PRO_NAME}"_"$API_VER"_"${CDATE}-${CTIME}" # 定義代碼目錄名稱cd ${TMP_DIR} && mv ${PRO_NAME} ${PKG_NAME} # 重命名代碼文件為web-demo_123-20170629-11-19-10格式}code_tar(){ # 對代碼打包函數writelog code_tarcd ${TMP_DIR} && tar czf ${PKG_NAME}.tar.gz ${PKG_NAME}writelog "${PKG_NAME}.tar.gz"
}code_scp(){ # 代碼壓縮包scp到客戶端的函數writelog "code_scp"for node in $PRE_LIST;do # 循環服務器節點列表scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot/ # 將壓縮后的代碼包復制到web服務器的/opt/webrootdonefor node in $GROUP1_LIST;do # 循環服務器節點列表scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot/ # 將壓縮后的代碼包復制到web服務器的/opt/webrootdone
}url_test(){URL=$1curl -s --head $URL |grep '200 OK'if [ $? -ne 0 ];thenshell_unlock;writelog "test error" && exit;fi
}cluster_node_add(){ #將web服務器添加至前端負載echo cluster_node_add
}cluster_node_remove(){ # 將web服務器從集群移除函數(正在部署的時候應該不處理業務)writelog "cluster_node_remove"
}pre_deploy(){writelog "pre_deploy"for node in ${PRE_LIST};do # 循環預生產服務器節點列表cluster_node_remove ${node} # 部署之前將節點從前端負載刪除echo "pre_deploy, cluster_node_remove ${node}"ssh ${node} "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" #分別到web服務器執行壓縮包解壓命令ssh ${node} "rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" # 整個自動化的核心,創建軟連接done
}pre_test(){ # 預生產主機測試函數for node in ${PRE_LIST};do # 循環預生產主機列表curl -s --head http://${node}:9999/index.html | grep "200 OK" # 測試web界面訪問if [ $? -eq 0 ];then # 如果訪問成功writelog " ${node} Web Test OK!" # 記錄日志echo " ${node} Web Test OK!"cluster_node_add ${node} # 測試成功之后調用添加函數把服務器添加至節點,writelog "pre,${node} add to cluster OK!" # 記錄添加服務器到集群的日志else # 如果訪問失敗writelog "${node} test no OK" # 記錄日志echo "${node} test not OK"shell_unlock # 調用刪除鎖文件函數break # 結束部署fidone}group1_deploy(){ # 代碼解壓部署函數writelog "group1_code_deploy"for node in ${GROUP1_LIST};do # 循環生產服務器節點列表cluster_node_remove $node echo "group1, cluster_node_remove $node"ssh ${node} "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" # 分別到各web服務器節點執行壓縮包解壓命令ssh ${node} "rm -f /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" # 整個自動化的核心,創建軟連接donescp ${CONFIG_DIR}/other/192.168.3.13.server.xml 192.168.3.13:/webroot/web-demo/server.xml # 將差異項目的配置文件scp到此web服務器并以項目結尾
} group1_test(){ # 生產主機測試函數for node in ${PRE_LIST};do # 循環生產主機列表curl -s --head http://${node}:9999/index.html | grep "200 OK" #測試web界面訪問if [ $? -eq 0 ];then #如果訪問成功writelog " ${node} Web Test OK!" #記錄日志echo "group1_test,${node} Web Test OK!"cluster_node_addwritelog " ${node} add to cluster OK!" #記錄將服務器 添加至集群的日志else #如果訪問失敗writelog "${node} test no OK" #記錄日志echo "${node} test no OK"shell_unlock # 調用刪除鎖文件函數break # 結束部署fidone
}rollback_fun(){ for node in $ROLLBACK_LIST;do # 循環服務器節點列表# 注意一定要加"號,否則無法在遠程執行命令ssh $node "rm -f /webroot/web-demo && ln -s /opt/webroot/$1 /webroot/web-demo" # 立即回滾到指定的版本,$1即指定的版本參數echo "${node} rollback success!"done
}rollback(){ # 代碼回滾主函數if [ -z $1 ];thenshell_unlock # 刪除鎖文件echo "Please input rollback version" && exit 3;ficase $1 in # 把第二個參數做當自己的第一個參數 list)ls -l /opt/webroot/*.tar.gz;;*)rollback_fun $1esac}main(){if [ -f $LOCK_FILE ] ;then # 先判斷鎖文件在不在,如果有鎖文件直接退出echo "Deploy is running" && exit 10fiDEPLOY_METHOD=$1 # 避免出錯誤將腳本的第一個參數作為變量ROLLBACK_VER=$2case $DEPLOY_METHOD indeploy) # 如果第一個參數是deploy就執行以下操作shell_lock; # 執行部署之前創建鎖。如果同時有其他人執行則提示鎖文件存在code_get; # 獲取代碼code_build; # 如果要編譯執行編譯函數code_config; # cp配置文件code_tar; # 打包code_scp; # scp到服務器pre_deploy; # 預生產環境部署pre_test; # 預生產環境測試group1_deploy; # 生產環境部署group1_test; # 生產環境測試shell_unlock; # 執行完成后刪除鎖文件;;rollback) # 如果第一個參數是rollback就執行以下操作shell_lock; # 回滾之前也是先創建鎖文件rollback $ROLLBACK_VER;shell_unlock; # 執行完成刪除鎖文件;;*)usage;esac
}
main $1 $2 ?
3.通過剛才編寫的shell腳本將html官網頁面部署到nginx中
①將代碼上傳到部署節點的/deploy/code/web-demo目錄中
[www@master web-demo]$
pwd
/deploy/code/web-
demo
[www@master web-
demo]$ ll
total 20
drwxr-xr-x
6 www www
4096 Jun
6 13:
46 assets
-rw-r--r--
1 www www
1150 Jun
6 17:
59 favicon.ico
drwxr-xr-x
2 www www
4096 Jun
6 15:
32 images
-rw-r--r--
1 www www
4323 Jun
6 16:
19 index.html
?
部署節點執行以下操作:
#
mkdir -p /deploy/code/web-
demo
# mkdir -p /deploy/config/web-demo/
base
# mkdir -p /deploy/config/web-demo/
other
# mkdir /deploy/
tmp
# mkdir /deploy/
tar# chown -R www.www /
deploy
# chown -R www.www /
webroot
# chown -R www.www /opt/webroot/
?
②需要在客戶端做的操作
# 安裝nginx
# yum install -y nginx
編輯nginx
vim /etc/nginx/conf.d/
cloudeye.confserver {listen 9999;server_name 192.168.
3.13; # 實際生產環境中需要填寫域名location /
{alias /webroot/web-demo/; # 這個web-demo目錄不需要創建,有軟鏈接指向/webroot/web-
demo目錄index index.html;}
} ?
創建相關目錄并修改權限
mkdir /opt/
webroot
mkdir /
webroot
chown -R www.www /
webroot
chown -R www.www /opt/webroot/
[www@ ~]$
touch /webroot/web-demo
?
③執行腳本
測試部署:
[www@master ~]$ ./deploy.
sh deploy
code_get
git pull
code_build
web-demo_123_2017-
06-
26-
12-
18-
09.
tar.gz
100% 1214KB
1.2MB/s
00:
00
web-demo_123_2017-
06-
26-
12-
18-
09.
tar.gz
100% 1214KB
1.2MB/s
00:
00
web-demo_123_2017-
06-
26-
12-
18-
09.
tar.gz
100% 1214KB
1.2MB/s
00:
00
pre_deploy, cluster_node_remove 192.168.
3.12
HTTP/
1.1 200 OK
192.168.
3.12 Web Test OK!
cluster_node_add
group1, cluster_node_remove 192.168.
3.12
group1, cluster_node_remove 192.168.
3.13
/deploy/config/web-demo/other/
192.168.
3.13.server.xml: No such
file or directory
HTTP/
1.1 200 OK
group1_test,192.168.
3.12 Web Test OK!
cluster_node_add ?
訪問客戶端,可以看到能夠正常訪問,說明部署成功
http://192.168.3.13:9999
修改代碼,測試回滾效果
[www@master ~]$ vim /deploy/code/web-demo/
index.html
[www@master ~]$ ./deploy.
sh deploy
code_get
git pull
code_build
web-demo_123_2017-
06-
26-
12-
18-
57.
tar.gz
100% 1214KB
1.2MB/s
00:
00
web-demo_123_2017-
06-
26-
12-
18-
57.
tar.gz
100% 1214KB
1.2MB/s
00:
00
web-demo_123_2017-
06-
26-
12-
18-
57.
tar.gz
100% 1214KB
1.2MB/s
00:
00
pre_deploy, cluster_node_remove 192.168.
3.12
HTTP/
1.1 200 OK
192.168.
3.12 Web Test OK!
cluster_node_add
group1, cluster_node_remove 192.168.
3.12
group1, cluster_node_remove 192.168.
3.13
/deploy/config/web-demo/other/
192.168.
3.13.server.xml: No such
file or directory
HTTP/
1.1 200 OK
group1_test,192.168.
3.12 Web Test OK!
cluster_node_add[www@master ~]$ ./deploy.
sh rollback list
-rw-rw-r--
1 www www
1243347 Jun
26 11:
36 /opt/webroot/web-demo_123_2017-
06-
26-
11-
36-
44.
tar.gz
-rw-rw-r--
1 www www
1243347 Jun
26 11:
39 /opt/webroot/web-demo_123_2017-
06-
26-
11-
39-
02.
tar.gz
-rw-rw-r--
1 www www
1243351 Jun
26 12:
04 /opt/webroot/web-demo_123_2017-
06-
26-
12-
04-
19.
tar.gz
-rw-rw-r--
1 www www
1243347 Jun
26 12:
16 /opt/webroot/web-demo_123_2017-
06-
26-
12-
16-
49.
tar.gz
-rw-rw-r--
1 www www
1243347 Jun
26 12:
18 /opt/webroot/web-demo_123_2017-
06-
26-
12-
18-
09.
tar.gz
-rw-rw-r--
1 www www
1243369 Jun
26 12:
18 /opt/webroot/web-demo_123_2017-
06-
26-
12-
18-
57.
tar.gz
?修改部署成功頁面
測試回滾,頁面再次回到修改前,說明回滾成功
[www@master ~]$ ./deploy.
sh rollback web-demo_123_2017-
06-
26-
12-
18-
09
192.168.
3.12 rollback success!
192.168.
3.13 rollback success!
?
轉載于:https://www.cnblogs.com/reblue520/p/7110213.html
總結
以上是生活随笔為你收集整理的运维与自动化系列③自动化部署基础与shell脚本实现的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。