前言
之前寫過一遍比較粗略的jenkins + docker部署文章,這次有時間,認真的寫一遍比較詳細完整的jenkins +docker部署文章,由於有時間所以這次就多寫一點吧,記錄下我自己對docker的看法,以及它的作用,若有不對之處還請指出。
Docker的作用
其實一般的小型項目是用不上也沒有必要使用docker的,docker的作用是資源隔離以及快速部署,在項目比較小的時間我們完全可以手動上傳jar/war 包到服務器上,並輸入命令啓動即可,但是,想像一下如果你用上了微服務,好幾個團隊開發,那麼這些服務加起來可能有好幾十個,這個時候再手動去部署,想想看你要做什麼? 1、安裝 JDK 2、配置環境變量 3、安裝一些必要的軟件如TOMCAT之類的 4、等等不止這些,有些服務甚至有可能要修改JDK配置。
每部署一臺機器都要做如此多的操作是不是得煩死?如果是這種情況下,那麼docker就可以派上用場了,我們可以直接把安裝好各種軟件以及配置的系統環境打包成一個docker鏡像並保存在某個鏡像中心,然後其它服務器只需幾行命令就可以輕鬆使用打包好的環境並完成部署了,而且由於各個docker容器之間是隔離了,一臺機器可以部署多種鏡像也不會有影響。
有感而發
最近網上看到很多老程序員們在談論中年危機,彷彿看到了幾年後的自己,我自認爲自己也不屬於那無可替代的1%,而且自己也確實感覺到了行情不好(如工資下降,面試變少等),感覺自己有可能以後會不再幹程序員,希望留下來的文章能夠幫到其他人吧,好了,下面開始正題。
一、安裝docker
最好將jenkins和docker安裝在同一臺服務器上,當然不是同一臺服務器也可以,只不過要多一個步驟,docker安裝步驟如下,以centOs爲例:
卸載舊版本:
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
設置docker存儲庫:
sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
安裝docker:
sudo yum install docker-ce docker-ce-cli containerd.io
啓動docker:
sudo systemctl start docker
測試docker:
sudo docker run hello-world
看到打印hello world! 就表示成功了。
如果你的服務器是其它系統,可以參考官方教程:https://docs.docker.com/install/ ,找到 SERVER 一欄點擊對應的系統查看教程。
二、安裝jenkins
1、直接打開 http://mirrors.jenkins.io/war-stable/latest/jenkins.war 下載。
2、或者去官網選擇想要的版本:https://jenkins.io/zh/download/ ,以war包爲例,下載後上傳到服務器上,使用java -jar jenkins.war --httpPort=你想要的端口 來啓動
3、注意第一次啓動控制檯會有個初始密碼,記下來(如果沒有,使用cat /var/lib/jenkins/secrets/initialAdminPassword 命令查看),然後打開jenkins操作頁面: 服務ip:啓動時設置的端口 .
4、輸入初始密碼然後設置admin密碼,然後安裝默認的初始插件即可。
三、配置jenkins
1、進入jenkins主頁面後點系統管理 -> 插件管理 通過搜索功能分別安裝 Maven Integration 、Publish Over SSH 、GitLab 、Git
2、配置jenkins的git,點擊系統管理 -> 全局工具配置 找到git 勾上自動安裝輸入名字,建議手動安裝git不要用jenkins的,gitlab的安裝自行搜索。
3、配置遠程服務器(jenkins和docker在同一臺服務器的可忽略),點擊系統管理 -> 系統設置 ,找到 Publish over SSH ,分別 配置name (名字隨意起)、 hostname(服務器IP)、Remote Directory(傳送文件時將要放置的目錄 ),記得勾上Use password authentication, or use a different key。
4、回到jenkins主界面,點擊新建任務,
1)在generel選項卡下勾選丟棄舊的構建,要保留的個數自己填
2)在源碼管理下選擇GIt,repository Url 爲git的url地址,如:http://xxx/project/bss.git ,Credentials 是gitlab的賬號密碼,點擊旁邊的添加按鈕,在彈出來的框中選擇類型爲username with password ,分別輸入gitlab的賬號和密碼點擊確定,然後在Credentials選中剛纔添加的賬號密碼, Branch Specifier 是gitlab的分支,填 */master就好
3)在build選項卡下填寫Root POM 和 Goals and options ,root pom是你的項目pom.xml文件的位置,Goals and options 是maven執行命令,可以填 clean install -DskipTests
4) 找到 Post Steps 點擊 Add post-build step 選擇send files or execute commands over ssh ,在name選項中選擇第3步添加的服務器然後填寫Transfers 裏的內容,需要填的內容分別是:
Source files(要發送的文件,可以填: **/ *.jar ,以逗號隔開) ,建議如下填寫:
**/system-service-*.jar,docker-build.sh,Dockerfile
將jar包、docker構建命令、以及Dockerfile文件都傳輸過去。
Remote directory (會新建一個文件夾並將文件放到該文件夾下)
Exec command (傳輸完畢後要執行的sheel命令),輸入如下命令:
cd /配置jenkins ssh服務器時配置的目錄/上一步發送文件配置的遠程目錄
bash docker-build.sh "bss-*.jar" #後面的參數是指定只打包匹配的jar
上面的docker-build.sh在後面的步驟中完成,先這麼配置好,填完後點擊保存.
PS:這一步如果docker和jenkins裝在同一臺服務器就可以省略,如果不是同一臺服務器就需要這一步把jar包發送到遠程服務器上再通過docker命令打包,如果在本機打包docker鏡像則直接選擇“執行shell”,然後輸入bash ${WORKSPACE}/docker-build.sh 即可(${WORKSPACE}是jenkins的變量,表示項目構造目錄,後面我們需要把docker-build.sh放在項目目錄中).
四、編寫docker構建shell命令
回到代碼編輯器,在項目根目錄新建docker-build.sh,輸入如下代碼:
#!/bin/bash -ilex
export BUILD_ID=dontKillMe
source /etc/profile
#此變量用來對應每個子項目的映射對應端口,避免隨機映射端口導致服務無法訪問
declare -A map=(["system-service"]="8014:8014" ["server-2"]="8006:8006" ["sys-service"]="8206:8206")
function buildAndRun()
{
#遍歷文件夾獲取jar
for file in `find * -name "${1}"`
do
#Jenkins中編譯好的jar名稱
jar_name=${file##*/}
#dockerfile位置
dockerfile="./"
echo "dockerfile: ==> $dockerfile"
catName="${jar_name%-*.*.*-SNAPSHOT.jar}"
#截取jar包的名稱作爲鏡像名
IMAGE_NAME="你的dockerhub賬號/$catName"
CONTAINER_NAME="$catName"
# 構建Docker鏡像
docker build -t $IMAGE_NAME "$dockerfile"
# 推送Docker鏡像
#docker push $IMAGE_NAME #docker login 再push
# 判斷鏡像存在才啓動容器
cid=$(docker images | grep $IMAGE_NAME |awk '{print $3}')
if [ x"$cid" != x ]
then
#獲取map中的值 --entrypoint=["java","-Djava.security.egd=file:/dev/./urandom","-jar","app.jar","--spring.profiles.active=test","--server.port=${START_PORT}"] --expose=${START_PORT}
PORT_VAL=${map[$catName]}
#截取:前的端口號作爲啓動端口
START_PORT=${PORT_VAL%%:*}
# 啓動Docker容器 大寫P表示隨機端口, --link分別是eureka、gateway的IP和端口,如果有多個eureka配置host並使用hostname.-link 可以讓兩個容器之間互相通信 -v xx:xx 設置映射目錄,這樣容器被刪除該文件夾下日誌也不會被刪
RUN_SHELL="docker run -d -p ${PORT_VAL} -v /docker/logs:/logs --name $CONTAINER_NAME $IMAGE_NAME"
echo $RUN_SHELL
$RUN_SHELL
fi
done
}
#此sh用於在構建前刪除已經存在的鏡像
function clearImage()
{
#遍歷文件夾獲取jar
for file in `find * -name "${1}"`
do
#Jenkins中編譯好的jar名稱
jar_name=${file##*/}
catName="${jar_name%-*.*.*-SNAPSHOT.jar}"
#截取jar包的名稱作爲鏡像名
IMAGE_NAME="你的dockerhub賬號/$catName"
CONTAINER_NAME="$catName"
echo "container name : $CONTAINER_NAME"
cid=$(docker ps -a | grep $CONTAINER_NAME |awk '{print $1}')
if [ x"$cid" != x ]
then
echo "REMOVE CONTAINER ==> $CONTAINER_NAME"
docker rm -f $cid
fi
# 刪除Docker鏡像
tid=$(docker images | grep $IMAGE_NAME |awk '{print $3}')
if [ x"$tid" != x ]
then
echo "REMOVE IMAGE ==> $IMAGE_NAME"
docker rmi -f $tid
fi
done
}
#判斷是否使用了參數,如有參數則只啓動符合參數條件的jar
if [ $# -gt 0 ] ;then
for regx in $*
do
echo $regx
clearImage $regx
buildAndRun $regx
done
else
clearImage "*.jar"
buildAndRun "*.jar"
fi
這段代碼有三處地方要修改下:
1) declare -A map=(["bss"]="8004:8004" ["server-2"]="8006:8006" ["sys-service"]="8206:8206") ,由於docker啓動後端口是隨機產生的,如果不指定暴露端口與服務端口綁定會導致服務雖然能註冊上註冊中心但是其它服務無法訪問。
2)IMAGE_NAME="你的github賬號/$catName" 替換爲你的dockerhub賬號,這是docker鏡像命名的規範要求,即:賬號名/鏡像名 ,別忘了上面的代碼有兩處 “IMAGE_NAME="你的github賬號/$catName” 要修改。
3) dockerfile="./" ,此變是你當前項目Dockerfile的位置,Dockerfile是構建docker鏡像必不可少的文件,如果它在你的項目根目錄,那麼直接./即可。
這段代碼的大致作用是先判斷有沒有參數,如果有參數則根據參數的匹配符查找當前目錄以及子目錄的文件,並截取文件名作爲鏡像、容器名,然後在啓動之前判斷是否已經存在同名的容器或鏡像,如果存在則刪除並重新構建並啓動新的容器,如果不傳參數則默認該目錄及子目錄下的所有jar文件,所以如果想只打包某個服務的話,在jenkins執行shell命令那應該這樣填寫: bash docker-build.sh "system-service-*.jar" 。
五、編寫Dockerfile文件
在項目根目錄添加Dockerfile文件(沒有後綴),輸入如下代碼:
FROM java:8-jre-alpine
#FROM 使用java環境鏡像
#設置掛載目錄,使用項目名作爲日誌文件夾,所有項目的日誌統一都是spring.log,因此使用文件夾區分
#VOLUME /docker/logs/system-service
VOLUME logs
#聲明使用maven傳過來的變量
#ARG JAR_FILE #現使用sh命令構建已不再需要
#將該項目的JAR添加到鏡像中
#ADD ${JAR_FILE} app.jar #原本使用maven插件構建並傳jar包位置作爲變量,現改爲寫死jar包位置
ADD target/system-service-*.jar app.jar
#RUN bash -c 'touch app.jar'
EXPOSE 8014
#jar運行命令
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","app.jar"]
有三處需要修改:
1) FROM java:8-jre-alpine 表示使用該鏡像建構容器,可以改爲你需要的鏡像,這裏沒有其它需求所以直接使用了jdk8環境鏡像。
2) ADD target/system-service-*.jar app.jar 改爲你要打包的項目的路徑,由於我使用的是maven + spring boot,所以打包好後在target文件夾下
3) EXPOSE 8014 當前容器要暴露出去的端口,修改爲當前服務的啓動端口
六、測試是否成功
回到jenkins操作頁面,點擊剛纔配置的任務,點擊立刻構建,左邊的Build History會出現灰點,點擊灰點進去看打印的日誌,如無異常最後結束時會打印:Finished: SUCCESS 。
測試docker
輸入docker images 看看是否成功構建了鏡像,再輸入docker ps,看看是否成功創建了容器,什麼?沒有?空的?
輸入docker ps -a 查看所有容器,如果此時有了表示容器創建成功但啓動失敗了,檢查Dockerfile 或者是不是因爲環境問題導致項目啓動失敗了。
推送docker鏡像
假設一切ok,此時想要在其它服務器上也部署一套,可以先輸入docker login ,登陸docker hub,再輸入docker push 你的鏡像名
將鏡像推送到docker hub上,這樣其它服務器就可以通過docker pull 命令直接拿到這個鏡像了。
查看服務日誌
構建docker鏡像代碼中其中一段:RUN_SHELL="docker run -d -p ${PORT_VAL} -v /docker/logs:/logs --name $CONTAINER_NAME $IMAGE_NAME" -v /docker/logs:/logs 是表示將宿主機的目錄 映射到該鏡像的logs目錄,衆所周知spring boot日誌默認目錄是logs,所以我將 /docker/logs目錄映射到了該鏡像的logs目錄,因此只要進入/docker/logs目錄即可看到該服務的啓動日誌了