熱門:DevOps實戰(zhàn)系列【第八章】:詳解Jenkins集成Docker私服Nexus3

2023-01-08 19:12:51 來源:51CTO博客

個人親自錄制全套DevOps系列實戰(zhàn)教程:??手把手教你玩轉(zhuǎn)DevOps全棧技術(shù)??


【資料圖】

Jenkins集成Docker鏡像倉庫

docker私服已經(jīng)搭建完畢,下邊我們期望jenkins做的事是:

①通過git拉取代碼②通過maven構(gòu)建生成jar包③構(gòu)建含有jar包的鏡像??④推送到docker倉庫????⑤通知宿主從倉庫拉取鏡像并啟動容器??

??有什么好處???避免將jar包拷貝到宿主機,而是直接將jar包打入鏡像上傳到私服。

??為什么不是jenkins直接拉取并啟動容器???從角色上看jenkins并不是docker服務(wù),生產(chǎn)中多數(shù)是部署docker集群,所以拉取鏡像并部署容器更應(yīng)該由docker自身操作。

??非要用jenkins拉取和部署可以嗎???當(dāng)然可以,但jenkins容器中一直只映射單個docker宿主機的docker.sock,如果是docker集群就不好解決了,比較麻煩。

Jenkins容器編排文件修改

??注意:??之前我們講的都是jenkins構(gòu)建完jar包后,傳輸?shù)剿拗鳈C,由宿主機通過docker命令完成構(gòu)建和啟動容器,

此處我們期望jenkins能完成這些事,有幾種方法:

在jenkins中安裝docker服務(wù)或安裝docker cli并連接到宿主直接將宿主機的docker內(nèi)核映射給jenkins容器,讓jenkins能操作宿主機的docker【推薦】
# 很簡單只需要將jenkins的docker-compose.yml修改一下即可version: "3"services:  jenkins:    build:       context: .      dockerfile: Dockerfile    image: "lij/jenkins:2.346.3-2-lts-centos7"    restart: always    container_name: "jenkins"    hostname: "jenkins"    environment:      - JAVA_OPTS="-Dhudson.model.DownloadService.noSignatureCheck=true"    ports:      - "9078:8080"      - "50000:50000"    networks:      - "exist-net-bloom"    volumes:      - "/docker/jenkins/home:/var/jenkins_home"      - "/docker/jenkins/mvnrepo:/mvnrepo"         - "/etc/timezone:/etc/timezone:ro"      - "/etc/localtime:/etc/localtime:ro"      # 新增加內(nèi)容      - "/var/run/docker.sock:/var/run/docker.sock"      - "/usr/bin/docker:/usr/bin/docker"      - "/etc/docker/daemon.json:/etc/docker/daemon.json"networks:  exist-net-bloom:    external:      name: devops

??解釋:??/var/run/docker.sock 是docker服務(wù)器后臺進(jìn)程執(zhí)行docker客戶端命令的服務(wù),

不論是docker cli還是對外開放的api最終都是與/var/run/docker.sock進(jìn)行交互,所以把他映射到j(luò)enkins內(nèi)部,jenkins就可以內(nèi)部操作宿主機了。

另外還需映射docker命令(即客戶端命令)和已經(jīng)配置好的配置文件。

??問題:???更新配置后執(zhí)行docker info報權(quán)限問題

分析:這應(yīng)該是執(zhí)行docker.sock的權(quán)限問題,我們進(jìn)入宿主機查看docker.sock的權(quán)限

??解決:??這里有幾種方式

以root用戶登錄jenkins,我實際我們用的是jenkins用戶,這樣容器導(dǎo)致用戶權(quán)限過大,不推薦
# 修改方法只需在docker-compose.yml中增加以root登錄即可user: root
將宿主機的docker.sock文件的權(quán)限改為可以讓jenkins的賬號ID=1000的用戶使用即可??【推薦】??這里我們粗暴些,直接777權(quán)限
# 第一種:授權(quán)777權(quán)限chmod 777 /var/run/docker.sock# 第二種:授權(quán)other組可讀寫chmod o+rw /var/run/docker.sock

修改jenkins的job配置

當(dāng)maven構(gòu)建后,直接在jenkins工作目錄構(gòu)建鏡像并推送鏡像到私服

[此處我們以Nexus作為私服演示,對于大型項目harbor優(yōu)勢較大,成本相對也較高,比如內(nèi)置數(shù)據(jù)庫PostgreSQL,而我們一般會使用公共數(shù)據(jù)庫,所以至少要有一個PostgreSQL實例,等等,而Nexus就就相對簡單些,也能和Maven倉庫復(fù)用,成本較低]

??注意:??jenkins中運行shell腳本的目錄是jenkins_home/workspace/jobName目錄

