添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Docker随着不断地发展与完善,其API接口变得越来越多,尤其在容器参数的配置方面,功能的完善势必造成参数列表的增长。若在Docker的范畴内管理容器,则唯一的途径是使用Docker client。而Docker client最原生的使用方式是:利用docker二进制文件发送命令行命令来完成容器的管理,这显然不是长久之计,很长一段时间内,全球的Docker爱好者都在探索以及寻找方便容器部署的途径。

Docker诞生于2013年3月,同年12月,基于Docker容器的部署工具Fig隆重登场。在Docker生态圈中,经过了两年多的洗礼,Fig项目得到飞速发展的同时,背后的东家也发生了很大的变化。作为Docker届容器自动化部署工具的翘楚,Fig原本是英国伦敦一家创业型公司的产品。随着产品的发展,Fig的巨大潜力受到工业界的普遍认可,在不到一年的时间内就受到Docker公司的密切关注。很快就在2014年7月双发爆出新闻:Docker收购Fig,收购完成之后,Fig改名为Compose,命令改为docker-compose。

Docker Compose的前身是Fig,它是一个定义及运行多个Docker容器的工具。使用Docker Compose你只需要在一个配置文件中定义多个Docker容器,然后使用一条命令将多个容器启动,Docker Compose会通过解析容器件的依赖关系(link, 网络容器 –net-from或数据容器 –volume-from)按先后顺序启动所定义的容器。

二、Compose介绍

探听Fig与Compose的前世今生之后,让我们回到Compose本身,认识一样新事物,从新事物的作用入手,往往不会出太大差错。而Compose最大的作用就是帮助用户缓解甚至解决容器部署的复杂性。最原始的情况下,通过Docker Client发送容器管理请求,尤其是docker run命令,一旦参数数量剧增,通过命令行终端来配置容器较为耗时,同时容错性较差。Compose则将所有容器参数通过精简的配置文件来存储,用户最终通过剪短有效的docker-compose命令管理该配置文件,完成Docker容器的部署。

编辑配置文件与编辑命令行命令的难易程度高下立判,同时配置文件数据的结构化程度越高,可读性也会越强。传统情况下,如docker run等命令的参数数量很多时,由于flag参数的书写格式各异,很容易造成用户费解的情况;而配置文件中一行内容就是一类具体的参数值,可读性大大增强。

在生产环境中,docker client还有一方面经常被Docker爱好者所诟病,那就是难以进行多容器的管理,每次管理的容器对象最多只能有1个。容器虽然运行时相对非常独立,但是很多情况下,容器之间会存在逻辑关系,如容器A使用容器B的data volume,如容器C需要对容器D执行link操作等。对于有逻辑关联的容器,如果能将其作为一个整体,被工具统一化管理,那将大大减少用户的认为参与,提高部署效率。

Compose软件的开发绝大部分是通过Python语言完成。由于Docker社区大部分项目是Go编写的,Compose使用python不利于项目间代码共享。 所幸的是,Compose社区目前已经开始着手此事,并以lib方式提供。

三、Compose架构

Docker生态圈中,Compose扮演的是部署工具的角色。用户使用Compose时,首先需要将部署意图通过配置文件的形式交给Compose。这样的需求包括:容器的服务名、容器镜像的build路径、容器运行环境的配置等。以下是一个较为简单的Compose配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
version : '2'
services :
web :
build : .
ports :
- "5000:5000"
volumes :
- / data / log : / var / log
links :
- redis
redis :
image : redis
container_name : redis - 01
hostname : live - app - redis - 01
restart : always
mem_limit : 1024M
#volumes:
#networks:

此配置文件定义了两个服务,名称分别为web以及redis。服务web的镜像可以通过docker build来构建,Dockerfile所处目录为该配置文件当前目录;服务web需要对redis服务进行links操作;最终服务web将宿主机上的5000端口映射到内部5000端口,并且挂载卷。服务redis通过镜像来创建。

