原军 發表於 2017-12-26 08:26:00

.NET Core容器化之多容器应用部署@Docker-Compose

<p><img src="//upload-images.jianshu.io/upload_images/2799767-b9f7ba6a3c3badba.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="" loading="lazy"></p>
<h1 id="1引言">1.引言</h1>
<p>紧接上篇.NET Core容器化@Docker,这一节我们先来介绍如何使用Nginx来完成.NET Core应用的反向代理,然后再介绍多容器应用的部署问题。</p>
<h1 id="2-why-need-nginx">2. Why Need Nginx</h1>
<p>.NET Core中默认的Web Server为Kestrel。</p>
<blockquote>
<p>Kestrel is great for serving dynamic content from ASP.NET, however the web serving parts aren’t as feature rich as full-featured servers like IIS, Apache or Nginx. A reverse proxy-server can allow you to offload work like serving static content, caching requests, compressing requests, and SSL termination from the HTTP server.</p>
</blockquote>
<p>Kestrel可以很好的用来为ASP.NET提供动态内容,然而在Web服务方面没有IIS、Apache、Nginx这些全功能的服务器完善。我们可以借助一个反向代理服务器接收来自互联网的HTTP请求并在经过一些初步处理(比如请求的缓存和压缩、提供静态内容、SSL Termination)后将其转发给Kestrel。<br>
<img src="//upload-images.jianshu.io/upload_images/2799767-ee9228530f570d3a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="" loading="lazy"><br>
<img src="//upload-images.jianshu.io/upload_images/2799767-e71be39ac1b7223b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="" loading="lazy"></p>
<p>借助反向代理服务器(本文使用Nginx),不仅可以给我们的Web网站提供了一个可选的附加层配置和防御,而且可以简化负载均衡和SSL设置。而更重要的是,反向代理服务器可以很好的与现有的基础设施进行整合。</p>
<h1 id="3-hello-nginx">3. Hello Nginx</h1>
<p>同样我们还是基于Docker来试玩一下Nginx。</p>
<pre><code>//拉取Nginx镜像
$ docker pull nginx
//启动Nginx容器
$ docker run -d -p 8080:80 --name hellonginx nginx
</code></pre>
<p>上面我们以后台运行的方式启动了一个命名为hellonginx的nginx容器,其端口映射到宿主机的8080端口,我们现在可以通过浏览器直接访问<code>http://&lt;ip address&gt;:8080</code>即可看到nginx的欢迎界面。<br>
<img src="//upload-images.jianshu.io/upload_images/2799767-afbbe3b660a43318.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="Hello Nginx" loading="lazy"></p>
<p>至此,一个Nginx容器就启动完毕了。那如何进行反向代理呢?别急,我们一步一步来。</p>
<h1 id="4-反向代理net-core-mvc">4. 反向代理.NET Core MVC</h1>
<h2 id="41-启动web容器">4.1. 启动Web容器</h2>
<p>还记得我们上一篇本地打包MVC项目创建的<code>hellodocker.web</code>的镜像吗?这里我们再启动该镜像创建一个容器:</p>
<pre><code>//启动一个helodocker.web的镜像并命名容器为hellodocker.web.nginx
#docker run -d -p 5000:5000 --name hellodocker.web.nginx hellodocker.web
160166b3556358502a366d1002567972e242f0c8be3a751da0a525f86c124933
//尝试访问刚刚运行的容器
# curl -I http://localhost:5000
HTTP/1.1 200 OK
Date: Sun, 24 Dec 2017 02:48:16 GMT
Content-Type: text/html; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked

