前言
本節需要對jenkinsfile有點了解,對dockerfile有點了解,對shell有點了解,對docker有點了解
執行流程
- jenkins拉取代碼倉庫中的代碼
- jenkins執行jenkinsfile文件(可指定文件名)
- 先在jenkins所在的服務器將拉取的項目build成docker鏡像
- 將鏡像發布到鏡像倉庫(我這里是騰訊雲配置的私有倉庫)
- 在應用服務器的節點上將該鏡像拉取下來(私有倉庫需要用戶名/密碼)
- 在應用服務器上執行該鏡像
一、jenkins配置
創建一個Pipeline SCM項目 jenkins項目名為springboot-test (和發布的工程名保持一致)
Definition選擇 【Pipeline Script from SCM】
Branch Specifier(blank for 'any'):選擇分支
Additional Behaviours: 添加郵箱通知的發送者 【這里沒有寫】
Script Path: 填寫使用項目中的Jenkinsfile文件的名字
二、應用工程配置
在工程的根目錄下創建Dockerfile文件和Jenkins_docker文件
jenkinsfile_docker文件內容如下
// docker集成docker部署
pipeline {
agent {label 'master'}
tools{
maven 'maven'
}
environment {
GIT_PROJECT_ADDR="git@gitee.com:uncleqiao/springboot-test.git" //項目的git地址
JENKINS_WORKSPACE="/root/.jenkins/workspace" //jenkins存放文件的地址
PROJECT_NAME="${JOB_NAME}" // 項目名
JAR_NAME="springboot-test-0.0.1-SNAPSHOT.jar" // 項目生成的jar的名字
IMAGE_NAME="springboot-test" // 鏡像名一般和項目名相同
IMAGE_ADDR="ccr.ccs.tencentyun.com/qiao_namespace/${IMAGE_NAME}" // 鏡像的位置
VERSION_ID="${BUILD_ID}"
}
stages {
stage('pullCode'){
steps{
echo 'This is a pullCode step'
//git branch: "${BRANCH}", credentialsId: '1001', url: "${GIT_PROJECT_ADDR}"
checkout scm
}
}
stage('Build') {
steps{
echo 'This is a Build step'
// 在有Jenkinsfile同一個目錄下(項目的根目錄下)
sh 'mvn clean package -Dmaven.test.skip=true'
}
}
// 創建目錄(如果不存在),並把jar文件上傳到該目錄下
stage('ssh') {
steps{
echo 'push jar to target server'
sh '''
ole_image_id=`docker images|grep ${IMAGE_NAME}|grep ${VERSION_ID}|awk '{print $3}'`
if [[ -n "${ole_image_id}" ]]; then
docker rmi -f ${ole_image_id}
fi
docker build -f Dockerfile --build-arg jar_name=${JAR_NAME} -t ${IMAGE_NAME}:${VERSION_ID} .
new_image_id=`docker images|grep ${IMAGE_NAME}|grep ${VERSION_ID}|awk '{print $3}'`
sudo docker tag ${new_image_id} ${IMAGE_ADDR}:${VERSION_ID}
sudo docker push ${IMAGE_ADDR}:${VERSION_ID}
'''
}
}
stage('run') {
// 在應用服務器節點 test
agent {
node {
label 'test'
//customWorkspace "${SERVER_TARGET_PATH}" //此參數會初始化目錄 注意填寫
}
}
options {
// 不讓它切換到節點上自動從倉庫拉取項目
skipDefaultCheckout()
}
steps {
echo 'pull image and docker run'
withEnv(['JENKINS_NODE_COOKIE=dontKillMe']) {
sh '''
sudo docker login --username=yourusername --password=yourpassword ccr.ccs.tencentyun.com
sudo docker pull ${IMAGE_ADDR}:${VERSION_ID}
container_id=`docker ps|grep ${IMAGE_ADDR}:${VERSION_ID}|awk '{print $1}'`
if [ -n "${container_id}" ]; then
docker rm -f "${container_id}"
fi
old_pid=`ps -ef|grep ${JAR_NAME}|grep -v grep|awk '{print $2}'`
if [[ -n $old_pid ]]; then
kill -9 $old_pid
fi
old_image=`docker images|grep ${IMAGE_ADDR}|grep ${VERSION_ID}`
if [[ -n $old_image ]]; then
old_image_id=`echo ${old_image}|awk '{print $3}'`
docker rmi -f ${old_image_id}
fi
sudo docker run --name "${PROJECT_NAME}_${VERSION_ID}" -p 9001:8081 -d ${IMAGE_ADDR}:${VERSION_ID}
'''
}
}
}
}
}
注意:
- if [ -n str ] 這個命令在使用的時候如果str為空,也是true,可以使用
if [ -n ${str} -a "${str}x" != "x" ]
或者使用if [[ -n ${str} ]]
來判斷 - shell語法中,$()` 和 `` (兩個單引號) 可以在子shell中執行命令,但是這兒$()不支持
- idea沒有jenkinsfile的語法提示,很容易出錯,這個很難受
步驟一:拉取項目 在【pullCode】步驟中
checkout scm , 這個scm是創建jenkins流水線時選擇的,屬於特殊變量,代表了你的倉庫信息,自動從倉庫中獲取項目
步驟二: 【Build】
將拉取下來的項目進行編譯並打包
步驟三:【build_image】 將打包好的項目build成docker鏡像,然后推送到鏡像倉庫(這里可以分成兩步)
# 獲取已經存在的鏡像
ole_image_id=`docker images|grep ${IMAGE_NAME}|grep ${VERSION_ID}|awk '{print $3}'`
# 刪掉存在的鏡像
if [[ -n "${ole_image_id}" ]]; then
docker rmi -f ${ole_image_id}
fi
# 通過項目根目錄下的Dokcerfile來構建鏡像 -f filename --build-arg <key=value> 給Dockerfile傳遞參數
# -t 鏡像的名稱:版本 這里我將jenkins的構建次數當作鏡像的版本
docker build -f Dockerfile --build-arg jar_name=${JAR_NAME} -t ${IMAGE_NAME}:${VERSION_ID} .
# 獲取構建好的鏡像的id
new_image_id=`docker images|grep ${IMAGE_NAME}|grep ${VERSION_ID}|awk '{print $3}'`
# 根據生成的鏡像,tag出一個名稱空間不同的鏡像(騰訊雲能識別的鏡像)
sudo docker tag ${new_image_id} ccr.ccs.tencentyun.com/qiao_namespace/${IMAGE_NAME}:${VERSION_ID}
# 將鏡像倉庫能夠試別的鏡像推送到倉庫
sudo docker push ccr.ccs.tencentyun.com/qiao_namespace/${IMAGE_NAME}:${VERSION_ID}
步驟四:【run】應用服務器拉取項目並且運行, 這一步要選擇節點(應用服務器,如果是集群,就不用節點用scp登陸吧)
# 登陸到鏡像倉庫
sudo docker login --username=yourusername --password=yourpassword ccr.ccs.tencentyun.com
# 從倉庫中拉取剛才生成的鏡像
sudo docker pull ccr.ccs.tencentyun.com/qiao_namespace/${IMAGE_NAME}:${VERSION_ID}
# 查看已經存在的容器, 存在則刪掉 存在則刪掉 這里應該是一個數組,有點小問題,待修改
container_id=`docker ps|grep ${IMAGE_ADDR}:${VERSION_ID}|awk '{print $1}'`
if [ -n "${container_id}" ]; then
docker rm -f "${container_id}"
fi
# 查看已經運行的同版本的項目, 存在則刪掉 這里應該是一個數組,有點小問題,待修改
pid=`ps -ef|grep ${JAR_NAME}|grep -v grep|awk '{print $2}'`
if [[ -n $pid ]]; then
kill -9 $pid
fi
# 查看已經存在的鏡像, 存在則刪掉 這里應該是一個數組,有點小問題,待修改
old_image=`docker images|grep ${IMAGE_ADDR}|grep ${VERSION_ID}`
if [[ -n $old_image ]]; then
old_image_id=`echo ${old_image}|awk '{print $3}'`
docker rmi -f ${old_image_id}
fi
# 運行容器
sudo docker run --name "${PROJECT_NAME}_${VERSION_ID}" -p 9001:8081 -d ${IMAGE_ADDR}:${VERSION_ID}
Dockerfile
文件內容如下
FROM ccr.ccs.tencentyun.com/qiao_namespace/myjdk8:v1
# 默認jar包的名字 注意分隔符為 :- 這里是由jenkinsfile中build dockerfile時傳遞過來的
ARG jar_name={jar_name:-springboot-test-0.0.1-SNAPSHOT.jar}
# RUN 用於容器內部執行命令
RUN mkdir -p /usr/local/project
WORKDIR /usr/local/project
# 將項目放到/usr/local/project下
COPY ./target/springboot-test-0.0.1-SNAPSHOT.jar ./
EXPOSE 8081
CMD java -jar -Dserver.port=8081 springboot-test-0.0.1-SNAPSHOT.jar
執行完畢后我們登陸到應用服務器
看到容器已經啟動,docker exec 進入到容器看到文件是存在的