当前位置: 首页 > news >正文

Jenkins + Docker 部署,使用,持续集成以及踩坑

对于 Jenkins 我只能用两个字形容,难用。就不过多吐槽了,本篇是基于 docker 环境的使用

1.安装

寻找需要的 Jenkins 镜像:https://hub.docker.com/r/jenkinsci/blueocean

docker pull jenkinsci/blueocean

我选择的镜像是 Jenkins-blueocean Jenkins 海洋版,为什么选这个?

  1. 踩坑:普通的 Jenkins 在部署的时候不少人都遇到过,插件下不下来,但是在海洋版没有这个问题(最主要原因)
  2. blueocean 的页面更加人性化,流程的监控上看着让人舒服的多,当然普通 Jenkins 也可以通过安装插件添加这个功能

启动镜像

docker run --name jenkinsci-blueocean -u root --rm  -d -p 7005:8080 -p 50000:50000 -v /data/jenkins:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock jenkinsci/blueocean
  • -u root:以 root 权限启动,防止出现权限问题
  • -p 7005:8080:端口映射,服务器的 7005 端口映射容器的 8080 端口
  • -p 50000:50000:Jenkins代理默认通过TCP端口50000与Jenkins主机通信
  • -v /data/jenkins:/var/jenkins_home:把容器内的 Jenkins 目录挂载到服务器的 /data/jenkins 目录以防容器没了,数据也没了
  • -v /var/run/docker.sock:/var/run/docker.sock:保证容器内的 docker 与 服务器上 docker 的通讯

附带下删除 jenkinsci/blueocean 容器

# 删除对应绑定网桥
docker network disconnect --force bridge jenkinsci-blueocean

# 删除 jenkinsci-blueocean 容器,xxxx  容器 ID
docker rm -f xxxx

输入密码进入

由于我们挂载映射到服务器,所以可以直接通过服务器路径找密码

cat /data/jenkins/secrets/initialAdminPassword

或者直接通过容器日志可以看到密码:docker logs xxxx(容器 ID)

接下来,我选择推荐插件安装

创建第一个账号,我用的 root 123456

然后完成安装,由于是用的是镜像,所以安装起来非常的简单,海洋版也没有出现插件无法下载的问题

2.创建项目与持续集成

踩坑PS:为什么说难用,就是在这。一开始我是把 jdk 和 maven 也挂载到容器里的,但是配置完全局变量后,根本无法使用,可能是容器内也要配置好这些才行,我就搞不懂容器内配了那还要专门配个全局环境变量干啥。。。自动安装也是完全没用,所以我放弃了,用我自己的方法进行持续集成部署。

接下来配置项目,选择流水线

配置

这里我们通过 webhook,让项目提交后,自动调用钩子函数进行部署,进行持续集成
配置构建触发器,也就是钩子函数

身份验证令牌自己写的,所以这里钩子函数的路径就是

http://127.0.0.1:7005/job/spring-cloud/build?token=123456

PS:身份验证令牌框下面就是钩子函数的请求路径说明,不太明白的,可以自己看看,我上面给的这个是示例

配置项目

公私密钥的可参考:https://blog.csdn.net/weixin_41235146/article/details/81780894

然后保存,这里暂时就配好了

root 创建 API token

记住这串 token,后面要和钩子函数一起使用,离开这个页面后再进入就看不到这串 token 了

系统管理 => 全局安全配置

PS踩坑:这里不配置的话,后面钩子函数的请求都会 403 失败

接下来配置钩子函数的请求了,这里以 gitee 为例

进入项目 => 管理 => WebHook

请求历史可以看到请求成功 201

 

先说下本人用于测试的这个项目是父子项目,打包时候把每个子项目打成 jar 包,然后通过 Dockerfile 生产 docker 镜像,然后启动镜像生成容器,这就是我的部署流程

项目根目录下新增 Jenkinsfile

PS踩坑:由于 maven 配置不成功,我也不想进容器配置 maven,因为服务器才 1G ,进容器就死机了,所以我改了依赖 maven 镜像部署,然后再通过另一个任务把 jar 包生成镜像,因为 maven 容器里没有 docker 环境

思路:
package:利用 docker 镜像构建 maven 环境,然后让项目打包,因为 Jenkins 是在容器内的,里面没有 maven 环境,虽说是在 docker 另一个容器环境内打包,但是 Jenkins 会自动把他挂到自己项目下的某个路径里。
build:由于已经打包完成,我们就不需要 maven 环境了,因此后续直接在 Jenkins 容器里操作即可,对项目打包镜像,发布运行

pipeline {
    agent any
    stages {
        stage('package') {
            agent {
        		docker {
            		        image 'maven:3-alpine'
            		        args '-v /root/.m2:/root/.m2  -v /data/maven/apache-maven-3.6.0/conf/settings.xml:/root/.m2/settings.xml --entrypoint='
        		}
    	    }
            steps {
                script{
                    echo "WORKSPACE:${env.WORKSPACE}"
                    echo "Branch:${env.NODE_NAME}"
                    if ("${env.NODE_NAME}" == "master") {
                        sh "sh package-prod.sh"
                    }
                }
            }
        }
        stage('build') {
            agent none
            steps {
                script{
                    echo "WORKSPACE:${env.WORKSPACE}"
                    echo "Branch:${env.NODE_NAME}"
                    if ("${env.NODE_NAME}" == "master") {
                        sh "sh build-prod.sh"
                    }
                }
            }
        }
    }
}

 先 pull 个 maven 镜像,以及在构建镜像时候所需要的 jdk8 的镜像

# maven:3-alpine 用于 Jenkins 构建有 maven 环境的容器
# Jenkins 官方提供的 maven 镜像,能避免不少问题
# 不自己 pull 也行,会自动 pull
docker pull maven:3-alpine

