神乎其神 發表於 2018-10-18 08:54:00

Docker Compose 之进阶篇

<p><span style="font-family: Microsoft YaHei; font-size: 15px">笔者在前文《Docker Compose 简介》和《Dcoker Compose 原理》两篇文章中分别介绍了 docker compose 的基本概念以及实现原理。本文我们将继续探索 docker compose,并通过 demo 介绍一些主要的用法。 </span><br><span style="font-family: Microsoft YaHei; font-size: 15px">说明:本文的演示环境为 ubuntu 16.04。</span></p>
<h1><span style="font-family: Microsoft YaHei; font-size: 15px">应用多个 compose 配置文件</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">docker-compose 命令默认使用的配置文件是当前目录中的 docker-compose.yml 文件,当然我们可以通过 -f 选项指定一个其它名称的配置文件,比如:</span></p>
<div class="cnblogs_code">
<pre>$ docker-compose -f docker-compose-dev.yml up</pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">更酷的是我们可以添加多个 -f 选项,docker-compose 会自动合并它们,当然也会根据先后顺序把一些重复的配置项覆盖掉。 下面我们来演示一个常见的使用场景,先创建一个名称为 docker-compose-base.yml 的配置文件,其内容如下:</span></p>
<div class="cnblogs_code">
<pre>version: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">3</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
services:
web:
    build: .
redis:
    image: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">redis:latest</span><span style="color: rgba(128, 0, 0, 1)">"</span></pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">然后再创建名称为 docker-compose-dev.yml 的配置文件:</span></p>
<div class="cnblogs_code">
<pre>version: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">3</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
services:
web:
    ports:
   </span>- <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">5000:5000</span><span style="color: rgba(128, 0, 0, 1)">"</span></pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">下面的命令会同时应用这两个配置文件:</span></p>
<div class="cnblogs_code">
<pre>$ docker-compose -f docker-compose-base.yml -f docker-compose-dev.yml config</pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">config 命令不会执行真正的操作,而是显示 docker-compose 程序解析到的配置文件内容:</span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px"><img src="https://img2018.cnblogs.com/blog/952033/201810/952033-20181017131032912-144319125.png"></span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">很显然,我们指定的两个配置文件的内容被合并了。接下来我们再来看看配置文件覆盖的情况。新创建一个名为 docker-compose-prod.yml 的配置文件,编辑其内容如下:</span></p>
<div class="cnblogs_code">
<pre>version: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">3</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
services:
web:
    ports:
   </span>- <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">80:5000</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
redis:
    image: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">redis:alpine</span><span style="color: rgba(128, 0, 0, 1)">"</span></pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">然后执行下面的命令:</span></p>
<div class="cnblogs_code">
<pre>$ docker-compose -f docker-compose-base.yml -f docker-compose-prod.yml config</pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px"><img src="https://img2018.cnblogs.com/blog/952033/201810/952033-20181017131118014-522763315.png"></span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">这次 docker-compose-prod.yml 文件中的 image 设置覆盖了 docker-compose-base.yml 文件中的设置,并且映射的端口也改成了 80:5000。</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">就像 demo 中演示的那样,我们可以通过多次指定 -f 选项的方式配置不同的环境,并且共用一份基础的配置文件。</span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">其实 docker-compse 还默认还支持一种合并、覆盖配置文件的写法,就是使用约定的文件名称 docker-compose.yml 和 docker-compose.override.yml。下面我们把 docker-compose-base.yml 文件改名为 docker-compose.yml,把 docker-compose-prod.yml 文件改名为 docker-compose.override.yml,并直接执行不带 -f 选项的命令:</span></p>
<div class="cnblogs_code">
<pre>$ docker-compose config</pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">结果和前面是一样的,docker-compose 自动合并了配置文件 docker-compose.yml 和 docker-compose.override.yml。这种方式虽然省去了指定 -f 选项的麻烦但其缺点也是很明显的,就是无法指定更多不同的应用场景。</span></p>
<h1><span style="font-family: Microsoft YaHei; font-size: 18pt">使用 network</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">Docker 提供的 network 功能能够对容器进行网络上的隔离,下面的 demo 中我们创建三个 service 和两个虚拟网络(注意,该 demo 主要是演示 network 的用法,所以笔者并没有配置 proxy service 中的 nginx):</span></p>
<div class="cnblogs_code">
<pre>version: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">3</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
services:
proxy:
    image: nginx
    ports:
      </span>- <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">80:80</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    networks:
      </span>-<span style="color: rgba(0, 0, 0, 1)"> frantnet
