一鍵部署進化史

前言


以前的文章說過 由 PHP 轉到 Java 以後,很是不適應的一點就是代碼部署過程耗時長,調試不便,雖然可使用 debug,但有時候仍是須要修改代碼,從新部署測試機系統,整個流程須要:css

  • 使用 mvn 命令將項目打成 war 包,耗時 1 min;
  • 從開發機向測試機上傳 war 包,公司內使用無線局域網,上傳速度峯值只有 1M 不到,並且很不穩定,面對 100M+ 的 war 包,有點力不從心,此步驟耗時 2.5 min;
  • 服務端重啓 docker 進程,耗時 1 min;

再加上須要兩臺機器切換操做,步驟之間不連貫,須要在邊上看着進度,以及時操做下一步。能夠說,等到想要的代碼上傳到測試機運行,花兒都謝了。html

做爲一個懶人,迫切地須要簡化一下流程,雖然可能達不到像 PHP 同樣秒傳文件當即生效,也要儘可能快且方便地部署測試包,別操這麼多心。本文就介紹我是怎麼一步步優化測試部署流程的。git

文章歡迎轉載,請尊重做者勞動成果,帶上原文連接:http://www.cnblogs.com/zhenbianshu/p/8733103.htmlgithub

nc 時代


剛入職時,對 Java 的部署相關一臉懵逼,有同事給了一個腳本和兩條命令,是爲最原始的「自動部署系統」:web

  1. 先在測試機上執行腳本,腳本會啓用一個 nc 接收進程,監聽某一個端口,命令爲 nc -4l xxPort > ROOT.war
  2. 本身在開發機上執行一條 mvn 命令,將項目打包,命令爲 mvn clean package project
  3. 再在開發機上執行 nc 上傳命令,鏈接測試機 IP 和端口,以打好的 war 包爲輸入流 nc testIp xxPort < test-1.0.0.war
  4. 傳輸完 war 包後,腳本會自動重啓 docker 機,重啓完成後就能夠進行測試了。

nc 是 NetCat 的簡稱,這個小工具用於同步兩臺服務器間的文件,使用時,先在接收端監聽一個端口並指定輸出文件,再在發送端鏈接 IP 和端口,並指定輸入流, nc 命令很簡單,網絡上資料也不少,這裏再也不多提了。算法

這個腳本雖然比所有手動好了一些,能幫我少輸兩個命令(nc 服務端、重啓命令),但是時間上並無縮短,但是烏龜似的上傳速度真的不能忍,這時我開始想着怎麼加速上傳。docker

rsync 「加速」上傳


其實一開始我是想從硬件方面解決這個問題的,即便用網線。爲此,買了一個網線轉接頭和一段網線,但是經過同事的設備測試發現轉接頭和網線都沒問題,但是接到一塊就不匹配(圍笑)。shell

窮則思變,接着我考慮從軟件方面解決這個問題。問了幾個同過後,發現有的同事在用 rsync 同步文件,但是 rsync 同步文件的單位不是文件 嗎?看了同事演示的上傳後,感受心態崩塌,很差好讀文檔的後果啊,走了好多彎路。apache

這裏簡要介紹一下 rsync 的使用:json

服務端

服務端須要啓動一個 rsync daemom 進程監聽某一端口,默認配置文件在 /etc/rsyncd.conf,以 module 爲單位進行用戶認證、權限校驗、目標文件夾等配置,一個常見的 rsyncd 配置以下:

# general conf
port=873 # 監聽端口
max connections=500
log file=/var/log/rsyncd.log
pid file=/var/run/rsyncd.pid # pid 文件

# module 可多個
[zbs]
path = /data1/zbs # zbs模塊的根目錄
read only=no
use chroot=no
uid=root
gid=root
auth users=zbs // 要進行用戶認證的用戶名
secrets file=/etc/rsyncd.scrt # 用戶名對應的密碼存放文件,每行一個,都是以 "zbs:password" 的形式
ignore errors
exclude = .git/ # 排除掉 .git 文件夾

客戶端

而在客戶端,咱們只須要使用 rsync [-option] fileOrDir rsync://{user}@{host}:{port}/{moduleName}/dir 就能夠將本地文件同步到服務端了。

至於密碼,可使用 --password-file=/path/to/pwdFile 的形式,也能夠在調用 rsync 命令以前設置環境變量:export RSYNC_PASSWORD=XXXX

至於 rsync 的同步算法, 推薦陳皓大神的文章:RSYNC 的核心算法

rsync 解決了上傳速度的問題,可是又引入了新的問題:我必須等着上傳結束,而且上傳結束後還要登錄測試機手動重啓 docker 服務,挺不方便的。

修改 rsync,添加回調選項


這時我開始打 rsync 源碼的主意了,rsync 是一個開源軟件,我考慮幫它加一個參數,讓它幫我在文件上傳結束後自動執行一些命令。