配置文件是Compose体系中不可或缺,Fig时代支持的配置文件名为fig.yml以及fig.yaml;为了兼容遗留的Fig化配置,目前Compose支持的配置文件类型非常丰富,主要有以下5种:fig.yaml、docker-compose.yml、docker-compose.yaml以及用户指定的配置文件路径。可通过环境变量COMPOSE_FILE或-f参数自定义配置文件。

配置文件的存在未Compose提供了容器服务的配置信息,在此基础上,Compose通过不同的命令类型,将用户的docker-compose命令请求分发到不同的处理方法进行相应的处理。用户docker-compose的命令类型有很多,如命令请求docker-compose up….的类型为up请求,Compose将up请求分发至隶属于up的处理方法来处理;命令请求docker-compose run…..的类型为run,Compose将run请求分发至隶属于run的处理方法来处理。对于不同的docker-compose请求,Compose将调用不同的处理方法来处理。由于最终处理必须落实到Docker Daemon对容器的部署与管理上,故Compose最终必须与Docker Daemon建立连接,并在该连接之上完成Docker的API请求。事实上,Compose借助docker-py来完成此任务。docker-py是一个使用Python开发并调用docker daemon API的docker client包。需要说明的是:毕竟docker-py作为docker官方的一个Python软件包,和docker并不隶属于同一个项目,因此docker-py在很多方面的发展均会滞后于Docker。

清楚了Compose的配置文件,处理方法以及docker-py概念之后,接下来可以看一下Compose的架构,如下图:

Compose将所管理的容器分为三层,工程(project),服务(service)以及容器(contaienr)。这三个概念均为Compose抽象的数据类型,其中project会包含service以及container。首先介绍这三者的意义。

project代表用户需要完成的一个项目,何为项目?Compose的一个配置文件可以解析为一个项目,即Compose通过分析指定配置文件,得出配置文件所需完成的所有容器管理与部署操作。例如:用户在当前目录下执行docker-compose up -d,配置文件为当前目录下的配置文件docker-compose.yml,命令请求类型为up,-d为命令参数,对于配置文件中的内容,compose会将其解析为一个project。一个project拥有特定的名称,并且包含多个或一个service,同时还带有一个Docker Client。

service,代表配置文件中的每一项服务,何为服务?即以容器为粒度,用户需要Compose所完成的任务,比如前面的配置文件中包含了两个service,第一个为web,第二个为redis。一个service包含的内容,无非是用户对服务的定义。定义一个服务,可以为服务容器指定镜像,设定构建的Dockerfile,可以为其指定link的其他容器,还可以为其指定端口的映射等。

从配置文件到service,实现了用户语义到Compose语义的转换。虽然一个service尽可能详细地描述了一个容器的具体信息,但是Compose并一定必须在service之上管理容器,如果用户使用docker-compose pull redis命令,则仅仅完成redis服务中指定镜像的下载。除此之外,Compose的service还可以映射到多个容器,如果用户使用docker-compose scale web=3命令,则可以将web服务横向扩展到3个容器。

