Jenkins踩坑系列--你試過linux主機ssh登陸windows,啓動java進程嗎,來試試吧

1、問題概述

在一個多月前,組長讓我研究下持續集成。我很天然地選擇了jenkins。當時,(包括如今也是),部分服務器用的是windows主機。java

我當時想了想,若是我把jenkins裝在windows上,在windows上打好包後,要怎麼把war包或jar包(針對spring boot項目)傳到remote windows主機上呢?linux

傳過去以後,要怎麼把這個包運行起來呢(好比war包丟tomcat,重啓tomcat;好比怎麼用java運行spring boot項目),運行確定是用腳本(bat),可是我怎麼git

調用這個腳本呢?github

想了想,很頭疼。可是我知道linux主機之間,是能夠ssh登陸的,而且能夠ssh遠程登陸後執行shell的。spring

因此,最終選擇了centos做爲持續集成服務jenkins的操做系統。shell

 

研究jenkins以來,做爲一個小菜鳥,找了相關的jenkins QQ羣加入,羣裏氣氛很好,你們提問題不少,回答問題的也不少。我就把上述問題在羣裏問了一下,獲得羣管理的回覆,windows

針對數據傳輸部分,回覆以下,共4種方案。centos

1。1 在win上裝sshd,在linux上用scp,sftp傳文件到win。
1。2在linux上裝samba客戶端,映射win共享磁盤符到linux。而後cp。
1。3 在linux上裝powershell,而後裝一個第三方模塊。而後在win上開啓。winrm,數據走的是winrm協議端口,即powershell服務器的端口。
1。4 在win上裝ftpd,和道理1。3同樣。數據走的是ftp協議。

 

今天我就找時間,本身試了下第一種。整整折騰了一天,原本覺得搞不出來了,不過仍是勉強解決了。tomcat

這邊作下記錄。bash

 

 

二(更新)、折騰記錄之安裝 freesshd

update:

當時寫的時候用的是openssh,後來實際狀況下,發現部分系統仍是執行一些命令會失敗。後來轉到了freesshd這個軟件。

該軟件我我的以爲仍是挺好用的。

這裏記錄下。

官網:http://www.freesshd.com/?ctt=download

下面是傻瓜式安裝。惟一要注意的是:

一、若是22端口已經被佔用,那麼只能換端口了,我這邊換成了29

二、要添加用戶名密碼,我這裏配了Administrator/1qaz@WSX

 

 

jenkins上配置ssh鏈接:

2、折騰記錄之安裝openssh

參考資料:

https://winscp.net/eng/docs/guide_windows_openssh_server

1.下載openssh

https://github.com/PowerShell/Win32-OpenSSH/releases

這邊按照本身的機器,選一個版本吧,我看了下,貌似都是beta版,但我感受仍是很穩定的。我選擇的是下圖箭頭所示的64位版本。

2.安裝

先解壓縮,不必定非要解壓縮到下圖的地方,本身開心就好。

 

在解壓的目錄下,按住shift,同時鼠標右鍵,打開cmd或者powershell。

執行:

powershell.exe -ExecutionPolicy Bypass -File install-sshd.ps1

 

繼續右鍵打開powershell(在我這,cmd不行,可是在powershell窗口能夠成功),

執行:(這句意思是加防火牆規則,放行22端口)

New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22

若是提示New-NetFirewallRule不被認識,找個powershell吧,或者查一下,或者手動添加入站規則

 

接下來,去到計算機管理-服務裏面,找到sshd服務,配置爲開機啓動,而後點下面的啓動,將服務啓動起來。

三、測試一下

1.在本身機器上telnet一下,看看ssh服務的22端口是不是通的。

cmd執行:telnet ip 22

 

2.shell遠程工具測試下,是否能夠登陸。

我這邊用的是secureCRT,XShell或者putty都行。

用戶名密碼就是:遠程桌面用的用戶名密碼。

 四、注意點

ssh進去後,主工做目錄在C:\Users\Administrator:

 

 3、Jenkins上配置ssh客戶端

一、jenkins配置ssh主機

在jenkins上,在我觀察,Publish Over SSH算是一個比較流行的ssh工具,能夠傳輸文件,也能夠執行命令(針對linux,能夠執行命令和shel;針對windows,cmd裏可以進行的操做均可以)。

 在Jenkins管理界面中,依次打開:系統管理--》系統設置--》Publish over SSH部分,按照下圖進行配置:

填寫完成後,能夠點擊下面的按鈕,測試下鏈接是否成功。

