先简要说明一下大致流程:
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
-
配置自定义
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会将编译的依赖包等放入工作空间
-
编译前清空
-
编译后清空
-