webapp:
    build: .
    networks:
      </span>-<span style="color: rgba(0, 0, 0, 1)"> frantnet
      </span>-<span style="color: rgba(0, 0, 0, 1)"> endnet
redis:
    image: redis
    networks:
      </span>-<span style="color: rgba(0, 0, 0, 1)"> endnet
networks:
frantnet:
endnet:</span></pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">其中的 proxy 和 webapp 连接到网络 frantnet 上,webapp 和 redis 连接在了 endnet 上(请使用《Docker Compose 简介》一文中介绍的 web 应用和 Dockerfile 来创建 webapp service)。请使用下面的命令来启动应用:</span></p>
<div class="cnblogs_code">
<pre>$ docker-compose -p testnet -f docker-compose-net.yml up -d</pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px"><img src="https://img2018.cnblogs.com/blog/952033/201810/952033-20181017131320811-1377033317.png"></span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">从上图我们可以看到该命令一共创建了两个 network 和 三个容器。然后我们检查一下这三个容器的网络连接状态。先从 testnet_webapp_1 中 ping 另外的两个容器:</span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px"><img src="https://img2018.cnblogs.com/blog/952033/201810/952033-20181017131354662-416336694.png"></span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">因为 webapp 服务同时连接到了 frantnet 和 endnet 两个网络中,所以它可以同时连接这两个网络中的其它容器(proxy 和 redis)。接下来再看看容器 proxy 和 redis 是否可以直接连通,我们从容器 testnet_redis_1 中 ping proxy(注意,执行这个操作前需要在容器&nbsp; testnet_redis_1 中通过 apt-get update &amp;&amp; apt-get install iputils-ping 命令安装 ping 命令):</span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px"><img src="https://img2018.cnblogs.com/blog/952033/201810/952033-20181017131431379-1023292312.png"></span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">无法从容器 testnet_redis_1 中 ping 通 proxy 容器,这也就说明我们通过不同的虚拟网络实现了容器网络之间的隔离,从而在最大程度上去保护后端网络的安全。</span></p>
<h1><span style="font-family: Microsoft YaHei; font-size: 18pt">按顺序启动容器</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">默认情况下 compose 启动容器的顺序是不确定的,但是有些场景下我们希望能够控制容器的启动顺序,比如应该让运行数据库的程序先启动。我们可以通过 depends_on 来解决有依赖关系的容器的启动顺序问题,看下面的 demo:</span></p>
<div class="cnblogs_code">
<pre>version: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">3</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
services:
proxy:
    image: nginx
    ports:
      </span>- <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">80:80</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    depends_on:
      </span>-<span style="color: rgba(0, 0, 0, 1)"> webapp
      </span>-<span style="color: rgba(0, 0, 0, 1)"> redis
webapp:
    build: .
    depends_on:
      </span>-<span style="color: rgba(0, 0, 0, 1)"> redis
redis:
    image: redis</span></pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">启动应用:</span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px"><img src="https://img2018.cnblogs.com/blog/952033/201810/952033-20181017131603316-913957749.png"></span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">无论我们执行多少次这样的启动操作,这三个容器的启动顺序都是不变的。如果不应用 depends_on,每次执行 up 命令容器的启动顺序可能都是不一样的。</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">需要注意的是 depends_on 只是解决了控制容器启动顺序的问题,如果一个容器的启动时间非常长,后面的容器并不会等待它完成启动。如果要解决这类问题(等待容器完成启动并开始提供服务),需要使用 wait-for-it 等工具。 </span></p>
<h1><span style="font-family: Microsoft YaHei; font-size: 18pt">配置数据卷(volume)</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">数据卷是处理容器中的持久化数据的主要方式,在 compose 中我们可以通过两种方式来指定数据卷:</span></p>
<ul>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">使用命名的数据卷</span></li>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">直接指定主机上的路径来创建数据卷</span></li>

</ul>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">下面的 demo 演示了这两种数据卷的配置方式:</span></p>
<div class="cnblogs_code">
<pre>version: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">3.2</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
services:
web:
    image: nginx:alpine
    volumes:
      </span>-<span style="color: rgba(0, 0, 0, 1)"> type: volume
      source: mydata
      target: </span>/<span style="color: rgba(0, 0, 0, 1)">data
      </span>-<span style="color: rgba(0, 0, 0, 1)"> type: bind
      source: .</span>/nginx/<span style="color: rgba(0, 0, 0, 1)">logs
      target: </span>/var/log/<span style="color: rgba(0, 0, 0, 1)">nginx