另外,這裏有個填ssh端口的輸入框,若是修改了服務端的監聽端口的話,記得對應修改。

二、填寫注意點

Name隨便填,Hostname是ip或者主機名,用戶名同遠程桌面 用的用戶名,點擊高級後,填寫密碼部分。

其中的Remote Directory須要重點關注,該參數表示的是:ssh文件上傳後,文件在遠端服務器上的保存路徑,路徑須要預先創建好。

同時,若是上傳了文件後,須要執行命令的話,這也是bat、shell等命令的工做目錄。

針對windows類型的ssh服務器,這邊的填寫只能寫相對路徑,(base 路徑爲C:\Users\Administrator,若是做爲非管理員登陸,可能會稍微不同,能夠本身用SecureCRT之類的登進去試試,看看在哪一個路徑下)

若是不填,就是在base路徑;

若是填寫內容爲「\」,(不含雙引號),則路徑會是c盤根路徑;

若是填"target",則路徑會是C:\Users\Administrator\target。

我這邊簡單起見,先不填。由於其做爲後續命令執行的工做路徑的緣由,會有一些坑。後邊我再補充。

 

4、配置job

一、job中,配置構建操做

先展現下個人構建操做,很簡單,maven編譯,打包

 

在jenkins的服務器上,找到jenkins的home路徑,其下的workspace目錄中,

 

我這邊拿來舉例的job是test-deploy。

編譯完成後,我這邊的目錄結構是這樣的:

 

 二、配置構建後操做--ssh發佈

 

cmd /c call C:\Users\Administrator\deploy.bat

 

以上配置,能夠和上一步的構建後文件目錄結構,仔細對照下就知道怎麼填寫了。

我這邊也不是最佳實踐,能夠留言討論。

 

三、遠端windows ssh服務器

在C:\Users\Administrator\下的目錄文件結構:

 

 deploy.bat的內容:

echo hello

java -version

javaw -Xms512m -Xmx512m -Xmn512m -jar target\bdmp-backstage-rest.jar echo bye
:end

重點關注的是上面標紅的地方:

這裏,必須是javaw。不信能夠多試試。最終是怎麼選定這個方案的,後面說。只關注結果的話,複製上面的就能夠。

我這邊由於bat水平有限,只寫了啓動程序的部分。

按理說,是須要上傳後,拷貝jar或war到別的目錄,先殺掉之前的進程,(避免端口衝突而啓動失敗),再開啓新進程。

這塊留做todo吧,有興趣的朋友能夠跟我交流。

 

四、終於ok了,測試一下

在job頁面,點「當即構建「。

運行過程以下:

 

咱們在遠程ssh主機上,看看咱們的服務啓動了沒,我這邊經過看端口的方式:

netstat -ano|findstr "18083"

其中18083是我這邊的spring boot應用的服務端口:

不放心的話,能夠看看任務管理器。

 

好了。啓動起來了。

咱們再看看jenkins中,job運行完了沒?

運行完了,可是是超時退出的,我這邊還沒想到好辦法。若是你有好的解決辦法,歡迎分享。

 

5、嘗試過的失敗方案-shell版

我最開始只打算作linux主機之間的持續集成,因此只弄了shell。基於懶,所以看看能不能經過在windows上安裝shell環境來執行shell。

一、準備shell

準備shell環境,我是經過安裝了一個git。而後將git的cmd和bin,配置到了path中。

我瞎搞的,不知道運維界的最佳實踐是啥。(我只是個java開發。。。)

二、windows上手動運行

這邊我把shell共享下(我也是在前人基礎上改的,自己shell水平堪憂)。

bdmp-backstage-rest.sh:

#!/bin/bash
source /etc/profile

export SERVICE_NAME=bdmp-backstage-rest
export JAR_ARTIFACT_NAME=./target/bdmp-backstage-rest.jar
export DEBUG_PORT=2222

export JAVA_OPTS="-Xms1024m -Xmx1024m -Xmn512m"


cd `dirname $0`
echo "CURRENT DIRECTORY:"`pwd`

export SCRIPT_NAME=$0
echo "SCRIPT_NAME:"$SCRIPT_NAME" parameters:"$@

echo "Invoke _server.sh now!"
./_server.sh $@
View Code

_server.sh:

#!/bin/bash

#date 2018-04-12
#author caokunliang
#version 1.0
#desc:

echo "_server.sh is called! paramters is "$@
echo "JAR_ARTIFACT_NAME:"$JAR_ARTIFACT_NAME
echo "SERVICE_NAME:"$SERVICE_NAME
echo "JAVA_OPTS:"$JAVA_OPTS

