Jenkins+docker 部署SpringCloud微服务
部署需要提前准备的环境:安装好Jenkins、docker、Maven、Jdk1.8、Git
说明:由于本例只说明如何部署,所以有关项目其他服务如nacos、mysql、redis、seata等默认已经安装好的;这里只演示如何部署SpringCloud/SpringBoot应用到docker;
一. Jenkins插件安全和全局环境配置
插件安装 进入Jenkins管理后台首页面板 系统管理→插件管理→可选插件
需要安装的插件: Pipeline Utility Steps(用于解析pom文件,因为后续创建的docker容器带了版本,解析pom去拿版本,如果你的DockerFile生成的容器不带版本,则不需要安装)
全局参数配置:进入Jenkins管理后台首页面板 系统管理→系统配置
在全局属性里面添加一个环境变量,不然使用mvn命令时可能会报以下错误:
........./jenkins5323864766359302328.sh: line 2: mvn: command not found
查看系统PATH变量: echo $PATH
将查询出的PATA添加到全局环境变量属性中
全局参数配置:进入Jenkins管理后台首页面板 系统管理→全局工具配置
编辑maven的setting.xml文件,设置远程仓库为阿里云,设置Docker打包插件白名单
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
<pluginGroups>
<pluginGroup>com.spotify</pluginGroup>
</pluginGroups>
配置maven的setting文件和本地仓库
设置git
配置Git账号密码:进入Jenkins管理后台首页面板 系统管理→Manage Credentials
点击添加凭据,范围为全局,输入用户名和密码点击确定,ID会自动生成;我的代码放在gitee,所以这里输入的是码云的账号密码
二. 开始新建构建项目
本演示项目来自一个开源的SpringCloudAlibaba项目 源码地址:https://gitee.com/liuyadu/open-cloud
components: 公用模块,包含启动的加载配置,工具类等公用的模块,其他服务可以引入,完成一些基本的配置;
platform: 基本的服务,包含base服务(用于获取基本数据),统一网关gateWay,统一用户认证中心 ,uaa-admin-server
services: 其他服务
这里我只构建 base-server、gateway、uaa-admin-server三个服务
Jenkins新建文件夹
点击新建任务,选择文件夹类型;之后在该文件夹下面创建所有的服务,统一管理。这边我已经创建好了,所以显示已存在
创建拉取代码任务项目
创建一个拉取代码的项目,在open-cloud文件夹里面,新建item,这里选择构建自由风格的软件项目,用于拉取我们的项目源码,这样就不需要每个服务都单独拉取一次了;
在源码管理里面选择Git,输入项目Git地址,然后选择我们之前就已经添加的gitee凭据,指定拉取的分支;
指定拉取的代码保存地址: 在Additional Behaviors里面新增行为,选择到指定本地分支;默认情况下拉取代码到Jenkins工作目录(默认是/var/lib/jenkins/workspace) 加上在jenkins创建的任务名称
因为我们有创建一个文件夹,在文件夹下面创建的任务,所以默认是 /var/lib/jenkins/workspace/open-cloud/pull-project,但是我不想显示pull-project,直接到open-cloud就行,所以我指定Git代码保存目录到open-cloud
点击保存,然后点击【立即构建】,拉取完之后就能在我们指定的路径下面找到源码了;
创建base-gateway服务
打包docker有两种思路:一种是maven先把打成jar包和Dockerfile,然后使用docker build成一个镜像,运行;另一种是使用maven的bulid工具,直接在本地打包输出到指定的docker host主机,需要开启2375端口给外界访问/配置ssh秘钥;
这边我是直接在服务器上使用maven的docker打包插件,打包到本地容器;源码pom坐标已经配置了maven docker打包插件,这边以部署gateway服务为例,其他服务器部署只需要修改一下名称即可;
在open-cloud文件夹下面,新建一个item,这里我叫base-gateway,选择流水线;如果不知道Pipeline流水线任务的的可以去看一下文档
官方文档:https://www.jenkins.io/zh/doc/book/pipeline/
w3cschool:https://www.w3cschool.cn/jenkins/jenkins-173a28n4.html
在流水线里面,编写自己的Pipeline脚本,Jenkins的Pipeline脚本支持直接编写Script和从SCM加载脚本文件。如果选择从SCM获取,则可以直接把脚本放到项目的源码里面,指定文件即可,为了方便我直接选择编写脚本。
脚本文件如下:
node {
// 指定工作目录,必须指定,否则路径默认会是/var/lib/jenkins/workspace/open-cloud/base-gateway/
dir('/var/lib/jenkins/workspace/open-cloud/') {
def workspace = pwd()
echo "workspace:${workspace}"
def image_name = 'open.cloud/open-cloud-base-gateway'
def container_name='open-cloud-base-gateway'
def project_home = 'open-cloud/open-cloud-base-gateway'
// docker 挂载目录,自行创建前面的目录路径
def root_path = "/data/docker/work/${project_home}"
//删除旧容器和镜像
stage('RM 删除旧容器和镜像') {
echo '================删除已经存在的容器和镜像=================='
sh "/data/docker/work/docker-rm.sh ${container_name}"
}
//编译代码和依赖
stage('Build 编译代码和依赖') {
// Run the maven build
echo "bulid components模块......."
sh "mvn -f components/pom.xml -Dmaven.test.skip=true clean install package -P test"
echo "bulid open-cloud-base-client......."
sh "mvn -f platform/open-cloud-base-client/pom.xml -Dmaven.test.skip=true clean install package -P test"
echo "bulid open-cloud-base-server......."
sh "mvn -f platform/${container_name}/pom.xml -Dmaven.test.skip=true clean install package -P test dockerfile:build"
}
//读取pom文件获取 version 和 port
def pom = readMavenPom file: 'pom.xml'
def port = "${pom.properties.appPort}"
//运行容器
stage('Run 运行容器') {
echo '================运行容器=================='
sh "docker run -p ${port}:${port} -d --name ${container_name} --restart=on-failure -v ${root_path}:${root_path} -v ${root_path}/log:/logs ${image_name}:${pom.version}"
}
}
}
这里我把port统一在每个服务的pom中配置,bootstrap.yml启动配置读取pom中的即可,这样就可以保证我们在本地测试和docker部署的端口一致;
上面有一个sh文件用于判断docker中是否已经存在此容器和镜像,如果存在则删除; sh文件内容如下,需要注意的是如果sh文件你是在Windows上创建的,格式可能无法直接运行,需要编辑文件 set ff=unix
#!/usr/bin/env bash
IMAGE_NAME=$1
echo "$IMAGE_NAME"
if [ ! -n "$IMAGE_NAME" ]; then
echo 参数不能为空
exit 4
fi
echo '================获取镜像id=================='
IID=$(docker images | grep "$IMAGE_NAME" | awk '{print $3}')
echo 镜像id=$IID
if [ -n "$IID" ]; then
echo 存在$IMAGE_NAME镜像
docker rmi $IID
else
echo 不存在$IMAGE_NAME镜像
fi
echo '================获取容器id=================='
CID=$(docker ps -aqf "name=$IMAGE_NAME")
echo 容器id=$CID
if [ -n "$CID" ]; then
echo 存在$IMAGE_NAME容器,停止容器并删除
docker rm -f $IMAGE_NAME
else
echo 不存在$IMAGE_NAME容器
fi
最后保存,点击立即构建;等待构建完成....
注意:构建中如果出现 org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use method java.util.Dictionary get java.lang.Object...错误,是因为读取pom文件时需要Jenkins安全签名认证,点击系统管理选择In-process Script Approval ,点击approval ,对拦截到的命令允许通过,重启Jenkins即可
- 相同步骤,创建base-serve、uaa-admin-serve
docker ps -a 查看容器运行情况,三个服务正常运行。
如果需要指定服务的启动顺序,可以使用构建触发器,让项目在其他项目构建完成之后触发