扩展Compose服务

Docker Compose extends关键字,在不同文件甚至不同项目共享相同的配置。扩展服务是有用的,当你有数个应用重新使用相同定义的服务。使用extends关键字,你可以定义一个服务在一个地方,然后在任何地方引用它。

当让,你可以部署相同应用在多个环境下多次,在每个实例上仅仅有一点细微的修改。因此,你可以做的不仅仅是粘贴复制配置。

理解extends配置

当定义任何服务在docker-compose.yml上,你可以像如下extends一样定义:

  1. web:
  2. extends:
  3. file: common-services.yml
  4. service: webapp

这个结构重用了webapp服务,定义在common-services.yml文件中。假设common-services.yml内容如下:

  1. webapp:
  2. build: .
  3. ports:
  4. - "8000:8000"
  5. volumes:
  6. - "/data"

在本实例,你将会得到相同的结果,如果你写好docker-compose.yml的build,ports,volumns配置都在web路径下。

你可以远端调用或者定义(重定义)配置,在docker-compose.yml里:

  1. web:
  2. extends:
  3. file: common-services.yml
  4. service: webapp
  5. environment:
  6. - DEBUG=1
  7. cpu_shares: 5

你也可以写其他的服务链接你的web服务。

  1. web:
  2. extends:
  3. file: common-services.yml
  4. service: webapp
  5. environment:
  6. - DEBUG=1
  7. cpu_shares: 5
  8. links:
  9. - db
  10. db:
  11. image: postgres

为了更加详细了解怎样使用extends,阅读下文“参考”。

自定义实例

本次,我们将有别于Compose用户指南中描述的。假设你想使用Compose既要在本地部署应用也要远端部署到生产环境中。

本地和生产环境是相似的,但是某些不同任然存在。在开发环境,你挂载应用代码作为数据卷的方式,可以很方便应用修改。在生产环境,代码需要相对于外部是不可变的。这保证它不被意外修改。开发环境使用本地Redis容器,但是生产环境,另外的团队在管理Redis服务,可以通过redis-production.example.com监听得到。

为了配置extends,你需要作如下事情:

  1. 定义web应用作为Docker镜像在Dockerfile里,以及作为Compose服务在common.yml里。

  2. 定义开发环境在标准的Compose文件里,docker-compose.yml。

  • 使用extends 拉去web服务。
  • 挂载有效代码重新加载。
  • 创建一个额外的Redis服务为本地应用使用。
  1. 定义生产环境在第三个Compose文件里, production.yml。
  • 使用extends 拉去web服务。
  • 配置wen服务,以便可以和生产环境下Redis服务进行通信。

定义web应用

定义wb应用要求如下:

  1. 创建app.py文件。

这个文件包含一个简单的Python应用,该应用使用Flask框架使HTTP和增加的Redis counter能正常使用。

  1. from flask import Flask
  2. from redis import Redis
  3. import os
  4. app = Flask(__name__)
  5. redis = Redis(host=os.environ['REDIS_HOST'], port=6379)
  6. @app.route('/')
  7. def hello():
  8. redis.incr('hits')
  9. return 'Hello World! I have been seen %s times.\n' % redis.get('hits')
  10. if __name__ == "__main__":
  11. app.run(host="0.0.0.0", debug=True)

本代码使用了一个环境变量REDIS_HOST,定义哪里发现redis服务。

  1. 定义python依赖包,在requirements.txt文件中。

    flask
    redis

  2. 创建一个Dockerfile构建一个镜像容器:

    FROM python:2.7
    ADD . /code
    WORKDIR /code
    RUN pip install -r
    requirements.txt
    CMD python app.py

  3. 创建一个Compose配置文件,叫做common.yml,其配置定义怎样运行应用。

    web:
    build: .
    ports:

    1. - "5000:5000"

当然,这本应该在docker-compose.yml文件引用,但是为了pull它在多个文件中使用extends,它需要是在单独的文件里的。

定义开发环境

  1. 创建docker-compose.yml文件。

extends参数pull得到web服务从common.yml文件那里(你创建上文里)。

  1. web:
  2. extends:
  3. file: common.yml
  4. service: web
  5. volumes:
  6. - .:/code
  7. links:
  8. - redis
  9. environment:
  10. - REDIS_HOST=redis
  11. redis:
  12. image: redis

