微服務(wù)項(xiàng)目在jenkins中基于Docker的構(gòu)建

目的

? ? ? ?通過(guò)當(dāng)前文檔的內(nèi)容,可以將springboot類的微服務(wù)項(xiàng)目基于Docker自動(dòng)構(gòu)建出成品,可以省去了大量的項(xiàng)目部署時(shí)間以及項(xiàng)目依賴環(huán)境的部署時(shí)間。
? ? ? ?閱讀本章內(nèi)容,請(qǐng)確保你已掌握Docker到基本使用,如未滿足該要求,請(qǐng)到Docker操作指南中進(jìn)行學(xué)習(xí)。

處理流程

  • 提交項(xiàng)目業(yè)務(wù)代碼和構(gòu)建代碼到SVN
  • Jenkins 構(gòu)建任務(wù)
  • 部署包上傳FTP
  • 測(cè)試人員從FTP下載部署包,使用腳本一鍵安裝部署包,開始測(cè)試

整體流程如圖所示:


process.png

下面就圍繞上面到處理流程進(jìn)行微服務(wù)項(xiàng)目在Docker環(huán)境下到構(gòu)建及部署教程。

微服務(wù)項(xiàng)目

下圖是整個(gè)項(xiàng)目到結(jié)構(gòu)圖:


project.jpg

業(yè)務(wù)代碼及配置說(shuō)明

? ? ? ?業(yè)務(wù)代碼正常修改,正常提交到SVN
? ? ? ?在src/main/resources下到application.yml文件中,有如下代碼:

db: 
 server: 192.168.7.200
 port: 3306
 user: root
 pwd: Admin@123
 redis:
  host: 127.0.0.1
  pwd: Admin@123
spring:
  profiles: dev
  redis:
    host: ${db.redis.host}
    password: ${db.redis.pwd}
  datasource:
    url: jdbc:mysql://${db.server}:${db.port}/ms-user?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
    driver-class-name: com.mysql.jdbc.Driver
    username: ${db.user}
    password: ${db.pwd}

其中,關(guān)于db部分的,是我自定義的,用于在單個(gè)docker容器啟動(dòng)的時(shí)候,可以動(dòng)態(tài)的設(shè)置其對(duì)應(yīng)的參數(shù)值,其實(shí)這個(gè)參數(shù)值,可以使用原生的配置項(xiàng),只不過(guò)我感覺(jué)原生的太長(zhǎng)了,不利于敲寫docker的啟動(dòng)命令,比如,設(shè)置數(shù)據(jù)庫(kù)的連接地址,如果使用原生的配置項(xiàng),則需要以下形式:

docker run image-app --spring.datasource.url=jdbc:mysql://x.x.x.x:port/ms-user?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull

這樣的編寫,是很不優(yōu)雅的,所以,我設(shè)置了一個(gè)簡(jiǎn)短的參數(shù)用來(lái)映射到已經(jīng)固定到其他參數(shù)項(xiàng)中。
例如,設(shè)置連接數(shù)據(jù)庫(kù)的地址,可以在啟動(dòng)的時(shí)候,指定為 --DB_SERVER=x.x.x.x。

部署代碼配置說(shuō)明

? ? ? ?在項(xiàng)目目錄中的Docker目錄中,存在mysql,redis的項(xiàng)目環(huán)境依賴的部署配置,如圖所示:


dockerFolder.png

項(xiàng)目依賴環(huán)境:mysql鏡像配置

? ? ? ?mysql的基礎(chǔ)鏡像已經(jīng)在192.168.7.68上構(gòu)建完成,且鏡像中已經(jīng)包含了很多配置項(xiàng),可以直接拿過(guò)來(lái)使用,而不用再次的去繼承mysql官方鏡像并且定制各項(xiàng)配置。
? ? ? ?項(xiàng)目依賴的mysql鏡像中,包含了一個(gè)初始化的sql腳本,通過(guò)繼承基礎(chǔ)mysql鏡像,生成一個(gè)新的帶當(dāng)前項(xiàng)目數(shù)據(jù)庫(kù)的鏡像。

