写点什么

🏆(不要错过!)【CI/CD 技术专题】「Jenkins 实战系列」(3)Jenkinsfile+DockerFile 实现自动部署

发布于: 2021 年 08 月 05 日
🏆(不要错过!)【CI/CD技术专题】「Jenkins实战系列」(3)Jenkinsfile+DockerFile实现自动部署

每日一句

没有人会因学问而成为智者。学问或许能由勤奋得来,而机智与智慧却有懒于天赋。

前提概要

  • Jenkins 下用 DockerFile 自动部署 Java 项目,项目的部署放心推向容器化时代机制。

  • 本节需要对 jenkinsfile 有点了解,对 dockerfile 有点了解,对 shell 有点了解,对 docker 有点了解

环境准备

新建-构建一个 Maven 项目


需要提一下,现在新安装的没有这个选项,需要在插件里安装一下 Maven Integration




java 配置,其他配置查看以前文章



发布到服务器,DockerFile 部署自动构建

Publish SSH 配置

执行流程

  1. jenkins 拉取代码仓库中的代码

  2. jenkins 执行 jenkinsfile 文件(可指定文件名)

  3. 先在 jenkins 所在的服务器将拉取的项目 build 成 docker 镜像

  4. 将镜像发布到镜像仓库

  5. 在应用服务器的节点上将该镜像拉取下来(私有仓库需要用户名/密码)

  6. 在应用服务器上执行该镜像

jenkins 配置

创建一个 Pipeline SCM 项目 jenkins 项目名为 sample-tezst (和发布的工程名保持一致)



  • 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="sample-tezst-0.0.1-SNAPSHOT.jar"   // 项目生成的jar的名字        IMAGE_NAME="sample-tezst"                    // 镜像名一般和项目名相同        IMAGE_ADDR="repository/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}x" != "x" ]或者使用 if [[ -n ()` 和 `` (两个单引号) 可以在子 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
复制代码


  • 通过项目根目录下的 Dockerfile 来构建镜像

  • -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} repoistory/qiao_namespace/${IMAGE_NAME}:${VERSION_ID}
复制代码
将镜像仓库能够识别的镜像推送到仓库
sudo docker push repoistory/qiao_namespace/${IMAGE_NAME}:${VERSION_ID}
复制代码

步骤四:【run】

应用服务器拉取项目并且运行, 这一步要选择节点(应用服务器,如果是集群,就不用节点用 scp 登陆吧)

登陆到镜像仓库
sudo docker login --username=yourusername --password=yourpassword repository
复制代码
从仓库中拉取刚才生成的镜像
sudo docker pull repository/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 $pidfi
复制代码
查看已经存在的镜像
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 repository/qiao_namespace/myjdk8:v1
复制代码
默认 jar 包的名字 注意分隔符为 :- 这里是由 jenkinsfile 中 build dockerfile 时传递过来的
ARG jar_name={jar_name:-sample-teszt-0.0.1-SNAPSHOT.jar}
复制代码
RUN 用于容器内部执行命令
RUN mkdir -p /usr/local/projectWORKDIR /usr/local/project
复制代码
将项目放到/usr/local/project 下
COPY ./target/sample-teszt-0.0.1-SNAPSHOT.jar ./EXPOSE 8081CMD java -jar -Dserver.port=8081 springboot-test-0.0.1-SNAPSHOT.jar
复制代码


执行完毕后我们登陆到应用服务器,看到容器已经启动

发布于: 2021 年 08 月 05 日阅读数: 8
用户头像

🏆2021年InfoQ写作平台-签约作者 🏆 2020.03.25 加入

👑【酷爱计算机技术、醉心开发编程、喜爱健身运动、热衷悬疑推理的”极客狂人“】 🏅 【Java技术领域,MySQL技术领域,APM全链路追踪技术及微服务、分布式方向的技术体系等】 我们始于迷惘,终于更高水平的迷惘

评论

发布
暂无评论
🏆(不要错过!)【CI/CD技术专题】「Jenkins实战系列」(3)Jenkinsfile+DockerFile实现自动部署