# jdk8 的镜像用于 Dockerfile 中设置构建拥有 jdk8 环境镜像的基础镜像
docker pull kdvolder/jdk8
  • image 'docker.io/maven':基于这个镜像生成容器部署,所以环境有 maven 环境
  • args 中 -v /root/.m2:/root/.m2:把依赖挂载导服务器上,不用每次打包都下依赖
    PS:首先,你要知道这个流程是如何进行的,在你根据下的那个 maven 镜像去打包时,由于内外 docker 建立了通讯,所有服务器的 docker 就会生成一个你 maven 的容器,而你的命令都会在这个容器里进行,所以这里挂载就能直接把 maven 这个临时容器里的依赖挂载到服务器上,打包的过程中,你用 docker ps 是可以看到这个 maven 容器的
  • args 中 -v /data/maven/apache-maven-3.6.0/conf/settings.xml:/root/.m2/settings.xml:阿里环境配置挂进去
    PS踩坑:这里注意,挂载进去的 settings.xml 文件必须放在 .m2 文件夹下,不是放在 maven 的 conf 下面,那样不会生效
  • --entrypoint=:配置下好像就不会打开进入容器了,没深入研究
  • ${env.WORKSPACE}:工作空间路径
  • ${env.NODE_NAME}:进行的分支

Jenkins 内置环境变量可参考:https://www.cnblogs.com/puresoul/p/4828913.htm
可以看到,我这部署先判度为 master 分支的情况下,package 任务中调用脚本进行打包,build 任务下调用脚本部署

下面贴下这两个脚本,大伙可以参考下

package-prod.sh

#!/bin/sh
#进入文件根目录
#cd "$WORKSPACE"

#项目打包
mvn clean install package '-Dmaven.test.skip=true'

build-prod.sh

#!/bin/sh
#进入文件根目录
#cd "$WORKSPACE"

#启用 prod 配置
ActiveProfiles=prod

#基本信息需要配置
#内部端口
targetPort=8081
#旧镜像版本号
oldVendor=1.0.0
#镜像版本号
vendor=1.0.0
#项目名
projectName=eureka

#进入target文件夹
#直接的构建是再容器里,这个是在 Jenkins 容器里,所以空间不一样
#容器的空间是原空间路径后面多了 @2
cd $WORKSPACE@2/$projectName/target

#创建Dockerfile文件
#-jar -Duser.timezone=GMT+08 保证生成出来的容器的时区与服务器一致
cat << EOF > Dockerfile
FROM kdvolder/jdk8
MAINTAINER $projectName
VOLUME /tmp
LABEL app="$projectName" version="$vendor" by="$projectName"
COPY $projectName.jar $projectName.jar
EXPOSE $targetPort
CMD -Xmx100m -Xms100m -jar -Duser.timezone=GMT+08 $projectName.jar --spring.profiles.active=$ActiveProfiles
ENTRYPOINT java
EOF

#删除镜像下所有容器
docker rm -f $(docker ps -a | grep "$projectName" | awk '{print $1}')

#删除旧镜像
docker rmi -f $projectName:$oldVendor

#创建镜像
docker build -t $projectName:$vendor .

#启动镜像生成容器
docker run --name $projectName -d -p $targetPort:$targetPort $projectName:$vendor

我写配置喜欢统一性配置,后面改起来简单,上面参数换下下面都不需要改,这里我的文件夹名,镜像名和生产的 jar 名都用一样的也是这个目的

打包成功,这画面看的好看不少

 

 

 

相关文章:

  • Docker 删除 Exited 容器以及删除 none 镜像
  • LeetCode Java 深度优先算法(DFS)实现岛屿个数计算,附带详细分析
  • LeetCode Java 队列结合广度优先算法(BFS)实现岛屿个数计算,附带详细分析
  • navicat连接oracle报错:ORA-12737 Instant Client Light:unsupported server character set ZHS16GBK
  • Spring Boot,Spring Cloud,Spring Cloud Alibaba 版本选择说明以及整理归纳
  • RestTemplate 工具类
  • SpringCloud 之 Ribbon
  • SpringCloud 之 Hystrix 断路器,服务降级,自定义配置
  • Oracle 让指定数据排在最前面
  • Gitlab 之 Windows 环境进行 tomcat 持续集成部署,包含项目打包,备份,部署以及问题
  • Git 克隆指定分支的代码
  • Vue 新手学习笔记:vue-element-admin 之 入门开发教程(v4.0.0 之后)
  • Tomcat 内存优化
  • SpringCloud 之 Zuul 基础使用与进阶
  • Navicat 连接 sqlserver 带端口号配置
  • ES6指北【2】—— 箭头函数
  • 【知识碎片】第三方登录弹窗效果
  • ES6语法详解(一)
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • Protobuf3语言指南
  • Python中eval与exec的使用及区别
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • 百度地图API标注+时间轴组件
  • 记录一下第一次使用npm
  • 力扣(LeetCode)22
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 微信小程序实战练习(仿五洲到家微信版)
  • 线性表及其算法(java实现)
  • 项目管理碎碎念系列之一:干系人管理
  • Java性能优化之JVM GC(垃圾回收机制)
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​第20课 在Android Native开发中加入新的C++类
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (function(){})()的分步解析
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (论文阅读30/100)Convolutional Pose Machines
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (一)基于IDEA的JAVA基础10
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • .net core 微服务_.NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .Net 代码性能 - (1)
  • .NET处理HTTP请求
  • .net反编译的九款神器
  • .NET下的多线程编程—1-线程机制概述
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • [ 云计算 | AWS ] 对比分析:Amazon SNS 与 SQS 消息服务的异同与选择
  • []AT 指令 收发短信和GPRS上网 SIM508/548