.Net Core微服务入门全纪录(八)——Docker Compose与容器网络
🐋关于微服务的概念解释网上有很多, 个人理解微服务是一种系统架构模式,它和语言无关,和框架无关,和工具无关,和服务器环境无关。微服务思想是将传统的单体系统按照业务拆分成多个职责单一、且可独立运行的接口服务。至于服务如何拆分,没有明确的定义。几乎任何后端语言都能做微服务开发。微服务也并不是完美无缺的,微服务架构会带来更多的问题,增加系统的复杂度,引入更多的技术栈。上一篇【.Net Core微服务入
系列文章目录
1、.Net Core微服务入门系列(一)——项目搭建
2、.Net Core微服务入门全纪录(二)——Consul-服务注册与发现(上)
3、.Net Core微服务入门全纪录(三)——Consul-服务注册与发现(下)
4、.Net Core微服务入门全纪录(四)——Ocelot-API网关(上)
5、.Net Core微服务入门全纪录(五)——Ocelot-API网关(下)
6、.Net Core微服务入门全纪录(六)——EventBus-事件总线
7、.Net Core微服务入门全纪录(七)——IdentityServer4-授权认证
8、.Net Core微服务入门全纪录(八)——Docker Compose与容器网络

前言📃
关于 微服务 的概念解释网上有很多, 个人理解微服务是一种系统架构模式,它和语言无关,和框架无关,和工具无关,和服务器环境无关。
微服务思想 是将传统的单体系统按照业务拆分成多个职责单一、且可独立运行的接口服务。至于服务如何拆分,没有明确的定义。几乎任何后端语言都能做微服务开发。微服务也并不是完美无缺的,微服务架构会带来更多的问题,增加系统的复杂度,引入更多的技术栈。
上一篇【.Net Core微服务入门全纪录(七)——IdentityServer4-授权认证】中使用 IdentityServer4 完成了鉴权中心的搭建,配合网关实现了统一的授权认证。进行到这里,系统环境已经比较复杂了,想把整个系统运行起来会非常繁琐:要运行 Consul、业务服务、网关、鉴权中心、web客户端,还要安装数据库、MQ等等。那么本篇将使用Docker Compose来解决以上问题,仅需一个简单的命令,即可启动整个环境。
一、Docker Compose
什么是Docker Compose?
🐋 Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
简单来理解,Compose 类似一个批量工具,可以执行一组命令,支持批量构建镜像,批量启动容器,批量删除容器等等功能。
Windows 的 Docker Desktop 中已经包括了 Compose,Linux 下 Compose 则需要单独安装一下。
1.1 yml file
yml 文件是使用 Compose 必不可少的,在编写 yml 文件之前还需要准备 Dockerfile 。
之前的章节中,有些服务不是在 Docker 中运行的,现在全部放到 Docker 中。确保解决方案中每个项目都添加Docker 支持。

在根目录新建 docker-compose.yml 文件:

以下是 docker-compose.yml 文件内容:
version: '3.4' #Compose文件版本
services: #服务
auth: #定义"auth"服务 对应的是鉴权中心项目
build: #构建
context: . #构建上下文(目录)
dockerfile: ./IDS4.AuthCenter/Dockerfile #Dockerfile文件目录
ports: #端口
- '9080:9080' #容器外部9080 容器内部9080
environment: #环境变量
- ASPNETCORE_URLS=http://+:9080 #程序在容器内部http://+:9080运行 也可以写成http://0.0.0.0:9080
networks: #容器网络
- my-net #自定义网络my-net
web: #定义"web"服务 对应的web客户端项目
build:
context: .
dockerfile: ./Web.MVC/Dockerfile
ports:
- '5000:5000'
environment:
- ASPNETCORE_URLS=http://+:5000
networks:
- my-net
depends_on: #"web"服务依赖于"auth"服务和"apigateway"服务,此服务会在依赖服务之后执行
- auth
- apigateway
apigateway: #定义"apigateway"服务 对应的网关项目
build:
context: .
dockerfile: ./Ocelot.APIGateway/Dockerfile
ports:
- '9070:9070'
environment:
- ASPNETCORE_URLS=http://+:9070
networks:
- my-net
depends_on:
- orderapi1
- orderapi2
- orderapi3
- productapi1
- productapi2
- productapi3
productapi1: #定义"productapi1"服务 对应的产品服务项目
image: productapi #指定镜像名称,如果不指定 默认是:netcoremicroservicedemo_productapi1,因为下面要用到所以指定一下
build:
context: .
dockerfile: ./Product.API/Dockerfile
ports:
- '9050:9050'
environment:
- ASPNETCORE_URLS=http://+:9050
- ConsulSetting:ServiceIP=productapi1 #程序参数
- ConsulSetting:ServicePort=9050 #程序参数
networks:
- my-net
depends_on:
- consul
- postgres
- rabbitmq
productapi2:
image: productapi #指定镜像名称为productapi,productapi1服务中已经构建了productapi镜像,所以不用重复构建
ports:
- '9051:9051'
environment:
- ASPNETCORE_URLS=http://+:9051
- ConsulSetting:ServiceIP=productapi2
- ConsulSetting:ServicePort=9051
networks:
- my-net
depends_on:
- productapi1
productapi3:
image: productapi
ports:
- '9052:9052'
environment:
- ASPNETCORE_URLS=http://+:9052
- ConsulSetting:ServiceIP=productapi3
- ConsulSetting:ServicePort=9052
networks:
- my-net
depends_on:
- productapi1
orderapi1:
image: orderapi
build:
context: .
dockerfile: ./Order.API/Dockerfile
ports:
- '9060:9060'
environment:
- ASPNETCORE_URLS=http://+:9060
- ConsulSetting:ServiceIP=orderapi1
- ConsulSetting:ServicePort=9060
networks:
- my-net
depends_on:
- consul
- postgres
- rabbitmq
orderapi2:
image: orderapi
ports:
- '9061:9061'
environment:
- ASPNETCORE_URLS=http://+:9061
- ConsulSetting:ServiceIP=orderapi2
- ConsulSetting:ServicePort=9061
networks:
- my-net
depends_on:
- orderapi1
orderapi3:
image: orderapi
ports:
- '9062:9062'
environment:
- ASPNETCORE_URLS=http://+:9062
- ConsulSetting:ServiceIP=orderapi3
- ConsulSetting:ServicePort=9062
networks:
- my-net
depends_on:
- orderapi1
consul:
image: consul #指定镜像名称为consul,本地如果没有consul镜像,会从docker远程仓库拉取
ports:
- '8500:8500'
networks:
- my-net
postgres:
image: postgres
environment:
POSTGRES_PASSWORD: pg123456
networks:
- my-net
rabbitmq:
image: rabbitmq
networks:
- my-net
networks: #定义容器网络
my-net: #my-net网络
driver: bridge #网络模式为bridge
以上 yml 文件定义了 auth,web,apigateway,productapi1,productapi2,productapi3,orderapi1,orderapi2,orderapi3,consul,postgres,rabbitmq 12个服务(容器),和一个容器网络 my-net。这里的productapi 和 orderapi 相当于是基于同样的镜像各运行了3个容器,这其实不太合理,正常他们应该分布在多个docker中。
文件的内容虽然有点多,但是应该不难理解,上面的关键字我都有注释。下面再简单介绍一下文件中的networks 容器网络。
1.2 容器网络
前面的章节中有提到过,默认情况下容器之间的通讯是比较麻烦的,之前是通过 host.docker.internal 或者容器的IP去访问,虽然是可以访问但有些不友好。更好的方式是,我们可以自定义一个 bridge 网络,将所有服务(容器)加入这个网络中,那么容器之间就可以直接通过服务名称通信了。bridge 模式只是 docker 网络模式中的一种,有兴趣的话可以自行搜索一下。
二、代码修改
既然程序都运行在 docker 中,那就不能写localhost,host.docker.internal之类的主机名了,统一改为docker-compose.yml文件中定义的服务名。如下:



还有多处修改就不全贴出来了,都是些类似的改动。这些配置还是不要写在代码里,改动起来比较乱。
这里有一个特殊的就是 identityserver4 鉴权服务,这个服务是容器内外部都需要访问的(容器内部ids4发现文档等接口的调用,外部浏览器访问),所以不能直接写服务名 auth,写 auth 的话外部无法访问,写 localhost的话内部又无法访问。最后是参考 eShopOnContainers 项目,使用 docker.for.win.localhost 来满足内外部的访问需求:


理论上用 host.docker.internal 或许也可以,没去测试。。。这个配置放到 Compose 的环境变量里会比较好,这里只是为了方便。
eShopOnContainers 项目是微软官方出品的开源项目,对于学习微服务,docker 等技术非常有帮助。
项目地址:https://github.com/dotnet-architecture/eShopOnContainers
三、构建与启动
完成以上操作后,进入项目根目录执行 docker-compose build 。

build 完成后,执行 docker-compose up -d ,-d 代表在后台运行。

(第一次up,orderapi2,orderapi3,productapi2,productapi3这4个服务会起不来,是因为他们启动时有创建数据库的操作,同时启动会导致后起来的4个重复的服务创建数据库时报错,因为 orderapi1 和 productapi1在创建同样的数据库。。。这个前面说过的。这里等up完再执行一次up就好了)
浏览器访问:http://localhost:5000/

登录后:

这样运行系统是不是非常简单呢?想要摧毁这个环境也很简单,只需要一句 docker-compose down 。

如果不习惯 docker 命令,推荐使用 vscode,装一下 docker 插件,很方便。

四、总结
上文用到了 Docker-Compose 的3个命令:
-
构建:docker-compose build
-
启动:docker-compose up
-
销毁:docker-compose down
其实 build 命令也可以省略,执行 up 时如果没有 build 的话会自动 build,无论多复杂的系统环境,只需要一个 docker-compose up 命令即可启动。不过镜像需要重新 bulid 的时候,还是要用到 build 命令。Compose 还有一些其他命令,需要的话可以自行搜索。
主要的工作量在于 docker-compose.yml 文件的编写。
需要代码的点这里:https://github.com/xiajingren/NetCoreMicroserviceDemo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐
所有评论(0)