jenkins:
    image: jenkins</span>/<span style="color: rgba(0, 0, 0, 1)">jenkins:lts
    volumes:
      </span>- jenkins_home:/var/<span style="color: rgba(0, 0, 0, 1)">jenkins_home
      </span>- mydata:/<span style="color: rgba(0, 0, 0, 1)">data
volumes:
mydata:
jenkins_home:</span></pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">在这个例子中我们一共创建了三个数据卷,分别是两个命名的数据卷 jenkins_home 和 mydata:</span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px"><img src="https://img2018.cnblogs.com/blog/952033/201810/952033-20181017131740766-2091840960.png"></span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">其中的 jenkins_home 数据卷是给 jenkins 保存数据的。如果要在多个容器之间共享数据卷,就必须在顶级的 volumes 节点中定义这个数据卷,比如 mydata 数据卷,它被 web 和 jenkins service 共享了。比如我们在 web service 中的 mydata 数据卷中创建一个名为 hello 的文件,该文件会同时出现在 jenkins service 中:</span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px"><img src="https://img2018.cnblogs.com/blog/952033/201810/952033-20181017131815127-1126854547.png"></span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">我们还创建了一个 bind 类型的 volume 在当前目录下的 nginx/logs 目录下保存 nginx 的日志:</span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px"><img src="https://img2018.cnblogs.com/blog/952033/201810/952033-20181017131845910-1606044961.png"></span></p>
<h1><span style="font-family: Microsoft YaHei; font-size: 18pt">配置日志驱动</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">我们还可以通过 logging 节点为 service 指定日志驱动及其相关的选项:</span></p>
<div class="cnblogs_code">
<pre>version: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">3</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
services:
web:
    build: .
    ports:
   </span>- <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">5000:5000</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    logging:
      driver: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">json-file</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
      options:
      max</span>-size: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">200k</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
      max</span>-<span style="color: rgba(0, 0, 255, 1)">file</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">10</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
redis:
    image: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">redis:latest</span><span style="color: rgba(128, 0, 0, 1)">"</span></pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">上面的代码指定日志驱动为 json-file,存储日志的最大文件 size 为 200k,最多存储 10 这样大的文件。</span></p>
<h1><span style="font-family: Microsoft YaHei; font-size: 18pt">在 compose file 文件中应用模板</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">从版本 3.4 开始,可以在 compose file 文件中使用 extension fields,其实我们可以简单的把它理解为可以重用的代码模板。模板的定义必须以 x- 开头,然后以 &amp; 开头的字符串为模板命名,之后就可以以 * 加上模板的名称引用模板:</span></p>
<div class="cnblogs_code">
<pre>version: <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">3.4</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
x</span>-<span style="color: rgba(0, 0, 0, 1)">logging:
</span>&amp;default-<span style="color: rgba(0, 0, 0, 1)">logging
driver: json</span>-<span style="color: rgba(0, 0, 255, 1)">file</span><span style="color: rgba(0, 0, 0, 1)">
options:
    max</span>-size: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">200k</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    max</span>-<span style="color: rgba(0, 0, 255, 1)">file</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">10</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">

services:
web:
    build: .
    ports:
   </span>- <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">5000:5000</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    logging: </span>*default-<span style="color: rgba(0, 0, 0, 1)">logging
redis:
    image: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">redis:latest</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    logging: </span>*default-logging</pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">运行下面的命令看看模板替换的情况:</span></p>
<div class="cnblogs_code">
<pre>$ docker-compose -p template -f docker-compose-template.yml config</pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px"><img src="https://img2018.cnblogs.com/blog/952033/201810/952033-20181017132006365-619863056.png"></span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">上图显示所有对模板的引用都被替换成了模板的内容。</span></p>
<h1><span style="font-family: Microsoft YaHei; font-size: 18pt">总结</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">Docker compose 是一件强有力的效率工具,本文只是介绍了一些常见的用法。如果你还想掌握更多内容,请参考 compose file 的官方文档。</span></p>
<p><strong><span style="font-family: Microsoft YaHei; font-size: 15px">参考:</span></strong><br><span style="font-family: Microsoft YaHei; font-size: 15px">Compose file version 3 reference</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">Docker Compose from development to production</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">Networking in Compose</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">Control startup order in Compose</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">3 Docker Compose features for improving team development workflow</span></p>

</div>
<div id="MySignature" role="contentinfo">
    <div>作者:sparkdev</div>
<div>出处:http://www.cnblogs.com/sparkdev/</div>
<div>本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。</div><br><br>
来源:https://www.cnblogs.com/sparkdev/p/9803554.html
頁: [1]
查看完整版本: Docker Compose 之进阶篇