# 注意:因為我們要構(gòu)建鏡像而不需要直接啟動容器,所以只需要Dockerfile文件,而暫時不需要使用docker-compose.yml# 1.構(gòu)建鏡像的命令,我們使用docker build,通過-t指定鏡像標(biāo)簽,最后指定Dockerfile的目錄,我們使用當(dāng)前目錄即可docker build -t 10.10.1.199:9082/busybox:v-${branch} .# 注意:jenkins中運行shell腳本當(dāng)前目錄是[workspace/jobName]目錄set -e \&& mv target/*.jar docker/ \  # 拷貝jar包到docker目錄&& cd docker \&& docker build -t demo:v-$branch . \  # 構(gòu)建鏡像,使用分支名作為版本號&& docker tag demo:v-$branch 10.10.1.199:9082/demo:v-$branch \  #給鏡像打標(biāo)簽,準(zhǔn)備推送私服&& docker login -u admin -p jie123456 10.10.1.199:9082 \ #登錄私服hosted倉庫&& docker push 10.10.1.199:9082/demo:v-$branch \#推送鏡像#避免構(gòu)建同一個鏡像產(chǎn)生懸空鏡像,假設(shè)已經(jīng)執(zhí)行了當(dāng)前jenkins job,那么再次執(zhí)行時,本地一定是拉取了鏡像,所以直接構(gòu)建會產(chǎn)生懸空鏡像&& docker image prune -f

???問題:???點擊構(gòu)建會報錯,如下:

???原因:???就是鏡像名稱定義的不規(guī)范,因為我們使用的git分支名,而分支默認(rèn)都是orgin/開頭,而放到鏡像中斜杠就不合適了,所以我們在git參數(shù)構(gòu)建時,將[orgin/]過濾掉,配置如下:使用正則??orgin/(.*)???即可

再次構(gòu)建,就沒問題了。

宿主機拉取鏡像并部署容器

??解決目標(biāo):??既然是jenkins通知宿主機,那么就可能是多個jenkins的job都有這種通知操作,

所以我們不能寫死拉取鏡像的信息,而是通過jenkins的通知將這些參數(shù)傳遞過來,比如拉取鏡像的地址、鏡像標(biāo)識等,并且要處理鏡像重復(fù)等問題。

??思路:??怎么讓jenkins給宿主傳參數(shù)呢?說的比較抽象,其實我們之前已經(jīng)做過了,就是ssh。

jenkins的job做完構(gòu)建鏡像并推送后,就可以執(zhí)行ssh連接宿主,然后執(zhí)行腳本,而jenkins的job中可以設(shè)置變量,在執(zhí)行宿主機腳本是可以直接引用過來,而這次腳本比較多,我們就不再jenkins中羅列了,而是直接寫入到shell腳本,讓jenkins直接調(diào)用。

??腳本內(nèi)容:??在宿主機目錄創(chuàng)建shell腳本, vi /share/jenkins/demo/script/publish.sh

??注意:??腳本權(quán)限問題,我是root創(chuàng)建,并且jenkins中ssh也是使用的root所以沒問題,大家根據(jù)自己情況去酌情處理。

# 定義變量repositoryUrl=$1jobName=$2imageVersion=$3remoteImageName=$repositoryUrl/$jobName:$imageVersion #遠(yuǎn)程私服倉庫的完整鏡像名稱echo "remoteImageName is "$remoteImageName### 檢查是否存在同名鏡像運行的容器,如果存在則需要先刪除,然后再刪除鏡像,然后再拉取新鏡像,最后以新鏡像啟動容器#獲取已啟動的容器IDcontainerId=$(docker ps -a | grep -w "$remoteImageName" | awk "{print $1}")if [ "$containerId" ! = "" ]; thendocker stop $containerId && docker rm $containerIdfi#如果鏡像存在同樣先刪除imageId=$(docker images | grep -w "$repositoryUrl/$jobName" | grep -w "$imageVersion" | awk "{print $3}")if [ "$imageId" ! = "" ]; thendocker rmi -f $imageIdfi#從私服拉取鏡像:如果不允許匿名,則需要先登錄,因為我已經(jīng)設(shè)置允許匿名,所以可以不登錄直接拉取docker login -u admin -p 123456 $repositoryUrldocker pull $remoteImageName#啟動容器:我們之前啟動都是拿docker-compose.yml,但此時因為在宿主機,并沒有這么一個docker-compose.yml文件,#所以我們可以直接使用docker run運行容器docker run -d \-p 9099:8080 \-v /etc/timezone:/etc/timezone:ro \-v /etc/localtime:/etc/localtime:ro \--network devops \--privileged=true \--name $jobName $remoteImageName

??解釋:??其實我們jenkins容器已經(jīng)拿到宿主機的docker執(zhí)行權(quán)了,那這個文件不傳到宿主機執(zhí)行,在本地容器執(zhí)行也是可以的,但由于角色不同,該腳本由docker服務(wù)器執(zhí)行更合適,并且如果是docker集群那么容器執(zhí)行會很麻煩。

??優(yōu)化:???簡單起見,或者說為了隔離、可擴展,我們把這個腳本文件放到springboot中,讓jenkins幫我們遠(yuǎn)程拷貝到宿主機的固定目錄,然后執(zhí)行

參數(shù)配置:我們腳本里引用了那么幾個參數(shù),哪里來的?

jenkins我們知道可以參數(shù)化構(gòu)建,比如我們用的git參數(shù),當(dāng)然他也可以指定普通參數(shù),如下,我們在job中增加這些參數(shù):

[當(dāng)然也可以直接寫到腳本執(zhí)行的后邊,我這里就只配一個示意一下,其他參數(shù)直接傳遞]

標(biāo)簽: 因為我們 當(dāng)前目錄

上一篇:世界訊息:如何利用filebeat把不同服務(wù)器上的log4j日志傳輸?shù)酵慌_ELK服務(wù)器
下一篇:【熱聞】MySQL 常用腳本