通過shell腳本實現代碼自動化部署
一、傳統部署方式及優缺點
1.傳統部署方式
(1)純手工scp
(2)純手工登錄git pull、svn update
(3)純手工xftp往上拉
(4)開發給打一個壓縮包,rz上去;解壓
2.缺點
(1)全程運維參與,占用大量時間
(2)上線速度慢
(3)人為失誤多,管理混亂
(4)回滾慢,不及時
二、環境規划
1、開發環境--開發者本地有自己的環境。
運維需要設置的開發環境,大家共用的服務。
2、測試環境:功能測試環境和性能測試環境。
3、預生產環境:生產環境集群中的某一個節點。
4、生產環境:直接對用戶提供服務的環境。
測試環境與生產環境的數據庫不一致時,可能會導致測試的功能不全面,在測試環境測無問題,放在線上可能出現問題
三、需求分析
一、功能需求需求
一個集群有十個節點
1.實現 一鍵部署10個節點
2.一鍵回滾到任意版本
3.一鍵回滾到上個版本
二、部署需求
部署:
1.代碼在哪里:svn、git
2.獲取什么版本代碼?
svn/git:直接拉去某個分支
svn:指定版本號
git:指定tag
3.差異解決:
(1)各個節點直接差異:配置文件未必一致(crontab.xml)。預生產節點。
(2)代碼倉庫和實際的差異。配置文件是否放在代碼倉庫中。
4.如何更新
更新時需要考慮是否重啟。例如java代碼,需要考慮重啟tomcat。重啟過程中,用戶就不能訪問了。
5.測試
部署多個節點,某個節點由於配置問題導致部署不成功。如何測試。
6.串行和並行
部署多個節點,串行部署還是並行部署,視具體業務需求決定。
7.如何執行
1.shell腳本,直接執行
2.web界面
三、部署流程
1.獲取代碼(直接拉取)----》 2.編譯(可選)----》 3.配置文件放進去----》 4.打包 ----》
5.SCP到目標服務器----》 6.將目標服務器移除集群----》 7.解壓 ----》 8.放置到webroot ----》
9.SCP差異文件 ----》 10.重啟(可選) ----》 11.測試 ----》 12.加入集群
四、代碼實現
1、設置無交互訪問
通過ssh-keygen將部署機的公鑰發送給應用服務器。
注意,這里通常是用普通用戶登陸部署機,生成公鑰后,再把公鑰發給應用服務器
ssh-keygen -t rsa
切換到.ssh目錄下
[www@linux-node1 ~/.ssh]$ ll
total 16
-rwx------ 1 www www 397 Jul 31 22:45 authorized_keys
-rwx------ 1 www www 1679 Jul 31 22:44 id_rsa
-rwx------ 1 www www 397 Jul 31 22:44 id_rsa.pub
將id_rsa.pub中的內容復制粘貼到應用服務器的www用戶的.ssh目錄下,
文件名稱為authorized_keys
[www@linux-node2 .ssh]$ cat authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqT3VwY9Wo7tKsXa4Ce1zXGLT/Iygy30tDBKnV4HW4g5BdUS48urTvYljL9cwJ/HWvoqbtJ5mc7PMmhDMOAjIh1CRZtGxKEkQFB/Xp5cLeAsE7iH+WfkNqavFHD75+YuM2mbNBvisDXO+/pJ/QfbmYwWJ6CW6uLpQKpitdJwrLpQDJGQv5H3aV0kHKZdoA+twdXm0LmQcWWJt7zruPq19CAXG5b93KTdgyt/1x4BfcT5/+PCaEd9suYwEneI2Io8CX9oTAe3MRyRPtlN0szT89qP/q+Q4sktVjc1nkxHhdP2mahqeiBLUGULfkgUBtEjaGAFSWb+ejFV0fRDHk6bSJ www@linux-node1
注意,修改authorized_keys的權限
chmod 600 authorized_keys
另外,將.ssh目錄的權限設置成700
chmod 700 .ssh
2、詳細代碼