读到这里,再来说一说容器怎么解决service之间关系的依赖的。如果Compose一味按照配置文件中的书写顺序来完成service的指定任务,显然会出现一些不可避免的问题,假设多个service所描述的容器之间存在依赖关系,一旦配置文件中的顺序与实际的正常启动顺序不一致,必将导致容器启动失败。一般而言,容器依赖关系会存在以下三种情况:

  • 存在links参数,容器的启动需要链接到另一个容器,就是一个容器需要通过本地访问另一个容器的服务。
  • 存在volumes_from参数,容器的启动需要挂载另一个容器的data volume。
  • 存在net参数,容器的启动过程中网络模式采用other container模式,使用另一个容器的网络栈。
  • 为了解决这些问题,对于用户的某些请求,如docker-compose up等,Compose在解析出所有service之后,需要根据各个service的定义情况,梳理出所有的依赖关系,并最终以一个没有冲突的顺序启动所有的service容器。当然,这种情况无法应对环式依赖。

    说说links参数?

    如上dockerfile,web服务links了redis服务,什么意思呢?

    容器之间的链接实际做了什么?一个链接允许一个源容器提供信息访问给一个接收容器。在本例中,web容器作为一个接收者,允许访问源容器redis的相关服务信息。Docker创建了一个安全隧道而不需要对外公开任何端口给外部容器,因此不需要在创建容器的时候添加-p或-P指定对外公开的端口,这也是链接容器的最大好处,也就是说redis无法对外提供服务,只能由web容器来调用。

    上面也说了Docker compose不会根据服务的先后顺序来启动容器。而是经过compose自身重新编排,梳理出所有的依赖关系,并最终以一个没有冲突的顺序启动所有的service容器。如web依赖redis,那么compose就会先启动redis容器,后启动web容器。

    解决依赖,先后启动。看似很美好的一个过程,虽然compose解决了依赖,先启动redis后再启动web。如果redis服务自身启动时间比web要长,比如redis启动5,而web启动只要3秒。这个时候用户访问一样会报错,也就是说compose无法判断被依赖的容器是否可以正常提供服务,如果正常后才启动依赖者。但是我猜想后面compose一定会解决这个问题的,而现在在GitHub上有人就为这个问题写了一个小工具。

    四、docker-compose.yml参考

    每个docker-compose.yml必须定义image或者build中的一个,其它的是可选的。

  • container_name
  • 设置容器名称

    如果image不存在,Compose会尝试拉取它,除非你也指定了build,在这种情况下,它使用指定的选项构建它,并用指定的标签标记它。

    等等,更多可以参考 Docker:Compose file v2 reference

    五、安装Compose

    docker-compose是Python写的,所以可以直接使用pip去安装docker-compose。官方: Compose file reference

    $ docker-compose up -d Creating network "root_default" with the default driver Pulling redis (redis:latest)... latest: Pulling from library/redis 75a822cd7888: Pull complete e40c2fafe648: Pull complete ce384d4aea4f: Pull complete 5e29dd684b84: Pull complete 29a3c975c335: Pull complete a405554540f9: Pull complete 4b2454731fda: Pull complete Digest: sha256:eed4da4937cb562e9005f3c66eb8c3abc14bb95ad497c03dc89d66bcd172fc7f Status: Downloaded newer image for redis:latest Creating root_redis_1 Attaching to root_redis_1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $ docker - compose up - d
    Creating network "root_default" with the default driver
    Pulling redis ( redis : latest ) . . .
    latest : Pulling from library / redis
    75a822cd7888 : Pull complete
    e40c2fafe648 : Pull complete
    ce384d4aea4f : Pull complete
    5e29dd684b84 : Pull complete
    29a3c975c335 : Pull complete
    a405554540f9 : Pull complete
    4b2454731fda : Pull complete
    Digest : sha256 : eed4da4937cb562e9005f3c66eb8c3abc14bb95ad497c03dc89d66bcd172fc7f
    Status : Downloaded newer image for redis : latest
    Creating root_redis_1
    Attaching to root_redis_1
    $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9ddfcb38c9b5 redis "docker-entrypoint.sh" 30 seconds ago Up 6 seconds 6379/tcp root_redis_1 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4c486384557e redis "docker-entrypoint.sh" 6 seconds ago Up 6 seconds 0.0.0.0:6370->6379/tcp test_redis_1 f98499e1acfe redis "docker-entrypoint.sh" 5 minutes ago Up 5 minutes 0.0.0.0:6379->6379/tcp root_redis_1
    1
    2
    3
    4
    $ docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    4c486384557e redis "docker-entrypoint.sh" 6 seconds ago Up 6 seconds 0.0.0.0 : 6370 -> 6379 / tcp test_redis_1
    f98499e1acfe redis "docker-entrypoint.sh" 5 minutes ago Up 5 minutes 0.0.0.0 : 6379 -> 6379 / tcp root_redis_1

    -p :设置一个项目名称,默认是当前目录的名称。

    Docker-compose的动作包括:

    build :构建yml中某个服务的镜像,本地需存在Dockerfile文件,才使用docker-compose build来构建服务的镜像。

    config :验证和查看yml文件。

    $ docker-compose exec redis ss -nplt | grep 6379 LISTEN 0 128 *:6379 *:* LISTEN 0 128 :::6379 :::* docker-compose ps Name Command State Ports ------------------------------------------------------------------------------ root_redis_1 docker-entrypoint.sh redis ... Up 0.0.0.0:6379->6379/tcp
    1
    2
    3
    4
    docker - compose ps
    Name Command State Ports
    -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    root_redis_1 docker - entrypoint .sh redis . . . Up 0.0.0.0 : 6379 -> 6379 / tcp
  • 没有Daemon
  • 没有Deamon,也就没有高可用、HA之说。 但是同时没有Deamon,所用动作需要用户自己触发。AutoScaling、self healing等也就没有办法提供。

    模型相对简单,只有service。 缺乏诸如网络、存储之类的资源抽象和管理。也缺乏诸如kubernetes中Pod、RC、service proxy之类的抽象,由于servie本身粒度太细,操作管理起来相对麻烦。

  • Python编写
  • 虽然我很喜欢Python语言,但是由于Docker社区大部分项目是Go编写的,Compose使用python不利于项目间代码共享。 所幸的是,Compose社区目前已经开始着手此事,并以lib方式提供。

  • 跨节点能力
  • Docker容器跨节点主机部署的需求逐步增大,稍令人失望的是,Compose目前在这方面的功能依旧不令人满意。实际应用场景下,Docker用户往往希望将不同类型的容器部署在不同的Docker节点上,满足负载、安全、资源利用等多方面的考虑。虽然Compose目前不具备这样的能力,但并不以为着Docker会放弃这方面的市场,再等等……..

    九、Compose与Swarm

    Docker容器跨节点部署方案的发展,用”需求决定方向”来形容再准确不过。目前,Docker正在酝酿着Compose与Swarm的深度结合,目标是:使用户在一个Swarm集群上运行Compose来部署容器,效果和在单机上使用Compose完全一致。

    先分析跨节点容器没有依赖的情况,容器之间一旦没有依赖,容器对自身所处的节点位置也就没有太多需求。这种情况下,理论上,Compose完全可以通过Swarm的label环境变量,将容器与满足条件的Docker Node联系在一起;同时也可以通过环境变量affinity,使几个容器部署在同一个Docker Node上或者避免在同一个Docker Node上。

    再研究跨节点容器存在依赖的情况,跨节点容器有依赖,第一个需要解决的问题是跨节点容器的通信能力。而在Docker的范畴内,如果不借助其他工具,跨节点容器的通信目前还没有很好的支持。因此,如links、volumes_from、net:container等容器依赖的情况,目前还会默认将相应的容器部署在同一台机器上运行。

    https://docs.docker.com/compose/

    https://docs.docker.com/compose/compose-file/


    如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
    喜欢 ( 1 )
  • 版权声明

    本站的文章和资源来自互联网或者站长
    的原创,按照 CC BY -NC -SA 3.0 CN
    协议发布和共享,转载或引用本站文章
    应遵循相同协议。如果有侵犯版权的资
    源请尽快联系站长,我们会在24h内删
    除有争议的资源。
  • Linux
  • Database
  • Network
  • Python
  • Ansible中文权威
  • 运维进行时
  • DB-engines
  • Python 3
  • MySQL Blog
  • Redis中文指南
  • Redis命令手册
  • 运维那点事

  •