Docker三剑客之Compose

What is Compose?
node

    Compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。经过Compose能够定义和运行多容器docker环境,使用Compose,可使用模版文件(YAML文件)来配置应用的服务。而后,经过compose相关命令,能够建立和启动全部应用服务。
python

Compose应用场景git

    使用Dockerfile模版文件,能够很方便的定义一个单独的应用容器。然而,在平常工做中,常常碰到须要多个容器相互配合来完成某项任务的状况。例如,要实现一个Web项目,除了Web服务容器自己,每每还须要在加上后端的数据库服务容器,甚至还包括负载均衡容器等。Compose刚好知足这样的需求,用户经过单独的docker-compose.yml模版文件来定义一组相关联的应用容器为一个项目。
github

Compose工做原理图web

image.png

Compose中的两个重要概念:redis

  • 服务(service):一个应用的容器,实际上能够包括若干运行相同镜像的容器 实例。docker

  • 项目(project):由一组关联的应用容器组成的一个完整业务单元,在 docker- compose.yml 文件中定义。数据库

Compose 的默认管理对象是项目,经过子命令对项目中的一组容器进行便捷地生 命周期管理。
安装Compose
flask

Compose能够安装在众多不一样的平台下,如:MacOS,Windows,Other 64-bit Linux。安装Compose方式也有不少,如pip方式安装、二进制包安装、容器中执行等等方式。后端

Linux下安装Compose

安装 Compose 以前,要先安装 Docker(须要 Docker Engine 1.7.1+)。

下载最新Compose版本:

[root@centos7 ~]# sudo curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

添加执行权限:

[root@centos7 ~]# chmod +x /usr/local/bin/docker-compose

检查安装:

[root@centos7 ~]# docker-compose --version
docker-compose version 1.22.0, build f46880fe

卸载Compose

若是使用curl安装,去卸载Comose:

sudo rm /usr/local/bin/docker-compose

Compose使用

使用Compose基本上分为三步:

    1.使用Dockerfile定义应用程序的环境,以即可以在任何地方进行复制。

    2.在docker-compose.yml中定义构成应用程序的服务,以便它们能够在隔离环境中一块儿运行。

    3.运行docker-compose up和Compose启动并运行整个应用程序。

    为了实现上述编排与部署的原理,能够从Docker Comose官网上的一个例子开始入手。

第一步:设置

定义应用程序的依赖项。

1.建立项目目录:

[root@centos7 ~]# mkdir composetest
[root@centos7 ~]#  cd composetest

2.建立一个名为app.py的应用,内容以下:

[root@centos7 composetest]# cat app.py 
#!/usr/bin/python3
# coding=utf-8
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)
@app.route('/')
def hello():
    count = get_hit_count()
    return 'Hello World! I have been seen {} times.\n'.format(count)
if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)

这是一个基于Python的轻Web的Flask应用,因此看到应用里有.route('/'),即反问根目录,而后返回一个从Redis里读取出来的值,该值经过自加来统计访问次数。最后Web容器在0.0.0.0上监听默认端口5000.

3.建立另外一个文件名为requirements.txt指定python依赖包:flask和redis,内容以下:

[root@centos7 composetest]# cat requirements.txt 
flask
redis

第二步:建立一个Dockerfile文件

咱们来写一个 Dockerfile 来定义 Docker 镜像,此镜像包含了 Python 的依赖包和 Python 环境。

一样在此目录下,咱们建立一个 Dockerfile 文件。

[root@centos7 composetest]# cat Dockerfile 
FROM python:3.4-alpine
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD ["python3", "app.py"]

注:我本地环境使用python2.7和python3兼容模式,因此须要指定python3去执行app.py文件。

代码表示“:

  • 继承python3.4基础镜像

  • 将当前目录.影射到/code下

  • 设置工做目录/code

  • 安装python依赖关系包

  • 启动app应用程序

第三步:Compose文件定义服务

建立一个名为docker-compose.yml文件,内容以下:

[root@centos7 composetest]# cat docker-compose.yml 
version: '3'
services: 
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