鏡像配置

? ? ? ?具體的鏡像構(gòu)建,請(qǐng)參照以下代碼或在項(xiàng)目中查看:

#繼承mysql的基礎(chǔ)鏡像
FROM 192.168.7.68:5000/sbr/mysql:1.0.0

#指定維護(hù)人
MAINTAINER 圣博潤(rùn)研發(fā)中心

#將容器啟動(dòng)后,執(zhí)行的腳本拷貝到容器內(nèi)的/docker-entrypoint-initdb.d下,該目錄會(huì)自動(dòng)執(zhí)行sql腳本
COPY ms-user.sql /docker-entrypoint-initdb.d
RUN chmod 775 /docker-entrypoint-initdb.d/ms-user.sql

#聲明容器暴漏的端口,只是聲明,沒(méi)有其他作用
EXPOSE 3306

? ? ? ?該構(gòu)建文件中,需要注意以下情況:

  • 在將數(shù)據(jù)庫(kù)腳本復(fù)制到鏡像中后,需要為該腳本設(shè)置權(quán)限,否則,在啟動(dòng)容器的時(shí),會(huì)導(dǎo)致mysql的容器啟動(dòng)失敗,原因是(ms-user.sql)腳本沒(méi)有執(zhí)行權(quán)限。

初始化腳本內(nèi)容需要注意:在mysql官方鏡像中提供了容器啟動(dòng)時(shí)自動(dòng)執(zhí)行/docker-entrypoint-initdb.d文件夾下的腳本的功能(包括shell腳本和sql腳本) docker-entrypoint.sh中的代碼如下:

for f in /docker-entrypoint-initdb.d/*; do
            case "$f" in
                *.sh)     echo "$0: running $f"; . "$f" ;;
                *.sql)    echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;;
                *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;;
                *)        echo "$0: ignoring $f" ;;
            esac
  echo
done

就是說(shuō)只要把你自己的初始化腳本放到/docker-entrypoint-initdb.d/文件夾下,mysql就會(huì)讀取其中的文件并執(zhí)行,但是,執(zhí)行順序,我們是無(wú)法控制的,所以,請(qǐng)盡量將初始化腳本內(nèi)容寫到一個(gè)文件中。

項(xiàng)目依賴環(huán)境:redis鏡像配置

? ? ? ?項(xiàng)目同樣也依賴redis服務(wù),所以,也需要?jiǎng)?chuàng)建一個(gè)redis的鏡像。

鏡像配置

? ? ? ?具體的鏡像構(gòu)建,請(qǐng)參照以下代碼或在項(xiàng)目中查看:

#繼承redis基礎(chǔ)鏡像,用來(lái)添加屬于項(xiàng)目的一些配置
FROM 192.168.7.68:5000/sbr/redis:1.0.0

#編寫人/維護(hù)人
MAINTAINER 圣博潤(rùn)研發(fā)中心

#聲明容器暴漏的端口
EXPOSE 6379

該鏡像,在目前來(lái)看,并沒(méi)有什么需要注意的地方。

項(xiàng)目鏡像配置

? ? ? ?將項(xiàng)目的jar包打進(jìn)基于jre的鏡像中,可以生成我們的項(xiàng)目鏡像。

鏡像配置

? ? ? ?具體的鏡像構(gòu)建,請(qǐng)參照以下代碼或在項(xiàng)目中查看:

#繼承jre8的基礎(chǔ)鏡像
FROM 192.168.7.68:5000/sbr/jre8:1.0.0

#編寫人/維護(hù)人
MAINTAINER 圣博潤(rùn)研發(fā)中心

#將jar包復(fù)制到容器根目錄
COPY ms-auth-2.1.2051-SNAPSHOT.jar /ms-auth-2.1.2051-SNAPSHOT.jar

#聲明端口
EXPOSE 9003

#容器啟動(dòng)后,執(zhí)行的命令
ENTRYPOINT ["java", "-jar", "/ms-auth-2.1.2051-SNAPSHOT.jar"]

至此,我們的微服務(wù)項(xiàng)目的所有鏡像已經(jīng)制作完畢,后續(xù)需要在jenkins中稍加配置處理,就可以生成我們想要的鏡像。

compose一鍵構(gòu)建

? ? ? ?在Docker操作指南中,我們知道,使用compose可以僅僅通過(guò)一個(gè)命令來(lái)根據(jù)配置文件構(gòu)建多個(gè)鏡像及容器。

鏡像構(gòu)建(build-compose.yml) 配置

使用如下配置文件:

#使用的compose版本
version: '3'

#compose關(guān)鍵字,定義services
services:

 #service的名稱 sbr_redis
 sbr_redis: 
  #service中容器的名稱
  container_name: sbr_redis
  #使用當(dāng)前目錄下的redis目錄下的Dockerfile來(lái)創(chuàng)建鏡像
  build: ./redis
  #當(dāng)前服務(wù)向外暴漏的端口
  ports: 
   - "6379:6379"
   
 #service的名稱 sbr_mysql
 sbr_mysql: 
  #service中容器的名稱
  container_name: sbr_mysql
  #使用當(dāng)前目錄下的mysql目錄下的Dockerfile來(lái)創(chuàng)建鏡像
  build: ./mysql 
  #當(dāng)前服務(wù)向外暴漏的端口
  ports: 
   - "3306:3306"
   
 #service的名稱 sbr_user_auth
 sbr_user_auth: 
  #service中容器的名稱
  container_name: sbr_app 
  #使用當(dāng)前目錄下的app目錄下的Dockerfile來(lái)創(chuàng)建鏡像
  build: ./app
  #當(dāng)前服務(wù)向外暴漏的端口
  ports: 
   - "9003:9003"

通過(guò)

docker-compose build

來(lái)進(jìn)行上述mysql、redis、微服務(wù)項(xiàng)目鏡像的的構(gòu)建和容器的啟動(dòng)。我們同樣可以將這段構(gòu)建指令配置到j(luò)enkins中去。

部署配置

? ? ? ?在項(xiàng)目源碼目錄中,我們發(fā)現(xiàn),還有兩個(gè)文件沒(méi)有介紹其內(nèi)容:


deploy.png

現(xiàn)在,我們來(lái)看以下這兩個(gè)文件是干什么到。

deploy-compose.yml配置

? ? ? ?我們已經(jīng)知道,通過(guò)compose可以一鍵啟動(dòng)docker到多個(gè)容器,我們這里就采用來(lái)這種方式,而在上一節(jié)中,也有一個(gè)build-compose.yml到配置文件,那個(gè)文件中,其實(shí)配置的是,在jenkins構(gòu)建服務(wù)器中到構(gòu)建鏡像到配置。而在測(cè)試端也需要提供一個(gè)一鍵啟動(dòng)到compose文件。所以這個(gè)deploy-compose.yml文件就是干這個(gè)用但。通過(guò)jenkins構(gòu)建后,我們已經(jīng)明確的知道了我們的鏡像名稱,所以,可以通過(guò)以下配置來(lái)一鍵啟動(dòng)容器,啟動(dòng)的容器都是受compose管理,而不用我們?nèi)斯とun/create等操作:

#使用的compose版本
version: '3'

#compose關(guān)鍵字,定義services
services:

 #service的名稱 sbr_redis
 sbr_redis: 
  #service中容器的名稱
  container_name: sbr_redis
  #使用當(dāng)前目錄下的redis目錄下的Dockerfile來(lái)創(chuàng)建鏡像
  image: docker_sbr_redis
  #當(dāng)前服務(wù)向外暴漏的端口
  ports: 
   - "6379:6379"
   
 #service的名稱 sbr_mysql
 sbr_mysql: 
  #service中容器的名稱
  container_name: sbr_mysql
  #使用當(dāng)前目錄下的mysql目錄下的Dockerfile來(lái)創(chuàng)建鏡像
  image: docker_sbr_mysql 
  #當(dāng)前服務(wù)向外暴漏的端口
  ports: 
   - "3306:3306"
   
 #service的名稱 sbr_user_auth
 sbr_user_auth: 
  #service中容器的名稱
  container_name: sbr_app 
  #使用當(dāng)前目錄下的app目錄下的Dockerfile來(lái)創(chuàng)建鏡像
  image: docker_sbr_user_auth
  #當(dāng)前服務(wù)向外暴漏的端口
  ports: 
   - "9003:9003"
  #當(dāng)前容器使用的環(huán)境變量
  environment:
   - DB_SERVER=sbr_mysql
   - DB_REDIS_HOST=sbr_redis
  #當(dāng)前服務(wù)依賴depends_on配置的服務(wù),docker compose會(huì)優(yōu)先啟動(dòng)依賴的服務(wù)
  depends_on:
   - sbr_mysql
   - sbr_redis

具體說(shuō)明已經(jīng)在配置文件中以注解的方式說(shuō)明來(lái)出來(lái)。

部署腳本

? ? ? ?我們沒(méi)有必要提供compose相關(guān)的配置文件給測(cè)試人員,除非對(duì)方堅(jiān)決的要這個(gè)文件,以達(dá)到他們自己控制容器操作的目的。
? ? ? ?那么,我們可以提供一個(gè)更加簡(jiǎn)便的操作方式來(lái)啟動(dòng)各個(gè)容器,那就是一個(gè)shell腳本:

#!/bin/bash

#定義可執(zhí)行函數(shù)的參數(shù)數(shù)組
parr=(load startup stop rm rma)

#定義檢查本機(jī)是否安裝了docker
checkDocker(){
    dockerpath=$(which docker)
    if [ ! -n "#dockerpath" ]; then
        echo "未檢測(cè)到Docker..."
        exit 1
    fi
}

#載入tar包中的鏡像
load(){
    checkDocker
    #導(dǎo)入docker鏡像:mysql
    echo "開始導(dǎo)入mysql鏡像...."
    docker load < sbr_mysql.tar

    #導(dǎo)入docker鏡像:redis
    echo "開始導(dǎo)入redis鏡像...."
    docker load < sbr_redis.tar

    #導(dǎo)入docker鏡像:user_auth
    echo "開始導(dǎo)入微服務(wù)應(yīng)用鏡像...."
    docker load < user_auth.tar
}

#開始執(zhí)行docker容器的啟動(dòng)
startup(){
    checkDocker
    echo "準(zhǔn)備啟動(dòng)容器...."
    docker-compose -f deploy-compose.yml up
}

#停止容器
stop(){
    checkDocker
    echo "準(zhǔn)備停止容器...."
    docker-compose -f deploy-compose.yml stop
}

#刪除容器
rm(){
    checkDocker
    stop
    echo "準(zhǔn)備刪除容器...."
    docker-compose -f deploy-compose.yml rm
}

#刪除容器以及鏡像
rma(){
    checkDocker
    rm
    echo "準(zhǔn)備刪除鏡像...."
    docker_sbr_user_auth_image=$(docker image ls | grep docker_sbr_user_auth)
    if [ -n "#docker_sbr_user_auth_image" ]; then
        docker rmi docker_sbr_user_auth:latest
    fi

    docker_sbr_redis_image=$(docker image ls | grep docker_sbr_redis)
    if [ -n "#docker_sbr_redis_image" ]; then
        docker rmi docker_sbr_redis:latest
    fi

    docker_sbr_mysql_image=$(docker image ls | grep docker_sbr_mysql)
    if [ -n "#docker_sbr_mysql_image" ]; then
        docker rmi docker_sbr_mysql:latest
    fi
}


if  [ ! -n "$1" ] ;then
    load
    startup
else
    if [[ "${parr[@]/$1/}" != "${parr[@]}" ]]; then
        $1
    else
        echo $1":參數(shù)不能執(zhí)行,請(qǐng)輸入正確參數(shù)!"
        exit
    fi
fi

通過(guò)這個(gè)腳本,測(cè)試人員可以執(zhí)行以下命令來(lái)簡(jiǎn)單的進(jìn)行容器管理:

  • load:載入/導(dǎo)入所有鏡像,如 ./deploy load
  • startup:啟動(dòng)容器,如 ./deploy startup
  • stop:停止容器,如 ./deploy stop
  • rm:刪除容器,如 ./deploy rm
  • rma:刪除鏡像及容器,如 ./deploy rma

README文件介紹

該文件是交給測(cè)試人員進(jìn)行查看到,有以下幾點(diǎn)內(nèi)容:

  • 部署腳本如何使用
  • 項(xiàng)目升級(jí)說(shuō)明
  • 其他備注信息

Jenkins構(gòu)建

? ? ? ?jenkins構(gòu)建系統(tǒng):http://192.168.7.26/jenkins/
? ? ? ?jenkins的界面如圖所示:

jenkins_main.png

我們的構(gòu)建任務(wù)在88.技術(shù)中,點(diǎn)擊去后,如下圖所示:
kenkins_list.png

構(gòu)建配置

SVN配置

svn配置信息如下圖所示:

  • Repository URL:填寫項(xiàng)目svn地址
  • Credentials:SVN賬戶信息
  • Local module directory:將SVN項(xiàng)目down到什么位置,如果是一個(gè)點(diǎn)(.),則表示將項(xiàng)目中到內(nèi)容down到88.技術(shù)/微服務(wù)2.0目錄下,如果什么也沒(méi)有,則會(huì)在微服務(wù)2.0目錄下創(chuàng)建一個(gè)項(xiàng)目名稱到目錄,然后再將項(xiàng)目?jī)?nèi)容down到該目錄下
jenkins_svn.png

構(gòu)建配置

這一個(gè)配置是整個(gè)自動(dòng)化構(gòu)建的核心

  • maven配置:


    jenkins_maven.jpg
  • shell 操作代碼

#先查找jenkins服務(wù)器中是否已經(jīng)構(gòu)建了微服務(wù)項(xiàng)目鏡像
#如果已經(jīng)構(gòu)建,則刪除
docker_sbr_user_auth_image=$(docker image ls | grep docker_sbr_user_auth)
if [ -n "#docker_sbr_user_auth_image" ]; then
    docker rmi docker_sbr_user_auth:latest
fi

#先查找jenkins服務(wù)器中是否已經(jīng)構(gòu)建了微服務(wù)項(xiàng)目依賴的redis鏡像
#如果已經(jīng)構(gòu)建,則刪除
docker_sbr_redis_image=$(docker image ls | grep docker_sbr_redis)
if [ -n "#docker_sbr_redis_image" ]; then
    docker rmi docker_sbr_redis:latest
fi

#先查找jenkins服務(wù)器中是否已經(jīng)構(gòu)建了微服務(wù)項(xiàng)目依賴的mysql鏡像
#如果已經(jīng)構(gòu)建,則刪除
docker_sbr_mysql_image=$(docker image ls | grep docker_sbr_mysql)
if [ -n "#docker_sbr_mysql_image" ]; then
    docker rmi docker_sbr_mysql:latest
fi

#使用項(xiàng)目中的docker目錄下的build-compose.yml文件進(jìn)行構(gòu)建鏡像
docker-compose -f ./docker/build-compose.yml build

#如果88.技術(shù)/微服務(wù)2.0目錄下不存在deploy目錄,則創(chuàng)建deploy目錄
#如果存在deploy目錄,則刪除deploy目錄下的所有文件,保留一個(gè)干凈的deploy目錄
if [ ! -d "deploy" ];then
    mkdir deploy
else
    rm -rf deploy/*
fi

#將項(xiàng)目源碼的docker目錄下的deploy-compose.yml 復(fù)制到deploy目錄下
cp docker/deploy-compose.yml deploy/deploy-compose.yml

#將將項(xiàng)目源碼的docker目錄下的script目錄下的deploy.sh復(fù)制到deploy目錄下
cp docker/script/deploy.sh deploy/deploy.sh
#將部署說(shuō)明復(fù)制到deploy目錄
cp docker/README.txt deploy/README.txt

#進(jìn)入deploy目錄,并進(jìn)行鏡像的保存,保存的鏡像會(huì)存到deploy目錄下
cd deploy
docker save -o user_auth.tar docker_sbr_user_auth:latest
docker save -o sbr_redis.tar docker_sbr_redis:latest
docker save -o sbr_mysql.tar docker_sbr_mysql:latest

#將導(dǎo)出的鏡像打成gz包,并刪除源包
tar -zcvf deploy.tar.gz * --remove-files

FTP文件傳輸配置

此時(shí),jenkins已經(jīng)在本機(jī)構(gòu)建好了所需的鏡像,并且,已經(jīng)在指定目錄將導(dǎo)出的鏡像打成了gz包,然后我們將該文件發(fā)送到FTP服務(wù)器之后,測(cè)試人員就可以下載到本機(jī)進(jìn)行測(cè)試了。

  • FTP配置


    jenkins_ftp.png

到此,整個(gè)jenkins到構(gòu)建已經(jīng)完成,我們也可以通過(guò)構(gòu)建控制臺(tái)來(lái)查看實(shí)時(shí)到構(gòu)建信息。

部署簡(jiǎn)要

測(cè)試人員操作說(shuō)明:

  • 到FTP服務(wù)器ftp://192.168.7.220中的【測(cè)試版本】-【88.技術(shù)】-【微服務(wù)2.0】中下載最新部署包和部署說(shuō)明

  • 部署包:deploy.tar.gz 部署說(shuō)明:README.txt

  • 部署包包含:user_auth.tar(微服務(wù)項(xiàng)目鏡像),sbr_redis.tar(微服務(wù)項(xiàng)目依賴的redis鏡像),sbr_mysql.tar(微服務(wù)項(xiàng)目依賴的mysql鏡像),deploy-compose.yml(測(cè)試人員無(wú)需關(guān)注),deploy.sh(測(cè)試人員主要的操作文件)

  • deploy.sh的使用:

    1. 使用 tar -zxvf deploy.tar.gz來(lái)解壓部署包
    2. 腳本一鍵執(zhí)行:
      • 腳本會(huì)檢查本機(jī)是否安裝docker,如果未安裝,會(huì)給出提示
      • 給腳本賦予可執(zhí)行權(quán)限: chmod 775 deploy.sh
      • 腳本參數(shù)介紹:
        如果只是輸入了 ./deploy 而不附帶任何參數(shù),該腳本會(huì)自動(dòng)導(dǎo)入鏡像并啟動(dòng)容器
        load:載入所有鏡像,如 ./deploy load
        startup:啟動(dòng)容器,如 ./deploy startup
        stop:停止容器,如 ./deploy stop
        rm:刪除容器,如 ./deploy rm
        rma:刪除鏡像及容器,如 ./deploy rma

至此,微服務(wù)項(xiàng)目在jenkins中基于Docker的構(gòu)建的內(nèi)容已經(jīng)完畢,若有不足之處,請(qǐng)予以支持與補(bǔ)充。謝謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容