Docker Compose 简介
<p><span style="color: rgba(255, 0, 0, 1)"><strong><span style="font-family: Microsoft YaHei; font-size: 15px">Compose 是 docker 提供的一个命令行工具,用来定义和运行由多个容器组成的应用。</span></strong></span><br><span style="color: rgba(255, 0, 0, 1)"><strong><span style="font-family: Microsoft YaHei; font-size: 15px">使用 compose,我们可以通过 YAML 文件声明式的定义应用程序的各个服务,并由单个命令完成应用的创建和启动。</span></strong></span></p><p><span style="font-family: Microsoft YaHei; font-size: 15px">Compose 的使用方式非常简单,基本上就是下面的三板斧:</span></p>
<ul>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">定义 Dockerfile</span></li>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">定义 docker-compose.yml</span></li>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">运行 docker-compose up</span></li>
</ul>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">其实 compose 提供的命令可以管理应用的整个生命周期:</span></p>
<ul>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">Start, stop, rebuild services</span></li>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">查看运行中 service 的状态</span></li>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">输出运行中 service 的日志</span></li>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">在 service 中执行一次性的命令</span></li>
</ul>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">本文我们通过一个简单的 demo 来介绍 Docker Compose 的基本用法。说明:本文的演示环境为 ubuntu 16.04。本文的演示代码可以从 github 上下载。</span></p>
<h1><span style="font-family: Microsoft YaHei; font-size: 18pt">安装 Docker Compose</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">安装 Docker Compose 前请先在本地安装 Docker。</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">Docker Compose 的安装十分简单,在 ubuntu 中直接把可执行文件下载到本地就可以了。</span></p>
<div class="cnblogs_code">
<pre>$ <span style="color: rgba(0, 0, 255, 1)">sudo</span> curl -L https:<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose</span>
$ <span style="color: rgba(0, 0, 255, 1)">sudo</span> <span style="color: rgba(0, 0, 255, 1)">chmod</span> +x /usr/local/bin/docker-compose</pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">其中 1.22.0 是最新的版本。当然 Docker Compose 是个开源项目,你可以选择安装不同的版本,或者是自行编译。下图为笔者安装之后显示的版本信息:</span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px"><img src="https://img2018.cnblogs.com/blog/952033/201810/952033-20181008130753846-118499818.png"></span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">注意,默认的安装并不包括命令补全功能,也就是说像 docker-compose restart 这样的命令,你输入 docker-compose re 后按 tab 键是无法自动补全的。想要这个功能还需要额外的安装,以 Bash 为例,执行下面的命令:</span></p>
<div class="cnblogs_code">
<pre>$ <span style="color: rgba(0, 0, 255, 1)">sudo</span> curl -L https:<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">raw.githubusercontent.com/docker/compose/1.22.0/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose</span></pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">然后重新登录 Bash,就可以通过 tab 键自动补全命令了!</span></p>
<h1><span style="font-family: Microsoft YaHei; font-size: 18pt">创建演示 demo</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">下面的示例来自 docker 官网,就是一个简单的 Flask 网页应用,后端使用 redis 存储数据,其 web server 的代码如下(可以从这里下载到本文中的代码): </span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> time
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> redis
</span><span style="color: rgba(0, 0, 255, 1)">from</span> flask <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> Flask
app </span>= Flask(<span style="color: rgba(128, 0, 128, 1)">__name__</span><span style="color: rgba(0, 0, 0, 1)">)
cache </span>= redis.Redis(host=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">redis</span><span style="color: rgba(128, 0, 0, 1)">'</span>, port=6379<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> get_hit_count():
retries </span>= 5
<span style="color: rgba(0, 0, 255, 1)">while</span><span style="color: rgba(0, 0, 0, 1)"> True:
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">:
</span><span style="color: rgba(0, 0, 255, 1)">return</span> cache.incr(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hits</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">except</span><span style="color: rgba(0, 0, 0, 1)"> redis.exceptions.ConnectionError as exc:
</span><span style="color: rgba(0, 0, 255, 1)">if</span> retries ==<span style="color: rgba(0, 0, 0, 1)"> 0:
</span><span style="color: rgba(0, 0, 255, 1)">raise</span><span style="color: rgba(0, 0, 0, 1)"> exc
retries </span>-= 1<span style="color: rgba(0, 0, 0, 1)">
time.sleep(</span>0.5<span style="color: rgba(0, 0, 0, 1)">)
@app.route(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> hello():
count </span>=<span style="color: rgba(0, 0, 0, 1)"> get_hit_count()
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Hello World! I have been seen {} times.\n</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">.format(count)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 128, 1)">__name__</span> == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
app.run(host</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">0.0.0.0</span><span style="color: rgba(128, 0, 0, 1)">"</span>, debug=True)</pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">代码非常简单,就是对请求计数并显示给用户。为了增加健壮性,在访问 redis 时做了一点处理:尝试访问 5 次再报错。把上面的代码保存到文件 app.py 中。</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">要运行上面的代码,需要在环境中安装 flask 和 redis 包。创建 requirements.txt 文件,编辑其内容为:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">flask
redis</span></pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">创建一个保存项目文件的目录,比如 composecounter,把 app.py 和 requirements.txt 文件都放进去。</span></p>
<h1><span style="font-family: Microsoft YaHei; font-size: 18pt">创建 Dockerfile 文件</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">接下来我们需要把上面的应用打包到容器镜像中。在 composecounter 目录下创建 Dockerfile 文件:</span></p>
<div class="cnblogs_code">
<pre>FROM python:<span style="color: rgba(128, 0, 128, 1)">3.4</span>-<span style="color: rgba(0, 0, 0, 1)">alpine
ADD . </span>/<span style="color: rgba(0, 0, 0, 1)">code
WORKDIR </span>/<span style="color: rgba(0, 0, 0, 1)">code
RUN pip </span><span style="color: rgba(0, 0, 255, 1)">install</span> -<span style="color: rgba(0, 0, 0, 1)">r requirements.txt
CMD [</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">python</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">app.py</span><span style="color: rgba(128, 0, 0, 1)">"</span>]</pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">上面代码的含义为:</span></p>
<ul>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">使用 python:3.4-alpine 作为基础镜像</span></li>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">把当前目录添加到镜像中的 /code 目录</span></li>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">设置容器中的工作目录为 /code</span></li>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">安装 requirements.txt 文件中指定的依赖包</span></li>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">把容器启动时的默认命令设置为 python app.py</span></li>
</ul>
<h1><span style="font-family: Microsoft YaHei; font-size: 18pt">创建 compose 配置文件</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">终于来到本文的重点了!我们需要创建 Docker Compose 的配置文件来定义我们的应用。</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">YAML 是一个可读性高,用来表达数据序列的格式。Docker Compose 使用 YAML 格式的文件作为配置文件。</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">在 composecounter 目录中创建 docker-compose.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: .
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)">
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">第一行的 version: '3' 表示当前的配置文件使用的语法版本。</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">services 中的内容指明该应用一共定义了多少个服务(容器镜像)。在运行时,一个服务是指从该镜像启动的一个或多个容器。</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">在我们的示例中一共需要两个容器镜像。web 服务由我们自己通过 build . 命令构建,映射的端口是 flask web server 默认的 5000 端口。</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">redis 服务则直接使用官方的镜像。</span></p>
<h1><span style="font-family: Microsoft YaHei; font-size: 18pt">构建并运行示例程序</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">在 composecounter 目录下执行命令:</span></p>
<div class="cnblogs_code">
<pre>$ docker-compose up</pre>
</div>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">跳过那些繁琐的输出,我们直接访问本机的 5000 端口:</span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px"><img src="https://img2018.cnblogs.com/blog/952033/201810/952033-20181008131051561-158088899.png"></span></p>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">一个 web 应用程序运行起来了,并且输出了我们访问服务器端的次数,看起来还不错!</span><br><span style="font-family: Microsoft YaHei; font-size: 15px">如果要让容器安静的运行在后台,加上 -d 选项就可以了:</span></p>
<div class="cnblogs_code">
<pre>$ docker-compose up -d</pre>
</div>
<h1><span style="font-family: Microsoft YaHei; font-size: 18pt">背后的事情</span></h1>
<p><span style="font-family: Microsoft YaHei; font-size: 15px">分析 docker-compose up 命令的输出可以看清事情的真相,但是日志过于繁琐,我们只说重点:</span></p>
<ol>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">创建名称为 composecounter_default 的网络</span></li>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">使用 Dockerfile 构建 composecounter_web 镜像</span></li>
<li><span style="font-family: Microsoft YaHei; font-size: 15px">创建容器 composecounter_redis_1 和 composecounter_web_1 并加入相同的网络</span></li>
</ol>
<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 被设计来管理应用的整个生命周期,我们也可以用它来极大的提高工作效率。笔者将在接下来的文章中介绍更多 Docker Compose 相关的内容。</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">Get started with Docker Compose</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/9753793.html
頁:
[1]