Compose文件定义了两个服务,web服务和redis服务,web服务:

  • 使用从当前目录中的Dockerfile构建的映像。

  • 将容器上的公开端口5000转发到主机上的端口5000。 咱们使用Flask Web服务器的默认端口5000。

redis服务使用从Docker Hub注册表中提取的公共Redis映像。

    这里是编排部署核心所在,在这个YAML文件里,能够看到高级别的key:web和redis,这意味着用Compose定义了由两个“服务”组成的Docker集群。其中第一个服务叫web,它从当前目录的Dockerfile build获得;以后在容器中运行python app.py;把容器内的5000端口映射到宿主机的5000端口;挂载执行这些操做所在的目录到容器/code目录下。以后,代码修改就在容器中体现。

    第二个服务redis直接使用已有的redis镜像,Dockerfile没必要另外编写。

    接下来执行一句docker-compose up就能够了,尝试访问一下宿主机的5000端口,若是没什么问题能看到容器里的python web服务统计访问次数了。

第四步:Comose构建和运行应用

在项目目录中,经过docker-compose up命令运行应用服务。

[root@centos7 composetest]# docker-compose up
WARNING: The Docker Engine you're using is running in swarm mode.
Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.
To deploy your application across the swarm, use `docker stack deploy`.
Creating network "composetest_default" with the default driver
Building web
Step 1/5 : FROM python:3.4-alpine
3.4-alpine: Pulling from library/python
4fe2ade4980c: Pull complete
7cf6a1d62200: Pull complete
599ae3a07d9d: Pull complete
1acdc2ab10cd: Pull complete
2c4249dd0b02: Pull complete
Digest: sha256:7087f61b8d11919f24d7f6115327683a85aecaa050019bd4b35042261e8d7773
Status: Downloaded newer image for python:3.4-alpine
 ---> 90d3f9764c4d
Step 2/5 : ADD . /code
 ---> 97ce6a2665ed
Step 3/5 : WORKDIR /code
 ---> Running in b959e84e8dcc
Removing intermediate container b959e84e8dcc
 ---> 85d8fefdf4ff
Step 4/5 : RUN pip install -r requirements.txt
 ---> Running in 2b07e63ee082