</code></pre>
<p>OK,我们开放了宿主机的5000端口用来映射我们启动的MVC容器。</p>
<h2 id="42-配置反向代理">4.2. 配置反向代理</h2>
<p>下面我们就来配置Nginx来反向代理我们刚启动的Web容器。<br>
要想Nginx成功代理指定的容器内运行的Web网站,首先我们得知道容器对应的IPAddress。使用<code>docker inspect &lt;container id/name&gt;</code>即可查到。</p>
<pre><code>//查看正在运行的容器列表
$ docker ps
CONTAINER ID      IMAGE                        COMMAND                  CREATED             STATUS            PORTS                            NAMES
d046b7b878a0      hellodocker.web                "dotnet run"             5 seconds ago       Up 3 seconds      0.0.0.0:5000-&gt;5000/tcp         hellodocker.web.nginx

//使用`|`管道操作符加上`grep`过滤操作符可以直接提取我们要查找的关键字
$ docker inspect hellodocker.web.nginx | grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "192.168.0.5",
                  "IPAddress": "192.168.0.5",
</code></pre>
<p>从上面可以看到我的Web容器运行在宿主机的<code>192.168.0.5:5000</code>。下面我们配置Nginx转发请求到<code>192.168.0.5:5000</code>即可完成反向代理。</p>
<p>Nginx配置反向代理的配置文件路径为:/etc/nginx/conf.d/default.conf。<br>
我们可以通过本地创建一个配置文件挂载到Nginx的容器内部进行反向代理配置。</p>
<pre><code>$ cd demo
$ mkdir nginx
//创建my_nginx.conf文件
$ touch my_nginx.conf
$ vi my_nginx.conf
server {
listen 80;

location / {
    proxy_pass http://192.168.0.5:5000;
}
}
</code></pre>
<p>上面我们通过指定<code>listen</code>配置nginx去监听80端口,指定<code>proxy_pass</code>为我们Web容器的IP和端口完成反向代理文件的配置。</p>
<p>接下来就是启动一个新的Nginx容器并通过挂载的方式将配置文件共享到容器内部。</p>
<pre><code>$ docker run -d -p 8080:80 \
&gt; -v $HOME/demo/nginx/my_nginx.conf:/etc/nginx/conf.d/default.conf \
&gt; nginx
95381aa56a336f65b6d01ff9964ae3364f37d25e5080673347c1878b3a5bb514
/usr/bin/docker-current: Error response from daemon: driver failed programming external connectivity on endpoint elated_mccarthy (5a576d5991dd164db69b1c568c94c15e47ec7c67e43a3dd6982a2e9b83b60e08): Bind for 0.0.0.0:8080 failed: port is already allocated.
</code></pre>
<p>我们发现容器启动失败,原因是8080端口被我们刚刚第一次启动的nginx容器占用了。怎么办?两个方法:第一种就是将刚才创建的nginx容器干掉;第二种就是映射到新的端口。这里选择第一种。</p>
<pre><code>$ docker ps
1bd630b60019      nginx                        "nginx -g 'daemon off"   59 minutes ago      Up 59 minutes       0.0.0.0:8080-&gt;80/tcp             hellonginx
//使用docker rm &lt;container id&gt;删除容器,指定-f进行强制删除
$ docker rm 1bd630b60019 -f
//重新启动Nginx容器
$ docker run -d -p 8080:80 \
&gt; -v $HOME/demo/nginx/my_nginx.conf:/etc/nginx/conf.d/default.conf \
&gt; nginx
793d4c62ec8ac4658d75ea0ab4273a0b1f0a9a68f9708d2f85929872888b121d
</code></pre>
<p>启动成功后,我们再在浏览器中访问<code>http://&lt;ipaddress&gt;:8080</code>,发现返回的不再是Nginx的默认欢迎页,而是我们启动的Web容器中运行的MVC的首页,说明反向代理配置成功!</p>
<p><img src="//upload-images.jianshu.io/upload_images/2799767-2af77358a32e572e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="" loading="lazy"></p>
<h1 id="5-docker-compose让一切更简单">5. Docker Compose让一切更简单</h1>
<p>上面的步骤虽然简单,但要分两步进行:第一个就是我们的Web和Nginx要分两次部署,第二个就是我们必须知道Web容器的IP和端口号,以完成反向代理文件的配置。</p>
<p>对于需要多个容器(比如需要Nginx、SqlServer、Redis、RabbitMQ等)协调运行的复杂应用中,使用以上方式进行部署时,很显然会很麻烦,而且还要为各个容器之间的网络连接而苦恼。<br>
还好,Docker体贴的为我们想到了这一点。借助Compose模块,我们可以编写一个<code>docker-compose.yml</code>文件,使用声明性语法启动一系列相互连接的容器,即可一步完成上面的任务。</p>
<blockquote>
<p>Docker Compose是一个用来定义和运行复杂应用的Docker工具。使用Compose,你可以在一个文件中定义一个多容器应用,然后使用一条命令来启动你的应用,完成一切准备工作。</p>
</blockquote>
<h2 id="51-安装docker-compose">5.1. 安装Docker Compose</h2>
<p>依次执行以下命令:</p>
<pre><code>$ sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
docker-compose version 1.18.0, build 1719ceb
</code></pre>
<h2 id="52-编写第一个docker-composeyml">5.2. 编写第一个docker-compose.yml</h2>
<p>dockers-compose.yml文件要定义在我们项目的文件夹下,我们的项目文件夹位于<code>$HOME/demo/HelloDocker.Web</code>。</p>
<pre><code>$ cd $HOME/demo/HelloDocker.Web
$ touch docker-compose.yml
$ vi docker-compose.yml
version: '2'
services:
    hellodocker-web:
      container_name: hellodocker.web.compose
      build: .

    reverse-proxy:
      container_name: reverse-proxy
      image: nginx
      ports:
         - "9090:8080"
      volumes:
         - ./proxy.conf:/etc/nginx/conf.d/default.conf
