【CI/CD技术专题】「Jenkins实战系列」Jenkinsfile+DockerFile实现自动部署

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 【CI/CD技术专题】「Jenkins实战系列」Jenkinsfile+DockerFile实现自动部署

前提概要


  • Jenkins下用DockerFile自动部署Java项目,项目的部署放心推向容器化时代机制。
  • 本节需要对jenkinsfile有点了解,对dockerfile有点了解,对shell有点了解,对docker有点了解



环境准备


新建-构建一个Maven项目

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

image.png

image.png


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

image.png


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


Publish SSH配置

image.png


执行流程


  1. jenkins拉取代码仓库中的代码
  2. jenkins执行jenkinsfile文件(可指定文件名)
  3. 先在jenkins所在的服务器将拉取的项目build成docker镜像
  4. 将镜像发布到镜像仓库
  5. 在应用服务器的节点上将该镜像拉取下来(私有仓库需要用户名/密码)
  6. 在应用服务器上执行该镜像



jenkins配置


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

image.png


  • 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−a"{str} -a "stra"{str}x" != "x" ]或者使用if [[ -n str]]来判断shell语法中,{str} ]]来判断 shell语法中,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
复制代码



  • 通过项目根目录下的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 $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 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/project
WORKDIR /usr/local/project
复制代码



将项目放到/usr/local/project下
COPY ./target/sample-teszt-0.0.1-SNAPSHOT.jar ./
EXPOSE 8081
CMD java -jar -Dserver.port=8081 springboot-test-0.0.1-SNAPSHOT.jar
复制代码

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













相关实践学习
通过容器镜像仓库与容器服务快速部署spring-hello应用
本教程主要讲述如何将本地Java代码程序上传并在云端以容器化的构建、传输和运行。
Kubernetes极速入门
Kubernetes(K8S)是Google在2014年发布的一个开源项目,用于自动化容器化应用程序的部署、扩展和管理。Kubernetes通常结合docker容器工作,并且整合多个运行着docker容器的主机集群。 本课程从Kubernetes的简介、功能、架构,集群的概念、工具及部署等各个方面进行了详细的讲解及展示,通过对本课程的学习,可以对Kubernetes有一个较为全面的认识,并初步掌握Kubernetes相关的安装部署及使用技巧。本课程由黑马程序员提供。 &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
7天前
|
jenkins Java 持续交付
Gitee+Jenkins+SonarQube代码上线的实战操作
通过以上步骤,就可以实现基于Gitee、Jenkins和SonarQube的代码上线流程,确保代码的质量和上线过程的自动化和可控性。在实际操作中,可以根据项目的具体需求和环境进行适当的调整和优化。
|
22天前
|
运维 监控 jenkins
运维自动化实战:利用Jenkins构建高效CI/CD流程
【10月更文挑战第18天】运维自动化实战:利用Jenkins构建高效CI/CD流程
|
1月前
|
jenkins Shell 持续交付
Jenkins持续集成GitLab项目 GitLab提交分支后触发Jenkis任务 持续集成 CI/CD 超级详细 超多图(二)
Jenkins持续集成GitLab项目 GitLab提交分支后触发Jenkis任务 持续集成 CI/CD 超级详细 超多图(二)
67 0
|
22天前
|
运维 监控 jenkins
运维自动化实践:利用Jenkins实现高效CI/CD流程
【10月更文挑战第18天】运维自动化实践:利用Jenkins实现高效CI/CD流程
|
1月前
|
jenkins Shell 持续交付
Jenkins持续集成GitLab项目 GitLab提交分支后触发Jenkis任务 持续集成 CI/CD 超级详细 超多图(一)
Jenkins持续集成GitLab项目 GitLab提交分支后触发Jenkis任务 持续集成 CI/CD 超级详细 超多图(一)
128 0
|
13天前
|
jenkins Devops Java
DevOps实践:Jenkins在持续集成与持续部署中的价值
【10月更文挑战第27天】在快速发展的软件开发领域,DevOps实践日益重要。Jenkins作为一款流行的开源自动化服务器,在持续集成(CI)和持续部署(CD)中扮演关键角色。本文通过案例分析,探讨Jenkins在Java项目中的应用,展示其自动化构建、测试和部署的能力,提高开发效率和软件质量。
34 2
|
3月前
|
jenkins 持续交付 开发者
自动化部署:使用Jenkins和Docker实现持续集成与交付
【8月更文挑战第31天】本文旨在为读者揭示如何通过Jenkins和Docker实现自动化部署,从而加速软件开发流程。我们将从基础概念讲起,逐步深入到实际操作,确保即使是初学者也能跟上步伐。文章将提供详细的步骤说明和代码示例,帮助读者理解并应用这些工具来优化他们的工作流程。
|
1天前
|
运维 jenkins Java
Jenkins在持续集成与持续部署中的价值
Jenkins在持续集成与持续部署中的价值
|
14天前
|
jenkins Devops 测试技术
DevOps实践:Jenkins在持续集成与持续部署中的价值
【10月更文挑战第26天】随着DevOps理念的普及,Jenkins作为一款开源自动化服务器,在持续集成(CI)与持续部署(CD)中发挥重要作用。本文通过某中型互联网企业的实际案例,展示了Jenkins如何通过自动化构建、持续集成和持续部署,显著提升开发效率、代码质量和软件交付速度,帮助企业解决传统手工操作带来的低效和错误问题。
40 4
|
3月前
|
持续交付 jenkins Devops
WPF与DevOps的完美邂逅:从Jenkins配置到自动化部署,全流程解析持续集成与持续交付的最佳实践
【8月更文挑战第31天】WPF与DevOps的结合开启了软件生命周期管理的新篇章。通过Jenkins等CI/CD工具,实现从代码提交到自动构建、测试及部署的全流程自动化。本文详细介绍了如何配置Jenkins来管理WPF项目的构建任务,确保每次代码提交都能触发自动化流程,提升开发效率和代码质量。这一方法不仅简化了开发流程,还加强了团队协作,是WPF开发者拥抱DevOps文化的理想指南。
82 1