自動化部署一:自動化部署基礎與實現
一:關於自動化的基礎知識:
1.1:當前程式碼部署的實現方式:
#當前程式碼部署的實現方式:
運維純手工scp到web伺服器
純手工登入git伺服器執行git pull或svn伺服器執行svn update更新程式碼
通過xftp上傳程式碼
開發打壓縮包上傳到伺服器然後解壓
#缺點:
1.需要運維全程參與,佔用大量的工作時間
2.上線時間比較慢
3.人為造成的失誤較多,管理比較混亂
4.回滾複雜而且慢,還不及時
1.2:執行環境規劃:
開發環境:開發者本地有自己的環境,然後運維需要設定開發環境的公用服務,例如開發資料庫、redis、memcached等
測試環境:功能測試環境和效能測試環境
預生成環境:由生產環境叢集中的某一個節點擔任測試,此節點只做測試不對外提供服務
生產環境:直接對外提供服務的環境
1.2.1:為什麼有預生成環境?
可能是生成環境預測試環境的資料庫或資料庫版本不一樣導致語句出現問題
或者是生成環境呼叫的介面不一樣,例如支付介面在測試環境無法呼叫
1.3:設計一套生成環境的程式碼自動化部署系統:
1.4:總體規劃流程:
一個服務的叢集節點數量,是一次部署還是分次部署
一鍵回滾到上個版本
一鍵回滾到任意版本
程式碼儲存在SVN還是Git
獲取指定分支或master的指定版本號的程式碼,svn指定版本號,git指定tag標籤,或直接拉取某個分支
配置檔案差異化,即測試環境和生產環境的配置檔案不一樣,如IP不一樣或主機名不一樣或資料庫連線不一樣等等
程式碼倉庫和實際的差異,即配置檔案是否放在程式碼倉庫中,如果儲存在git則所有人都可以從配置檔案看到資料庫使用者密碼等資訊,可以使用單獨分支儲存配置檔案,或配置檔案只在部署伺服器的某個專案的目錄,比如是config.example
如何更新程式碼,java tomcat需要重啟
測試部署後的web頁面是否可以正常訪問是否是想要的頁面
並行(saltstack)或並行(shell)的問題,涉及到分組部署重啟服務
如何執行,shell執行還是web執行
1.5:總體規劃圖如下:
二:實現程式碼自動化部署
2.1:通過shell指令碼實現,後續會寫一個python版的,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 [email protected]
$ chmod 600/home/www/.ssh/authorized_keys
2.1.3:測試部署伺服器可以免祕鑰用www使用者登入各個web伺服器
2.2:編寫shell指令碼:
2.2.1:#完成第一節點,主題框架完成:
#!/bin/bash
#Author: Zhangjie
#指令碼位置等變數
SHELL_NAME="deploy.sh" #指令碼名稱
SHELL_DIR="/home/www" #指令碼路徑
SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.LOG" #指令碼執行日誌
LOCK_FILE="/tmp/deploy.lock"
#程式碼變數
CODE_DIR="/deploy/code/deploy" #程式碼目錄
CONFIG_DIR="/deploy/config" #配置檔案目錄
TMP_DIR="/deploy/tmp" #臨時目錄
TAR_DIR="/deploy/tar" #打包目錄
usage(){ #使用幫助函式
echo $"$0使用幫助:$0 + [deploy | rollback]"
}
code_get(){
echo "code_get"
}
code_build(){
echo code_build
}
code_config(){
echo conde_config
}
code_tar(){
echo conde_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 cluster_node_in
}
rollback(){
echo rollback
}
touch_key_file(){
touch /tmp/deploy.lock
echo "keyfile"
}
delete_key_file(){
rm -rf /tmp/deploy.lock
}
main(){ #主函
if [ -f $LOCK_FILE ];then #先判斷鎖檔案在不在
echo "鎖檔案已存在,請稍後執行,退出..." && exit 10 #如果有鎖檔案直接退出
fi
DEPLOY_METHOD=$1 #避免出錯誤將指令碼的第一個引數作為變數
case $DEPLOY_METHOD in #判斷第一個引數
deploy) #如果第一個引數是deploy就執行以下操作
touch_key_file #執行部署之前建立鎖。如果同時有其他人執行則提示鎖檔案存在
code_get;
code_build;
code_config;
code_tar;
code_scp;
cluster_node_remove;
code_deploy;
config_diff;
code_test;
cluster_node_in;
delete_key_file #執行完成後刪除鎖檔案
;;
rollback) #如果第一個引數是rollback就執行以下操作
touch_key_file #回滾之前也是先建立鎖檔案
rollback;
delete_key_file #執行完成刪除鎖檔案
;;
*) #其他輸入執行以下操作
usage;
esac
}
main $1 #執行主函式並把第一個變數當引數
2.2.2:完成指令碼第二階段,實現程式碼部署:
#!/bin/bash
#Author: Zhangjie
#伺服器節點:
# for i in `seq 1 20`;do echo 192.168.10.$i;done #web伺服器,多主機多用for迴圈
NODE_LIST="192.168.10.101 192.168.10.102" #自定義的web伺服器列表
#日誌日期和時間變數
LOG_CDATE=`date "+%Y-%m-%d"` #如果執行的話後面執行的時間,此時間是不固定的,這是記錄日誌使用的時間
LOG_CTIME=`date "+%H-%M-%S"`
#程式碼打包時間變數
CDATE=$(date "+%Y-%m-%d") #指令碼一旦執行就會取一個固定時間賦值給變數,此時間是固定的
CTIME=$(date "+%H-%M-%S")
#指令碼位置等變數
SHELL_NAME="deploy.sh" #指令碼名稱
SHELL_DIR="/home/www" #指令碼路徑
SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.LOG" #指令碼執行日誌檔案路徑
LOCK_FILE="/tmp/deploy.lock" #鎖檔案路徑
#程式碼變數
PRO_NAME="web-demo" #專案名稱的函式
CODE_DIR="/deploy/code/web-demo" #從版本管理系統更新的程式碼目錄
CONFIG_DIR="/deploy/config/web-demo" #儲存不同專案的配置檔案,一個目錄裡面就是一個專案的一個配置檔案或多個配置檔案
TMP_DIR="/deploy/tmp" #臨時目錄
TAR_DIR="/deploy/tar" #打包目錄
usage(){ #使用幫助函式
echo $"$0使用幫助:$0 + [deploy | rollback]"
}
writelog(){ #寫入日誌的函式
LOGINFO=$1 #將引數作為日誌輸入
echo "${CDATA} ${CTIME}: ${SHELL_NAME}:${LOGINFO}" >> ${SHELL_LOG}
}
code_get(){ #獲取程式碼的函式
writelog "code_get"
cd ${CODE_DIR} && echo " git pull" #進入到程式碼目錄更新程式碼,此處必須免密碼更新,此目錄僅用於程式碼更新不能放其他任何檔案
/bin/cp -rf ${CODE_DIR} ${TMP_DIR}/ #臨時儲存程式碼並重命名,包名為時間+版本號,準備複製到web伺服器
API_VER="123456789"
}
code_build(){ #程式碼構建函式
echo code_build
}
code_config(){ #配置檔案函式
writelog "conde_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_123456-20160505-21-20-10格式
}
code_tar(){ #對程式碼打包函式
writelog "conde_tar"
cd ${TMP_DIR} && tar czvf ${PKG_NAME}.tar.gz ${PKG_NAME} #將目錄打包成壓縮檔案,便於網路傳輸
writelog "${PKG_NAME}.tar.gz 打包成功" #記錄打包成功的日誌
}
code_scp(){