github+jenkins+maven+docker自動化構建部署
前言
傳統的開發、測試、部署方式,是由開發人員本機或打包機進行打包,將war包提交給測試人員部署,測試通過後,再由實施人員負責部署到預發、生產環境中。中間的銜接不連貫,容易出錯,而且打包、部署存在重複的工作量。自動化構建部署(CICD)就是解決該問題,將從開發到部署的一系列流程變成自動化,銜接連貫,在構建失敗時能夠告知開發,構建成功後能夠告知測試和實施人員。無論大中小公司,都應該有此流程。
我本人在前公司搭建了基於svn(git)+jenkins+maven的自動化構建部署結構,所出的war包部署在tomcat中。此架構仍然不可避免要安裝jdk、tomcat、mysql、nginx等應用,而且需要配置環境變數,使用docker可解決上述問題,將所有服務打包成docker映象,推送到docker registry中。docker的優點就不在這裡贅述了
目標
最終目標:在linux系統中,搭建jenkins
服務,定時(或githook)的方式從github
上拉取maven工程,構建war包。使用docker構建image,推送到docker registry
上。
我使用的是ubuntu系統,使用docker形式的jenkins,拉取github工程,gitlab同理,構建war包,再在tomcat映象的基礎上將war包進去,構成新映象,推送到阿里的registry中,其他的registry(包括自建registry)同理。
為了更好的寫這個教程,我逐步完成最終目標,將目標拆分成3個部分。
- 第一步:github程式碼伺服器,提交maven專案
- 第二部:安裝jenkins,拉取github工程,構建war包
- 第三步:構建的war包自動推送到tomcat伺服器中
- 第四步:基於Dockfile將war包和tomcat映象構建出新映象推送到阿里雲
PS:讀者最好有linux使用經驗,會編寫shell指令碼。
第一步 git程式碼伺服器
這裡以github為例,其他如svn、gitlab、碼雲等VCS也都大同小異。有時間我會補充私有的gitlab搭建方式。
第二步 jenkins整合
首先你需要有一臺linux系統,我使用VMWare搭建的Ubuntu16的虛擬機器(本人低配本,覺得VM比VB更快些,虛擬機器磁碟最好使用固態,並多分些cpu和記憶體)。
有些命令沒有時,要會使用
apt-get install
安裝。
安裝jenkins的docker版本(ps:docker版方便快捷)
開啟終端,先把docker安裝上
sudo apt install docker.io
使用docker安裝jenkins,直接呼叫run命令,會自動pull映象並執行
sudo docker run -d \
-p 8080:8080 \
-p 50000:50000 \
--name jenkins \
-u root \
-v ~/jenkins:/var/jenkins_home \
jenkinsci/jenkins:lts
8080埠是jenkins的埠,5000埠是master和slave通訊埠(jenkins叢集部署後期我再補充,本次為單機配置)。
順便說一句,此映象為jenkins原生,存在一些外掛和配置問題,比如不能使用sudo,可根據原聲映象自行擴充套件,由於不影響此次目標,就不進行再構建了。
初次啟動的時候,可以通過docker logs -f jenkins
檢視控制檯的密碼,通過這個密碼登入系統。(~/jenkins的初始化檔案也有密碼)
啟動後就可以通過127.0.0.1:8080
訪問jenkins了。輸入密碼,新建使用者,安裝預設外掛。手動需要安裝的外掛有:
Maven Integration plugin
:有了它在新建Job時才能有Maven專案可以選擇
Deploy to container Plugin
:將war包部署到tomcatshang
Publish Over SSH
:通過ssh推送檔案,並可以執行shell命令
外掛安裝完成後最好重啟一下jenkins,有機率jenkins會不生效
還需要指定jenkins的jdk和maven,進入系統管理
->全域性工具配置
,jdk在jenkins中的/usr/lib/jvm/java-8-openjdk-amd64
目錄中,maven需要讓他自動下載(這種方式不是很好,可以使用docker的volumn去掛載一個maven供jenkins使用)
下面開始新建一個Maven專案,在主頁左側點選新建
,選擇構建一個Maven專案
,點選確定,主頁列表會出現該專案。
進入該專案,左側樹中有配置
按鈕,點選進去出現如下介面。
從上到下的配置是(構建時也是按照從上到下進行執行的):
描述
:就是專案詳情,根據專案情況實際情況隨意填寫
原始碼管理
:Repositories
裡面填寫giturl,由於開源沒有使用者密碼和ssh檔案,下面的Credentials
為空即可,如果是gitlab私有庫或有許可權限制則需要Add
,Branches to build
選擇你需要構建的分支。
構建觸發器
:我選擇了兩個常用的觸發構建方式,觸發遠端構建
讓git使用hook的方式訪問一個jenkins的url進行觸發,本例中觸發的url為127.0.0.1:8080/job/DataPlatform/build?token=zhangchx。輪訓SCM
是定時檢查程式碼是否有變化,有變化則觸發構建,值為5個*
,分別表示分鐘(0-59),小時(0-23),天(1-31),月份(1-12),周(0-7),其中H表示隨機,H/5表示每5分鐘檢查一次。
構建環境
:無需配置
Pre Steps
:構建前的操作,可以增加執行shell
,配置指令碼echo "Pre Steps指令碼啟動成功"
,此內容會在構建控制檯中打印出來
Build
:Root POM
配置pom.xml(要構建的工程必須是maven,有pom檔案),Goals and options
配置clean package
(也就是mvn的構建命令)
Post Steps
:構建完成後的操作,可以增加執行shell
,配置指令碼echo "Post Steps指令碼啟動成功${WORKSPACE}"
,${WORKSPACE}
為jenkins的環境變數。上方的3個單選項分別代表構建成功後執行、構建成功或不穩定執行、總是執行
構建設定
:可以配置構建完成後Email通知,我這裡沒有配置。(很簡單,在設定-全域性設定中配置Email的發件人賬戶,這裡再配置收件人即可)
構建後操作
:這一步先不配置
到此基本的配置都已經完成了,可以使用jenkins將github上的程式碼拉下來進行構建了。返回專案頁面,在左側點選立即構建
或修改程式碼等待5分鐘或訪問觸發遠端構建
的URL。jenkins就會開始構建了。
檢視控制檯,我們可以看到日誌,如果失敗需要根據日誌判斷失敗原因,是工程build失敗還是和jenkins配置有關。
第一次構建時由於maven要下載jar包,所以有些慢,實在不行就修改pom.xml,把倉庫映象改成國內地址。
第三步 推送war包到tomcat伺服器
上一步已經可以構建出war包,並在target中。這一步我們將war包推送到遠端的一臺tomcat伺服器上去(tomcat我部署在執行VM的宿主機器上)。
進入jenkins的專案配置,修改構建後操作
這一項
構建後操作
:由於前面安裝了Deploy to container Plugin
,Publish Over SSH
外掛,這裡就會有兩個選項
這一步我們只用到Deploy to container Plugin
,選擇它之後,會出現下面這個配置窗。
WAR/EAR files
:war包相對workspace的地址
Context path
:部署到tomcat的上下文名稱,例如:127.0.0.1:8080/DataCollect可以訪問到該專案
Containers
:指定部署到的tomcat版本,tomcat伺服器的地址以及使用者名稱密碼,這裡使用者需要在tomcat中有manager的許可權,你需要修改tomcat目錄下conf/tomcat-user.xml,新增類似如下的使用者。
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<user username="njzcx" password="njzcx" roles="manager-gui,manager-script"/>
先啟動你的tomcat,再在jenkins構建你的專案,最後war包會被推送到tomcat中去。看構建日誌和tomcat日誌如下。
訪問tomcat的專案地址,可以訪問。
這裡我碰到一個坑,就是
WAR/EAR files
一定要存在,不然每次構建都不會執行構建後操作
,jenkins也不會報錯。我一直找不到原因,後來發現war包名稱讓我寫錯了
還有就是選擇的tomcat版本和你tomcat伺服器版本要對應,不然有些介面發生變化jenkins會訪問不到的。
第四步 基於Dockerfile構建映象
這一步也很簡單,首先你不考慮jenkins,只寫一個Dockerfile,能夠基於tomcat的映象+war包構建一個新的映象就可以了。jenkins的作用就是遠端呼叫一下Dockerfile的build指令碼。
Dockerfile在的github裡也已經提供了,這裡再粘一份。
#基礎映象
FROM tomcat:7.0.86
#作者
LABEL maintainer="zhangchx <[email protected]>"
#執行安裝telnet和nc
RUN apt-get install -y telnet nc; exit 0
#
VOLUME ["/home/zhangchx/tomcat"]
#TOMCAT環境變數
ENV CATALINA_BASE: /usr/local/tomcat \
CATALINA_HOME: /usr/local/tomcat \
CATALINA_TMPDIR: /usr/local/tomcat/temp \
JRE_HOME: /usr
#啟動入口
ENTRYPOINT ["catalina.sh","run"]
#健康檢查
# HEALTHCHECK --interval=10s --timeout=3s \
# CMD nc -z localhost 5198 >/dev/null || exit 1
#拷貝war包到tomcat
COPY target/DataCollect.war ${CATALINA_HOME}/webapps/
Dockerfile如何編寫這個需要各位讀者自行學習,我這裡使用的是tomcat的標準映象,並通過COPY命令將target的war包拷貝到webapps中。
此Dockerfile在github中,jenkins在拉取原始碼時,該檔案也會被拉取。我們只需要讓jenkins把Dockerfile和war包傳給docker打包伺服器,再呼叫打包命令就可以生成新的docker映象,再推送到阿里的registry。
這裡我使用的docker打包機器是VM虛擬機器,也就是jenkins的宿主機
由於之前安裝了Publish Over SSH
這個外掛,就可以完成上述傳輸操作。
首先需要到系統管理
->系統設定
配置Publish over SSH
內容。我這裡使用的是使用賬戶密碼方式登入(可以使用ssh檔案登入)。配置如下:
Passphrase
:登入密碼
Name
:伺服器名稱(自定)
Hostname
:遠端伺服器地址
Username
:登入使用者
Remote Directory
:訪問的遠端目錄
再進入jenkins的專案配置,修改構建後操作
這一項
構建後操作
:使用Publish Over SSH
這個外掛,對應的選項是Send build artifacts over SSH
對Send build artifacts over SSH
進行配置如下:
SSH server Name
:需要SSH連線的Name(剛才配置好的)
Source files
:要拷貝的檔案地址(相對workspace
)
Remove prefix
:去掉Source files
的字首部分
Remote directory
:要拷貝到host機器的哪個目錄(這個目錄是相對Remote Directory
的目錄)
Exec command
:拷貝完成執行的命令
我這裡需要傳輸兩個檔案,一個是war包,另一個是Dockerfile。我的配置如下:
第一個Exec command
呼叫的test.sh是隨便echo點東西
第二個Exec command
是呼叫一個shell指令碼,裡面docker會執行build、push等一系列命令,這裡貼出來
/home/zhangchx/docker/docker-datacollect.sh "`pwd`/docker/DataCollect" $BUILD_NUMBER
echo "當前位置:"`pwd`
echo "當前使用者:"`whoami`
# 環境變數ps:我本地的docker在snap中,如果沒有這句話下面docker命令找不到
export PATH=$PATH:/snap/bin
# 定義變數
WORKHOME=$1
BUILD_NUMBER=$2
API_NAME="datacollect"
API_VERSION="1.0"
API_PORT=8081
DOCKER_REGISTRY="registry.cn-hangzhou.aliyuncs.com/zhangchx/test"
IMAGE_NAME="$API_NAME:$BUILD_NUMBER"
CONTAINER_NAME=$API_NAME-$API_VERSION
docker --version
# 進入target 目錄複製Dockerfile 檔案
#cd $WORKSPACE/target
#cp classes/Dockerfile .
cd $WORKHOME
#構建docker 映象
docker build -t $IMAGE_NAME .
#推送docker映象
docker push $DOCKER_REGISTRY$IMAGE_NAME
#刪除同名docker容器
cid=$(docker ps -a| grep "$CONTAINER_NAME" | awk '{print $1}')
if [ "$cid" != "" ]; then
docker rm -f $cid
fi
#啟動docker 容器
docker run -d -p $API_PORT:8080 --name $CONTAINER_NAME $IMAGE_NAME
#刪除 Dockerfile 檔案
#rm -f Dockerfile
這裡有坑,由於使用的DooD的形式(docker裡的jenkins訪問宿主機構建),登入使用者必須對docker命令有許可權,不能加sudo。同時宿主機的docker是在snap目錄下,宿主機可以正常使用docker命令(宿主機環境變數裡有配置snap),而jenkins遠端過來使用的環境變數是jenkins這臺docker虛擬機器的,所有無法訪問docker命令,必須先對PATH進行擴展才行。
非root執行docker的命令,使用者名稱jmh新增到docker組內:sudo gpasswd jmh docker
,修改sock許可權:sudo chmod a+rw /var/run/docker.sock
執行jenkins的構建,可以從控制檯看到日誌
進入Ubuntu裡面檢視docker映象和容器,可以看到容器在執行,也可以正常訪問。
結尾
至此,github+jenkins+maven+docker自動化構建已經達成。該構造可執行在中小公司完全沒問題,如果構建頻繁等原因效能跟不上,可在此結構上進行擴充套件,增加jenkins叢集和docker伺服器。