新添加的配置文件特性如下:

  • 显示web在common.yml文件需要定义的基本配置信息。
  • 添加数据卷和指向common.yml配置的链接。
  • 设置REDIS_HOST环境变量,指向链接的redis容器。这环境使用存在的redis镜像。
  1. 运行docker-compose up。

Compose 创建,链接,并启动web和redis容器。挂载了代码到web应用中。

  1. 确认代码被挂载到,修改app.py里的信息,从Hello word修改为Hello from Compose!

不要忘了,刷新你的浏览器看到修改。

定义生产环境

差不多的东西已经定义了,现在,该定义你的生产环境了:

  1. 创建production.yml文件。

和docker-compose.yml一样, extends参数pull得到web服务从common.yml文件那里(你创建上文里)。

  1. web:
  2. extends:
  3. file: common.yml
  4. service: web
  5. environment:
  6. - REDIS_HOST=redis-production.example.com
  1. 运行docker-compose -f production.yml up

Compose创建web容器,配置redis通过REDIS_HOST环境变量。这个变量指向生产环境Redis实例。

说明:如果你尝试加载webapp在你的浏览器,你将得到一个错误redis-production.example.com不是实际的Redis服务。

你现在已经做了一个基本的extends配置。当你的应用发展,你可以做任何需要的修改在web服务上(common.yml里定义的)。Compose学会了既可以在开发环境,也可以在生产环境,当你接下来运行docker-compose时。你不必做任何粘贴与复制,你不必人为保持两个环境的同步。

Reference

You can use extends on any service together with other configuration keys. It always expects a dictionary that should always contain two keys: file and service.

The file key specifies which file to look in. It can be an absolute path or a relative one—if relative, it’s treated as relative to the current file.

The service key specifies the name of the service to extend, for example web or database.

You can extend a service that itself extends another. You can extend indefinitely. Compose does not support circular references and docker-compose returns an error if it encounters them.

Adding and overriding configuration
Compose copies configurations from the original service over to the local one, except for links and volumes_from. These exceptions exist to avoid implicit dependencies—you always define links and volumes_from locally. This ensures dependencies between services are clearly visible when reading the current file. Defining these locally also ensures changes to the referenced file don’t result in breakage.

If a configuration option is defined in both the original service and the local service, the local value either overrides or extends the definition of the original service. This works differently for other configuration options.

For single-value options like image, command or mem_limit, the new value replaces the old value. This is the default behaviour - all exceptions are listed below.

  1. # original service
  2. command: python app.py
  3. # local service
  4. command: python otherapp.py
  5. # result
  6. command: python otherapp.py

In the case of build and image, using one in the local service causes Compose to discard the other, if it was defined in the original service.

  1. # original service
  2. build: .
  3. # local service
  4. image: redis
  5. # result
  6. image: redis

  1. # original service
  2. image: redis
  3. # local service
  4. build: .
  5. # result
  6. build: .

For the multi-value options ports, expose, external_links, dns and dns_search, Compose concatenates both sets of values:

  1. # original service
  2. expose:
  3. - "3000"
  4. # local service
  5. expose:
  6. - "4000"
  7. - "5000"
  8. # result
  9. expose:
  10. - "3000"
  11. - "4000"
  12. - "5000"

In the case of environment, Compose “merges” entries together with locally-defined values taking precedence:

  1. # original service
  2. environment:
  3. - FOO=original
  4. - BAR=original
  5. # local service
  6. environment:
  7. - BAR=local
  8. - BAZ=local
  9. # result
  10. environment:
  11. - FOO=original
  12. - BAR=local
  13. - BAZ=local

Finally, for volumes, Compose “merges” entries together with locally-defined bindings taking precedence:

  1. # original service
  2. volumes:
  3. - /original-dir/foo:/foo
  4. - /original-dir/bar:/bar
  5. # local service
  6. volumes:
  7. - /local-dir/bar:/bar
  8. - /local-dir/baz/:baz
  9. # result
  10. volumes:
  11. - /original-dir/foo:/foo
  12. - /local-dir/bar:/bar
  13. - /local-dir/baz/:baz