Collecting flask (from -r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/7f/e7/08578774ed4536d3242b14dacb4696386634607af824ea997202cd0edb4b/Flask-1.0.2-py2.py3-none-any.whl (91kB)
Collecting redis (from -r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/3b/f6/7a76333cf0b9251ecf49efff635015171843d9b977e4ffcf59f9c4428052/redis-2.10.6-py2.py3-none-any.whl (64kB)
Collecting Jinja2>=2.10 (from flask->-r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/7f/ff/ae64bacdfc95f27a016a7bed8e8686763ba4d277a78ca76f32659220a731/Jinja2-2.10-py2.py3-none-any.whl (126kB)
Collecting itsdangerous>=0.24 (from flask->-r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz (46kB)
Collecting click>=5.1 (from flask->-r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/fa/37/45185cb5abbc30d7257104c434fe0b07e5a195a6847506c074527aa599ec/Click-7.0-py2.py3-none-any.whl (81kB)
Collecting Werkzeug>=0.14 (from flask->-r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/20/c4/12e3e56473e52375aa29c4764e70d1b8f3efa6682bef8d0aae04fe335243/Werkzeug-0.14.1-py2.py3-none-any.whl (322kB)
Collecting MarkupSafe>=0.23 (from Jinja2>=2.10->flask->-r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz
Building wheels for collected packages: itsdangerous, MarkupSafe
  Running setup.py bdist_wheel for itsdangerous: started
  Running setup.py bdist_wheel for itsdangerous: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/2c/4a/61/5599631c1554768c6290b08c02c72d7317910374ca602ff1e5
  Running setup.py bdist_wheel for MarkupSafe: started
  Running setup.py bdist_wheel for MarkupSafe: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/33/56/20/ebe49a5c612fffe1c5a632146b16596f9e64676768661e4e46
Successfully built itsdangerous MarkupSafe
Installing collected packages: MarkupSafe, Jinja2, itsdangerous, click, Werkzeug, flask, redis
Successfully installed Jinja2-2.10 MarkupSafe-1.0 Werkzeug-0.14.1 click-7.0 flask-1.0.2 itsdangerous-0.24 redis-2.10.6
Removing intermediate container 2b07e63ee082
 ---> 23354c79c570
Step 5/5 : CMD ["python3", "app.py"]
 ---> Running in 1de84ec9dcd3
Removing intermediate container 1de84ec9dcd3
 ---> 1cdd437daa30
Successfully built 1cdd437daa30
Successfully tagged composetest_web:latest
WARNING: Image for service web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Pulling redis (redis:alpine)...
alpine: Pulling from library/redis
4fe2ade4980c: Already exists
fb758dc2e038: Pull complete
989f7b0c858b: Pull complete
d5318f13abaa: Pull complete
3521559474dd: Pull complete
af5d048338ef: Pull complete
Digest: sha256:fc78e96c8036b6fa69ce8d4e811ba84b9278e772047a93fb6d5549de4ddecc32
Status: Downloaded newer image for redis:alpine
Creating composetest_redis_1 ... done
Creating composetest_web_1   ... done
Attaching to composetest_redis_1, composetest_web_1
redis_1  | 1:C 27 Sep 08:31:29.854 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1  | 1:C 27 Sep 08:31:29.854 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1  | 1:C 27 Sep 08:31:29.854 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis_1  | 1:M 27 Sep 08:31:29.857 # Not listening to IPv6: unsupproted
redis_1  | 1:M 27 Sep 08:31:29.857 * Running mode=standalone, port=6379.
redis_1  | 1:M 27 Sep 08:31:29.857 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_1  | 1:M 27 Sep 08:31:29.858 # Server initialized
redis_1  | 1:M 27 Sep 08:31:29.858 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
redis_1  | 1:M 27 Sep 08:31:29.858 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_1  | 1:M 27 Sep 08:31:29.858 * Ready to accept connections
web_1    |  * Serving Flask app "app" (lazy loading)
web_1    |  * Environment: production
web_1    |    WARNING: Do not use the development server in a production environment.
web_1    |    Use a production WSGI server instead.
web_1    |  * Debug mode: on
web_1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
web_1    |  * Restarting with stat
web_1    |  * Debugger is active!
web_1    |  * Debugger PIN: 830-423-564

查看本地网络状态,并访问http://127.0.0.1:5000,以下:

image.png

浏览器中访问docker主机ip,每次刷新网页会有一个计数:

image.png

此时列出镜像列表会返回redis和web:image.png

中止应用,能够在工做目录中经过docker-compose down中止服务,或者在启动应用的窗口中经过CTRL+C中止应用:

[root@centos7 composetest]# docker-compose down
Stopping composetest_web_1   ... done
Stopping composetest_redis_1 ... done
Removing composetest_web_1   ... done
Removing composetest_redis_1 ... done
Removing network composetest_default

第五步:编辑Comose文件添加绑定挂载

编辑项目目录中的docker-compose.yml文件,为web服务添加绑定挂载:

[root@centos7 composetest]# cat docker-compose.yml 
version: '3'
services: 
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
  redis:
    image: "redis:alpine"

新键值对volumes是将本地的项目目录composetest挂载到容器内的/code目录下,这样能够动态的修改代码,从而没必要在从新建立镜像。

第六步:使用compose从新建立和运行应用

使用docker-compose up从新建立应用:

[root@centos7 composetest]# docker-compose up
WARNING: The Docker Engine you're using is running in swarm mode.
Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.
To deploy your application across the swarm, use `docker stack deploy`.
Recreating composetest_web_1 ... done
Starting composetest_redis_1 ... done
Attaching to composetest_redis_1, composetest_web_1
redis_1  | 1:C 28 Sep 01:46:01.941 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1  | 1:C 28 Sep 01:46:01.942 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1  | 1:C 28 Sep 01:46:01.942 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis_1  | 1:M 28 Sep 01:46:01.944 # Not listening to IPv6: unsupproted
redis_1  | 1:M 28 Sep 01:46:01.945 * Running mode=standalone, port=6379.
redis_1  | 1:M 28 Sep 01:46:01.945 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_1  | 1:M 28 Sep 01:46:01.945 # Server initialized
redis_1  | 1:M 28 Sep 01:46:01.945 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
redis_1  | 1:M 28 Sep 01:46:01.945 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_1  | 1:M 28 Sep 01:46:01.945 * DB loaded from disk: 0.000 seconds
redis_1  | 1:M 28 Sep 01:46:01.945 * Ready to accept connections
web_1    |  * Serving Flask app "app" (lazy loading)
web_1    |  * Environment: production
web_1    |    WARNING: Do not use the development server in a production environment.
web_1    |    Use a production WSGI server instead.
web_1    |  * Debug mode: on
web_1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
web_1    |  * Restarting with stat
web_1    |  * Debugger is active!
web_1    |  * Debugger PIN: 328-944-619
web_1    | 192.168.39.1 - - [28/Sep/2018 01:46:13] "GET / HTTP/1.1" 200 -
web_1    |  * Detected change in '/code/app.py', reloading
web_1    |  * Restarting with stat
web_1    |  * Debugger is active!
web_1    |  * Debugger PIN: 328-944-619
web_1    | 192.168.39.1 - - [28/Sep/2018 01:49:48] "GET / HTTP/1.1" 200 -

第七步:修改应用

如今,app.py代码能够直接编辑app.py进行修改,如:

 return 'Hello World from docker! I have been seen {} times.\n'.format(count)

从新刷新,浏览器:

image.png

第八步:尝试一些其余命令

若是你但愿你的应用程序在后台运行,你能够将 -d 标记传递给 docker-compose up 并使用 docker-compose ps 来查看当前运行的应用。

$ docker-compose up -d
Starting composetest_redis_1...
Starting composetest_web_1...

$ docker-compose ps
Name                 Command            State       Ports
-------------------------------------------------------------------
composetest_redis_1   /usr/local/bin/run         Up
composetest_web_1     /bin/sh -c python app.py   Up      5000->5000/tcp

docker-compose run 命令容许你为你的应用程序运行一次性命令。例如,查看哪些环境变量能够用于 web 服务:

$ docker-compose run web env

经过 docker-compose --help 查看全部可用的命令。

若是你使用 docker-compose up -d 启动了 Compose,你可能但愿在它们运行完成后中止服务:

$ docker-compose stop

你能够停掉全部一切,使用 down 命令彻底移除容器。传递 —volumes 还能够删除 Redis 容器中所使用的数据卷。

$ docker-compose down --volumes

这时,你已经看到了 Compose 工做的基础知识。

Compose工做原理

    Docker-compose的调用过程很是的扁平,以下图所示。

image.png

                                                                    图1.compose的一次调用流程    

    以docker-compose up操做为例,docker-compose更像是docker client加强版,它为docker client引入“组”的概念,如上图所示docker-comose定义了一组“服务”来组成一个docker-comose的project,在经过service创建docker-comose.yml参数,从而与container创建关系,最后使用container来完成对docker-py(Docker client的python版)的调用,向 Daemon发起HTTP请求。

    首先,用户执行的docker-comose up指令调用了命令行的启动方式。一个docker-compose.yml定义了一个docker-compose的project,docker-compose up操做提供的命令行参数做为想这个Project的启动参数交由project模块去处理。

    而后,若是当前宿主机已经存在与该应用对应的容器,docker-comose将进行行为逻辑判断。若是用户指定能够从新启动已有服务,docker-comose就会执行service模块的容器重启方式,不然就将直接启动已有容器。这两种操做的区别在于前者会中止旧的容器,建立启动新的容器,并把旧容器移除掉。在这个过程当中建立容器的各项自定义参数都是从docker-compose up指令和docker-compose.yml中传入。

    接下来,这个方法中完成了一个Docker容器启动所需的主要参数的封装,并在Container模块执行启动。

    最后,container模块会调用docker-py客户端来执行向Docker daemon发起建立容器的POST请求,在交由Docker处理。

    

未完待续..

参考https://docs.docker.com/compose/overview/

           Docker容器与容器云

相关文章
相关标签/搜索