美文网首页
基于Jenkins的持续集成部署(CI/CD)

基于Jenkins的持续集成部署(CI/CD)

作者: 一二先生 | 来源:发表于2019-11-24 12:42 被阅读0次

先简要说明一下大致流程:
1. 提交代码至gitlab代码仓库
2. 配置jenkins集成部署任务

集成部署任务包含以下步骤:
1.拉取gitlab代码
2.编译代码,同时生成docker镜像
3.将docker镜像推送至docker镜像仓库
4.使用docker远程命令模式,远程docker主机拉取docker镜像仓库镜像,并运行
如果不使用docker镜像仓库,可合并3、4步骤

  • 环境

    • Gitlab:项目代码仓库
    • Jenkins:持续集成部署任务管理工具
    • Docker:部署容器
  • 编译准备(Java)
    由于工作需要,平时都是使用gradle进行java代码编译,因此我们需要对build.gradle进行配置(如果使用的是Maven,请修改想要的pom.xml),配置如下:

    buildscript {
        ...
        dependencies {
            ...
            classpath("se.transmode.gradle:gradle-docker:1.2")
        }
    }
    
    ...
    apply plugin: 'docker'
    
    docker {
        baseImage 'adoptopenjdk/openjdk8-openj9'
        maintainer 'lv@eairlv'
    }
    
    sourceCompatibility = '1.8'
    group = 'com.eairlv.cli'
    archivesBaseName = 'projectName'
    version = '1.0.3'
    
    task buildDocker(type: Docker, dependsOn: build) {
        applicationName = archivesBaseName
        tagVersion = version.toString()
        addFile("${applicationName}-${tagVersion}.jar","app.jar")
        entryPoint(["sh","-c",'java $JAVA_OPTIONS -jar app.jar $APP_OPTIONS'])
        doFirst {
            copy {
                from jar
                into stageDir
            }
        }
    }
    

    JAVA_OPTIONS:配置jvm参数
    APP_OPTIONS:配置程序启动参数

  • 任务准备
    之前在另外一篇文章中介绍了jenkins的安装与简述了一下任务创建的步骤:

    • 输入gitlab地址与分支

    • 选择之前创建的全局凭据

    • 配置gradle脚本(选择版本、配置task启动任务):-x test clean buildDocker

      image.png
    • 配置自定义shell脚本(用于执行docker部署指令的脚本),这里分享一个示例吧:

      #!/bin/bash
      set +v
      
      # -------------------主机配置-------------------
      
      # 步骤配置:1 编译构建,并推送至远程仓库;2 从远程仓库拉取镜像运行;3 编译构建,推送至远程仓库,拉取镜像运行
      STEP=3
      
      # 主机IP,多个IP以空格隔开,如:(192.168.1.1 192.168.1.2)
      HOST_IP=(192.168.1.1)
      
      # 主机端口,多个端口以空格隔开,如:(8090 8090),注意数量需要和<主机IP>保持一致
      HOST_PORT=(8761)
      
      # 主机日志目录
      HOST_LOG_PATH=/home/eairlv
      
      # -------------------项目配置-------------------
      
      # 项目名称
      PROJECT_NAME=projectName
      
      # 项目包路径
      PROJECT_PACKAGE=com.eairlv.cli
      
      # 项目版本
      PROJECT_VERSION=1.0.3
      
      # 项目分支
      PROJECT_BRANCH=develop
      
      # 项目端口,如果设置为-1,则默认项目端口为映射的主机端口
      PROJECT_PORT=-1
      
      # 项目参数
      PROJECT_APP_OPTIONS="--spring.cloud.config.label=${PROJECT_BRANCH} --eureka.client.service-url.defaultZone=http://192.168.1.1:8761/eureka/"
      
      # 项目日志目录
      PROJECT_LOG_PATH=/eairlv
      
      # -------------------编译配置-------------------
      
      # 远端仓库地址
      MIRROR_WAREHOUSE={MIRROR_WAREHOUSE}
      
      # 远端仓库组织
      MIRROR_WAREHOUSE_ORG={MIRROR_WAREHOUSE_ORG}
      
      # 远端仓库用户
      MIRROR_WAREHOUSE_USER={MIRROR_WAREHOUSE_USER}
      
      # 远端仓库密钥
      MIRROR_WAREHOUSE_PWD={MIRROR_WAREHOUSE_PWD}
      
      # 编译后镜像名,项目包路径/项目名称:项目版本(多环境下同一项目版本号生成的镜像名一致,极端情况下可能会出现镜像交叉问题)
      JENKINS_IMAGE_NAME=${PROJECT_PACKAGE}/${PROJECT_NAME}:${PROJECT_VERSION}
      
      # 远端仓库镜像名,远端仓库地址/远端仓库组织/项目名称:项目版本-项目分支
      WAREHOUSE_IMAGE_NAME=${MIRROR_WAREHOUSE}/${MIRROR_WAREHOUSE_ORG}/${PROJECT_NAME}:${PROJECT_VERSION}-${PROJECT_BRANCH}
      
      # -------------------环境配置-------------------
      
      # 语言环境配置,快速启动;编码设置;(可自定义增加其他参数,如限制内存使用:-Xms100m -Xmx 500m)
      JAVA_OPTIONS="-Duser.timezone=GMT+8 -Djava.security.egd=file:/dev/./urandom -Dfile.encoding=UTF-8"
      
      # 容器环境配置,日志限制;时区同步;日志挂载
      DOCKER_ENVIRONMENT="--log-opt max-size=1m --log-opt max-file=1 -v /etc/localtime:/etc/localtime:ro -v ${HOST_LOG_PATH}:${PROJECT_LOG_PATH} -d"
      
      # DOCKER远程端口
      DOCKER_REMOTE_PORT=2375
      
      # -------------------运行配置-------------------
      
      # 1 推送至远程仓库
      function step1(){
          
          # 将镜像标记为远程仓库名
          docker tag ${JENKINS_IMAGE_NAME} ${WAREHOUSE_IMAGE_NAME}
          
          # 删除历史编译镜像,释放空间(不可删除未使用镜像,因为编译的镜像均为未使用,且系统可同时进行代码编译与镜像构建)
          if [ -n "$(docker images | grep none | awk '{print $3}')" ]; then
              docker images | grep none | awk '{print $3}' | sort -u | xargs docker rmi -f
          fi
          
          # 登录远程仓库
          docker login -u ${MIRROR_WAREHOUSE_USER} -p ${MIRROR_WAREHOUSE_PWD} ${MIRROR_WAREHOUSE}
          
          # 推送镜像至远程仓库
          docker push ${WAREHOUSE_IMAGE_NAME}
          
          # 删除本次编译镜像,释放空间
          if [ -n "$(docker images | grep ${PROJECT_NAME} | awk '{print $3}')" ]; then
              docker images | grep ${PROJECT_NAME} | awk '{print $3}' | sort -u | xargs docker rmi -f
          fi
      }
      
      # 2 从远程仓库拉取镜像运行
      function step2(){
          
          # 主机与端口配置校验
          if [ ${#HOST_IP[@]} -eq ${#HOST_PORT[@]} ];then
              
              # 遍历主机列表
              for ip_index in "${!HOST_IP[@]}";
              do
                  remote_ip=${HOST_IP[$ip_index]}
                  remote_port=${HOST_PORT[$ip_index]}
                  
                  echo "------------远程主机:$remote_ip:$remote_port 拉取远程仓库镜像------------"
                  docker login -u ${MIRROR_WAREHOUSE_USER} -p ${MIRROR_WAREHOUSE_PWD} ${MIRROR_WAREHOUSE}
                  docker -H $remote_ip:${DOCKER_REMOTE_PORT} pull ${WAREHOUSE_IMAGE_NAME}
                  
                  if [ -n "$(docker -H $remote_ip:${DOCKER_REMOTE_PORT} ps -a | grep ${PROJECT_NAME}.$remote_port | awk '{print $1}' | sed 's/%//g')" ]; then
                      echo "------------远程主机:$remote_ip:$remote_port 停止并删除容器------------"
                      docker -H $remote_ip:${DOCKER_REMOTE_PORT} stop $(docker -H $remote_ip:${DOCKER_REMOTE_PORT} ps -a | grep ${PROJECT_NAME}.$remote_port | awk '{print $1}' | sed 's/%//g')
                      docker -H $remote_ip:${DOCKER_REMOTE_PORT} rm -f $(docker -H $remote_ip:${DOCKER_REMOTE_PORT} ps -a | grep ${PROJECT_NAME}.$remote_port | awk '{print $1}' | sed 's/%//g')
                  fi
      
                  echo "------------远程主机:$remote_ip:$remote_port 启动容器------------"
                  if [ ${PROJECT_PORT} -eq -1 ];then
                      docker -H $remote_ip:${DOCKER_REMOTE_PORT} run -e JAVA_OPTIONS="${JAVA_OPTIONS}" -e APP_OPTIONS="${PROJECT_APP_OPTIONS} --eureka.instance.ip-address=$remote_ip --server.port=$remote_port" ${DOCKER_ENVIRONMENT} --name ${PROJECT_NAME}.$remote_port -p $remote_port:$remote_port ${WAREHOUSE_IMAGE_NAME}
                  else
                      docker -H $remote_ip:${DOCKER_REMOTE_PORT} run -e JAVA_OPTIONS="${JAVA_OPTIONS}" -e APP_OPTIONS="${PROJECT_APP_OPTIONS} --eureka.instance.ip-address=$remote_ip" ${DOCKER_ENVIRONMENT} --name ${PROJECT_NAME}.$remote_port -p $remote_port:${PROJECT_PORT} ${WAREHOUSE_IMAGE_NAME}
                  fi
                  
                  # 删除未使用的镜像,释放空间
                  docker -H $remote_ip:${DOCKER_REMOTE_PORT} image prune -a -f
              done
          else
              echo "HOST_IP HOST_PORT 数量不匹配,请重新配置"
          fi
      }
      
      # 3 推送至远程仓库,并拉取镜像运行
      function step3(){
          step1
          step2
      }
      
      # 步骤控制
      if [ ${STEP} -eq 1 ];then
          step1
      elif [ ${STEP} -eq 2 ];then
          step2
      else
          step3
      fi
      

      可根据实际情况对脚本进行调整。这里友情提示一下,在配置任务的时候建议将任务的删除工作空间功能给选上,不然jenkins编译的机器上的磁盘空间很容易就会被占满,因为jenkins会将编译的依赖包等放入工作空间

      • 编译前清空


        image.png
      • 编译后清空


        image.png

相关文章

网友评论

      本文标题:基于Jenkins的持续集成部署(CI/CD)

      本文链接:https://www.haomeiwen.com/subject/btxuyctx.html