天天看點

一鍵部署進化史

為了解決調試不便的問題,先是同步工具由 nc 轉到 rsync,再修改 rsync 源碼添加回調參數,最後添加 docker 重新開機完成的通知資訊,成功完成一鍵部署系統。

前言

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

  • 使用 mvn 指令将項目打成 war 包,耗時 1 min;
  • 從開發機向測試機上傳 war 包,公司内使用無線區域網路,上傳速度峰值隻有 1M 不到,而且很不穩定,面對 100M+ 的 war 包,有點力不從心,此步驟耗時 2.5 min;
  • 服務端重新開機 docker 程序,耗時 1 min;

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

作為一個懶人,迫切地需要簡化一下流程,雖然可能達不到像 PHP 一樣秒傳檔案立即生效,也要盡量快且友善地部署測試包,别操這麼多心。本文就介紹我是怎麼一步步優化測試部署流程的。

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

nc 時代

剛入職時,對 Java 的部署相關一臉懵逼,有同僚給了一個腳本和兩條指令,是為最原始的“自動部署系統”:

  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 服務端、重新開機指令),可是時間上并沒有縮短,可是烏龜似的上傳速度真的不能忍,這時我開始想着怎麼加速上傳。

rsync “加速”上傳

其實一開始我是想從硬體方面解決這個問題的,即使用網線。為此,買了一個網線轉接頭和一段網線,可是通過同僚的裝置測試發現轉接頭和網線都沒問題,可是接到一塊就不比對(圍笑)。

窮則思變,接着我考慮從軟體方面解決這個問題。問了幾個同僚後,發現有的同僚在用 rsync 同步檔案,可是

rsync 同步檔案的機關不是檔案

嗎?看了同僚示範的上傳後,感覺心态崩塌,不好好讀文檔的後果啊,走了好多彎路。

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

服務端

服務端需要啟動一個 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 過代碼後就可以迅速測試的場景。果然,懶才是第一生産力啊~

關于本文有什麼問題可以在下面留言交流,如果您覺得本文對您有幫助,可以點選下面的

推薦

支援一下我,部落格一直在更新,歡迎

關注

繼續閱讀