系列文章目录

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 类似一个批量工具,可以执行一组命令,支持批量构建镜像,批量启动容器,批量删除容器等等功能。

WindowsDocker Desktop 中已经包括了 ComposeLinuxCompose 则需要单独安装一下。

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个重复的服务创建数据库时报错,因为 orderapi1productapi1在创建同样的数据库。。。这个前面说过的。这里等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


在这里插入图片描述

Logo

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

更多推荐