1 #!/bin/bash 2 3 #Node List 4 5 PRE_LIST="192.168.56.11" 6 7 GROUP1_LIST="192.168.56.12" 8 9 ROLLBACK_LIST="192.168.56.11 192.168.56.12" 10 11 #Date/Time Variable 12 13 LOG_DATE='date "+%Y-%m-%d"' 14 15 LOG_TIME='date "+%H-%M-%S"' 16 17 CDATE=$(date "+%Y-%m-%d") 18 19 CTIME=$(date "+%H-%M-%S") 20 21 #Shell env 22 23 SHELL_NAME="/deploy1.sh" 24 25 SHELL_DIR="/home/www/" 26 27 SHELL_LOG="${SHELL_DIR}/${SHELL_NAME}.log" 28 29 #Code ENV 30 31 PRO_NAME="web-demo" 32 33 CODE_DIR="/deploy/code/web-demo" 34 35 CONFIG_DIR="/deploy/config/web-demo" 36 37 TMP_DIR="/deploy/tmp" 38 39 TAR_DIR="/deploy/tar" 40 41 LOCK_FILE="/tmp/deploy.lock" 42 43 44 45 usage(){ 46 47 echo $"Usage: $0 {deploy | rollback [ list | version ]} " 48 49 } 50 51 52 53 writelog(){ 54 55 LOGINFO=$1 56 57 echo "${CDATE}${CTIME}: ${SHELL_NAME}: ${LOGINFO} " >> ${SHELL_LOG} 58 59 } 60 61 62 63 64 65 shell_lock(){ 66 67 touch ${LOCK_FILE} 68 69 } 70 71 72 73 shell_unlock(){ 74 75 rm -f ${LOCK_FILE} 76 77 } 78 79 80 81 code_get(){ 82 83 writelog "code_get"; 84 85 cd $CODE_DIR && echo "git pull"; 86 87 cp -r ${CODE_DIR} ${TMP_DIR}/ 88 89 API_VER="456" 90 91 } 92 93 94 95 code_build(){ 96 97 echo code_build 98 99 } 100 101 102 103 code_config(){ 104 105 writelog "code_config" 106 107 /bin/cp -r ${CONFIG_DIR}/base/* ${TMP_DIR}/"${PRO_NAME}" 108 109 PKG_NAME="${PRO_NAME}"_"$API_VER"_"${CDATE}-${CTIME}" 110 111 cd ${TMP_DIR} && mv ${PRO_NAME} ${PKG_NAME} 112 113 } 114 115 116 117 code_tar(){ 118 119 writelog "code_tar" 120 121 cd ${TMP_DIR} && tar czf ${PKG_NAME}.tar.gz $PKG_NAME 122 123 writelog "${PKG_NAME}.tar.gz" 124 125 } 126 127 128 129 code_scp(){ 130 131 writelog "code_scp" 132 133 for node in $PRE_LIST;do 134 135 scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot 136 137 done 138 139 for node in $GROUP1_LIST;do 140 141 scp ${TMP_DIR}/${PKG_NAME}.tar.gz $node:/opt/webroot 142 143 done 144 145 } 146 147 148 149 cluster_node_remove(){ 150 151 writelog "cluster_node_remove" 152 153 } 154 155 156 157 pre_deploy(){ 158 159 writelog "remove from cluster" 160 161 ssh $PRE_LIST "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" 162 163 ssh $PRE_LIST "rm -rf /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" 164 165 } 166 167 url_test(){ 168 169 URL=$1 170 171 curl -s --head $URL|grep "200 OK" 172 173 if [ $? -ne 0 ];then 174 175 shell_unlock; 176 177 writelog "test error" && exit; 178 179 fi 180 181 } 182 183 pre_test(){ 184 185 url_test "http://${PRE_LIST}/index.html" 186 187 echo "add to cluster" 188 189 } 190 191 192 193 group1_deploy(){ 194 195 writelog "remove from cluster" 196 197 198 199 for node in $GROUP1_LIST;do 200 201 ssh $node "cd /opt/webroot && tar zxf ${PKG_NAME}.tar.gz" 202 203 ssh $node "rm -rf /webroot/web-demo && ln -s /opt/webroot/${PKG_NAME} /webroot/web-demo" 204 205 done 206 207 scp ${CONFIG_DIR}/other/192.168.56.12.crontab.xml 192.168.56.12:/webroot/web-demo/crontab.xml 208 209 } 210 211 212 213 group1_test(){ 214 215 url_test "http://192.168.56.12/index.html" 216 217 echo "add to cluster" 218 219 } 220 221 rollback_fun(){ 222 223 for node in $ROLLBACK_LIST;do 224 225 ssh $node "rm -rf /webroot/web-demo && ln -s /opt/webroot/$1 /webroot/web-demo" 226 227 done 228 229 } 230 231 rollback(){ 232 233 if [ -z $1 ];then 234 235 shell_unlock; 236 237 echo "please input rollback version" && exit; 238 239 fi 240 241 case $1 in 242 243 list) 244 245 ls -l /opt/webroot/*.tar.gz 246 247 ;; 248 249 *) 250 251 rollback_fun $1 252 253 esac 254 255 } 256 257 258 259 main(){ 260 261 if [ -f $LOCK_FILE ];then 262 263 echo "Deploy is running" && exit; 264 265 fi 266 267 DEPLOY_METHON=$1 268 269 ROLLBACK_VER=$2 270 271 case $DEPLOY_METHON in 272 273 deploy) 274 275 shell_lock; 276 277 code_get; 278 279 code_build; 280 281 code_config; 282 283 code_tar; 284 285 code_scp; 286 287 pre_deploy; 288 289 pre_test; 290 291 group1_deploy; 292 293 group1_test; 294 295 shell_unlock; 296 297 ;; 298 299 rollback) 300 301 shell_lock; 302 303 rollback $ROLLBACK_VER; 304 305 shell_unlock; 306 307 ;; 308 309 *) 310 311 usage; 312 313 esac 314 315 } 316 317 main $1 $2
測試方式
[www@linux-node1 ~]$ curl --head http://192.168.56.11/index.html
HTTP/1.1 200 OK
Date: Mon, 01 Aug 2016 09:42:23 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.1e-fips PHP/5.4.16 mod_wsgi/3.4 Python/2.7.5
Last-Modified: Mon, 01 Aug 2016 09:39:52 GMT
ETag: "17-538ff61ca0a00"
Accept-Ranges: bytes
Content-Length: 23
Content-Type: text/html; charset=UTF-8
[www@linux-node1 ~]$ curl -s --head http://192.168.56.11/index.html|grep "200 OK"
HTTP/1.1 200 OK
上面腳本遠程執行命令或者拷貝 是使用ssh/scp完成的。當服務器稍多的時候,效率並不高。
我在生產環境中是使用 ansible 替代的,個人感覺對於這個腳本來說,就是個並行、串行的區別。
進一步的發展,還可以開發一些WEB界面去結合這個腳本,做到WEB化自動部署,當然也可以使用開源的jenkis。
3、回滾
1.列出回滾版本
2.目標服務器移除集群
3.執行回滾
4.重啟和測試
5.加入集群
===========
如果是遇到重大bug
1.列出回滾版本
2.執行回滾(重啟)
==========
非常緊急
1.直接回滾到上個版本(重啟)
自動化部署的核心是創建軟鏈接,同樣在回滾的時候也能實現秒級回滾。
但是在生產環境中,使用軟連接可能會造成WEB打開頁面空白,這點需要注意。