if [ -z "$JAR_ARTIFACT_NAME" ]; then
    echo "請不要直接調用本腳本,並確保調用腳本中設置了JAVA_MAIN_CLASS"
    exit 1
fi

if [ -z "$SERVICE_NAME" ]; then
    echo "請在調用腳本中設置SERVICE_NAME"
    exit 2
fi

if [ -z "$JAVA_OPTS" ]; then
    JAVA_OPTS="-Xms1024m -Xmx1024m -Xmn512m"
fi

#服務進程的pid
pids=""
#調試模式下的參數
DEBUG_OPTS=""

#==============================================================================
#根據啓動類類名搜索服務進程的pid
#==============================================================================
function get_pids() {
    echo "(${FUNCNAME[@]})"

    #默認使用JDK自帶的jps
    echo "jps -l:"
    jps -l
    JPS_STATUS=$?
    if [ $JPS_STATUS -ne 0 ]; then
        pids=`ps -e -o pid -o command | grep -vi ' grep ' | grep -i 'java' | grep "$JAR_ARTIFACT_NAME" | awk '{print $1}'`
    else
        pids=`jps -l|grep "$JAR_ARTIFACT_NAME" | awk '{print $1}'`
    fi

    echo ""
    if [ -z "$pids" ]; then
        echo "the process of "$JAR_ARTIFACT_NAME " is not found"
    fi
}

#==============================================================================
#終止服務進程
#==============================================================================
function svr_stop() {
    get_pids
    if [ -n "$pids" ]; then
        for p in $pids
        do
            echo "kill -9 "$p
            kill -9 $p
        done
        echo ""
        echo "the process are stopped"
    fi
}

#==============================================================================
#啓動服務前進行環境準備
#==============================================================================
function svr_test() {
    echo ""
    java -version > /dev/null
    JAVA_STATUS=$?
    if [ $JAVA_STATUS -ne 0 ]; then
        echo "java not found under the path,please make sure jdk is installed"
        exit 3
    fi

    cd `dirname $0`

    if [ "$1" = "debug" ]; then
        DEBUG_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address="$DEBUG_PORT" "
    fi

    if [ -n "$SERVICE_NAME" ]; then
        echo "SERVICE_NAME    = "$SERVICE_NAME
    fi
    echo "JAR_ARTIFACT_NAME = "$JAR_ARTIFACT_NAME
    echo "JAVA_OPTS       = "$JAVA_OPTS
    echo "DEBUG_OPTS      = "$DEBUG_OPTS
    echo "CUSTOM_PARAM    = "$@
    echo "HOME_DIR        = "`pwd`
    echo "LAUNCH_COMMAND  = nohup java  "$JAVA_OPTS" "$DEBUG_OPTS" "-jar" "$JAR_ARTIFACT_NAME" >/dev/null 2>&1 &"
    echo ""
}

#==============================================================================
#啓動服務
#==============================================================================
function svr_start() {
    #nohup java  $JAVA_OPTS $DEBUG_OPTS -jar $JAR_ARTIFACT_NAME  > nohup.out &
    nohup java  $JAVA_OPTS $DEBUG_OPTS -jar $JAR_ARTIFACT_NAME  >/dev/null 2>&1 &
}


#==============================================================================
#根據參數調用對應的服務
#==============================================================================
if [ "$1" = "stop" ]; then
    svr_stop
elif [ "$1" = "start" ]; then
    svr_test $@
    svr_start $@
elif [ "$1" = "restart" ]; then
    svr_stop
    sleep 2
    svr_test $@
    svr_start $@
elif [ "$1" = "debug" ]; then
    svr_stop
    sleep 2
    svr_test $@
    svr_start $@
elif [ "$1" = "test" ]; then
    svr_test $@
    get_pids
    if [ -n "$pids" ]; then
        for p in $pids
        do
            echo "當前服務進程PID = "$p
        done
    fi