說作就作,從 rsync官網 下載到 rsync 的源碼開始查看並動手修改。rsync 的源碼代碼量仍是挺大的,不過修改它咱們不須要通讀,只修改讀取參數並使用就好了。我將這個問題分爲兩個步驟:

  • 讀取到 callback 參數的值;
  • 上傳結束後調用 callback 參數的值;

首先在 proto.h 文件裏添加函數聲明: char *lp_callback(int module_id);

讀取參數的相關代碼在 load_param.c 文件內,首先添加變量聲明、設置默認值,最後添加參數調用函數。

服務端文件同步的代碼在 clientserver.c 文件內,主體是 rsync_module 函數,前面的一系列操做如用戶認證、權限校驗等咱們能夠沒必要管,找到最後一步,在其調用下一次同步函數前 添加以下代碼(解釋在註釋中):

char * callback = lp_callback(i); // 讀取 callback 參數
    if (callback != NULL && strlen(callback) != 0) {
        char cmd[strlen(callback) + 2];
        strcpy(cmd, callback);
        strcat(cmd, " &"); // system 命令會阻塞,須要在命令上添加 & 讓它後臺執行
        system(cmd); // 使用 stdlib 的 system 執行 callback 命令
    }

修改後的源碼見:Github-zhenbianshu-rsyncCallback

這樣,我給本身上傳用的 module 添加一個腳本做爲 callback,在每次上傳完後,都會執行這個 callback 腳本,腳本里我能夠配置上服務的重啓,自動部署就實現了。

docker-compose tomcat 自動部署


其實 tomcat 是能夠自動部署的,須要配置 server.xml的 Host 元素,將 autoDeploy 屬性置爲 true,文檔:Tomcat Web Application Deployment

但是咱們的服務是基於 docker-compose 進行部署的,若是修改 server.xml 還須要將文件映射到 docker image 裏。

其中 docker 能夠這麼配置:

FROM tomcat:7-jre8
COPY server.xml /usr/local/tomcat/conf/

docker-compose 能夠在 yml 配置文件裏添加以下配置:

image:
    tomcat-base
volumes:
   - ./path/server.xml:/usr/local/tomcat/conf/server.xml
   - ./path/webapps:/data1/project/webapps

這樣,每當上傳了新的 war 包,tomcat 就會自動監測到並從新部署服務;

此時,還有一個需求, war 包同步完成,重啓完成後我不知道,得隨時關注 tomcat 的服務日誌,以儘快得知重啓結果,及時測試,若是服務重啓完就當即告訴我就最好了。

添加通知


此時,我修改的 rsync 就有了做用了,使用 callback 參數在測試機啓動一個腳本以監測 tomcat 的服務日誌,服務重啓完成後會輸出 Server startup in xxx ms,若是監測到有新的 log 輸出,則發送一個通知告訴我。

callback 參數配置的腳本相似於:

#!/bin/bash

docker-compose stop -t 0
`rm /data1/project/webapps/ROOT -rf`
sleep 1
docker-compose start

sleep 5 # 這裏等待一會,使大量 tomcat 日誌覆蓋掉上一次重啓的結果日誌
date=`date "+%Y-%m-%d"`
catalina_log="/data1/project/logs/catalina.$date.log"

while : # 重複檢測日誌最後一行,直到輸出了重啓成功的標識
do
    finish=`tail -n 1 $catalina_log | grep 'Server startup'`
    if [ -n "$finish" ]
    then
        break
    fi
    sleep 0.1
done

`curl -u "user:password" -d "uid=5715965217&text=succ" "messages/new.json"` # 調用接口發送通知

其實在測試機啓動一個守護進程用來實時監測日誌也是能夠的,可是須要處理日誌的新舊邏輯。

至於通知,有不少工具可使用,微博、QQ、微信、短信等通信工具都提供有對外的 http 接口,這個能夠依各人喜愛選擇使用。

小結


最後把開發機上的 mvn 打包命令和 rsync 同步命令也包裝成腳本,以下所示:

#!/bin/bash
mvn clean  -DskipTests=true package -Pwar -am -pl project
file=`find /path/to/project/target -name "*.war"`
export RSYNC_PASSWORD=123456
rsync -avz $file rsync://zbs@IP:PORT/zbs/ROOT.war

再給腳本添加一個 alias 別名 alias test="myshell.sh",真正的一鍵部署就完成了,在部署測試環境時,只須要在項目目錄下輸入一條命令 test 就開始自動部署了,這時候能夠放手去喝杯水或作些其餘事,等收到消息通知後,回來繼續測試便可。

部門正在搭配 git 系統作自動部署測試系統,很是期待 push 過代碼後就能夠迅速測試的場景。果真,懶纔是第一輩子產力啊~

關於本文有什麼問題能夠在下面留言交流,若是您以爲本文對您有幫助,能夠點擊下面的 推薦 支持一下我,博客一直在更新,歡迎 關注

相關文章
相關標籤/搜索