还在那 發表於 2020-7-9 08:22:00

.Net Core微服务入门全纪录(八)——Docker Compose与容器网络

<p>Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章。</p>
<h1 id="前言">前言</h1>
<p>上一篇【.Net Core微服务入门全纪录(七)——IdentityServer4-授权认证】中使用IdentityServer4完成了鉴权中心的搭建,配合网关实现了统一的授权认证。进行到这里,系统环境已经比较复杂了,想把整个系统运行起来会非常繁琐:要运行Consul、业务服务、网关、鉴权中心、web客户端,还要安装数据库、MQ等等。。。那么本篇将使用Docker Compose来解决以上问题,仅需一个简单的命令,即可启动整个环境。</p>
<h1 id="docker-compose">Docker Compose</h1>
<p>什么是Docker Compose?</p>
<blockquote>
<p>Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。</p>
</blockquote>
<p>简单来理解,Compose类似一个批量工具,可以执行一组命令,支持批量构建镜像,批量启动容器,批量删除容器等等功能。</p>
<p>Windows的Docker Desktop中已经包括了Compose,Linux下Compose则需要单独安装一下。</p>
<h1 id="yml-file">yml file</h1>
<p>yml文件是使用Compose必不可少的,在编写yml文件之前还需要准备Dockerfile。</p>
<p>之前的章节中,有些服务不是在Docker中运行的,现在全部放到Docker中。确保解决方案中每个项目都添加Docker支持。</p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714140709709-1235371265.png" alt="" loading="lazy"></p>
<p>在根目录新建docker-compose.yml文件:</p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714140717887-1074234825.png" alt="" loading="lazy"></p>
<p>以下是docker-compose.yml文件内容:</p>
<pre><code class="language-yaml">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
</code></pre>
<p>以上yml文件定义了auth,web,apigateway,productapi1,productapi2,productapi3,orderapi1,orderapi2,orderapi3,consul,postgres,rabbitmq 12个服务(容器),和一个容器网络 my-net。这里的productapi和orderapi相当于是基于同样的镜像各运行了3个容器,这其实不太合理,正常他们应该分布在多个docker中。。。</p>
<p>文件的内容虽然有点多,但是应该不难理解,上面的关键字我都有注释(注意,正式使用最好还是不要加中文注释,可能会出现编码格式错误问题)。下面再简单介绍一下文件中的networks容器网络。</p>
<h2 id="容器网络">容器网络</h2>
<p>前面的章节中有提到过,默认情况下容器之间的通讯是比较麻烦的,之前是通过<code>host.docker.internal</code>或者容器的IP去访问,虽然是可以访问但有些不友好。更好的方式是,我们可以自定义一个bridge网络,将所有服务(容器)加入这个网络中,那么容器之间就可以直接通过服务名称通信了。bridge模式只是docker网络模式中的一种,有兴趣的话可以自行搜索一下。</p>
<h1 id="代码修改">代码修改</h1>
<p>既然程序都运行在docker中,那就不能写<code>localhost</code>,<code>host.docker.internal</code>之类的主机名了,统一改为docker-compose.yml文件中定义的服务名。如下:</p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714140733600-1625664826.png" alt="" loading="lazy"></p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714140748637-139462613.png" alt="" loading="lazy"></p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714140808611-612191288.png" alt="" loading="lazy"></p>
<p>还有多处修改就不全贴出来了,都是些类似的改动。这些配置还是不要写在代码里,改动起来比较乱。</p>
<p>这里有一个特殊的就是identityserver4鉴权服务,这个服务是容器内外部都需要访问的(容器内部ids4发现文档等接口的调用,外部浏览器访问),所以不能直接写服务名auth,写auth的话外部无法访问,写localhost的话内部又无法访问。最后是参考eShopOnContainers项目,使用<code>docker.for.win.localhost</code>来满足内外部的访问需求:</p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714140849021-913415661.png" alt="" loading="lazy"></p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714140904521-1272533954.png" alt="" loading="lazy"></p>
<p>理论上用<code>host.docker.internal</code>或许也可以,没去测试。。。这个配置放到Compose的环境变量里会比较好,这里只是为了方便。</p>
<p>eShopOnContainers项目是微软官方出品的开源项目,对于学习微服务,docker等技术非常有帮助。</p>
<p>项目地址:https://github.com/dotnet-architecture/eShopOnContainers</p>
<h1 id="构建与启动">构建与启动</h1>
<p>完成以上操作后,进入项目根目录执行<code>docker-compose build</code></p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714140918892-88050374.png" alt="" loading="lazy"></p>
<p>build完成后,执行<code>docker-compose up -d</code>,-d代表在后台运行</p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714140923237-1283052166.png" alt="" loading="lazy"></p>
<p>(第一次up,orderapi2,orderapi3,productapi2,productapi3这4个服务会起不来,是因为他们启动时有创建数据库的操作,同时启动会导致后起来的4个重复的服务创建数据库时报错,因为orderapi1和productapi1在创建同样的数据库。。。这个前面说过的。这里等up完再执行一次up就好了)</p>
<p>浏览器访问:http://localhost:5000/</p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714140929681-1443387721.png" alt="" loading="lazy"></p>
<p>登录后:</p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714140939080-434376616.gif" alt="" loading="lazy"></p>
<p>这样运行系统是不是非常简单呢?想要摧毁这个环境也很简单,只需要一句<code>docker-compose down</code></p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714140948975-1760813333.png" alt="" loading="lazy"></p>
<p>如果不习惯docker命令,推荐使用vscode,装一下docker插件,很方便。</p>
<p><img src="https://img2020.cnblogs.com/blog/610959/202007/610959-20200714141053907-2130247866.png" alt="" loading="lazy"></p>
<h1 id="总结">总结</h1>
<p>上文用到了Docker-Compose的3个命令:</p>
<p>构建:<code>docker-compose build</code></p>
<p>启动:<code>docker-compose up</code></p>
<p>销毁:<code>docker-compose down</code></p>
<p>其实build命令也可以省略,执行up时如果没有build的话会自动build,无论多复杂的系统环境,只需要一个<code>docker-compose up</code>命令即可启动。不过镜像需要重新bulid的时候,还是要用到build命令。Compose还有一些其他命令,需要的话可以自行搜索。</p>
<p>主要的工作量在于docker-compose.yml文件的编写。</p>
<p>需要代码的点这里:https://github.com/xiajingren/NetCoreMicroserviceDemo</p>


</div>
<div id="MySignature" role="contentinfo">
    <p style="font-size:12px;text-align:right;font-style: italic;padding: 10px;margin: 10px 0;border-top: 1px solid #ccc;">——本文使用【Typora】+【EasyBlogImageForTypora】编辑</p>
<div style="border: #c0c0c0 2px dashed;padding:20px;">
<p>欢迎关注我的公众号,一起学习。 </p>
<p>如果本文对您有所帮助,您可以点击右下方的【推荐】按钮支持一下;文中如有不妥之处,还望指正,非常感谢!!!</p>
<img src="https://images.cnblogs.com/cnblogs_com/xhznl/1786441/o_2006130816545ee48a5d08000_5ee48a5f18c90.png">
<hr style="margin: 10px 0;"/>
<p>作者:xhznl</p>
<p>出处:http://www.cnblogs.com/xhznl/</p>
<p>文章可以转载,但请注明出处 </p>
</div><br><br>
来源:https://www.cnblogs.com/xhznl/p/13268940.html
頁: [1]
查看完整版本: .Net Core微服务入门全纪录(八)——Docker Compose与容器网络