zoukankan      html  css  js  c++  java
  • 🏆(不要错过!)【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} -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
    
    • 通过项目根目录下的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
    

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

    极限就是为了超越而存在的
  • 相关阅读:
    bzoj3721
    [BZOJ3555] [Ctsc2014]企鹅QQ(Hash)
    [POJ3233] Matrix Power Series(矩阵快速幂)
    矩阵运算所满足的定律
    [luoguP1962] 斐波那契数列(矩阵快速幂)
    [luoguP3390]【模板】矩阵快速幂
    【转】关于LIS和一类可以用树状数组优化的DP 预备知识
    [BZOJ1264][AHOI2006]基因匹配Match(DP + 树状数组)
    [luoguP1439] 排列LCS问题(DP + 树状数组)
    蛤蛤蛤(树状数组 | 二分)
  • 原文地址:https://www.cnblogs.com/liboware/p/15105420.html
Copyright © 2011-2022 走看看