elif [ "$1" = "dump" ]; then
    get_pids
    if [ -n "$pids" ]; then
        for p in $pids
        do
            echo "當前服務進程PID = "$p
            echo ""
            echo "jinfo "$p" > "$SERVICE_NAME"."$p".jinfo.log"
            jinfo $p > $SERVICE_NAME.$p.jinfo.log
            echo ""
            echo "jstack "$p" > "$SERVICE_NAME"."$p".jstack.log"
            jstack $p > $SERVICE_NAME.$p.jstack.log
            echo ""
            echo "jmap -heap "$p" > "$SERVICE_NAME"."$p".heap.log"
            jmap -heap $p > $SERVICE_NAME.$p.heap.log
            echo ""
            echo "jmap -histo "$p" > "$SERVICE_NAME"."$p".histo.log"
            jmap -histo $p > $SERVICE_NAME.$p.histo.log
            echo ""
            echo "jmap -dump:format=b,file="$SERVICE_NAME"."$p".dump "$p
            jmap -dump:format=b,file=$SERVICE_NAME.$p.dump $p
            echo ""
            TAR_NAME=$SERVICE_NAME".dump."$p"."`date +%Y%m%d.%H%M`".tar.gz"
            echo "tar --remove-files --exclude=\"*.gz\" -zcvf "$TAR_NAME" "$SERVICE_NAME"."$p".*"
            tar --remove-files --exclude="*.gz" -zcvf $TAR_NAME $SERVICE_NAME.$p.*
            echo ""
            echo "生成打包文件 "`du -h $TAR_NAME | awk '{print $1}'`
            echo `pwd`"/"$TAR_NAME
        done
    fi
else
    echo ""
    echo "用法: "$SCRIPT_NAME" [參數]"
    echo ""
    echo "  start      正常啓動服務,服務器首次啓動時使用,綁定端口時若是端口已經被佔用"
    echo "             會直接報錯退出"
    echo ""
    echo "  stop       使用直接終止進程的方式關閉服務"
    echo ""
    echo ""
    echo "  restart    重啓服務,先將原來的服務進程關閉,而後啓動服務"
    echo ""
    echo "  debug      關閉當前的服務並用debug模式重啓,用於遠程調試"
    echo ""
    echo ""
    echo "  dump       保存服務進程的內存堆棧等信息,用於排查問題"
    echo ""
    echo "  test       查看服務啓動配置信息,不會啓動服務"
fi

echo "success"
View Code

 

我經過遠程桌面,在服務器裏,手動執行bdmp-backstage-rest.sh文件,服務(端口18083)是能夠啓動起來的。

 

三、jenkins ssh啓動shell:

job配置:

job的狀態是success,日誌以下:

 可是實際上,服務並無啓動(或者是啓動了,可是ssh退出登陸時又關閉了)。

 

四、shell腳本-修改腳本睡眠時間1:

運行:

應該是卡在sleep那一句了。此時,看看windows主機上,進程是否啓動。

 

 進程是啓動的。

後續不出所料的,jenkins那邊,job超時,標記爲unstable。而後我繼續查看windows主機,發現進程還在。這有點出乎個人意料。

我想是否是由於睡眠的時間太長,可能睡眠結束,這個進程也就被kill了。

 

 

五、shell腳本-修改腳本睡眠時間2:

 

job日誌顯示,20s後,job結束:

windows上,進程還在:

順便看看個人日誌吧:

 

六、shell腳本-修改腳本睡眠時間3:

接下來,修改成3s,個人程序啓動大概要10多秒,這邊若是設爲小於程序啓動並綁定端口的時間的話,會怎樣?

 

 這邊不截圖了,效果和第五步同樣。

七、疑惑

可是,爲啥必定要sleep呢?昨天我用shell方案的時候,沒想到這茬,所以在屢次嘗試無果後,轉向了bat。

 有知道的,麻煩解惑。

 

 

 

6、嘗試過的失敗方案-bat版

 一、方案1

 

二、方案2

這個是最開始的版本。網上都是這樣寫的。在遠程桌面進去,手動執行,沒問題的

start javaw -Xms512m -Xmx512m -Xmn512m -jar target\bdmp-backstage-rest.jar 

 

 可是,用在我這裏,(ssh登陸進來執行bat的方式),卻不行。

後來,我在javaw後,加了pause。

這時,能夠查到進程了。可是一旦jenkins那邊,ssh退出了。就查不到了。估計是被kill了。

因此我開始查找,windows要怎麼忽略nohup信號(像linux那樣)

三、結論

參考:https://stackoverflow.com/questions/3382082/whats-the-nohup-on-windows

仔細看了這個問題下的每一個回答,我總算知道了緣由。

 

 在ssh到windows的狀況下,只要ssh退出,ssh啓動的任務都會被kill掉。惟一可行的辦法,就是使用javaw。

 

7、結論

因此,linux經過ssh遠程到windows上,執行sh或者bat,去啓動java子進程。

目前我只知道這兩種方式,一種shell,(須要加sleep,具體緣由未明),一種就是bat,必須使用javaw

相關文章
相關標籤/搜索