最近玩了下docker和jenkins并且实战了微服务的项目,在这里记录下实现细节。
这也是我第一次写博文,以前学习的东西都是记录在印象笔记上,此次打算分享出来,如果写的不好或有错误的地方,请见谅、请指正。废话不多说,现在开始 。 ==本教程适合新手新手新新手,大神请绕道==
此次用到的工具有docker、jenkins、gitlab, 项目是springboot2.0+ 的springcloud 项目 使用gradle构建,项目的构建过程不在赘述,不会的可自行百度,jenkins使用通用的war包方式运行,本地git和gitlab的搭建,便不再这里写了,官网有很详细的教程地址:https://about.gitlab.com/installation/。后面我会在写一篇在docker中搭建gitlab和jenkins的文章 ,至于docker 的安装就同样不在赘述,网上教程一大堆。
1.安装jenkins
下载下来之后,放到自己喜欢的目录,在jenkins.war 包所在的目录下,运行 java -jar jenkins.war --httpPort=9090 命令,由于spring项目占用了8080端口,所以jenkins不在使用默认的8080,指定--httpPort=9090 端口 效果如下
第一次运行jenkins时,控制台会打印一段比较重要的信息,新手经常容易忽略,如下图
其中1是jenkins生成的默认密码,第一次登陆是需要用的, 2是密码存放位置 如果以后还使用默认密码,则可以再这个目录下找到,这段信息只有第一次运行时才打印。 好了,现在在浏览器输入 localhost:9090试试,你会看到如下界面,此界面也会告诉你密码存放路径,并且也是第一次运行才提示。输入密码,然后点击继续
点击安装推荐的插件,然后等待安装完成,进入管理界面,输入用户名,密码和邮件地址,邮件地址必输,否则无法保存。然后一路点击完成
最后开始愉快的玩耍吧。。
开始使用时,我们需要配置你的jdk,gradle和Gitlab地址, 这里我们只配置最基础和必须的项,先实现自动化部署在完善别的。点击系统管理 -> 全局工具配置
1.点击新增jdk,这里有两种方式,一种是本机JAVA_HOME路径配置,注意,不带bin目录,一种是在线安装,在线安装有个要求是需要注册oracle账户,嫌麻烦,用本地的。2.点击安装gradle ,同样自动安装或本机GRADLE_HOME 路径,这个没什么要求,只要你开心,选哪个都行,我用本机的,上图
点击保存,然后下载gitlab插件,点击系统管理 -> 插件管理->可选插件,搜索gitlab 选择gitlab插件,点击直接安装。等待安装完成
回到系统管理->系统设置 找到gitlab 配置项,这里有三个选项,1.连接名称,可随便输,2.gitlab地址,如:http://git.xxxxxx.com,3.秘钥
点击ADD添加TOKEN令牌, 选择gitlab api token,token的获取方式我在下面会上图
获取gitlab private key 登录gitlab, 点击右上角头像->settings -> account 复制private token ,此处token就是上面需要的api token
输入api token,点击添加,在令牌那一项,选择你刚才输入的项,点击Test Connection ,显示 Success表示配置成功,最后点击保存。如图:
到这里,基本配置就完成了,可以构建项目了。点击新建任务 -> 随便输入一个任务名称 -> 选择构建一个自由分隔的软件 -> 点击确定
这个界面上,gitlab Connection 便是你刚才配置的gitlab,描述中可以随便输写内容,不输也可以
源码管理 -> 选择git 输入你要构建gitlab 项目的路径 -> 选择刚才配置的令牌 -> 输入要拉取得git分支 -> 点击保存
到这里git的配置就完成了,我们测试下项目是否拉取成功,回到主页,你会看到你所配置的工程 -> 点击工程名称
点击立即构建,你会在左下方看到构建历史窗口
这里显示你的构建历史,#1表示第一次构建,后面会有#2. #3......
点击 #1 进入构建界面 -> 点击 控制台输出, 你会看到刚才构建的日志信息
最后显示Finished: SUCCESS 表示你构建成功
此时,你的项目被clone到 jenkins目录下,就是开头说过的你存放密码的路径的上一级。或者本机当前用户下有个 .jenkins/workspace,在此目录下你还看到你拉取下来的项目
2.使用gradle将项目打包并使用docker启动
在这里我先说明下我项目工程的目录结构,在这里我只用三个服务,eureka-service、bussines-service、admin-service,整个项目的结构如下(注:本教程主要是讲解如何将项目自动化搭建到docker上,而不是部署spring-cloud微服务,所以像config-Service等待啥的都不要了,部署细节啥的也都不讲了,毕竟网上教程一大堆)
分解过程步骤 ,首先,我先说明下我的实现一种简单的方式
1. 使用gradle将各个服务打成 jar 包
2. 将新打的jar包copy 到指定docker-compose所在目录( ==dockerfile 和 docker-compose 的编写我在后面会详细讲解== )
3. 停止并删除容器
4. 删除镜像
5. 启动docker-compose 重新构建镜像并且启动容器
先实现第一步,打jar 包, 这里 会用到shell 脚本, 不过放心,shell 脚本非常非常非常简单,而且我会给详细注释, 首先在我们项目根目录下建个build.sh文件 内容如下
#!/bin/sh
echo "更新服务开始。。。。"
###jenkins 从 gitlab 上拉取的项目所在路径
home="/Users/Function/.jenkins/workspace/spring-cloud"
### 自定义的docker-compose.yml 文件所在路径
docker_home="/Users/Function/Documents/workspace/docker-workspace/spring-cloud"
### admin服务文件夹名
admin_home="/admin-service"
### eureka服务文件夹名
eureka_home="/eureka-service"
### business服务文件夹名
business_home="/business-service/business-service-impl"
### 判断admin服务路径是否存在
if [ ! -e ${home}${admin_home} ];then
echo "${admin_home} 不存在"
exit 1;
fi
### 判断eureka服务路径是否存在
if [ ! -e "${home}${eureka_home}" ];then
echo "${eureka_home} 不存在"
exit 1;
fi
### 判断bussines_home服务路径是否存在
if [ ! -e "${home}${business_home}" ];then
echo "${business_home} 不存在"
exit 1;
fi
### 执行项目根目录下gradlew文件
echo "清除上次构建文件......"
cd ${home}
sh ${home}/gradlew clean
sleep 3
echo "开始构建Admin服务...."
cd ${home}${admin_home}
sh ${home}/gradlew bootJar -x test
echo "Admin服务构建完成...."
sleep 3
echo "开始构建eureka服务...."
cd ${home}${eureka_home}
sh ${home}/gradlew bootJar -x test
echo "开始构建eureka服务构建完成...."
sleep 3
echo "开始构建business服务...."
cd ${home}${business_home}
sh ${home}/gradlew bootJar -x test
echo "Service服务构建完成...."
if [ ! $? -eq 0 ];then
echo "gradle 执行失败: $?"
exit 1;
fi
echo "将最新jar包移动到DOCKER目录. ${docker_home}"
if [ ! -e "${docker_home}" ]; then
echo "${docker_home} 不存在"
exit 1;
fi
echo "删除旧的jar..."
rm -rf ${docker_home}/*.jar
echo "开始移动Eurake.."
mv ${home}${eureka_home}/build/libs/eureka-service.jar ${docker_home}
echo "开始移动Admin.."
mv ${home}${admin_home}/build/libs/admin-service.jar ${docker_home}
echo "开始移动Business.."
mv ${home}${business_home}/build/libs/business-service-impl.jar ${docker_home}
### 进入 docker-compose 文件所在目录
cd ${docker_home}
echo "停止并删除启动的容器....."
### 先停止并删除 上一次根据docker-compose启动的容器 注:echo 中输入的是你本机电脑密码,用 shell 执行 docker 命令时需要sudo 权限
echo "ccz123456..." | sudo -S docker-compose down
sleep 1
echo "删除spring-cloud 服务镜像....."
### 删除上一次构建的spring-cloud项目镜像 其中 grep service 中的service 是镜像名中包含的字段,是生成镜像时可以指定,如镜像名为: sc-service ,编写docker-compose时会说明
echo "ccz123456..." | sudo -S docker rmi --force `docker images | grep service | awk '{print $3}'`
sleep 1
echo "构建spring-cloud新的服务镜像....."
### 构建镜像镜像
echo "ccz123456..." | sudo -S docker-compose build
sleep 1
echo "启动服务容器....."
### 构建镜像并启动容器
echo "ccz123456..." | sudo -S docker-compose up -d
shell就是这样了,是不是非常简单? 其中有很多地方你们可以自行优化。下面编写dockerfile 文件,dockerfile文件我也会写的非常简单,多余的东西就不往上加了,在 脚本中的docker_home目录下新建三个dockerfile文件,命名为dockerfile-admin、dockerfile-business、dockerfile-eureka (文件名随意,你们开心就行)其中dockerfile-admin内容如下
# 依赖的java版本
FROM java:8
# 在容器中创建工作目录
RUN mkdir /app
# 指定工作目录
WORKDIR /app
#将你本机docker-home 目录下的 admin-service.jar ADD 到 容器 工作目录下并命名为 app.jar (不重命名也行)
ADD admin-service.jar /app/app.jar
# 执行环境 其中-Djava.security.egd=file:/dev/./urandom 是JVM 熵池 参数,想了解的可百度
# --spring.profiles.active=docker 是springcloud 配置文件 application.yml文件配置项,当有多个application.yml时用来指定加载哪个配置文件
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar","--spring.profiles.active=docker"]
# 开放8080端口
EXPOSE 8080
dockerfile-bussines、dockerfile-eureka 文件内容一样,只需将 ADD admin-service.jar /app/app.jar 中的 admin-service.jar 替换成 business-service.jar 和 eureka.jar 并且修改 EXPOSE business-service 端口 9090 和 eureka-service端口 8761. 接下来是docker-compose.yml,同样,在docker-home目录下新建文件 docker-compose.yml内容如下
version: "3" # docker-compose 版本
services: # 服务
eureka-service: # 定义eureka-service 名字随意
container_name: eureka-container # 指定容器名 随意
build:
context: . # dockerfile 文件所在路径 点 指的是 dockerfile 文件在当前docker-compose.yml所在目录下
dockerfile: dockerfile-eureka # dockerfile 文件名
image: eureka-service:v1 # 指定生成的镜像名 并打上tag 标签 v1
hostname: eurekaservice # 容器hostname
ports:
- "8761:8761" # 暴露容器端口到主机
business-service:
container_name: business-container
build:
context: .
dockerfile: dockerfile-business
image: business-service:v1
ports:
- "8020:8020"
depends_on: # 当前容器依赖于eureka 容器 ,当前容器会在 eureka-service 容器启动后执行
- eureka-service
links: # 链接 注册到eureka eurekaservice 我会在下面说明
- "eureka-service:eurekaservice"
admin-service:
container_name: admin-container
build:
context: .
dockerfile: dockerfile-admin
image: admin-service:v1
ports:
- "8080:8080"
depends_on: # 当前容器依赖于以上两个容器
- eureka-service
- business-service
links:
- "eureka-service:eurekaservice"
- "business-service"
这里需要说明下docker-compose.yml 文件中 links : - "eureka-service:eurekaservice" docker中,容器直接链接的方式有两种,一种是服务名方式,一种是别名的方式,而别名的方式必须是以 服务名:别名 来指定。不然,你会发现你的服务无法注册到eureka中 文件中的 eurekaservice 为spring-cloud项目配置文件application.yml 中eureka url 中的hostname ,原因是docker 默认的网络模式为 bridge, 每个容器的IP都不同,使用localhost无法满足需求,所以用主机名来访问,三个服务的url都改用容器主机名的方式
好了,到这里一切都已准备就绪,我们实验下效果。提交修改过得项目到Gitlab ,打开jenkins -> 进入工程 -> 配置当前工程
找到构建项 -> 增加构建步骤 -> 选择 执行shell
在命令中 输入你刚才建的 build.sh 脚本的路径 或者 直接将脚本内容考皮到命令框中,如果是路径,应该是 ~/.jenkins/workspace/spring-cloud/build.sh , 然后点击保存,点击立即构建
见证奇迹的时刻就要到了,当你点击立即构建之后,然后进入控制台,你会看到构建过程日志
由用户 xxx 启动
构建中 在工作空间 /Users/Function/.jenkins/workspace/spring-cloud 中
> git rev-parse --is-inside-work-tree # timeout=10
Fetching changes from the remote Git repository
> git config remote.origin.url [http://git.xxxx.com/spring-cloud.git](http://git.xxxx.com/spring-cloud.git) # timeout=10
Fetching upstream changes from [http://git.xxxx.com/spring-cloud.git](http://git.xxxx.com/spring-cloud.git)
> git --version # timeout=10
using GIT_SSH to set credentials
> git fetch --tags --progress [http://git.xxxx.com/spring-cloud.git](http://git.xxxx.com/spring-cloud.git) +refs/heads/*:refs/remotes/origin/*
> git rev-parse refs/remotes/origin/master^{commit} # timeout=10
> git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
Checking out Revision c85486e6447c023c0e70f98885760761aaaa928e (refs/remotes/origin/master)
> git config core.sparsecheckout # timeout=10
> git checkout -f c85486e6447c023c0e70f98885760761aaaa928e
Commit message: "修改shell了嘞嘞"
> git rev-list --no-walk c85486e6447c023c0e70f98885760761aaaa928e # timeout=10
[spring-cloud] $ /bin/sh -xe /var/folders/26/b1nkkk7j22v7dx9mvdty84vr0000gn/T/jenkins3559310015219383127.sh
+ cd /Users/Function/.jenkins/workspace/spring-cloud/
+ chmod u+x build.sh
+ ./build.sh
更新服务开始。。。。
清除上次构建文件......
:admin-service:clean
:business-service:clean UP-TO-DATE
:eureka-service:clean
:business-service:business-service-api:clean
:business-service:business-service-impl:clean
BUILD SUCCESSFUL in 0s
5 actionable tasks: 4 executed, 1 up-to-date
开始构建Admin服务....
:business-service:business-service-api:compileJava
:business-service:business-service-api:processResources NO-SOURCE
:business-service:business-service-api:classes
:business-service:business-service-api:jar
:admin-service:compileJava
:admin-service:processResources
:admin-service:classes
:admin-service:bootJar
BUILD SUCCESSFUL in 4s
5 actionable tasks: 5 executed
Admin服务构建完成....
开始构建eureka服务....
:eureka-service:compileJava
:eureka-service:processResources
:eureka-service:classes
:eureka-service:bootJar
BUILD SUCCESSFUL in 2s
3 actionable tasks: 3 executed
开始构建eureka服务构建完成....
开始构建business服务....
:business-service:business-service-api:compileJava UP-TO-DATE
:business-service:business-service-api:processResources NO-SOURCE
:business-service:business-service-api:classes UP-TO-DATE
:business-service:business-service-api:jar UP-TO-DATE
:business-service:business-service-impl:compileJava
:business-service:business-service-impl:processResources
:business-service:business-service-impl:classes
:business-service:business-service-impl:bootJar
BUILD SUCCESSFUL in 2s
5 actionable tasks: 3 executed, 2 up-to-date
Service服务构建完成....
将最新jar包移动到DOCKER目录. /Users/Function/Documents/workspace/docker-workspace/spring-cloud
删除旧的jar...
开始移动Eurake..
开始移动Admin..
开始移动Business..
停止并删除启动的容器.....
Password:Removing admin-container ...
Removing busines-container ...
Removing eureka-container ...
�[3A�[2K
Removing admin-container ... �[32mdone�[0m
�[3B�[2A�[2K
Removing busines-container ... �[32mdone�[0m
�[2B�[1A�[2K
Removing eureka-container ... �[32mdone�[0m
�[1BRemoving network spring-cloud_default
删除spring-cloud 服务镜像.....
Untagged: admin-service:v1
Deleted: sha256:8bb51f82162535270d6bc7274ea8cac1e0a98ca103facf6548056ca3a1bcb484
Deleted: sha256:60257e125ebc783f930f79f16516091204e99a4a9d0390dcefa63703cb8c598c
Deleted: sha256:0e7e5c3a29df6fb7142fa37da4fc00526341f5b966099e6125f728efd2c52a6e
Deleted: sha256:169fc43041641f26b1046cd843d1e347bfd557625b4b39e798b621042721437c
Untagged: busines-service:v1
Deleted: sha256:d8cd89f0b7eba9a0b31eda5ec36b83bb1da4ebabfc549a915af36a62a4173b32
Deleted: sha256:03fc157106a95d58a0233655e55c616a68ca76d1d72fbf58705072e6729a4caf
Deleted: sha256:67e010d66dbf3e30adbd94f5eb33ad893ce7bba97f0cccec676d5f0834c7f44f
Deleted: sha256:2e2005d82ca03e80ed71f3b5c3c9087d720d6e727e2286f01967ec6fb0318023
Untagged: eureka-service:v1
Deleted: sha256:bf7b59c1673b09613df678a0cfe0156e645dad6aa9230a0fe90af2fd89163acc
Deleted: sha256:df664e41f222cb957a484110824f4bb977011698247e13b1413ca4097d17f003
Deleted: sha256:93cb206e2f8772c8b7d1f84a7a46d67393cdd0d8c7e61d28461087c82c0fdeec
Deleted: sha256:60863060e250a714a33dea8bef0393a8ea5a4f75fa96c28cef084392059e1128
构建spring-cloud新的服务镜像.....
Building eureka-service
Step 1/6 : FROM java:8
---> d23bdf5b1b1b
Step 2/6 : RUN mkdir /app
---> Using cache
---> 27c94e92d2a7
Step 3/6 : WORKDIR /app
---> Using cache
---> 49efed4c9ca0
Step 4/6 : ADD eureka-service.jar /app/app.jar
---> 56270e100c2a
Step 5/6 : ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar","--spring.profiles.active=default"]
---> Running in 8a997301d5b3
Removing intermediate container 8a997301d5b3
---> 2134b5a800a4
Step 6/6 : EXPOSE 8761
---> Running in 26c507af1c50
Removing intermediate container 26c507af1c50
---> 593b51aa6fa4
Successfully built 593b51aa6fa4
Successfully tagged eureka-service:v1
Building busines-service
Step 1/6 : FROM java:8
---> d23bdf5b1b1b
Step 2/6 : RUN mkdir /app
---> Using cache
---> 27c94e92d2a7
Step 3/6 : WORKDIR /app
---> Using cache
---> 49efed4c9ca0
Step 4/6 : ADD business-service-impl.jar /app/app.jar
---> 638b8674ee26
Step 5/6 : ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar","--spring.profiles.active=docker"]
---> Running in 5774538bd4d9
Removing intermediate container 5774538bd4d9
---> 0505d456c863
Step 6/6 : EXPOSE 8020
---> Running in f9714296fe56
Removing intermediate container f9714296fe56
---> 8d2ab6dd3c19
Successfully built 8d2ab6dd3c19
Successfully tagged busines-service:v1
Building admin-service
Step 1/6 : FROM java:8
---> d23bdf5b1b1b
Step 2/6 : RUN mkdir /app
---> Using cache
---> 27c94e92d2a7
Step 3/6 : WORKDIR /app
---> Using cache
---> 49efed4c9ca0
Step 4/6 : ADD admin-service.jar /app/app.jar
---> 8eb5a94001ff
Step 5/6 : ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar","--spring.profiles.active=default"]
---> Running in f7e7ce480b15
Removing intermediate container f7e7ce480b15
---> cd478f10383b
Step 6/6 : EXPOSE 8080
---> Running in 8509924c9984
Removing intermediate container 8509924c9984
---> d31a4a4c3358
Successfully built d31a4a4c3358
Successfully tagged admin-service:v1
启动服务容器.....
Creating network "spring-cloud_default" with the default driver
Creating eureka-container ...
�[1A�[2K
Creating eureka-container ... �[32mdone�[0m
�[1BCreating busines-container ...
�[1A�[2K
Creating busines-container ... �[32mdone�[0m
�[1BCreating admin-container ...
�[1A�[2K
Creating admin-container ... �[32mdone�[0m
�[1BFinished: SUCCESS
当最后 显示finished:SUCCESS 时,表示已经成功,由于在 build 中设置了 项目后台启动,所以这里只看到了构建过程,没有项目启动日志,如果需要,看官们可自行修改,只需将build.sh 最后 -d 去掉即可
最后,在终端输入docker-container ls 你会看到启动的三个容器
然后访问 0.0.0.0:8761,你会看到服务已经注册到eureka 上了
OK 大功告成!后面你可以在优化一些关于jenkins自动构建的步骤,这种教程网上也很多,我就不列举了。有什么错误的地方请留言指正。项目代码和 docker文件我都放到了GitHub上,GitHup地址