</code></pre>
<p>简单介绍下上面的配置文件,其中定义了两个服务:一个是<code>hellodocker-web</code>,即以我们当前项目目录来构建镜像并启动一个叫<code>hellodocker.web.compose</code>的容器。一个是<code>reverse-proxy</code>,用来使用nginx镜像进行反向代理,其中又通过指定<code>volumes</code>来使用挂载的方式进行配置。</p>
<pre><code>$ touch proxy.conf
$ vi proxy.conf
server {
    listen 8080;

    location / {
      proxy_pass http://hellodocker-web:5000;
    }
}
$ ls
# ls
appsettings.Development.jsonControllers             Models      Startup.cs
appsettings.json            docker-compose.yml      obj         Views
bin                           Dockerfile            Program.cswwwroot
bundleconfig.json             HelloDocker.Web.csprojproxy.conf
#
</code></pre>
<p>其中要注意反向代理的配置:<code>proxy_pass http://hellodocker-web:5000;</code>,其中ip部分直接指定的是docker-compose.yml中定义的第一个服务的名称<code>hellodocker-web</code>。<br>
下面我们就来启动Compose:</p>
<pre><code>$ docker-compose up -d
Building hellodocker-web
Step 1 : FROM microsoft/dotnet:latest
---&gt; 7d4dc5c258eb
Step 2 : WORKDIR /app
---&gt; Using cache
---&gt; 98d48a4e278c
Step 3 : COPY . /app
---&gt; 0cb9fc540afe
Removing intermediate container 9fecf088f03f
Step 4 : RUN dotnet restore
---&gt; Running in 4bb7f34edbbe
Restore completed in 597.13 ms for /app/HelloDocker.Web.csproj.
Restoring packages for /app/HelloDocker.Web.csproj...
Restore completed in 1.76 sec for /app/HelloDocker.Web.csproj.
---&gt; 6869609ece23
Removing intermediate container 4bb7f34edbbe
Step 5 : EXPOSE 5000
---&gt; Running in a97febf01e5a
---&gt; 9b2639862a94
Removing intermediate container a97febf01e5a
Step 6 : ENV ASPNETCORE_URLS http://*:5000
---&gt; Running in 4e2f4af28a8d
---&gt; 0069661e891a
Removing intermediate container 4e2f4af28a8d
Step 7 : ENTRYPOINT dotnet run
---&gt; Running in cbbf08d906f9
---&gt; 0bbeef249b30
Removing intermediate container cbbf08d906f9
Successfully built 0bbeef249b30
WARNING: Image for service hellodocker-web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating hellodocker.web.compose ... done
Starting reverse-proxy ... done
//执行docker-compose ps验证启动的服务
$ docker-compose ps
         Name                   Command          State               Ports
