前言
在之前写的《在Docker中部署springmvc + maven 结构的项目》和《在Docker中部署springboot + maven 结构的项目》两篇文章里,都已经对项目部署进行了的讲解,希望你有所进步。
根据上面两篇文章中的讲解,项目部署简单来说可以有以下几种方式:
通过 run 命令启动容器服务(这是初学者最初使用的方式,也是最普遍的方式)
通过 docker-compose 编排并运行服务(实际企业项目部署采用的方式)
通过run来启动容器服务的缺点很明显,在单机服务器上执行还是可以的,但是如果在真正的企业大型微服务架构下,服务是非常多的,所需要启动的容器服务也非常多,你总不能在每一台机器上都去重复执行run命令吧,这显然不合适!
这就引入了我们接下来需要讲解的内容 —— Docker集群部署。
主要讲的两大块内容是 Dokcer Swarm 与 Docker Stack,关于这两者的知识,请大家自行网上查阅资料了解。
【注意】: 目前由于对Docker高级知识掌握的有限,对于Docker集群部署的讲解,暂时不去整理。下面的文章,是针对于单个容器的项目部署的。
学习此文章需要具备的知识技能
- 能在Docker中部署简单的SpringBoot项目
如果不了解的话,可以参考学习之前写的Springboot在Docker中部署的文章 https://yuque.com/zhoubang/docker/docker-deploy-springboot-maven)
- 对SpringCloud有基本的了解(比如Eureka等组件、yml文件结构与配置等)
如果对SpringCloud不熟悉的,可以去看看我以前写的项目用例,只要认真研究学习,总会掌握的
- 会使用maven编译、打包项目
项目用例源码
该文章中所使用的项目测试用例,我已经共享在了开源中国上,如果想使用的话,可自行拉取源码。
项目用例中,只简单集成了eureka注册中心,写了一个user的service服务,controller提供了一个访问入口,并返回json格式的用户信息(后台模拟的用户数据)。
项目源码地址:
https://gitee.com/zhoubang85/sea-docker-example
该文章使用的项目模块是“springcloud-maven”这个模块,其他的模块是该文章最顶部列出的2个文章所使用的用例,所以不用理会。 项目源码结构如下:
yml文件中的eureka配置的改动
我们平常在springcloud项目中使用eureka组件的时候,都是在yml配置文件中配置了eureka注册中心的服务地址,配置的话都是写死的(当然,也可以通过其他方式实现动态化),如果配置写死的话,最大的缺点就是无法实现扩容、维护,比如ip、port发生了变化,会影响实际业务服务。
既然我们采用Docker部署项目,那我们就不能使用以往的思路来配置了,需要对yml文件里面的相关配置进行调整,实现动态化指定。
对比一下前后的配置文件的内容吧,让你们有一个感官的感觉!
- 传统的yml配置(单机环境下,服务地址都是写死的)
- 当前项目中的yml配置(主要看eureka服务地址列表的配置)
可以看到,eureka服务地址配置项中,使用了一个变量参数,该参数的意思,其实也就是为了实现服务地址的动态扩容,最终在编写docker-compoer的服务编排的配置文件的时候,会对该变量参数进行赋值,具体的配置会在后面讲到,这里只要大体的明白什么意思就行。
通过这前后的yml配置文件的内容对比,可以发现,单机环境下是很简单的,不用考虑太多的东西;但是在多服务器集群环境下,只是一个简单的eureka服务地址的配置,都变得相对麻烦了很多;
项目打包、上传jar至服务器
编译打包
该步骤我不多说了,本地编译打包的话,各位都会! 上面已经说了,我们只需要打包好 springcloud-maven 这个模块即可,该模块里面分别有2个子模块,所以,我们最终打包好后应该得到2个jar:sea-server-eureka-0.0.1-SNAPSHOT.jar 、 sea-service-user-0.0.1-SNAPSHOT.jar。
上传jar以及Dockerfile文件至服务器
本文章为了降低学习难度,就不考虑使用Jenkins来实现自动化部署了,我们手动上传jar,然后手动启动容器服务。
【注意】:需要将对应模块的 /src/main/docker 目录下的Dockerfile文件也上传到对应jar相同的目录下面。
- eureka应用jar以及Dockerfile文件的存放目录
/opt/docker_eureka
- user服务jar以及Dockerfile文件的存放目录
/opt/projects/springcloud_maven/user-service
要想在Docker容器中运行 eureka服务 和 user服务的话,前提肯定是要有对应的 eureka服务 和 user服务 的镜像。 所以我们需要构建应用的镜像!
构建镜像
先查看一下当前服务器上的Docker镜像列表
可以看到,目前还没有eureka-server的镜像。
构建镜像的方式
通过 Dockerfile 文件构建镜像。
构建【eureka应用】镜像
首先进入到 /opt/docker_eureka/ 目录下,然后运行下面命令进行镜像构建:
docker build -t eureka-server .
构建成功后,通过 docker images 命令可以看到有一个新的镜像“eureka-server”。
构建【user-service】镜像
与上面的构建步骤一样,先进入 /opt/projects/springcloud_maven/user-service/ 目录下,然后执行下面命令构建镜像:
docker build -t user-service .
注意最后面的一个“.”。 构建成功后,通过 docker images 命令可以看到有一个新的镜像“user-service”。
以上,便构建好了 eureka注册中心 和 user服务 的镜像。
启动Docker容器
运行单实例容器
【方式一】使用run命令启动容器
- 启动 eureka-server 容器
docker run -d -p 8762:8761 --name eureka-server -e ADDITIONAL_EUREKA_SERVER_LIST=http://39.106.18.21:8762/eureka eureka-server
其中的 -e 用于设置参数,“ADDITIONAL_EUREKA_SERVER_LIST”参数名称,就是我们在项目模块sea-server-eureka中的application.yml文件中设置的eureka服务地址列表的参数;实现启动容器的时候,动态赋值。 eureka默认端口是 8761,这里映射成宿主机端口 8762。其中,IP地址“39.106.18.21”是我的服务器外网IP。
浏览器访问如下:
- 启动 user-service 容器
与上面类似,执行命令启动user-service容器:
docker run -d -p 8080:8080 --name user-service -e EUREKA_SERVER_ADDRESS=http://39.106.18.21:8762/eureka user-service
其中的 -e 用于设置参数值,“EUREKA_SERVER_ADDRESS”变量名就是我们在项目模块sea-service-user中的application.yml文件中设置的eureka服务地址列表的参数名称; user应用的默认端口是 8080,这里映射成宿主机端口 8080。其中,IP地址“39.106.18.21”是我的服务器外网IP。
浏览器访问:
我的服务器域名是 www.2b2b92b.com,当然也可以使用外网IP地址 39.106.18.21 来访问。
因为我们在sea-service-user项目中写了一个controller用于测试,所以可以通过浏览器访问url,来验证user服务是否正常提供服务,后台代码部分截图如下:
当user-service容器启动成功后,这时候我们再重新访问一下eureka服务,看看发生了什么变化:
看到了吧,user-service已经成功注册到了eureka注册中心上了。
【方式二】通过docker-compose启动容器
- 启动eureka-server容器
首先,在eureka应用jar的目录下(/opt/docker_eureka)新建一个 eureka-server-compose.yml文件,在文件中加入以下配置内容:
version: '2'
services:
eureka1:
image: eureka-server
ports:
- "8763:8761"
environment:
- spring.profiles.active=dev
- ADDITIONAL_EUREKA_SERVER_LIST=http://39.106.18.21:8763/eureka
因为在上面的【方式一】中,启动的eureka服务已经在服务器上映射了一个 8762 端口,因此在这里指定 8763 端口映射。
其实不难看出,该文件中的内容,其实与我们通过 run 命令启动容器的命令以及参数,其实是差不多的。这也就说明了docker-compose文件其实就是将传统的通过run命令启动容器的方式,搬到了配置文件中而已,毕竟手动敲打run命令是很累的、容易出错、维护困难。
这里就不对docker-compose.yml中的配置做过多讲解,如果不明白的,请自行网上查阅资料学习。
通过docker-compose命令执行 eureka-server-compose.yml 服务编排文件
docker-compose -f eureka-server-compose.yml up -d
浏览器访问eureka服务
上图说明eureka服务已经正常启动了!也就印证了,使用docker-compose也是可以启动容器、部署服务的! 当然,docker-compose天生是为了集群环境部署而诞生的,单实例部署容器肯定也是支持的。 真正集群环境部署的时候,在docker-compose文件中将会配置N多个服务,实现一键部署运行,这个在后面会讲到。
- 启动user-service容器
同上面【启动eureka-server】的流程一样,首先,在user-service应用jar的目录下(/opt/projects/springcloud_maven/user-service)新建一个 user-service-compose.yml文件,在文件中加入以下配置内容:
version: '2'
services:
user-service-02:
image: user-service
ports:
- "8081:8080"
environment:
- EUREKA_SERVER_ADDRESS=http://39.106.18.21:8763/eureka/
通过docker-compose命令执行 user-service-compose.yml 服务编排文件
docker-compose -f user-service-compose.yml up -d
浏览器访问user服务的测试接口
当user-service容器启动成功后,这时候我们再重新访问一下eureka服务,看看发生了什么变化:
到此,也就说明了,通过docker-compose也可以实现单实例容器的部署运行!
目前暂停更新下面的集群部署的内容!
因为涉及的内容太多了,好像一下子写不完。精力有限,等以后有时间再更新吧,各位也可以自行研究Docker集群部署;涉及的技术点有:Docker Swarm、Docker Stack、Docker Network。
Docker容器集群部署(未完结)
两种启动容器方式的对比
在上面的【运行单实例容器】的章节中,主要介绍了两种启动容器的方式:
1、通过 run 命令启动容器
2、通过 docker-compose 启动容器
上面两种方式主要有什么区别呢?
对于run命令启动容器的方式来说,在单机环境下,是显得比较简单直接,是可以接受的,但是也有缺点,比如命令容器输入错误、命令语法忘记、参数错误等,最大的不足就是在分布式集群环境下面,如果在每一台机器上都使用 run 命令来启动容器,这显得很浪费时间、重复性工作太多、不友好!
而使用了docker-compose这个组件后,服务的编排都是写在docker-compose.yml文件中,只需要一个简单的命令,就可以实现容器的部署运行,比run要简单的多、也实用的多。当要想新增容器实例的时候,只需要在docker-compose.yml文件中的添加相应的服务容器配置,然后重新执行这个docker-compose.yml文件即可动态扩容容器实例,且不会影响处于运行状态的容器,实现了平滑扩容。
上面简单介绍了两种启动容器方式的区别,可以看出,run命令不适合容器的集群部署,而docker-compose适合容器的集群部署。
因此,在接下来的重要环节中,我们就采用docker-compose的方式来实现容器的集群部署!希望你能认真阅读~
容器的集群部署会使用到的技术
提前告诉你吧,在下面的内容讲解中,会涉及到Docker的另外两种技术:Docker Swarm 和 Docker Stack。
如果你对Docker Swarm 和 Docker Stack不了解的话,建议去网上查阅相关资料,最终能清楚的知道这两者的关联以及各自的作用就行了。
既然要搞集群部署,那么,除了引入 Docker Swarm 和 Docker Stack 这两种技术外,还需要对docker-compose.yml文件进行相应的修改调整,而不是仅仅单实例的配置了;而是在一个docker-compose.yml文件中配置N个容器服务,实现服务的编排!
我们一步步的来~
(未完结,敬请期待后续更新)
结语
如果想结合Jenkins实现项目自动化部署的话,请参考之前写的文章:
https://yuque.com/zhoubang/docker/docker-jenkins-springboot-maven-deploy
该文章虽然是对springboot项目进行自动化构建部署,但是springcloud其实与springboot的构建部署操作流程是差不多的,如果你会通过Jenkins自动化部署springboot项目的话,对于springcloud项目完全可以自行操作。我就不重复写文章了。
实际企业项目架构,远远比我这个要复杂的多,我这个只能算是一个引领的作用吧,让不懂的人有一个入门的技能。这是基础,也是通往更深层次学习的必经之路~ 感觉还是很重要的一步哈~
(陆续整理,敬请期待)