---------------------------------------------------------------------------------------
hellodocker.web.compose   dotnet run             Up      5000/tcp
reverse-proxy             nginx -g daemon off;   Up      80/tcp, 0.0.0.0:9090-&gt;8080/tcp
//使用curl指令验证nginx的反向代理
$curl -I http://localhost:9090
HTTP/1.1 200 OK
Server: nginx/1.13.7
Date: Sun, 24 Dec 2017 04:37:35 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
</code></pre>
<p>可以看到,通过执行<code>curl -I http://localhost:9090</code>验证代理服务器配置成功,我们再通过浏览器访问<code>http://&lt;ip address&gt;:9090</code>发现正确返回了我们MVC项目的默认首页。</p>
<pre><code>// 查看当前运行的容器
$ docker ps
CONTAINER ID      IMAGE                            COMMAND                  CREATED             STATUS            PORTS                            NAMES
a52830499cff      hellodockerweb_hellodocker-web   "dotnet run"             7 minutes ago       Up 7 minutes      5000/tcp                         hellodocker.web.compose
e1fe109e10bc      nginx                            "nginx -g 'daemon off"   11 minutes ago      Up 4 minutes      80/tcp, 0.0.0.0:9090-&gt;8080/tcp   reverse-proxy
</code></pre>
<p>我们同时也发现通过<code>docker-compose</code>正确的创建了两个容器<code>hellodocker.web.compose</code>和<code>reverse-proxy</code>。</p>
<h1 id="6-最后">6. 最后</h1>
<p>经过以上的练习,我们对Nginx有了一定的了解,且知道如何进行配置。同时了解了如何借助docker-compose打包运行需要多容器的复杂应用。</p>
<p>本篇就先讲到这里,下一篇我们介绍如何在Linux上玩耍MySql并打通Nginx+Web+MySql的容器化部署。</p>


</div>
<div id="MySignature" role="contentinfo">
    <div style="display: block; border: 2px solid #6ecaa8; padding: 10px; background: aliceblue">
<img src="https://files.cnblogs.com/files/sheng-jie/maf-course-card-scan.bmp">
<blockquote>
<b>👆面向.NET开发者的AI Agent 开发课程【.NET+AI | 智能体开发进阶】已上线,欢迎扫码加入学习。👆</b>
</blockquote>
</div>

<img src="https://files.cnblogs.com/files/sheng-jie/scan-follow.bmp">
<blockquote>
<b>
关注我的公众号『向 AI 而行』,我们微信不见不散。
<br>
阅罢此文,如果您觉得本文不错并有所收获,请【打赏】或【推荐】,也可【评论】留下您的问题或建议与我交流。

你的支持是我不断创作和分享的不竭动力!</b>
</blockquote>

<div style="display: block; border: 2px solid #6ecaa8; padding: 10px; background: aliceblue" id="AllanboltSignature">   
      <div>作者:『圣杰』</div>
      <div>出处:http://www.cnblogs.com/sheng-jie/</div>
      <div>本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。</div>
</div><br><br>
来源:https://www.cnblogs.com/sheng-jie/p/8116276.html
頁: [1]
查看完整版本: .NET Core容器化之多容器应用部署@Docker-Compose