diff --git a/README.md b/README.md index 0fbe2cb..ffbece6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Docker — 从入门到实践 -0.8.1 +0.8.2 [Docker](http://www.docker.com) 是个划时代的开源项目,它彻底释放了计算虚拟化的威力,极大提高了应用的运行效率,降低了云计算资源供应的成本! 使用 Docker,可以让应用的部署、测试和分发都变得前所未有的高效和轻松! diff --git a/SUMMARY.md b/SUMMARY.md index e2a1199..20a18d3 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -84,7 +84,7 @@ * [联合文件系统](underly/ufs.md) * [容器格式](underly/container_format.md) * [网络](underly/network.md) -* [Docker Compose 项目](compose/README.md) +* [Docker 三剑客之 Compose 项目](compose/README.md) * [简介](compose/intro.md) * [安装与卸载](compose/install.md) * [使用](compose/usage.md) @@ -93,16 +93,18 @@ * [实战 Django](compose/django.md) * [实战 Rails](compose/rails.md) * [实战 wordpress](compose/wordpress.md) -* [Docker Machine 项目](machine/README.md) +* [Docker 三剑客之 Machine 项目](machine/README.md) * [简介](machine/intro.md) * [安装](machine/install.md) * [使用](machine/usage.md) -* [Docker Swarm 项目](swarm/README.md) - * [简介](swarm/intro.md) - * [安装](swarm/install.md) - * [使用](swarm/usage.md) - * [调度器](swarm/scheduling.md) - * [过滤器](swarm/filter.md) +* [Docker 三剑客之 Docker Swarm](swarm/README.md) + * [Swarm 简介](swarm/intro.md) + * [安装 Swarm](swarm/install.md) + * [使用 Swarm](swarm/usage.md) + * [使用其它服务发现后端](swarm/servicebackend.md) + * [Swarm 中的调度器](swarm/scheduling.md) + * [Swarm 中的过滤器](swarm/filter.md) + * [本章小结](swarm/summary.md) * [Etcd 项目](etcd/README.md) * [简介](etcd/intro.md) * [安装](etcd/install.md) @@ -117,12 +119,14 @@ * [基本概念](kubernetes/concepts.md) * [kubectl 使用](kubernetes/kubectl.md) * [架构设计](kubernetes/design.md) -* [Mesos 项目](mesos/README.md) - * [简介](mesos/intro.md) +* [Mesos - 优秀的集群资源调度平台](mesos/README.md) + * [Mesos 简介](mesos/intro.md) * [安装与使用](mesos/installation.md) * [原理与架构](mesos/architecture.md) - * [配置项解析](mesos/configuration.md) - * [常见框架](mesos/framework.md) + * [Mesos 配置项解析](mesos/configuration.md) + * [日志与监控](mesos/monitor.md) + * [常见应用框架](mesos/framework.md) + * [本章小结](mesos/summary.md) * [容器与云计算](cloud/README.md) * [简介](cloud/intro.md) * [亚马逊云](cloud/aws.md) diff --git a/mesos/README.md b/mesos/README.md index 012b3e1..ec9b7f4 100644 --- a/mesos/README.md +++ b/mesos/README.md @@ -1 +1,6 @@ -# Mesos 项目 +# Mesos - 优秀的集群资源调度平台 +Mesos 项目是源自 UC Berkeley 的对集群资源进行抽象和管理的开源项目,类似于操作系统内核,用户可以使用它很容易地实现分布式应用的自动化调度。 + +同时,Mesos 自身也很好地结合和主持了 Docker 等相关容器技术,基于 Mesos 已有的大量应用框架,可以实现用户应用的快速上线。 + +本章将介绍 Mesos 项目的安装、使用、配置以及核心的原理知识。 \ No newline at end of file diff --git a/_images/marathon.png b/mesos/_images/marathon.png similarity index 100% rename from _images/marathon.png rename to mesos/_images/marathon.png diff --git a/mesos/_images/marathon_basic0.png b/mesos/_images/marathon_basic0.png new file mode 100644 index 0000000..2b8f920 Binary files /dev/null and b/mesos/_images/marathon_basic0.png differ diff --git a/_images/mesos-architecture.png b/mesos/_images/mesos-architecture.png similarity index 100% rename from _images/mesos-architecture.png rename to mesos/_images/mesos-architecture.png diff --git a/_images/mesos.png b/mesos/_images/mesos.png similarity index 100% rename from _images/mesos.png rename to mesos/_images/mesos.png diff --git a/mesos/architecture.md b/mesos/architecture.md index 7264f4d..22b1d85 100644 --- a/mesos/architecture.md +++ b/mesos/architecture.md @@ -1,64 +1,83 @@ -## Mesos 基本原理与架构 +## 原理与架构 -首先,Mesos 自身只是一个资源调度框架,并非一整套完整的应用管理平台,本身是不能干活的。但是它可以比较容易的跟各种应用管理或者中间件平台整合,一起工作,提高资源使用效率。 +首先,再次需要强调 Mesos 自身只是一个资源调度框架,并非一整套完整的应用管理平台,所以只有 Mesos 自己是不能干活的。但是基于 Mesos,可以比较容易地为各种应用管理框架或者中间件平台(作为 Mesos 的应用)提供分布式运行能力;同时多个框架也可以同时运行在一个 Mesos 集群中,提高整体的资源使用效率。 + +Mesos 对自己定位范围的划分,使得它要完成的任务很明确,其它任务框架也可以很容易的与它进行整合。 ### 架构 -![mesos-arch](../_images/mesos-architecture.png) -master-slave 架构,master 使用 zookeeper 来做 HA。 +下面这张基本架构图来自 Mesos 官方。 -master 单独运行在管理节点上,slave 运行在各个计算任务节点上。 +![mesos 的基本架构](_images/mesos-architecture.png) -各种具体任务的管理平台,即 framework 跟 master 交互,来申请资源。 +可以看出,Mesos 采用了经典的主-从(master-slave)架构,其中主节点(管理节点)可以使用 zookeeper 来做 HA。 +Mesos master 服务将运行在主节点上,Mesos slave 服务则需要运行在各个计算任务节点上。 + +负责完成具体任务的应用框架们,跟 Mesos master 进行交互,来申请资源。 ### 基本单元 +Mesos 中有三个基本的组件:管理服务(master)、任务服务(slave)以及应用框架(framework)。 -#### master -负责整体的资源调度和逻辑控制。 +#### 管理服务 - master +跟大部分分布式系统中类似,主节点起到管理作用,将看到全局的信息,负责不同应用框架之间的资源调度和逻辑控制。应用框架需要注册到管理服务上才能被使用。 -#### slave -负责汇报本节点上的资源给 master,并负责隔离资源来执行具体的任务。 +用户和应用需要通过主节点提供的 API 来获取集群状态和操作集群资源。 -隔离机制当然就是各种容器机制了。 +#### 任务服务 - slave +负责汇报本从节点上的资源状态(空闲资源、运行状态等等)给主节点,并负责隔离本地资源来执行主节点分配的具体任务。 -#### framework -framework 是实际干活的,包括两个主要组件: +隔离机制目前包括各种容器机制,包括 LXC、Docker 等。 -* scheduler:注册到主节点,等待分配资源; -* executor:在 slave 节点上执行本framework 的任务。 +#### 应用框架 - framework +应用框架是实际干活的,包括两个主要组件: -framework 分两种:一种是对资源需求可以 scale up 或者 down 的(Hadoop、Spark);一种是对资源需求大小是固定的(MPI)。 +* 调度器(scheduler):注册到主节点,等待分配资源; +* 执行器(executor):在从节点上执行框架指定的任务(框架也可以使用 Mesos 自带的执行器,包括 shell 脚本执行器和 Docker 执行器)。 + +应用框架可以分两种:一种是对资源的需求是会扩展的(比如 Hadoop、Spark 等),申请后还可能调整;一种是对资源需求大小是固定的(MPI 等),一次申请即可。 ### 调度 -对于一个资源调度框架来说,最核心的就是调度机制,怎么能快速高效的完成对某个 framework 资源的分配(最好是能猜到它的实际需求)。 +对于一个资源调度框架来说,最核心的就是调度机制,怎么能快速高效地完成对某个应用框架资源的分配,是核心竞争力所在。最理想情况下(大部分时候都无法实现),最好是能猜到应用们的实际需求,实现最大化的资源使用率。 -#### 两层调度算法: -master 先调度一大块资源给某个 framework,framework 自己再实现内部的细粒度调度。 +Mesos 为了实现尽量优化的调度,采取了两层(two-layer)的调度算法。 -调度机制支持插件。默认是 DRF。 +#### 算法基本过程 +调度的基本思路很简单,master 先全局调度一大块资源给某个 framework,framework 自己再实现内部的细粒度调度,决定哪个任务用多少资源。两层调度简化了 Mesos master 自身的调度过程,通过将复杂的细粒度调度交由 framework 实现,避免了 Mesos master 成为性能瓶颈。 -#### 基本调度过程 -调度通过 offer 方式交互: +调度机制支持插件机制来实现不同的策略。默认是 Dominant Resource Fairness(DRF)。 -* master 提供一个 offer(一组资源) 给 framework; -* framework 可以决定要不要,如果接受的话,返回一个描述,说明自己希望如何使用和分配这些资源(可以说明只希望使用部分资源,则多出来的会被 master 收回); -* master 则根据 framework 的分配情况发送给 slave,以使用 framework 的 executor 来按照分配的资源策略执行任务。 +*注:DRF 算法细节可以参考论文《Dominant Resource Fairness: Fair Allocation of Multiple Resource Types》。其核心思想是对不同类型资源的多个请求,计算请求的主资源类型,然后根据主资源进行公平分配。* + +#### 调度过程 +调度通过 offer 发送的方式进行交互。一个 offer 是一组资源,例如 `<1 CPU, 2 GB Mem>`。 + +基本调度过程如下: + +* 首先,slave 节点会周期性汇报自己可用的资源给 master; +* 某个时候,master 收到应用框架发来的资源请求,根据调度策略,计算出来一个资源 offer 给 framework; +* framework 收到 offer 后可以决定要不要,如果接受的话,返回一个描述,说明自己希望如何使用和分配这些资源来运行某些任务(可以说明只希望使用部分资源,则多出来的会被 master 收回); +* 最后,master 则根据 framework 答复的具体分配情况发送给 slave,以使用 framework 的 executor 来按照分配的资源策略执行任务。 + +具体给出一个例子,某从节点向主节点汇报自己有 `<4 CPU, 8 GB Mem>` 的空闲资源,同时,主节点看到某个应用框架请求 `<3 CPU, 6 GB Mem>`,就创建一个 offer `` 把满足的资源发给应用框架。应用框架(的调度器)收到 offer 后觉得可以接受,就回复主节点,并告诉主节点希望运行两个任务:一个占用 `<1 CPU, 2 GB Mem>`,一个占用 一个占用 `<2 CPU, 4 GB Mem>`。主节点收到任务信息后分配任务到从节点上进行运行(实际上是应用框架的执行器来负责执行任务)。任务运行结束后资源可以被释放出来。 + +剩余的资源还可以继续分配给其他应用框架或任务。 + +应用框架在收到 offer 后,如果 offer 不满足自己的偏好(例如希望继续使用上次的 slave 节点),则可以选择拒绝 offer,等待 master 发送新的 offer 过来。另外,可以通过过滤器机制来加快资源的分配过程。 #### 过滤器 -framework 可以通过过滤器机制告诉 master 它的资源偏好,比如希望分配过来的 offer 有哪个资源,或者至少有多少资源。 +framework 可以通过过滤器机制告诉 master 它的资源偏好,比如希望分配过来的 offer 有哪个资源,或者至少有多少资源等。 -主要是为了加速资源分配的交互过程。 +过滤器可以避免某些应用资源长期分配不到所需要的资源的情况,加速整个资源分配的交互过程。 #### 回收机制 -master 可以通过回收计算节点上的任务来动态调整长期任务和短期任务的分布。 +为了避免某些任务长期占用集群中资源,Mesos 也支持回收机制。 +主节点可以定期回收计算节点上的任务所占用的资源,可以动态调整长期任务和短期任务的分布。 ### HA -#### master -master 节点存在单点失效问题,所以肯定要上 HA,目前主要是使用 zookpeer 来热备份。 +从架构上看,最为核心的节点是 master 节点。除了使用 ZooKeeper 来解决单点失效问题之外,Mesos 的 master 节点自身还提供了很高的鲁棒性。 -同时 master 节点可以通过 slave 和 framework 发来的消息重建内部状态(具体能有多快呢?这里不使用数据库可能是避免引入复杂度。)。 +Mesos master 节点在重启后,可以动态通过 slave 和 framework 发来的消息重建内部状态,虽然可能导致一定的时延,但这避免了传统控制节点对数据库的依赖。 -#### framework 通知 -framework 中相关的失效,master 将发给它的 scheduler 来通知。 +当然,为了减少 master 节点的负载过大,在集群中 slave 节点数目较多的时候,要避免把各种通知的周期配置的过短。实践中,可以通过部署多个 Mesos 集群来保持单个集群的规模不要过大。 diff --git a/mesos/configuration.md b/mesos/configuration.md index 5b447d8..bacec5d 100644 --- a/mesos/configuration.md +++ b/mesos/configuration.md @@ -1,108 +1,172 @@ ## Mesos 配置项解析 -Mesos 的 [配置项](http://mesos.apache.org/documentation/latest/configuration/) 可以通过启动时候传递参数或者配置目录下文件的方式给出(推荐方式,一目了然)。 +Mesos 支持在运行时通过命令行参数形式提供的配置项。如果是通过系统服务方式启动,也支持以配置文件或环境变量方式给出。当然,实际上最终是提取为命令行参数传递给启动命令。 -分为三种类型:通用项(master 和 slave 都支持),只有 master 支持的,以及只有 slave 支持的。 +Mesos 的配置项分为三种类型:通用项(master 和 slave 都支持),只有 master 支持的,以及只有 slave 支持的。 +Mesos 配置项比较多,下面对一些重点配置进行描述。少数为必备项,意味着必须给出配置值;另外一些是可选配置,自己带有默认值。 ### 通用项 -* `--ip=VALUE` 监听的 IP 地址 -* `--firewall_rules=VALUE` endpoint 防火墙规则,`VALUE` 可以是 JSON 格式或者存有 JSON 格式的文件路径。 -* `--log_dir=VALUE` 日志文件路径,默认不存储日志到本地 -* `--logbufsecs=VALUE` buffer 多少秒的日志,然后写入本地 -* `--logging_level=VALUE` 日志记录的最低级别 -* `--port=VALUE` 监听的端口,master 默认是 5050,slave 默认是 5051。 +通用项数量不多,主要涉及到服务绑定地址和日志信息等,包括: + +* `--advertise_ip=VALUE` 可以通过该地址访问到服务,比如应用框架访问到 master 节点; +* `--advertise_port=VALUE` 可以通过该端口访问到服务; +* `--external_log_file=VALUE` 指定存储日志的外部文件,可通过 Web 界面查看; +* `--firewall_rules=VALUE` endpoint 防火墙规则,`VALUE` 可以是 JSON 格式或者存有 JSON 格式的文件路径; +* `--ip=VALUE` 服务绑定到的IP 地址,用来监听外面过来的请求; +* `--log_dir=VALUE` 日志文件路径,如果为空(默认值)则不存储日志到本地; +* `--logbufsecs=VALUE` buffer 多少秒的日志,然后写入本地; +* `--logging_level=VALUE` 日志记录的最低级别; +* `--port=VALUE` 绑定监听的端口,master 默认是 5050,slave 默认是 5051。 ### master 专属配置项 -* `--quorum=VALUE` 必备项,使用基于 replicated-Log 的注册表时,复制的个数 -* `--work_dir=VALUE` 必备项,注册表持久化信息存储位置 -* `--zk=VALUE` 必备项,zookeepr 的接口地址,支持多个地址,之间用逗号隔离,可以为文件路径 -* `--acls=VALUE` ACL 规则或所在文件 -* `--allocation_interval=VALUE` 执行 allocation 的间隔,默认为 1sec -* `--allocator=VALUE` 分配机制,默认为 HierarchicalDRF -* `--[no-]authenticate` 是否允许非认证过的 framework 注册 -* `--[no-]authenticate_slaves` 是否允许非认证过的 slaves 注册 -* `--authenticators=VALUE` 对 framework 或 salves 进行认证时的实现机制 -* `--cluster=VALUE` 集群别名 -* `--credentials=VALUE` 存储加密后凭证的文件的路径 -* `--external_log_file=VALUE` 采用外部的日志文件 -* `--framework_sorter=VALUE` 给定 framework 之间的资源分配策略 -* `--hooks=VALUE` master 中安装的 hook 模块 -* `--hostname=VALUE` master 节点使用的主机名,不配置则从系统中获取 -* `--[no-]log_auto_initialize` 是否自动初始化注册表需要的 replicated 日志 -* `--modules=VALUE` 要加载的模块,支持文件路径或者 JSON -* `--offer_timeout=VALUE` offer 撤销的超时 -* `--rate_limits=VALUE` framework 的速率限制,比如 qps -* `--recovery_slave_removal_limit=VALUE` 限制注册表恢复后可以移除或停止的 slave 数目,超出后 master 会失败,默认是 100% -* `--slave_removal_rate_limit=VALUE slave` 没有完成健康度检查时候被移除的速率上限,例如 1/10mins 代表每十分钟最多有一个 -* `--registry=VALUE` 注册表的持久化策略,默认为 `replicated_log`,还可以为 `in_memory` -* `--registry_fetch_timeout=VALUE` 访问注册表失败超时 -* `--registry_store_timeout=VALUE` 存储注册表失败超时 -* `--[no-]registry_strict` 是否按照注册表中持久化信息执行操作,默认为 false -* `--roles=VALUE` 集群中 framework 可以所属的分配角色 -* `--[no-]root_submissions` root 是否可以提交 framework,默认为 true -* `--slave_reregister_timeout=VALUE` 新的 lead master 节点选举出来后,多久之内所有的 slave 需要注册,超时的 salve 将被移除并关闭,默认为 10mins -* `--user_sorter=VALUE` 在用户之间分配资源的策略,默认为 drf -* `--webui_dir=VALUE` webui 实现的文件目录所在,默认为 `/usr/local/share/mesos/webui` -* `--weights=VALUE` 各个角色的权重 -* `--whitelist=VALUE` 文件路径,包括发送 offer 的 slave 名单,默认为 None -* `--zk_session_timeout=VALUE` session 超时,默认为 10secs -* `--max_executors_per_slave=VALUE` 配置了 `--with-network-isolator` 时可用,限制每个 slave 同时执行任务个数 +这些配置项是针对主节点上的 Mesos master 服务的,围绕高可用、注册信息、对应用框架的资源管理等。用户应该根据本地主节点资源情况来合理的配置这些选项。 + +用户可以通过 `mesos-master --help` 命令来获取所有支持的配置项信息。 + +必须指定的配置项有三个: + +* `--quorum=VALUE` 必备项,使用基于 replicated-Log 的注册表(即利用 ZooKeeper 实现 HA)时,参与投票时的最少节点个数; +* `--work_dir=VALUE` 必备项,注册表持久化信息存储位置; +* `--zk=VALUE` 如果主节点为 HA 模式,此为必备项,指定 ZooKeepr 的服务地址,支持多个地址,之间用逗号隔离,例如 `zk://username:password@host1:port1,host2:port2,.../path`。还可以为存有路径信息的文件路径。 + + +可选的配置项有: + +* `--acls=VALUE` ACL 规则或所在文件; +* `--allocation_interval=VALUE` 执行 allocation 的间隔,默认为 1sec; +* `--allocator=VALUE` 分配机制,默认为 HierarchicalDRF; +* `--[no-]authenticate` 是否允许非认证过的 framework 注册; +* `--[no-]authenticate_slaves` 是否允许非认证过的 slaves 注册; +* `--authenticators=VALUE` 对 framework 或 salves 进行认证时的实现机制; +* `--cluster=VALUE` 集群别名,显示在 Web 界面上供用户识别的; +* `--credentials=VALUE` 存储加密后凭证的文件的路径; +* `--external_log_file=VALUE` 采用外部的日志文件; +* `--framework_sorter=VALUE` 给定 framework 之间的资源分配策略; +* `--hooks=VALUE` master 中安装的 hook 模块; +* `--hostname=VALUE` master 节点使用的主机名,不配置则从系统中获取; +* `--[no-]log_auto_initialize` 是否自动初始化注册表需要的 replicated 日志; +* `--modules=VALUE` 要加载的模块,支持文件路径或者 JSON; +* `--offer_timeout=VALUE` offer 撤销的超时; +* `--rate_limits=VALUE` framework 的速率限制,即 query per second (qps); +* `--recovery_slave_removal_limit=VALUE` 限制注册表恢复后可以移除或停止的 slave 数目,超出后 master 会失败,默认是 100%; +* `--slave_removal_rate_limit=VALUE slave` 没有完成健康度检查时候被移除的速率上限,例如 1/10mins 代表每十分钟最多有一个; +* `--registry=VALUE` 注册表信息的持久化策略,默认为 `replicated_log` 存放本地,还可以为 `in_memory` 放在内存中; +* `--registry_fetch_timeout=VALUE` 访问注册表失败超时; +* `--registry_store_timeout=VALUE` 存储注册表失败超时; +* `--[no-]registry_strict` 是否按照注册表中持久化信息执行操作,默认为 false; +* `--roles=VALUE` 集群中 framework 可以所属的分配角色; +* `--[no-]root_submissions` root 是否可以提交 framework,默认为 true; +* `--slave_reregister_timeout=VALUE` 新的 lead master 节点选举出来后,多久之内所有的 slave 需要注册,超时的 salve 将被移除并关闭,默认为 10mins; +* `--user_sorter=VALUE` 在用户之间分配资源的策略,默认为 drf; +* `--webui_dir=VALUE` webui 实现的文件目录所在,默认为 `/usr/local/share/mesos/webui`; +* `--weights=VALUE` 各个角色的权重; +* `--whitelist=VALUE` 文件路径,包括发送 offer 的 slave 名单,默认为 None; +* `--zk_session_timeout=VALUE` session 超时,默认为 10secs; +* `--max_executors_per_slave=VALUE` 配置了 `--with-network-isolator` 时可用,限制每个 slave 同时执行任务个数。 + +下面给出一个由三个节点组成的 master 集群典型配置,工作目录指定为 `/tmp/mesos`,集群名称为 `mesos_cluster`。 + +```sh +mesos-master \ +--zk=zk://10.0.0.2:2181,10.0.0.3:2181,10.0.0.4:2181/mesos \ +--quorum=2 \ +--work_dir=/tmp/mesos \ +--cluster=mesos_cluster +``` + ### slave 专属配置项 -* `--master=VALUE` 必备项,master 所在地址,或 zookeeper 地址,或文件路径,可以是列表 -* `--attributes=VALUE` 机器属性 -* `--authenticatee=VALUE` 跟 master 进行认证时候的认证机制 -* `--[no-]cgroups_enable_cfs` 采用 CFS 进行带宽限制时候对 CPU 资源进行限制,默认为 false -* `--cgroups_hierarchy=VALUE` cgroups 的目录根位置,默认为 `/sys/fs/cgroup` -* `--[no-]cgroups_limit_swap` 限制内存和 swap,默认为 false,只限制内存 -* `--cgroups_root=VALUE` 根 cgroups 的名称,默认为 mesos -* `--container_disk_watch_interval=VALUE` 为容器进行硬盘配额查询的时间间隔 -* `--containerizer_path=VALUE` 采用外部隔离机制(`--isolation=external`)时候,外部容器机制执行文件路径 -* `--containerizers=VALUE` 可用的容器实现机制,包括 mesos、external、docker -* `--credential=VALUE` 加密后凭证,或者所在文件路径 -* `--default_container_image=VALUE` 采用外部容器机制时,任务缺省使用的镜像 -* `--default_container_info=VALUE` 容器信息的缺省值 -* `--default_role=VALUE` 资源缺省分配的角色 -* `--disk_watch_interval=VALUE` 硬盘使用情况的周期性检查间隔,默认为 1mins -* `--docker=VALUE` docker 执行文件的路径 -* `--docker_remove_delay=VALUE` 删除容器之前的等待时间,默认为 6hrs -* `--[no-]docker_kill_orphans` 清除孤儿容器,默认为 true -* `--docker_sock=VALUE` docker sock 地址,默认为 `/var/run/docker.sock` -* `--docker_mesos_image=VALUE` 运行 slave 的 docker 镜像,如果被配置,docker 会假定 slave 运行在一个 docker 容器里 -* `--docker_sandbox_directory=VALUE` sandbox 映射到容器里的哪个路径 -* `--docker_stop_timeout=VALUE` 停止实例后等待多久执行 kill 操作,默认为 0secs -* `--[no-]enforce_container_disk_quota` 是否启用容器配额限制,默认为 false -* `--executor_registration_timeout=VALUE` 执行应用最多可以等多久再注册到 slave,否则停止它,默认为 1mins -* `--executor_shutdown_grace_period=VALUE` 执行应用停止后,等待多久,默认为 5secs -* `--external_log_file=VALUE` 外部日志文件 -* `--frameworks_home=VALUE` 执行应用前添加的相对路径,默认为空 -* `--gc_delay=VALUE` 多久清理一次执行应用目录,默认为 1weeks -* `--gc_disk_headroom=VALUE` 调整计算最大执行应用目录年龄的硬盘留空量,默认为 0.1 -* `--hadoop_home=VALUE` hadoop 安装目录,默认为空,会自动查找 HADOOP_HOME 或者从系统路径中查找 -* `--hooks=VALUE` 安装在 master 中的 hook 模块列表 -* `--hostname=VALUE` slave 节点使用的主机名 -* `--isolation=VALUE` 隔离机制,例如 `posix/cpu,posix/mem`(默认)或者 `cgroups/cpu,cgroups/mem` -* `--launcher_dir=VALUE` mesos 可执行文件的路径,默认为 `/usr/local/lib/mesos` -* `--modules=VALUE` 要加载的模块,支持文件路径或者 JSON -* `--perf_duration=VALUE` perf 采样时长,必须小于 perf_interval,默认为 10secs -* `--perf_events=VALUE` perf 采样的事件 -* `--perf_interval=VALUE` perf 采样的时间间隔 -* `--recover=VALUE` 回复后是否重连上旧的执行应用 -* `--recovery_timeout=VALUE` slave 恢复时的超时,太久则所有相关的执行应用将自行退出,默认为 15mins -* `--registration_backoff_factor=VALUE` 跟 master 进行注册时候的重试时间间隔算法的因子,默认为 1secs,采用随机指数算法,最长 1mins -* `--resource_monitoring_interval=VALUE` 周期性监测执行应用资源使用情况的间隔,默认为 1secs -* `--resources=VALUE` 每个 slave 可用的资源 -* `--slave_subsystems=VALUE` slave 运行在哪些 cgroup 子系统中,包括 memory,cpuacct 等,缺省为空 -* `--[no-]strict` 是否认为所有错误都不可忽略,默认为 true -* `--[no-]switch_user` 用提交任务的用户身份来运行,默认为 true -* `--fetcher_cache_size=VALUE` fetcher 的 cache 大小,默认为 2 GB -* `--fetcher_cache_dir=VALUE` fetcher cache 文件存放目录,默认为 /tmp/mesos/fetch -* `--work_dir=VALUE` framework 的工作目录,默认为 /tmp/mesos +slave 节点支持的配置项是最多的,因为它所完成的事情也最复杂。这些配置项既包括跟主节点打交道的一些参数,也包括对本地资源的配置,包括隔离机制、本地任务的资源限制等。 -下面的选项需要配置 `--with-network-isolator` 一起使用 -* `--ephemeral_ports_per_container=VALUE` 分配给一个容器的临时端口,默认为 1024 -* `--eth0_name=VALUE` public 网络的接口名称,如果不指定,根据主机路由进行猜测 -* `--lo_name=VALUE` loopback 网卡名称 -* `--egress_rate_limit_per_container=VALUE` 每个容器的 egress 流量限制速率 -* `--[no-]network_enable_socket_statistics` 是否采集每个容器的 socket 统计信息,默认为 false +用户可以通过 `mesos-slave --help` 命令来获取所有支持的配置项信息。 + +必备项就一个: + +* `--master=VALUE` 必备项,master 所在地址,或对应 ZooKeeper 服务地址,或文件路径,可以是列表。 + +以下为可选配置项: + +* `--attributes=VALUE` 机器属性; +* `--authenticatee=VALUE` 跟 master 进行认证时候的认证机制; +* `--[no-]cgroups_enable_cfs` 采用 CFS 进行带宽限制时候对 CPU 资源进行限制,默认为 false; +* `--cgroups_hierarchy=VALUE` cgroups 的目录根位置,默认为 `/sys/fs/cgroup`; +* `--[no-]cgroups_limit_swap` 限制内存和 swap,默认为 false,只限制内存; +* `--cgroups_root=VALUE` 根 cgroups 的名称,默认为 mesos; +* `--container_disk_watch_interval=VALUE` 为容器进行硬盘配额查询的时间间隔; +* `--containerizer_path=VALUE` 采用外部隔离机制(`--isolation=external`)时候,外部容器机制执行文件路径; +* `--containerizers=VALUE` 可用的容器实现机制,包括 mesos、external、docker; +* `--credential=VALUE` 加密后凭证,或者所在文件路径; +* `--default_container_image=VALUE` 采用外部容器机制时,任务缺省使用的镜像; +* `--default_container_info=VALUE` 容器信息的缺省值; +* `--default_role=VALUE` 资源缺省分配的角色; +* `--disk_watch_interval=VALUE` 硬盘使用情况的周期性检查间隔,默认为 1mins; +* `--docker=VALUE` docker 执行文件的路径; +* `--docker_remove_delay=VALUE` 删除容器之前的等待时间,默认为 6hrs; +* `--[no-]docker_kill_orphans` 清除孤儿容器,默认为 true; +* `--docker_sock=VALUE` docker sock 地址,默认为 `/var/run/docker.sock`; +* `--docker_mesos_image=VALUE` 运行 slave 的 docker 镜像,如果被配置,docker 会假定 slave 运行在一个 docker 容器里; +* `--docker_sandbox_directory=VALUE` sandbox 映射到容器里的哪个路径; +* `--docker_stop_timeout=VALUE` 停止实例后等待多久执行 kill 操作,默认为 0secs; +* `--[no-]enforce_container_disk_quota` 是否启用容器配额限制,默认为 false; +* `--executor_registration_timeout=VALUE` 执行应用最多可以等多久再注册到 slave,否则停止它,默认为 1mins; +* `--executor_shutdown_grace_period=VALUE` 执行应用停止后,等待多久,默认为 5secs; +* `--external_log_file=VALUE` 外部日志文件; +* `--fetcher_cache_size=VALUE` fetcher 的 cache 大小,默认为 2 GB; +* `--fetcher_cache_dir=VALUE` fetcher cache 文件存放目录,默认为 /tmp/mesos/fetch; +* `--frameworks_home=VALUE` 执行应用前添加的相对路径,默认为空; +* `--gc_delay=VALUE` 多久清理一次执行应用目录,默认为 1weeks; +* `--gc_disk_headroom=VALUE` 调整计算最大执行应用目录年龄的硬盘留空量,默认为 0.1; +* `--hadoop_home=VALUE` hadoop 安装目录,默认为空,会自动查找 HADOOP_HOME 或者从系统路径中查找; +* `--hooks=VALUE` 安装在 master 中的 hook 模块列表; +* `--hostname=VALUE` slave 节点使用的主机名; +* `--isolation=VALUE` 隔离机制,例如 `posix/cpu,posix/mem`(默认)或者 `cgroups/cpu,cgroups/mem`、`external` 等; +* `--launcher_dir=VALUE` mesos 可执行文件的路径,默认为 `/usr/local/lib/mesos`; +* `--image_providers=VALUE` 支持的容器镜像机制,例如 'APPC,DOCKER'; +* `--oversubscribed_resources_interval=VALUE` slave 节点定期汇报超配资源状态的周期; +* `--modules=VALUE` 要加载的模块,支持文件路径或者 JSON; +* `--perf_duration=VALUE` perf 采样时长,必须小于 perf_interval,默认为 10secs; +* `--perf_events=VALUE` perf 采样的事件; +* `--perf_interval=VALUE` perf 采样的时间间隔; +* `--qos_controller=VALUE` 超配机制中保障 QoS 的控制器名; +* `--qos_correction_interval_min=VALUE` Qos 控制器纠正超配资源的最小间隔,默认为 0secs; +* `--recover=VALUE` 回复后是否重连旧的执行应用,reconnect(默认值)是重连,cleanup 清除旧的执行器并退出; +* `--recovery_timeout=VALUE` slave 恢复时的超时,太久则所有相关的执行应用将自行退出,默认为 15mins; +* `--registration_backoff_factor=VALUE` 跟 master 进行注册时候的重试时间间隔算法的因子,默认为 1secs,采用随机指数算法,最长 1mins; +* `--resource_monitoring_interval=VALUE` 周期性监测执行应用资源使用情况的间隔,默认为 1secs; +* `--resources=VALUE` 每个 slave 可用的资源,比如主机端口默认为 [31000, 32000]; +* `--[no-]revocable_cpu_low_priority` 运行在可撤销 CPU 上容器将拥有较低优先级,默认为 true。 +* `--slave_subsystems=VALUE` slave 运行在哪些 cgroup 子系统中,包括 memory,cpuacct 等,缺省为空; +* `--[no-]strict` 是否认为所有错误都不可忽略,默认为 true; +* `--[no-]switch_user` 用提交任务的用户身份来运行,默认为 true; +* `--work_dir=VALUE` framework 的工作目录,默认为 /tmp/mesos。 + +下面这些选项需要配置 `--with-network-isolator` 一起使用(编译时需要启用 ` --with-network-isolator` 参数)。 + +* `--ephemeral_ports_per_container=VALUE` 分配给一个容器的临时端口的最大数目,需要为 2 的整数幂(默认为 1024); +* `--eth0_name=VALUE` public 网络的接口名称,如果不指定,根据主机路由进行猜测; +* `--lo_name=VALUE` loopback 网卡名称; +* `--egress_rate_limit_per_container=VALUE` 每个容器的输出流量限制速率限制(采用 fq_codel 算法来限速),单位是字节每秒; +* `--[no-]-egress_unique_flow_per_container` 是否把不同容器的流量当作彼此不同的流,避免彼此影响(默认为 false); +* `--[no-]network_enable_socket_statistics` 是否采集每个容器的 socket 统计信息,默认为 false。 + +下面给出一个典型的 slave 配置,容器为 Docker,监听在 `10.0.0.10` 地址;节点上限制 16 个 CPU、64 GB 内存,容器的非临时端口范围指定为 [31000-32000],临时端口范围指定为 [32768-57344];每个容器临时端口最多为 512 个,并且外出流量限速为 50 MB/s。 + +```sh +mesos-slave \ +--master=zk://10.0.0.2:2181,10.0.0.3:2181,10.0.0.4:2181/mesos \ +--containerizers=docker \ +--ip=10.0.0.10 \ +--isolation=cgroups/cpu,cgroups/mem,network/port_mapping \ +--resources=cpus:16;mem:64000;ports:[31000-32000];ephemeral_ports:[32768-57344] \ +--ephemeral_ports_per_container=512 \ +--egress_rate_limit_per_container=50000KB \ +--egress_unique_flow_per_container +``` + +为了避免主机分配的临时端口跟我们指定的临时端口范围冲突,需要在主机节点上进行配置。 +```sh +$ echo "57345 61000" > /proc/sys/net/ipv4/ip_local_port_range +``` + +*注:非临时端口是 Mesos 分配给框架,绑定到任务使用的,端口号往往有明确意义;临时端口是系统分配的,往往不太关心具体端口号。* diff --git a/mesos/framework.md b/mesos/framework.md index 8418cd5..dde1e11 100644 --- a/mesos/framework.md +++ b/mesos/framework.md @@ -1,25 +1,37 @@ -## Mesos 常见框架 +## 常见应用框架 -framework 是实际干活的,可以理解为 mesos 上跑的 `应用`,需要注册到 master 上。 +应用框架是实际干活的,可以理解为 Mesos 之上跑的 `应用`。应用框架注册到 Mesos master 服务上即可使用。 + +用户大部分时候,只需要跟应用框架打交道。因此,选择合适的应用框架十分关键。 + +Mesos 目前支持的应用框架分为四大类:长期运行任务(以及 PaaS)、大数据处理、批量调度、数据存储。 + +随着 Mesos 自身的发展,越来越多的框架开始支持 Mesos,下面总结了目前常用的一些框架。 ### 长期运行的服务 -#### [Aurora](http://aurora.incubator.apache.org/) +#### [Aurora](http://aurora.incubator.apache.org) +项目维护地址在 http://aurora.incubator.apache.org。 + 利用 mesos 调度安排的任务,保证任务一直在运行。 提供 REST 接口,客户端和 webUI(8081 端口) #### [Marathon](https://github.com/mesosphere/marathon) -一个 PaaS 平台。 +项目维护地址在 https://github.com/mesosphere/marathon。 -保证任务一直在运行。如果停止了,会自动重启一个新的任务。 +一个私有 PaaS 平台,保证运行的应用不被中断。 + +如果任务停止了,会自动重启一个新的相同任务。 支持任务为任意 bash 命令,以及容器。 提供 REST 接口,客户端和 webUI(8080 端口) #### [Singularity](https://github.com/HubSpot/Singularity) -一个 PaaS 平台。 +项目维护地址在 https://github.com/HubSpot/Singularity。 + +一个私有 PaaS 平台。 调度器,运行长期的任务和一次性任务。 @@ -27,30 +39,70 @@ framework 是实际干活的,可以理解为 mesos 上跑的 `应用`,需要 ### 大数据处理 #### [Cray Chapel](https://github.com/nqn/mesos-chapel) +项目维护地址在 https://github.com/nqn/mesos-chapel。 + 支持 Chapel 并行编程语言的运行框架。 #### [Dpark](https://github.com/douban/dpark) +项目维护地址在 https://github.com/douban/dpark。 + Spark 的 Python 实现。 #### [Hadoop](https://github.com/mesos/hadoop) +项目维护地址在 https://github.com/mesos/hadoop。 + 经典的 map-reduce 模型的实现。 -#### [Spark](http://spark.incubator.apache.org/) +#### [Spark](http://spark.incubator.apache.org) +项目维护地址在 http://spark.incubator.apache.org。 + 跟 Hadoop 类似,但处理迭代类型任务会更好的使用内存做中间状态缓存,速度要快一些。 #### [Storm](https://github.com/mesosphere/storm-mesos) +项目维护地址在 https://github.com/mesosphere/storm-mesos。 + 分布式流计算,可以实时处理数据流。 ### 批量调度 #### [Chronos](https://github.com/airbnb/chronos) -Cron 的分布式实现,负责任务调度。 +项目维护地址在 https://github.com/airbnb/chronos。 + +Cron 的分布式实现,负责任务调度,支持容错。 #### [Jenkins](https://github.com/jenkinsci/mesos-plugin) -大名鼎鼎的 CI 引擎。使用 mesos-jenkins 插件,可以将 jenkins 的任务被 mesos 来动态调度执行。 +项目维护地址在 https://github.com/jenkinsci/mesos-plugin。 -#### [ElasticSearch](https://github.com/mesosphere/elasticsearch-mesos) -功能十分强大的分布式数据搜索引擎。 +大名鼎鼎的 CI 引擎。使用 mesos-jenkins 插件,可以将 jenkins 的任务被 Mesos 集群来动态调度执行。 + +#### JobServer +项目维护地址在 http://www.grandlogic.com/content/html_docs/jobserver.html。 + +基于 Java 的调度任务和数据处理引擎。 + +#### GoDocker +项目维护地址在 https://bitbucket.org/osallou/go-docker。 + +基于 Docker 容器的集群维护工具。提供用户接口,除了支持 Mesos,还支持 Kubernetes、Swarm 等。 ### 数据存储 #### [Cassandra](https://github.com/mesosphere/cassandra-mesos) -高性能分布式数据库。 +项目维护地址在 https://github.com/mesosphere/cassandra-mesos。 + +高性能的分布式数据库。可扩展性很好,支持高可用。 + +#### [ElasticSearch](https://github.com/mesosphere/elasticsearch-mesos) +项目维护地址在 https://github.com/mesosphere/elasticsearch-mesos。 + +功能十分强大的分布式数据搜索引擎。 + +一方面通过分布式集群实现可靠的数据库,一方面提供灵活的 API,对数据进行整合和分析。ElasticSearch + LogStash + Kibana 目前合成为 ELK 工具栈。 + +#### Hypertable +项目维护地址在 https://code.google.com/p/hypertable。 + +高性能的分布式数据库,支持结构化或者非结构化的数据存储。 + +#### Tachyon +项目维护地址在 http://tachyon-project.org/。 + +内存为中心的分布式存储系统,利用内存访问的高速提供高性能。 diff --git a/mesos/installation.md b/mesos/installation.md index 419170a..903ee29 100644 --- a/mesos/installation.md +++ b/mesos/installation.md @@ -1,77 +1,116 @@ -## Mesos + Marathon 安装与使用 +## Mesos 安装与使用 +以 Mesos 结合 Marathon 应用框架为例,来看下如何快速搭建一套 Mesos 平台。 -Marathon 是可以跟 Mesos 一起协作的一个 framework,用来运行持久性的应用。 +Marathon 是可以跟 Mesos 一起协作的一个 framework,基于 Scala 实现,可以实现保持应用的持续运行。 + +另外,Mesos 默认利用 ZooKeeper 来进行多个主节点之间的选举,以及从节点发现主节点的过程。一般在生产环境中,需要启动多个 Mesos master 服务(推荐 3 或 5 个),并且推荐使用 supervisord 等进程管理器来自动保持服务的运行。 + +ZooKeeper 是一个分布式集群中信息同步的工具,通过自动在多个节点中选举 `leader`,保障多个节点之间的某些信息保持一致性。 ### 安装 -一共需要安装四种组件,mesos-master、marathon、zookeeper 需要安装到所有的主节点,mseos-slave 需要安装到从节点。 +安装主要需要 mesos、zookeeper 和 marathon 三个软件包。 -mesos 利用 zookeeper 来进行主节点的同步,以及从节点发现主节点的过程。 +Mesos 也采用了经典的主-从结构,一般包括若干主节点和大量从节点。其中,mesos master 服务和 zookeeper 需要部署到所有的主节点,mesos slave 服务需要部署到所有从节点。marathon 可以部署到主节点。 + +安装可以通过源码编译、软件源或者 Docker 镜像方式进行,下面分别进行介绍。 #### 源码编译 -下载源码 -```bash -git clone https://git-wip-us.apache.org/repos/asf/mesos.git +源码编译方式可以保障获取到最新版本,但编译过程比较费时间。 + +首先,从 apache.org 开源网站下载最新的源码。 + +```sh +$ git clone https://git-wip-us.apache.org/repos/asf/mesos.git ``` -安装依赖 +其中,主要代码在 `src` 目录下,应用框架代码在 `frameworks` 目录下,文档在 `docs` 目录下,`include ` 中包括了跟 Mesos 打交道使用的一些 API 定义头文件。 -```bash -#jdk-7 -sudo apt-get update && sudo apt-get install -y openjdk-7-jdk -#autotools -sudo apt-get install -y autoconf libtool -#Mesos dependencies. -sudo apt-get -y install build-essential python-dev python-boto libcurl4-nss-dev libsasl2-dev maven libapr1-dev libsvn-dev +安装依赖,主要包括 Java 运行环境、Linux 上的自动编译环境等。 + +```sh +$ sudo apt-get update +$ sudo apt-get install -y openjdk-8-jdk autoconf libtool \ +build-essential python-dev python-boto libcurl4-nss-dev \ +libsasl2-dev maven libapr1-dev libsvn-dev ``` -编译&安装 -```bash +后面就是常规 C++ 项目的方法,configure 之后利用 Makefile 进行编译和安装。 + +```sh $ cd mesos - -# Bootstrap (Only required if building from git repository). $ ./bootstrap - $ mkdir build -$ cd build && ../configure +$ cd build && ../configure --with-network-isolator $ make -$ make check && make install +$ make check && sudo make install ``` -#### [软件源安装](https://mesosphere.com/downloads/) -以 ubuntu 系统为例。 +#### 软件源安装 -安装 Docker,不再赘述,可以参考 [这里](http://yeasy.gitbooks.io/docker_practice/content/install/index.html)。 +通过软件源方式进行安装相对会省时间,但往往不是最新版本。 -```bash -# Setup -sudo apt-key adv --keyserver keyserver.ubuntu.com --recv E56151BF -DISTRO=$(lsb_release -is | tr '[:upper:]' '[:lower:]') -CODENAME=$(lsb_release -cs) +这里以 Ubuntu 系统为例,首先添加软件源地址。 -# Add the repository -echo "deb http://repos.mesosphere.io/${DISTRO} ${CODENAME} main" | \ - sudo tee /etc/apt/sources.list.d/mesosphere.list - -sudo apt-get -y update && sudo apt-get -y install zookeeper mesos marathon +```sh +$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv E56151BF +$ DISTRO=$(lsb_release -is | tr '[:upper:]' '[:lower:]') +$ CODENAME=$(lsb_release -cs) +$ echo "deb http://repos.mesosphere.io/${DISTRO} ${CODENAME} main" | \ +sudo tee /etc/apt/sources.list.d/mesosphere.list ``` +刷新本地软件仓库信息并安装 zookeeper、mesos、marathon 三个软件包。 + +```sh +$ sudo apt-get -y update && sudo apt-get -y install zookeeper mesos marathon +``` + +注意,Marathon 最新版本需要 jdk 1.8+ 的支持。如果系统中有多个 Java 版本,需要检查配置默认的 JDK 版本符合要求。 + +```sh +$ sudo update-alternatives --config java +``` + +安装 Mesos 成功后,会在 `/usr/sbin/` 下面发现 `mesos-master` 和 `mesos-slave` 两个二进制文件,分别对应主节点上需要运行的管理服务和从节点上需要运行的任务服务。 + +用户可以手动运行二进制文件启动服务,也可以通过 `service` 命令来方便进行管理。 + +例如,在主节点上重启 Mesos 管理服务: + +```sh +$ sudo service mesos-master restart +``` + +通过 `service` 命令来管理,实际上是通过调用 `/usr/bin/mesos-init-wrapper` 脚本文件进行处理。 + #### [基于 Docker](https://github.com/sekka1/mesosphere-docker) -将基于如下镜像: + +需要如下三个镜像。 * ZooKeeper:https://registry.hub.docker.com/u/garland/zookeeper/ * Mesos:https://registry.hub.docker.com/u/garland/mesosphere-docker-mesos-master/ * Marathon:https://registry.hub.docker.com/u/garland/mesosphere-docker-marathon/ -其中 mesos-master 镜像将作为 master 和 slave 容器使用。 +其中 mesos-master 镜像在后面将分别作为 master 和 slave 角色进行使用。 -导出本地机器的地址到环境变量。 -```bash -HOST_IP=10.11.31.7 +首先,拉取三个镜像。 + +```sh +$ docker pull garland/zookeeper +$ docker pull garland/mesosphere-docker-mesos-master +$ docker pull garland/mesosphere-docker-marathon ``` -启动 Zookeepr 容器。 -```bash +导出主节点机器的地址到环境变量。 + +```sh +$ HOST_IP=10.0.0.2 +``` + +在主节点上启动 Zookeepr 容器。 + +```sh docker run -d \ -p 2181:2181 \ -p 2888:2888 \ @@ -79,8 +118,9 @@ docker run -d \ garland/zookeeper ``` -启动 Mesos Master 容器。 -```bash +在主节点上启动 Mesos Master 服务容器。 + +```sh docker run --net="host" \ -p 5050:5050 \ -e "MESOS_HOSTNAME=${HOST_IP}" \ @@ -95,16 +135,18 @@ docker run --net="host" \ garland/mesosphere-docker-mesos-master ``` -启动 Marathon。 -```bash +在主节点上启动 Marathon。 + +```sh docker run \ -d \ -p 8080:8080 \ garland/mesosphere-docker-marathon --master zk://${HOST_IP}:2181/mesos --zk zk://${HOST_IP}:2181/marathon ``` -启动 Mesos slave 容器。 -```bash +在从节点上启动 Mesos slave 容器。 + +```sh docker run -d \ --name mesos_slave_1 \ --entrypoint="mesos-slave" \ @@ -119,73 +161,227 @@ garland/mesosphere-docker-mesos-master:latest ### 配置说明 +下面以本地通过软件源方式安装为例,解释如何修改各个配置文件。 + #### ZooKeepr -ZooKeepr 是一个分布式应用的协调工具,用来管理多个 Master 节点的选举和冗余,监听在 2181 端口。 +ZooKeepr 是一个分布式应用的协调工具,用来管理多个主节点的选举和冗余,监听在 2181 端口。推荐至少布置三个主节点来被 ZooKeeper 维护。 -配置文件在 /etc/zookeeper/conf/ 目录下。 +配置文件默认都在 `/etc/zookeeper/conf/` 目录下。比较关键的配置文件有两个:`myid` 和 `zoo.cfg`。 -首先,要修改 myid,手动为每一个节点分配一个自己的 id(1-255之间)。 +myid 文件会记录加入 ZooKeeper 集群的节点的序号(1-255之间)。`/var/lib/zookeeper/myid` 文件其实也是软连接到了该文件。 -zoo.cfg 是主配置文件,主要修改如下的三行(如果你启动三个 zk 节点)。 -```bash -server.1=zookeeper1:2888:3888 -server.2=zookeeper2:2888:3888 -server.3=zookeeper3:2888:3888 +比如配置某节点序号为 1,则需要在该节点上执行: + +```sh +$ echo 1 | sudo dd of=/etc/zookeeper/conf/myid ``` -主机名需要自己替换,并在 /etc/hosts 中更新。 +节点序号在 ZooKeeper 集群中必须唯一,不能出现多个拥有相同序号的节点。 -第一个端口负责从节点连接到主节点的;第二个端口负责主节点的选举通信。 +另外,需要修改 zoo.cfg 文件,该文件是主配置文件,主要需要添加上加入 ZooKeeper 集群的机器的序号和对应监听地址。 + +例如,现在 ZooKeeper 集群中有三个节点,地址分别为 `10.0.0.2`、`10.0.0.3`、`10.0.0.4`,序号分别配置为 `2`、`3`、`4`。 + +则配置如下的三行: + +```sh +server.2=10.0.0.2:2888:3888 +server.3=10.0.0.3:2888:3888 +server.4=10.0.0.4:2888:3888 +``` + +其中第一个端口 2888 负责从节点连接到主节点的;第二个端口 3888 则负责主节点进行选举时候通信。 + +也可以用主机名形式,则需要各个节点 `/etc/hosts` 文件中都记录地址到主机名对应的映射关系。 + +完成配置后,启动 ZooKeeper 服务。 + +```sh +$ sudo service zookeeper start +``` #### Mesos -Mesos 的默认配置目录分别为: +Mesos 的默认配置目录有三个: -* /etc/mesos:共同的配置文件,最关键的是 zk 文件; -* /etc/mesos-master:主节点的配置,等价于启动 mesos-master 时候的默认选项; -* /etc/mesos-slave:从节点的配置,等价于启动 mesos-master 时候的默认选项。 +* /etc/mesos/:主节点和从节点都会读取的配置文件,最关键的是 zk 文件存放主节点的信息; +* /etc/mesos-master/:只有主节点会读取的配置,等价于启动 mesos-master 命令时候的默认选项; +* /etc/mesos-slave/:只有从节点会读取的配置,等价于启动 mesos-master 命令时候的默认选项。 -###### 主节点 -首先在所有节点上修改 /etc/mesos/zk,为 主节点的 zookeeper 地址列表,例如: -```bash -zk://ip1:2181,ip2:2181/mesos -``` -创建 /etc/mesos-master/ip 文件,写入主节点监听的地址。 +最关键的是需要在所有节点上修改 `/etc/mesos/zk`,写入主节点集群的 ZooKeeper 地址列表,例如: -还可以创建 /etc/mesos-master/cluster 文件,写入集群的别名。 - -之后,启动服务: -```bash -sudo service mesos-master start -``` -更多选项可以参考[这里](http://open.mesosphere.com/reference/mesos-master/)。 - -###### 从节点 - -在从节点上,修改 /etc/mesos-slave/ip 文件,写入跟主节点通信的地址。 - -之后,启动服务。 -```bash -sudo service mesos-slave start +```sh +zk://10.0.0.2:2181,10.0.0.3:2181,10.0.0.4:2181/mesos ``` -更多选项可以参考[这里](http://open.mesosphere.com/reference/mesos-slave/)。 +此外,`/etc/default/mesos`、`/etc/default/mesos-master`、`/etc/default/mesos-slave` 这三个文件中可以存放一些环境变量定义,Mesos 服务启动之前,会将这些环境变量导入进来作为启动参数。格式为 `MESOS_OPTION_NAME`。 -此时,通过浏览器访问本地 5050 端口,可以看到节点信息。 +下面分别说明在主节点和从节点上的配置。 -![mesos](../_images/mesos.png) +##### 主节点 + +一般只需要关注 `/etc/mesos-master/` 目录下的文件。默认情况下目录下为空。 + +该目录下文件命名和内容需要跟 mesos-master 支持的命令行选项一一对应。可以通过 `mesos-master --help` 命令查看支持的选项。 + +例如某个文件 `key` 中内容为 `value`,则在 mesos-master 服务启动的时候,会自动添加参数 `--key=value` 给二进制命令。 + +例如,mesos-master 服务默认监听在 loopback 端口,即 `127.0.0.1:5050`,我们需要修改主节点监听的地址,则可以创建 /etc/mesos-master/ip 文件,在其中写入主节点监听的外部地址。 + +为了正常启动 mesos-master 服务,还需要指定 `work_dir` 参数(表示应用框架的工作目录)的值,可以通过创建 /etc/mesos-master/work_dir 文件,在其中写入目录,例如 ` /var/lib/mesos`。工作目录下会生成一个 `replicated_log` 目录,会存有各种同步状态的持久化信息。 + +以及指定 quorum 参数的值,该参数用来表示 ZooKeeper 集群中要求最少参加表决的节点数目。一般设置为比 ZooKeeper 集群中节点个数的半数多一些(比如三个节点的话,可以配置为 `2`)。 + +此外,要修改 Mesos 集群的名称,可以创建 `/etc/mesos-master/cluster` 文件,在其中写入集群的别名,例如 `MesosCluster`。 + +总结下,建议在 `/etc/mesos-master` 目录下,配置至少四个参数文件:`ip`、`quorum`、`work_dir`、`cluster`。 + +修改配置之后,需要启动服务即可生效。 +```sh +$ sudo service mesos-master start +``` + +更多选项可以参考后面的配置项解析章节。 + +主节点服务启动后,则可以在从节点上启动 mesos-slave 服务来加入主节点的管理。 + +##### 从节点 +一般只需要关注 `/etc/mesos-slave/` 目录下的文件。默认情况下目录下为空。 + +文件命名和内容也是跟主节点类似,对应二进制文件支持的命令行参数。 + +建议在从节点上,创建 `/etc/mesos-slave/ip` 文件,在其中写入跟主节点通信的地址。 + +修改配置之后,也需要重新启动服务。 + +```sh +$ sudo service mesos-slave start +``` + +更多选项可以参考后面的配置项解析章节。 #### Marathon -启动 marathon 服务。 -```bash -sudo service marathon start +Marathon 作为 Mesos 的一个应用框架,配置要更为简单,必需的配置项有 `--master` 和 `--zk`。 + +安装完成后,会在 /usr/bin 下多一个 marathon shell 脚本,为启动 marathon 时候执行的命令。 + +配置目录为 `/etc/marathon/conf`(需要手动创建),此外默认配置文件在 `/etc/default/marathon`。 + +我们手动创建配置目录,并添加配置项(文件命名和内容跟 Mesos 风格一致),让 Marathon 能连接到已创建的 Mesos 集群中。 + +```sh +$ sudo mkdir -p /etc/marathon/conf +$ sudo cp /etc/mesos/zk /etc/marathon/conf/master ``` -启动成功后,在 mesos 的 web界面的 frameworks 标签页下面将能看到名称为 marathon 的框架出现。 +同时,让 Marathon 也将自身的状态信息保存到 ZooKeeper 中。创建 `/etc/marathon/conf/zk` 文件,添加 ZooKeeper 地址和路径。 -同时可以通过浏览器访问 8080 端口,看到 marathon 的管理界面。 +```sh +zk://10.0.0.2:2181,10.0.0.2:2181,10.0.0.2:2181/marathon +``` -![marathon](../_images/marathon.png) +启动 marathon 服务。 + +```sh +$ sudo service marathon start +``` + +### 访问 Mesos 图形界面 + +Mesos 自带了 Web 图形界面,可以方便用户查看集群状态。 + +用户在 Mesos 主节点服务和从节点服务都启动后,可以通过浏览器访问主节点 5050 端口,看到类似如下界面,已经有两个 slave 节点加入了。 + +![mesos 界面查看加入的 slave 节点](_images/mesos.png) + +通过 Slaves 标签页能看到加入集群的从节点的信息。 + +如果没有启动 Marathon 服务,在 Frameworks 标签页下将看不到任何内容。 + +### 访问 Marathon 图形界面 + +Marathon 服务启动成功后,在 Mesos 的 web 界面的 Frameworks 标签页下面将能看到名称为 marathon 的框架出现。 + +同时可以通过浏览器访问 8080 端口,看到 Marathon 自己的管理界面。 + +![marathon 图形管理界面](_images/marathon.png) 此时,可以通过界面或者 REST API 来创建一个应用,Marathon 会保持该应用的持续运行。 + +![marathon 查看任务支持的参数](_images/marathon_basic0.png) + +通过界面方式可以看到各任务支持的参数(包括资源、命令、环境变量、健康检查等),同时可以很容易地修改任务运行实例数进行扩展,非常适合进行测试。 + +如果要更自动化地使用 Marathon,则需要通过它的 REST API 进行操作。 + +一般的,启动新任务需要先创建一个定义模板(JSON 格式),然后发到指定的 API。 + +例如,示例任务 basic-0 的定义模板为: + +```json +{ + "id": "basic-0", + "cmd": "while [ true ] ; do echo 'Hello Marathon' ; sleep 5 ; done", + "cpus": 0.1, + "mem": 10.0, + "instances": 1 +} +``` + +该任务申请资源为 0.1 个单核 CPU 资源和 10 MB 的内存资源,具体命令为每隔五秒钟用 shell 打印一句 `Hello Marathon`。 + +可以通过如下命令发出 basic-0 任务到 Marathon 框架,框架会分配任务到某个满足条件的从节点上,成功会返回一个 json 对象,描述任务的详细信息。 + +```sh +$ curl -X POST http://marathon_host:8080/v2/apps -d @basic-0.json -H "Content-type: application/json" +{"id":"/basic-0","cmd":"while [ true ] ; do echo 'Hello Marathon' ; sleep 5 ; done","args":null,"user":null,"env":{},"instances":1,"cpus":0.1,"mem":10,"disk":0,"executor":"","constraints":[],"uris":[],"storeUrls":[],"ports":[0],"requirePorts":false,"backoffSeconds":1,"backoffFactor":1.15,"maxLaunchDelaySeconds":3600,"container":null,"healthChecks":[],"dependencies":[],"upgradeStrategy":{"minimumHealthCapacity":1,"maximumOverCapacity":1},"labels":{},"acceptedResourceRoles":null,"version":"2015-12-28T05:33:05.805Z","tasksStaged":0,"tasksRunning":0,"tasksHealthy":0,"tasksUnhealthy":0,"deployments":[{"id":"3ec3fbd5-11e4-479f-bd17-813d33e43e0c"}],"tasks":[]}% +``` + +Marathon 的更多 REST API 可以参考本地自带的文档:`http://marathon_host:8080/api-console/index.html`。 + +此时,如果运行任务的从节点出现故障,任务会自动在其它可用的从节点上启动。 + +此外,目前也已经支持基于 Docker 容器的任务。需要先在 Mesos slave 节点上为 slave 服务配置 `--containerizers=docker,mesos` 参数。 + +例如如下面的示例任务: + +```json +{ + "id": "basic-3", + "cmd": "python3 -m http.server 8080", + "cpus": 0.5, + "mem": 32.0, + "container": { + "type": "DOCKER", + "volumes": [], + "docker": { + "image": "python:3", + "network": "BRIDGE", + "portMappings": [ + { + "containerPort": 8080, + "hostPort": 31000, + "servicePort": 0, + "protocol": "tcp" + } + ], + "privileged": false, + "parameters": [], + "forcePullImage": true + } + } +} +``` + +该任务启动一个 `python:3` 容器,执行 `python3 -m http.server 8080` 命令,作为一个简单的 web 服务,实际端口会映射到宿主机的 31000 端口。 + +注意区分 hostPort 和 servicePort,前者代表任务映射到的本地可用端口(可用范围由 Mesos slave 汇报,默认为 31000 ~ 32000);后者作为服务管理的端口,可以被用作一些服务发行机制使用进行转发,在整个 Marathon 集群中是唯一的。 + +任务执行后,也可以在对应 slave 节点上通过 Docker 命令查看容器运行情况,容器将以 `mesos-SLAVE_ID` 开头。 + +```sh +$ docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +1226b4ec8d7d python:3 "/bin/sh -c 'python3 " 3 days ago Up 3 days 0.0.0.0:10000->8080/tcp mesos-06db0fba-49dc-4d28-ad87-6c2d5a020866-S10.b581149e-2c43-46a2-b652-1a0bc10204b3 +``` diff --git a/mesos/intro.md b/mesos/intro.md index 4f400bf..c243c7b 100644 --- a/mesos/intro.md +++ b/mesos/intro.md @@ -1,2 +1,20 @@ ## 简介 -Mesos 是一个集群资源的自动调度平台,Apache 开源项目,它的定位是要做数据中心操作系统的内核。目前由 Mesosphere 公司维护,更多信息可以自行查阅 [Mesos 项目地址](http://mesos.apache.org/)或 [Mesosphere](https://mesosphere.com)。 +Mesos 最初由 UC Berkeley 的 AMP 实验室于 2009 年发起,遵循 Apache 协议,目前已经成立了 Mesosphere 公司进行运营。Mesos 可以将整个数据中心的资源(包括 CPU、内存、存储、网络等)进行抽象和调度,使得多个应用同时运行在集群中分享资源,并无需关心资源的物理分布情况。 + +如果把数据中心中的集群资源看做一台服务器,那么 Mesos 要做的事情,其实就是今天操作系统内核的职责:抽象资源 + 调度任务。Mesos 项目是 Mesosphere 公司 Datacenter Operating System (DCOS) 产品的核心部件。 + +Mesos 项目主要由 C++ 语言编写,项目官方地址为 [http://mesos.apache.org](http://mesos.apache.org),代码仍在快速演化中,已经发布了正式版 1.0.0 版本。 + +Mesos 拥有许多引人注目的特性,包括: +* 支持数万个节点的大规模场景(Apple、Twitter、eBay 等公司实践); +* 支持多种应用框架,包括 Marathon、Singularity、Aurora 等; +* 支持 HA(基于 ZooKeeper 实现); +* 支持 Docker、LXC 等容器机制进行任务隔离; +* 提供了多个流行语言的 API,包括 Python、Java、C++ 等; +* 自带了简洁易用的 WebUI,方便用户直接进行操作。 + +值得注意的是,Mesos 自身只是一个资源抽象的平台,要使用它往往需要结合运行其上的分布式应用(在 Mesos 中被称作框架,framework),比如 Hadoop、Spark 等可以进行分布式计算的大数据处理应用;比如 Marathon 可以实现 PaaS,快速部署应用并自动保持运行;比如 ElasticSearch 可以索引海量数据,提供灵活的整合和查询能力…… + +大部分时候,用户只需要跟这些框架打交道即可,完全无需关心底下的资源调度情况,因为 Mesos 已经自动帮你实现了。这大大方便了上层应用的开发和运维。 + +当然,用户也可以基于 Mesos 打造自己的分布式应用框架。 diff --git a/mesos/monitor.md b/mesos/monitor.md new file mode 100644 index 0000000..641b38d --- /dev/null +++ b/mesos/monitor.md @@ -0,0 +1,110 @@ +## 日志与监控 + +Mesos 自身提供了强大的日志和监控功能,某些应用框架也提供了针对框架中任务的监控能力。通过这些接口,用户可以实时获知集群的各种状态。 + +### 日志配置 +日志文件默认在 `/var/log/mesos` 目录下,根据日志等级带有不同后缀。 + +用户可以通过日志来调试使用中碰到的问题。 + +一般的,推荐使用 `--log_dir` 选项来指定日志存放路径,并通过日志分析引擎来进行监控。 + + +### 监控 + +Mesos 提供了方便的监控接口,供用户查看集群中各个节点的状态。 + +#### 主节点 +通过 `http://MASTER_NODE:5050/metrics/snapshot` 地址可以获取到 Mesos 主节点的各种状态统计信息,包括资源(CPU、硬盘、内存)使用、系统状态、从节点、应用框架、任务状态等。 + +例如查看主节点 `10.0.0.2` 的状态信息,并用 jq 来解析返回的 json 对象。 + +```sh +$ curl -s http://10.0.0.2:5050/metrics/snapshot |jq . +{ + "system/mem_total_bytes": 4144713728, + "system/mem_free_bytes": 153071616, + "system/load_5min": 0.37, + "system/load_1min": 0.6, + "system/load_15min": 0.29, + "system/cpus_total": 4, + "registrar/state_store_ms/p9999": 45.4096616192, + "registrar/state_store_ms/p999": 45.399272192, + "registrar/state_store_ms/p99": 45.29537792, + "registrar/state_store_ms/p95": 44.8336256, + "registrar/state_store_ms/p90": 44.2564352, + "registrar/state_store_ms/p50": 34.362368, + ... + "master/recovery_slave_removals": 1, + "master/slave_registrations": 0, + "master/slave_removals": 0, + "master/slave_removals/reason_registered": 0, + "master/slave_removals/reason_unhealthy": 0, + "master/slave_removals/reason_unregistered": 0, + "master/slave_reregistrations": 2, + "master/slave_shutdowns_canceled": 0, + "master/slave_shutdowns_completed": 1, + "master/slave_shutdowns_scheduled": 1 +} +``` + +#### 从节点 + +通过 `http://SLAVE_NODE:5051/metrics/snapshot` 地址可以获取到 Mesos 从节点的各种状态统计信息,包括资源、系统状态、各种消息状态等。 + +例如查看从节点 `10.0.0.10` 的状态信息。 + +```sh +$ curl -s http://10.0.0.10:5051/metrics/snapshot |jq . +{ + "system/mem_total_bytes": 16827785216, + "system/mem_free_bytes": 3377315840, + "system/load_5min": 0.11, + "system/load_1min": 0.16, + "system/load_15min": 0.13, + "system/cpus_total": 8, + "slave/valid_status_updates": 11, + "slave/valid_framework_messages": 0, + "slave/uptime_secs": 954125.458927872, + "slave/tasks_starting": 0, + "slave/tasks_staging": 0, + "slave/tasks_running": 1, + "slave/tasks_lost": 0, + "slave/tasks_killed": 2, + "slave/tasks_finished": 0, + "slave/executors_preempted": 0, + "slave/executor_directory_max_allowed_age_secs": 403050.709525191, + "slave/disk_used": 0, + "slave/disk_total": 88929, + "slave/disk_revocable_used": 0, + "slave/disk_revocable_total": 0, + "slave/disk_revocable_percent": 0, + "slave/disk_percent": 0, + "containerizer/mesos/container_destroy_errors": 0, + "slave/container_launch_errors": 6, + "slave/cpus_percent": 0.025, + "slave/cpus_revocable_percent": 0, + "slave/cpus_revocable_total": 0, + "slave/cpus_revocable_used": 0, + "slave/cpus_total": 8, + "slave/cpus_used": 0.2, + "slave/executors_registering": 0, + "slave/executors_running": 1, + "slave/executors_terminated": 8, + "slave/executors_terminating": 0, + "slave/frameworks_active": 1, + "slave/invalid_framework_messages": 0, + "slave/invalid_status_updates": 0, + "slave/mem_percent": 0.00279552715654952, + "slave/mem_revocable_percent": 0, + "slave/mem_revocable_total": 0, + "slave/mem_revocable_used": 0, + "slave/mem_total": 15024, + "slave/mem_used": 42, + "slave/recovery_errors": 0, + "slave/registered": 1, + "slave/tasks_failed": 6 +} +``` + +另外,通过 `http://MASTER_NODE:5050/monitor/statistics.json` 地址可以看到该从节点上容器网络相关的统计数据,包括进出流量、丢包数、队列情况等。获取方法同上,在此不再演示。 \ No newline at end of file diff --git a/mesos/summary.md b/mesos/summary.md new file mode 100644 index 0000000..53d5891 --- /dev/null +++ b/mesos/summary.md @@ -0,0 +1,7 @@ +## 本章小结 + +本章讲解了 Mesos 的安装使用、基本原理和架构,以及支持 Mesos 的重要应用框架。Mesos 最初设计为资源调度器,然而其灵活的设计和对上层框架的优秀支持,使得它可以很好的支持大规模的分布式应用场景。结合 Docker,Mesos 可以很容易部署一套私有的容器云。 + +除了核心功能之外,Mesos 在设计上有许多值得借鉴之处,比如它清晰的定位、简洁的架构、细致的参数、高度容错的可靠,还有对限速、监控等的支持等。 + +Mesos 作为一套成熟的开源项目,可以很好的被应用和集成到生产环境中。但它的定位集中在资源调度,往往需要结合应用框架或二次开发。 \ No newline at end of file diff --git a/revision.md b/revision.md index fa1512d..7f3259e 100644 --- a/revision.md +++ b/revision.md @@ -1,5 +1,11 @@ ## 主要修订记录 +* 0.9.0: 2017-XX-YY + + * 完善 Compose 项目 + * 更新 Swarm 项目 + * 更新 Mesos 项目 + * 0.8.0: 2017-01-08 * 修正文字内容 diff --git a/swarm/README.md b/swarm/README.md index 43f40d2..790c39d 100644 --- a/swarm/README.md +++ b/swarm/README.md @@ -1,4 +1,6 @@ -# Docker Swarm 项目 -Docker Swarm 是 Docker 官方编排(Orchestration)项目之一,负责对 Docker 集群进行管理。 +# Docker 三剑客之 Docker Swarm +Docker Swarm 是 Docker 官方三剑客项目之一,提供 Docker 容器集群服务,是 Docker 官方对容器云生态进行支持的核心方案。 -本章将介绍 Swarm 项目情况以及安装和使用。 +使用它,用户可以将多个 Docker 主机封装为单个大型的虚拟 Docker 主机,快速打造一套容器云平台。 + +本章将介绍 Swarm 项目的相关情况,以及如何进行安装和使用。最后还对 Swarm 的服务发现后端、调度器和过滤器等功能进行讲解。 diff --git a/swarm/_images/docker_swarm.png b/swarm/_images/docker_swarm.png new file mode 100644 index 0000000..1631913 Binary files /dev/null and b/swarm/_images/docker_swarm.png differ diff --git a/swarm/_images/swarm.png b/swarm/_images/swarm.png new file mode 100644 index 0000000..4af7b27 Binary files /dev/null and b/swarm/_images/swarm.png differ diff --git a/swarm/filter.md b/swarm/filter.md index e9a3eb7..ce84bcf 100644 --- a/swarm/filter.md +++ b/swarm/filter.md @@ -1,100 +1,108 @@ -## Swarm 过滤器 -swarm 的调度器(scheduler)在选择节点运行容器的时候支持几种过滤器 (filter):Constraint,Affinity,Port,Dependency,Health +## Swarm 中的过滤器 -可以在执行 `swarm manage` 命令的时候通过 `--filter` 选项来设置。 +Swarm 的调度器可以按照指定调度策略自动分配容器到节点。但有些时候希望能对这些分配加以干预。比如说,让 IO 敏感的容器分配到安装了 SSD 的节点上;让计算敏感的容器分配到 CPU 核数多的机器上;让网络敏感的容器分配到高带宽的机房;让某些容器尽量放同一个节点……。 -###Constraint Filter -constraint 是一个跟具体节点相关联的键值对,可以看做是每个节点的标签,这个标签可以在启动docker daemon的时候指定,比如 -```bash -sudo docker -d --label label_name=label01 +这可以通过过滤器(filter)来实现,目前支持 `Constraint`、`Affinity`、`Port`、`Dependency`、`Health` 等五种过滤器。 + +### Constraint 过滤器 +Constraint 过滤器是绑定到节点的键值对,相当于给节点添加标签。 + +可在启动 Docker 服务的时候指定,例如指定某个节点颜色为 `red`。 + +```sh +$ sudo docker daemon --label color=red -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock ``` -也可以写在docker的配置文件里面(在ubuntu上面是 `/etc/default/docker`)。 +同样的,可以写在 Docker 服务的配置文件里面(以 Ubuntu 14.04 为例,是 `/etc/default/docker`)。 -在本次试验中,给083添加标签--label label_name=083,084添加标签--label label_name=084,124添加标签--label label_name=124, - -以083为例,打开/etc/default/docker文件,修改DOCKER_OPTS: -```bash -DOCKER_OPTS="-H 0.0.0.0:2375 -H unix:///var/run/docker.sock --label label_name=083" +```sh +DOCKER_OPTS="--label color=red -H 0.0.0.0:2375 -H unix:///var/run/docker.sock" ``` -在使用docker run命令启动容器的时候使用 `-e constarint:key=value` 的形式,可以指定container运行的节点。 +使用 Swarm 启动容器的时候,采用 `-e constarint:key=value` 的形式,可以过滤选择出匹配条件的节点。 -比如我们想在84上面启动一个 redis 容器。 -```bash -rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name redis_1 -d -e constraint:label_name==084 redis -fee1b7b9dde13d64690344c1f1a4c3f5556835be46b41b969e4090a083a6382d -``` -注意,是**两个**等号,不是一个等号,这一点会经常被忽略。 +例如,我们将 `192.168.0.2` 节点打上红色标签,`192.168.0.3` 节点打上绿色标签。 -接下来再在084这台机器上启动一个redis 容器。 -```bash -rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name redis_2 -d -e constraint:label_name==084 redis 4968d617d9cd122fc2e17b3bad2f2c3b5812c0f6f51898024a96c4839fa000e1 -``` -然后再在083这台机器上启动另外一个 redis 容器。 -```bash -rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name redis_3 -d -e constraint:label_name==083 redis 7786300b8d2232c2335ac6161c715de23f9179d30eb5c7e9c4f920a4f1d39570 +然后,分别启动两个容器,指定使用过滤器分别为红色和绿色。 + +```sh +$ docker -H 192.168.0.2:12375 run -d -e constraint:color==red ubuntu:14.04 ping 127.0.0.1 +252ffb48e64e9858c72241f5eedf6a3e4571b1ad926faf091db3e26672370f64 +$ docker -H 192.168.0.2:12375 run -d -e constraint:color==green ubuntu:14.04 ping 127.0.0.1 +3d6f8d7af8583416b17061d038545240c9e5c3be7067935d3ef2fbddce4b8136 ``` -现在来看下执行情况: -```bash -rio@085:~$ sudo docker -H 192.168.1.83:2376 ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -7786300b8d22 redis:latest "/entrypoint.sh redi 15 minutes ago Up 53 seconds 6379/tcp 083/redis_3 -4968d617d9cd redis:latest "/entrypoint.sh redi 16 minutes ago Up 2 minutes 6379/tcp 084/redis_2 -fee1b7b9dde1 redis:latest "/entrypoint.sh redi 19 minutes ago Up 5 minutes 6379/tcp 084/redis_1 +*注:指定标签中间是两个等号* + +查看它们将被分配到指定节点上。 + +```sh +$ docker -H 192.168.0.2:12375 ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +252ffb48e64e ubuntu:14.04 "ping 127.0.0.1" 1 minutes ago Up 1 minutes Host-2/sick_galileo +3d6f8d7af858 ubuntu:14.04 "ping 127.0.0.1" 2 minutes ago Up 2 minutes Host-3/compassionate_ritchie ``` -可以看到,执行结果跟预期的一样。 +另外,Docker 内置了一些常见的过滤器,包括 `node`、`storagedriver`、`executiondriver`、`kernelversion`、`operatingsystem` 等。这些值可以通过 `docker info` 命令查看。 -但是如果指定一个不存在的标签的话来运行容器会报错。 -```bash -rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name redis_0 -d -e constraint:label_name==0 redis -FATA[0000] Error response from daemon: unable to find a node that satisfies label_name==0 +例如,目前集群中各个节点的信息为: + +```sh +$ docker -H 192.168.0.2:12375 info +Containers: 5 +Images: 39 +Role: primary +Strategy: spread +Filters: health, port, dependency, affinity, constraint +Nodes: 2 + Host-2: 192.168.0.2:2375 + └ Containers: 4 + └ Reserved CPUs: 0 / 4 + └ Reserved Memory: 1 GiB / 4.053 GiB + └ Labels: color=red, executiondriver=native-0.2, kernelversion=3.16.0-43-generic, operatingsystem=Ubuntu 14.04.3 LTS, storagedriver=aufs + Host-3: 192.168.0.3:2375 + └ Containers: 1 + └ Reserved CPUs: 0 / 8 + └ Reserved Memory: 0 B / 16.46 GiB + └ Labels: color=green, executiondriver=native-0.2, kernelversion=3.16.0-30-generic, operatingsystem=Ubuntu 14.04.3 LTS, storagedriver=aufs +CPUs: 12 +Total Memory: 20.51 GiB +Name: 946d65606f7c ``` -###Affinity Filter -通过使用 Affinity Filter,可以让一个容器紧挨着另一个容器启动,也就是说让两个容器在同一个节点上面启动。 +### Affinity 过滤器 +Affinity 过滤器允许用户在启动一个容器的时候,让它分配到某个已有容器的节点上。 + +例如,下面我们将启动一个 nginx 容器,让它分配到已经运行某个 ubuntu 容器的节点上。 + +在 Constraint 过滤器的示例中,我们分别启动了两个 ubuntu 容器 `sick_galileo` 和 `compassionate_ritchie`,分别在 Host-2 和 Host-3 上。 -现在其中一台机器上面启动一个 redis 容器。 -```bash -rio@085:~$ sudo docker -H 192.168.1.83:2376 run -d --name redis redis -ea13eddf667992c5d8296557d3c282dd8484bd262c81e2b5af061cdd6c82158d -rio@085:~$ sudo docker -H 192.168.1.83:2376 ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -ea13eddf6679 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 6379/tcp 083/redis +现在启动一个 nginx 容器,让它跟容器 `sick_galileo` 放在一起,都放到 Host-2 节点上。可以通过 `-e affinity:container==` 参数来实现。 + +```sh +$ docker -H 192.168.0.2:12375 run -d -e affinity:container==sick_galileo nginx ``` -然后再次启动两个 redis 容器。 -```bash -rio@085:~$ sudo docker -H 192.168.1.83:2376 run -d --name redis_1 -e affinity:container==redis redis -bac50c2e955211047a745008fd1086eaa16d7ae4f33c192f50412e8dcd0a14cd -rio@085:~$ sudo docker -H 192.168.1.83:2376 run -d --name redis_1 -e affinity:container==redis redis -bac50c2e955211047a745008fd1086eaa16d7ae4f33c192f50412e8dcd0a14cd -``` -现在来查看下运行结果,可以看到三个容器都是在一台机器上运行 -```bash -rio@085:~$ sudo docker -H 192.168.1.83:2376 ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -449ed25ad239 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 6379/tcp 083/redis_2 -bac50c2e9552 redis:latest /entrypoint.sh redis 25 minutes ago Up 10 seconds 6379/tcp 083/redis_1 -ea13eddf6679 redis:latest /entrypoint.sh redis 28 minutes ago Up 3 minutes 6379/tcp 083/redis -``` -通过 `-e affinity:image=image_name` 命令可以指定只有已经下载了`image_name`镜像的机器才运行容器 -```bash -sudo docker –H 192.168.1.83:2376 run –name redis1 –d –e affinity:image==redis redis -``` -redis1 这个容器只会在已经下载了 redis 镜像的节点上运行。 +然后启动一个 redis 容器,让它跟容器 `compassionate_ritchie` 放在一起,都放到 Host-3 节点上。 -```bash -sudo docker -H 192.168.1.83:2376 run -d --name redis -e affinity:image==~redis redis -``` -这条命令达到的效果是:在有 redis 镜像的节点上面启动一个名字叫做 redis 的容器,如果每个节点上面都没有 redis 容器,就按照默认的策略启动 redis 容器。 - -###Port Filter -Port 也会被认为是一个唯一的资源 -```bash -sudo docker -H 192.168.1.83:2376 run -d -p 80:80 nginx +```sh +$ docker -H 192.168.0.2:12375 run -d -e affinity:container==compassionate_ritchie redis ``` -执行完这条命令,之后任何使用 80 端口的容器都是启动失败。 +查看所有容器运行情况。 + +```sh +$ docker -H 192.168.0.2:12375 ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +0a32f15aa8ee redis "/entrypoint.sh redis" 2 seconds ago Up 1 seconds 6379/tcp Host-3/awesome_darwin +d2b9a53e67d5 nginx "nginx -g 'daemon off" 29 seconds ago Up 28 seconds 80/tcp, 443/tcp Host-2/fervent_wilson +252ffb48e64e ubuntu:14.04 "ping 127.0.0.1" 2 minutes ago Up 2 minutes Host-2/sick_galileo +3d6f8d7af858 ubuntu:14.04 "ping 127.0.0.1" 3 minutes ago Up 3 minutes Host-3/compassionate_ritchie +``` + +### 其它过滤器 +其它过滤器的使用方法也是大同小异,例如通过 `-e affinity:image==` 来选择拥有指定镜像的节点;通过 `-e affinity:label_name==value` 来选择拥有指定标签的容器所允许的节点。 + +此外,当容器端口需要映射到宿主机指定端口号的时候,Swarm 也会自动分配容器到指定宿主机端口可用的节点。 + +当不同容器之间存在数据卷或链接依赖的时候,Swarm 会分配这些容器到同一个节点上。 diff --git a/swarm/install.md b/swarm/install.md index fa9c159..cfc26d1 100644 --- a/swarm/install.md +++ b/swarm/install.md @@ -1,9 +1,81 @@ -## 安装 -安装swarm的最简单的方式是使用Docker官方的swarm镜像 -> $ sudo docker pull swarm +## 安装 Swarm +Swarm 安装有几种方式,可以基于 Docker Machine 来进行安装,也可以手动配置。为了能更容易理解 Swarm 的组件和更灵活的进行管理,推荐使用手动配置方式。 -可以使用下面的命令来查看swarm是否成功安装。 - > $ sudo docker run --rm swarm -v - - 输出下面的形式则表示成功安装(具体输出根据swarm的版本变化) -> swarm version 0.2.0 (48fd993) +对于 Docker 1.12+ 版本,Swarm 相关命令已经原生嵌入到了 Docker engine 的支持,对于较低版本的 Docker,需要额外进行配置。 + +### 下载镜像 +Docker 官方已经提供了 Swarm 镜像使用,需要在所有被 Swarm 管理的 Docker 主机上下载该镜像。 + +```sh +$ docker pull swarm +``` + +可以使用下面的命令来查看 Swarm 版本,验证是否成功下载 Swarm 镜像。 + +```sh +$ docker run --rm swarm -v +swarm version 1.2.2 (34e3da3) +``` + +### 配置节点 +Docker 主机在加入 Swarm 集群前,需要进行一些简单配置,添加 Docker daemon 的网络监听。 + +例如,在启动 Docker daemon 的时候通过 `-H` 参数: + +```sh +$ sudo docker daemon -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock +``` + +*注:Docker 1.8.0 版本之前不支持 daemon 命令,可以用 -d 代替。* + +如果是通过服务方式启动,则需要修改服务的配置文件。 + +以 Ubuntu 14.04 为例,配置文件为 `/etc/default/docker`(其他版本的 Linux 上略有不同)。 + +在文件的最后添加: + +```sh +DOCKER_OPTS="$DOCKER_OPTS -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock" +``` + +### 启动集群 +Docker 集群管理需要使用服务发现(Service Discover)功能,Swarm 支持以下的几种方式:DockerHub、本地文件、etcd、consel、zookeeper 和手动指定节点 IP 地址信息等。 + +除了手动指定外,这些方法原理上都是通过维护一套数据库机制,来管理集群中注册节点的 Docker daemon 的访问信息。 + +本地配置集群推荐使用 consel 作为服务发现后端。利用社区提供的 Docker 镜像,整个过程只需要三步即可完成。 + +#### 启动 Consel 服务后端 +启动 consel 服务容器,映射到主机的 8500 端口。 + +```sh +$ docker run -d -p 8500:8500 --name=consul progrium/consul -server -bootstrap +``` + +获取到本地主机的地址作为 consul 的服务地址:`:8500`。 + +#### 启动管理节点 +首先,启动一个主管理节点,映射到主机的 4000 端口,并获取所在主机地址为 ``。其中 4000 端口是 Swarm 管理器的默认监听端口,用户也可以指定映射为其它端口。 + +```sh +$ docker run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise :4000 consul://:8500 +``` + +为了提高高可用性,用户也可以启动从管理节点。假定获取所在主机地址为 ``。 + +```sh +$ docker run -d swarm manage -H :4000 --replication --advertise :4000 consul://:8500 +``` + +#### 启动工作节点 +需要在每个工作节点上启动 agent 服务。 + +获取节点的主机地址为 ``,并指定前面获取到的 consel 服务地址。 + +```sh +$ docker run -d swarm join --advertise=:2375 consul://:8500 +``` + +节点启动后,用户可以指定 Docker 服务地址为 `:4000>` 来测试各种 Docker 命令,可以看到整个 Swarm 集群就像一个虚拟的 Docker 主机一样正常工作。 + +由于 Swarm 实际上是通过 agent 调用了本地的 Docker daemon 来运行容器,当 Swarm 集群服务出现故障时,无法接受新的请求,但已经运行起来的容器将不会受到影响。 diff --git a/swarm/intro.md b/swarm/intro.md index cdde327..dbe7807 100644 --- a/swarm/intro.md +++ b/swarm/intro.md @@ -1,16 +1,16 @@ -## 简介 -Docker Swarm 是 Docker公司官方在 2014 年 12月初发布的一套管理 Docker 集群的工具。它将一群 Docker 宿主机变成一个单一的,虚拟的主机。 +## Swarm 简介 +![Docker Swarm](_images/docker_swarm.png) -Swarm 使用标准的 Docker API 接口作为其前端访问入口,换言之,各种形式的 Docker 工具比如 Dokku,Compose,Krane,Deis,docker-py,Docker 本身等都可以很容易的与 Swarm 进行集成。 +Docker Swarm 是 Docker 公司推出的官方容器集群平台,基于 Go 语言实现,代码开源在 [https://github.com/docker/swarm](https://github.com/docker/swarm)。目前,包括 Rackspace 等平台都采用了 Swarm,用户也很容易在 AWS 等公有云平台使用 Swarm。 -![Swarm 结构图](../_images/swarm.png) +Swarm 的前身是 Beam 项目和 libswarm 项目,首个正式版本(Swarm V1)在 2014 年 12 月初发布。为了提高可扩展性,2016 年 2 月对架构进行重新设计,推出了 V2 版本,支持超过 1K 个节点。最新的 Docker Engine 已经集成了 SwarmKit,加强了对 Swarm 的协作支持。 -在使用 Swarm 管理docker 集群时,会有一个 swarm manager 以及若干的 swarm node,swarm manager上运行 swarm daemon,用户只需要跟 swarm manager 通信,然后 swarm manager 再根据discovery service的信息选择一个swarm node 来运行container。 +作为容器集群管理器,Swarm 最大的优势之一就是 100% 支持标准的 Docker API。各种基于标准 API 的工具比如 Compose、docker-py、各种管理软件,甚至 Docker 本身等都可以很容易的与 Swarm 进行集成。这大大方便了用户将原先基于单节点的系统移植到 Swarm 上。同时 Swarm 内置了对 Docker 网络插件的支持,用户可以很容易地部署跨主机的容器集群服务。 -值得注意的是 swarm daemon 只是一个任务调度器(scheduler)和路由器(router),它本身不运行容器,它只接受 Docker client 发送过来的请求,调度合适的 swarm node 来运行 container。这意味着,即使 swarm daemon 由于某些原因挂掉了,已经运行起来的容器也不会有任何影响。 +![Swarm 基本结构图](_images/swarm.png) +上图是来自官方的 V1 结构图。可以看出,Swarm 是典型的 master-slave 结构,通过发现服务来选举 manager。manager 是中心管理节点,各个 node 上运行 agent 接受 manager 的统一管理。 -有以下两点需要注意: +在 V2 中,集群中会自动通过 Raft 协议分布式选举出 manager 节点,无需额外的发现服务支持,避免了单点瓶颈。同时,V2 中内置了基于 DNS 的负载均衡和对外部负载均衡机制的集成支持。 -* 集群中的每台节点上面的 Docker 的版本都不能小于1.4 -* 为了让 swarm manager 能够跟每台 swarm node 进行通信,集群中的每台节点的 Docker daemon 都必须监听同一个网络接口。 +目前,Swarm V1 支持 Docker 版本为 1.6.0+,V2 支持 Docker 版本为 1.12.0+。本章将以 Swarm V1 为主进行介绍,并结合 V2 的部分最新特性。 diff --git a/swarm/scheduling.md b/swarm/scheduling.md index ad675bf..83be863 100644 --- a/swarm/scheduling.md +++ b/swarm/scheduling.md @@ -1,73 +1,73 @@ -## swarm 调度策略 -swarm支持多种调度策略来选择节点。每次在swarm启动container的时候,swarm会根据选择的调度策略来选择节点运行container。目前支持的有:spread,binpack和random。 +## Swarm 中的调度器 +调度是集群十分重要的功能,Swarm 目前支持三种调度策略:`spread`、`binpack` 和 `random`。 -在执行`swarm manage`命令启动 swarm 集群的时候可以通过 `--strategy` 参数来指定,默认的是spread。 +在执行`swarm manage`命令启动管理服务的时候,可以通过 `--strategy` 参数指定调度策略,默认的是 `spread`。 -spread和binpack策略会根据每台节点的可用CPU,内存以及正在运行的containers的数量来给各个节点分级,而random策略,顾名思义,他不会做任何的计算,只是单纯的随机选择一个节点来启动container。这种策略一般只做调试用。 +简单来说,这三种调度策略的优化目标如下: -使用spread策略,swarm会选择一个正在运行的container的数量最少的那个节点来运行container。这种情况会导致启动的container会尽可能的分布在不同的机器上运行,这样的好处就是如果有节点坏掉的时候不会损失太多的container。 +* `spread`:如果节点配置相同,选择一个正在运行的容器数量最少的那个节点,即尽量平摊容器到各个节点; +* `binpack`:跟 `spread` 相反,尽可能的把所有的容器放在一台节点上面运行,即尽量少用节点,避免容器碎片化。 +* `random`:直接随机分配,不考虑集群中节点的状态,方便进行测试使用。 -binpack 则相反,这种情况下,swarm会尽可能的把所有的容器放在一台节点上面运行。这种策略会避免容器碎片化,因为他会把未使用的机器分配给更大的容器,带来的好处就是swarm会使用最少的节点运行最多的容器。 +### spread 调度策略 +仍然以之前创建好的集群为例,来演示下 spread 策略的行为。 -### spread 策略 -先来演示下 spread 策略的情况。 -```bash -rio@083:~$ sudo docker run -d -p 2376:2375 -v $(pwd)/cluster:/tmp/cluster swarm manage --strategy=spread file:///tmp/cluster -7609ac2e463f435c271d17887b7d1db223a5d696bf3f47f86925c781c000cb60 -ats@sclu083:~$ sudo docker ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -7609ac2e463f swarm:latest "/swarm manage --str 6 seconds ago Up 5 seconds 0.0.0.0:2376->2375/tcp focused_babbage -``` -三台机器除了83运行了 Swarm之外,其他的都没有运行任何一个容器,现在在85这台节点上面在swarm集群上启动一个容器 -```bash -rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-1 -d -P redis -2553799f1372b432e9b3311b73e327915d996b6b095a30de3c91a47ff06ce981 -rio@085:~$ sudo docker -H 192.168.1.83:2376 ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -2553799f1372 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 192.168.1.84:32770->6379/tcp 084/node-1 -``` -启动一个 redis 容器,查看结果 -```bash +在 `192.168.0.2` 节点启动管理服务,管理 token://946d65606f7c2f49766e4dddac5b4365 的集群。 -rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-2 -d -P redis -7965a17fb943dc6404e2c14fb8585967e114addca068f233fcaf60c13bcf2190 -rio@085:~$ sudo docker -H 192.168.1.83:2376 ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -7965a17fb943 redis:latest /entrypoint.sh redis Less than a second ago Up 1 seconds 192.168.1.124:49154->6379/tcp 124/node-2 -2553799f1372 redis:latest /entrypoint.sh redis 29 minutes ago Up 4 minutes 192.168.1.84:32770->6379/tcp 084/node-1 -``` -再次启动一个 redis 容器,查看结果 -```bash -rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-3 -d -P redis -65e1ed758b53fbf441433a6cb47d288c51235257cf1bf92e04a63a8079e76bee -rio@085:~$ sudo docker -H 192.168.1.83:2376 ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -7965a17fb943 redis:latest /entrypoint.sh redis Less than a second ago Up 4 minutes 192.168.1.227:49154->6379/tcp 124/node-2 -65e1ed758b53 redis:latest /entrypoint.sh redis 25 minutes ago Up 17 seconds 192.168.1.83:32770->6379/tcp 083/node-3 -2553799f1372 redis:latest /entrypoint.sh redis 33 minutes ago Up 8 minutes 192.168.1.84:32770->6379/tcp 084/node-1 -``` -可以看到三个容器都是分布在不同的节点上面的。 - -### binpack 策略 -现在来看看binpack策略下的情况。在083上面执行命令: -```bash -rio@083:~$ sudo docker run -d -p 2376:2375 -v $(pwd)/cluster:/tmp/cluster swarm manage --strategy=binpack file:///tmp/cluster -f1c9affd5a0567870a45a8eae57fec7c78f3825f3a53fd324157011aa0111ac5 +```sh +$ docker run -d -p 12375:2375 swarm manage --strategy "spread" token://946d65606f7c2f49766e4dddac5b4365 +c6f25e6e6abbe45c8bcf75ac674f2b64d5f31a5c6070d64ba954a0309b197930 ``` -现在在集群中启动三个 redis 容器,查看分布情况: -```bash -rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-1 -d -P redis -18ceefa5e86f06025cf7c15919fa64a417a9d865c27d97a0ab4c7315118e348c -rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-2 -d -P redis -7e778bde1a99c5cbe4701e06935157a6572fb8093fe21517845f5296c1a91bb2 -rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-3 -d -P redis -2195086965a783f0c2b2f8af65083c770f8bd454d98b7a94d0f670e73eea05f8 -rio@085:~$ sudo docker -H 192.168.1.83:2376 ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -2195086965a7 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 192.168.1.83:32773->6379/tcp 083/node-3 -7e778bde1a99 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 192.168.1.83:32772->6379/tcp 083/node-2 -18ceefa5e86f redis:latest /entrypoint.sh redis 25 minutes ago Up 22 seconds 192.168.1.83:32771->6379/tcp 083/node-1 +列出集群中节点。 + +```sh +$ docker run --rm swarm list token://946d65606f7c2f49766e4dddac5b4365 +192.168.0.3:2375 +192.168.0.2:2375 ``` -可以看到,所有的容器都是分布在同一个节点上运行的。 \ No newline at end of file +此时,两个节点上除了 swarm 外都没有运行其它容器。 + +启动一个 ubuntu 容器。 + +```sh +$ docker -H 192.168.0.2:12375 run -d ubuntu:14.04 ping 127.0.0.1 +bac3dfda5306181140fc959969d738549d607bc598390f57bdd432d86f16f069 +``` + +查看发现它实际上被调度到了 `192.168.0.3` 节点(当节点配置相同时候,初始节点随机选择)。 + +再次启动一个 ubuntu 容器。 + +```sh +$ docker -H 192.168.0.2:12375 run -d ubuntu:14.04 ping 127.0.0.1 +8247067ba3a31e0cb692a8373405f95920a10389ce3c2a07091408281695281c +``` + +查看它的位置,发现被调度到了另外一个节点:`192.168.0.2` 节点。 + +```sh +$ docker -H 192.168.0.2:12375 ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +8247067ba3a3 ubuntu:14.04 "ping 127.0.0.1" 1 minutes ago Up 1 minutes Host-2/sick_galileo +bac3dfda5306 ubuntu:14.04 "ping 127.0.0.1" 2 minutes ago Up 2 minutes Host-3/compassionate_ritchie +``` + +当节点配置不同的时候,`spread`会更愿意分配到配置较高的节点上。 + +### binpack 调度策略 +现在来看看 `binpack` 策略下的情况。 + +直接启动若干 ubuntu 容器,并查看它们的位置。 + +```sh +$ docker -H 192.168.0.2:12375 run -d ubuntu:14.04 ping 127.0.0.1 +$ docker -H 192.168.0.2:12375 ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +4c4f45eba866 ubuntu:14.04 "ping 127.0.0.1" 3 minutes ago Up 3 minutes Host-3/hopeful_brown +5e650541233c ubuntu:14.04 "ping 127.0.0.1" 3 minutes ago Up 3 minutes Host-3/pensive_wright +99c5a092530a ubuntu:14.04 "ping 127.0.0.1" 3 minutes ago Up 3 minutes Host-3/naughty_engelbart +4ab392c26eb2 ubuntu:14.04 "ping 127.0.0.1" 3 minutes ago Up 3 minutes Host-3/thirsty_mclean +``` +可以看到,所有的容器都是分布在同一个节点(`192.168.0.3`)上运行的。 \ No newline at end of file diff --git a/swarm/servicebackend.md b/swarm/servicebackend.md new file mode 100644 index 0000000..f9042c0 --- /dev/null +++ b/swarm/servicebackend.md @@ -0,0 +1,97 @@ +## 使用其它服务发现后端 + +Swarm 目前可以支持多种服务发现后端,这些后端功能上都是一致的,即维护属于某个集群的节点的信息。不同方案并无优劣之分,在实际使用时候,可以结合自身需求和环境限制进行选择,甚至自己定制其它方案。 + +使用中可以通过不同的路径来选择特定的服务发现后端机制。 + +* `token://`:使用 DockerHub 提供的服务,适用于可以访问公网情况; +* `file://path/to/file`:使用本地文件,需要手动管理; +* `consul:///`:使用 consul 服务,私有环境推荐; +* `etcd://,/`:使用 etcd 服务,私有环境推荐; +* `zk://,/`:使用 zookeeper 服务,私有环境推荐; +* `[nodes://],`:手动指定集群中节点的地址,方便进行服务测试。 + +### 使用文件 + +使用本地文件的方式十分简单,就是讲所有属于某个集群的节点的 Docker daemon 信息写入一个文件中,然后让 manager 从这个文件中直接读取相关信息。 + +首先,在 Swarm 管理节点(`192.168.0.2`)上新建一个文件,把要加入集群的机器的 Docker daemon 信息写入文件: + +```sh +$ tee /tmp/cluster_info <<-'EOF' +192.168.0.2:2375 +192.168.0.3:2375 +EOF +``` + +然后,本地执行 `swarm manage` 命令,并指定服务发现机制为本地文件,注意因为是容器方式运行 manager,需要将本地文件挂载到容器内。 + +```sh +$ docker run -d -p 12375:2375 -v /tmp/cluster_info:/tmp/cluster_info swarm manage file:///tmp/cluster_info +``` + +接下来就可以通过使用 Swarm 服务来进行管理了,例如使用 info 查看所有节点的信息。 + +```sh +$ docker -H 192.168.0.2:12375 info +Containers: 18 +Images: 36 +Role: primary +Strategy: spread +Filters: health, port, dependency, affinity, constraint +Nodes: 2 + Host-1: 192.168.0.2:2375 + └ Containers: 15 + └ Reserved CPUs: 0 / 4 + └ Reserved Memory: 1 GiB / 4.053 GiB + └ Labels: executiondriver=native-0.2, kernelversion=3.16.0-43-generic, operatingsystem=Ubuntu 14.04.3 LTS, storagedriver=aufs + Host-2: 192.168.0.3:2375 + └ Containers: 3 + └ Reserved CPUs: 0 / 8 + └ Reserved Memory: 0 B / 16.46 GiB + └ Labels: executiondriver=native-0.2, kernelversion=3.16.0-30-generic, operatingsystem=Ubuntu 14.04.3 LTS, storagedriver=aufs +CPUs: 12 +Total Memory: 20.51 GiB +Name: e71eb5f1d48b +``` + +### 其它发现服务后端 +其它服务发现后端的使用方法,也是大同小异,不同之处在于使用 Swarm 命令时指定的路径格式不同。 + +例如,对于前面介绍的 consul 服务后端来说。 + +快速部署一个 consul 服务的命令为: + +```sh +$ docker run -d -p 8500:8500 --name=consul progrium/consul -server -bootstrap +``` + +之后创建 Swarm 的管理服务,指定使用 consul 服务,管理端口监听在本地的 4000 端口。 + +```sh +$ docker run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise :4000 consul://:8500 +``` + +Swarm 节点注册时候命令格式类似于: + +```sh +$ swarm join --advertise= consul:/// +``` + +对于 etcd 服务后端来说,节点注册时候命令格式类似于: + +```sh +$ swarm join --addr= etcd://,/ +``` +启动管理服务时候,格式类似于: + +```sh +$ swarm manage -H tcp://:4000 etcd://,/ +``` + +### 地址和端口的范围匹配 +对于基于文件,以及手动指定节点信息两种服务发现后端机制来说,其中地址和端口域可以支持指定一个范围,以一次性指定多个地址。 +例如: + +* `192.168.0.[2:10]:2375` 代表 `192.168.0.2:2375` -- `192.168.0.10:2375` 一共 9 个地址; +* `192.168.0.2:[2:9]375` 代表 `192.168.0.2:2375` -- `192.168.0.2:9375` 一共 8 个地址。 \ No newline at end of file diff --git a/swarm/summary.md b/swarm/summary.md new file mode 100644 index 0000000..12709a7 --- /dev/null +++ b/swarm/summary.md @@ -0,0 +1,10 @@ +## 本章小结 +本章笔者介绍了 Docker Swarm 的安装、使用和主要功能。 + +通过使用 Swarm,用户可以将若干 Docker 主机节点组成的集群当作一个大的虚拟 Docker 主机使用。并且,原先基于单机的 Docker 应用,可以无缝的迁移到 Swarm 上来。 + +实现这些功能的前提是服务自动发现能力。在现代分布式系统中,服务的自动发现、注册、更新等能力将成为系统的基本保障和重要基础。 + +在生产环境中,Swarm 的管理节点和发现服务后端要采用高可用性上的保护,可以采用集群模式。 + +值得一提的是,Swarm V2 功能已经被无缝嵌入到了 Docker 1.12+ 版本中,用户今后可以直接使用 Docker 命令来完成相关功能的配置,这将使得集群功能的管理更加简便。 \ No newline at end of file diff --git a/swarm/usage.md b/swarm/usage.md index ab6eb1c..6f40fb3 100644 --- a/swarm/usage.md +++ b/swarm/usage.md @@ -1,170 +1,181 @@ -## 使用 -在使用 swarm 管理集群前,需要把集群中所有的节点的 docker daemon 的监听方式更改为 `0.0.0.0:2375`。 +## 使用 Swarm +前面演示了基于 consel 服务发现后端来配置一个本地 Swarm 集群。其中,consel 也可以被替换为 etcd、zookeeper 等。 -可以有两种方式达到这个目的,第一种是在启动docker daemon的时候指定 -```bash -sudo docker -H 0.0.0.0:2375& +另外一个更方便的方式是直接使用 DockerHub 提供的免费服务发现后端。 + +下面使用这种方式来演示 Swarm 的主要操作,包括: + +* create:创建一个集群; +* list:列出集群中的节点; +* manage:管理一个集群; +* join:让节点加入到某个集群。 + +注意,使用 DockerHub 的服务发现后端,需要各个节点能通过公网访问到 DockerHub 的服务接口。 + +### 创建集群 id + +在任意一台安装了 Swarm 的机器上执行 `swarm create` 命令来在 DockerHub 服务上进行注册。 + +Swarm 会通过服务发现后端(此处为 DockerHub 提供)来获取一个唯一的由数字和字母组成的 token,用来标识要管理的集群。 + +```sh +$ docker run --rm swarm create +946d65606f7c2f49766e4dddac5b4365 ``` -第二种方式是直接修改 Docker 的配置文件(Ubuntu 上是 `/etc/default/docker`,其他版本的 Linux 上略有不同) +注意返回的字符串,这是集群的唯一 id,加入集群的各个节点将需要这个信息。 -在文件的最后添加下面这句代码: -```bash -DOCKER_OPTS="-H 0.0.0.0:2375 -H unix:///var/run/docker.sock" +### 配置集群节点 + +在所有要加入集群的普通节点上面执行 `swarm join` 命令,表示把这台机器加入指定集群当中。 + +例如某台机器 IP 地址为 `192.168.0.2`,将其加入我们刚创建的 `946d65606f7c2f49766e4dddac5b4365` 集群,则可以通过: + +```sh +$ docker run --rm swarm join --addr=192.168.0.2:2375 token://946d65606f7c2f49766e4dddac5b4365 +time="2015-12-09T08:59:43Z" level=info msg="Registering on the discovery service every 20s..." addr="192.168.0.2:2375" discovery="token://946d65606f7c2f49766e4dddac5b4365" +... ``` +*注:其中 `--addr` 指定的 IP 地址信息将被发送给服务发现后端,用以区分集群不同的节点。manager 服务必须要通过这个地址可以访问到该节点。* -需要注意的是,一定要在所有希望被 Swarm 管理的节点上进行的。修改之后要重启 Docker -```bash -sudo service docker restart +通过控制台可以看到,上述命令执行后,默认每隔 20 秒(可以通过 `--heartbeat` 选项指定),会输出一条心跳信息。对于发现服务后端来说,默认如果超过 60 秒(可以通过 `--ttl` 选项指定)没有收到心跳信息,则将节点从列表中删除。 + +如果不希望看到输出日志信息,则可以用 `-d` 选项替换 `--rm` 选项,让服务后台执行。 + +执行 `swarm join` 命令实际上是通过 agent 把自己的信息注册到发现服务上,因此,此时对于后端的发现服务来说,已经可以看到有若干节点注册上来了。那么,如何管理和使用这些节点呢,这就得需要 Swarm 的 manager 服务了。 + + +### 配置管理节点 +配置管理节点需要通过 `swarm manage` 命令,该命令将启动 manager 服务,默认监听到 `2375` 端口,所有对集群的管理可以通过该服务接口进行。 + +读者可能注意到,manager 服务默认监听的端口跟 Docker 服务监听端口是一样的,这是为了兼容其它基于 Docker 的服务,可以无缝地切换到 Swarm 平台上来。 + +仍然在节点 `192.168.0.2` 进行操作。由于我们是采用 Docker 容器形式启动 manager 服务,本地的 `2375` 端口已经被 Docker Daemon 占用。我们将 manager 服务监听端口映射到本地一个空闲的 `12375` 端口。 + +```sh +$ docker run -d -p 12375:2375 swarm manage token://946d65606f7c2f49766e4dddac5b4365 +1e1ca8c4117b6b7271efc693f9685b4e907d8dc95324350392b21e94b3cffd18 ``` -Docker 集群管理需要使用服务发现(Discovery service backend)功能,Swarm支持以下的几种方式:DockerHub 提供的服务发现功能,本地的文件,etcd,consul,zookeeper 和 IP 列表,本文会详细讲解前两种方式,其他的用法都是大同小异的。 +可以通过 `docker ps` 命令来查看启动的 swarm manager 服务容器。 -先说一下本次试验的环境,本次试验包括三台机器,IP地址分别为192.168.1.84,192.168.1.83和192.168.1.124.利用这三台机器组成一个docker集群,其中83这台机器同时充当swarm manager节点。 - -### 使用 DockerHub 提供的服务发现功能 - -#### 创建集群 token - -在上面三台机器中的任何一台机器上面执行 `swarm create` 命令来获取一个集群标志。这条命令执行完毕后,Swarm 会前往 DockerHub 上内置的发现服务中获取一个全球唯一的 token,用来标识要管理的集群。 -```bash -sudo docker run --rm swarm create +```sh +$ docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +1e1ca8c4117b swarm "/swarm manage token:" 11 seconds ago Up 10 seconds 0.0.0.0:12375->2375/tcp jovial_rosalind ``` -我们在84这台机器上执行这条命令,输出如下: -```bash -rio@084:~$ sudo docker run --rm swarm create -b7625e5a7a2dc7f8c4faacf2b510078e +命令如果执行成功会返回刚启动的 Swarm 容器的 ID,此时一个简单的 Swarm 集群就已经搭建起来了,包括一个普通节点和一个管理节点。 + +### 查看集群节点列表 + +集群启动成功以后,用户可以在任何一台节点上使用 `swarm list` 命令查看集群中的节点列表。例如 + +```sh +$ docker run --rm swarm list token://946d65606f7c2f49766e4dddac5b4365 +192.168.0.2:2375 +``` +显示正是之前用 `swarm join` 命令加入集群的节点的地址。 + +我们在另外一台节点 `192.168.0.3` 上同样使用 `swarm join` 命令新加入一个节点: +```sh +$docker run --rm swarm join --addr=192.168.0.3:2375 token://946d65606f7c2f49766e4dddac5b4365 +time="2015-12-10T02:05:34Z" level=info msg="Registering on the discovery service every 20s..." addr="192.168.0.3:2375" discovery="token://946d65606f7c2f49766e4dddac5b4365" +... ``` -可以看到我们返回的 token 是 `b7625e5a7a2dc7f8c4faacf2b510078e`,每次返回的结果都是不一样的。这个 token 一定要记住,后面的操作都会用到这个 token。 +再次使用 `swarm list` 命令查看集群中的节点列表信息,可以看到新加入的节点: -#### 加入集群 - -在所有要加入集群的节点上面执行 `swarm join` 命令,表示要把这台机器加入这个集群当中。在本次试验中,就是要在 83、84 和 124 这三台机器上执行下面的这条命令: -```bash -sudo docker run -d swarm join --addr=ip_address:2375 token://token_id +```sh +$ docker run --rm swarm list token://946d65606f7c2f49766e4dddac5b4365 +192.168.0.3:2375 +192.168.0.2:2375 ``` -其中的 ip_address 换成执行这条命令的机器的 IP,token_id 换成上一步执行 `swarm create` 返回的 token。 -在83这台机器上面的执行结果如下: -```bash -rio@083:~$ sudo docker run -d swarm join --addr=192.168.1.83:2375 token://b7625e5a7a2dc7f8c4faacf2b510078e -3b3d9da603d7c121588f796eab723458af5938606282787fcbb03b6f1ac2000b +### 使用集群服务 +那么,怎么使用 Swarm 提供的服务呢? + +实际上,所有 Docker 客户端可以继续使用,只要指定使用 Swarm manager 服务的监听地址即可。 + +例如,manager 服务监听的地址为 `192.168.0.2:12375`,则可以通过指定 `-H 192.168.0.2:12375` 选项来继续使用 Docker 客户端,执行任意 Docker 命令,例如 `ps`、`info`、`run` 等等。 + +在任意节点上使用 `docker run` 来启动若干容器,例如 + +```sh +$docker -H 192.168.0.2:12375:12375 run -d ubuntu ping 127.0.0.1 +4c9bccbf86fb6e2243da58c1b15e9378fac362783a663426bbe7058eea84de46 ``` -这条命令通过 `-d` 参数启动了一个容器,使得83这台机器加入到集群。如果这个容器被停止或者被删除,83这台机器就会从集群中消失。 -#### 启动swarm manager -因为我们要使用 83 这台机器充当 swarm 管理节点,所以需要在83这台机器上面执行 `swarm manage` 命令: -```bash -sudo docker run -d -p 2376:2375 swarm manage token://b7625e5a7a2dc7f8c4faacf2b510078e +使用 `ps` 命令查看集群中正在运行的容器。 + +```sh +$ docker -H 192.168.0.2:12375 ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +4c9bccbf86fb ubuntu "ping 127.0.0.1" About a minute ago Up About a minute clever_wright +730061a3801a registry:latest "docker-registry" 2 minutes ago Up 2 minutes 192.168.0.2:5000->5000/tcp Host-1/registry_registry_1 +72d99f24a06f redis:3.0 "/entrypoint.sh redis" 2 minutes ago Up 2 minutes 6379/tcp Host-1/registry_redis_1,Host-1/registry_registry_1/redis,Host-1/registry_registry_1/redis_1,Host-1/registry_registry_1/registry_redis_1 ``` -执行结果如下: -```bash -rio@083:~$ sudo docker run -d -p 2376:2375 swarm manage token://b7625e5a7a2dc7f8c4faacf2b510078e -83de3e9149b7a0ef49916d1dbe073e44e8c31c2fcbe98d962a4f85380ef25f76 -``` -这条命令如果执行成功会返回已经启动的 Swarm 的容器的 ID,此时整个集群已经启动起来了。 -现在通过 `docker ps` 命令来看下有没有启动成功。 -```bash -rio@083:~$ sudo docker ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -83de3e9149b7 swarm:latest "/swarm manage token 4 minutes ago Up 4 minutes 0.0.0.0:2376->2375/tcp stupefied_stallman -``` -可以看到,Swarm 已经成功启动。 -在执行 `Swarm manage` 这条命令的时候,有几点需要注意的: +输出结果中显示目前集群中正在运行的容器(注意不包括 Swarm manager 服务容器),可以在不同节点上使用 `docker ps` 查看本地容器,发现这些容器实际上可能运行在集群中多个节点上(被 Swarm 调度策略进行分配)。 -* 这条命令需要在充当 swarm 管理者的机器上执行 -* Swarm 要以 daemon 的形式执行 -* 映射的端口可以使任意的除了 2375 以外的并且是未被占用的端口,但一定不能是 2375 这个端口,因为 2375 已经被 Docker 本身给占用了。 +使用 info 查看所有节点的信息。 -集群启动成功以后,现在我们可以在任何一台节点上使用 `swarm list` 命令查看集群中的节点了,本实验在 124 这台机器上执行 `swarm list` 命令: -```bash -rio@124:~$ sudo docker run --rm swarm list token://b7625e5a7a2dc7f8c4faacf2b510078e -192.168.1.84:2375 -192.168.1.124:2375 -192.168.1.83:2375 -``` -输出结果列出的IP地址正是我们使用 `swarm join` 命令加入集群的机器的IP地址。 - -现在我们可以在任何一台安装了 Docker 的机器上面通过命令(命令中要指明swarm manager机器的IP地址)来在集群中运行container了。 -本次试验,我们在 192.168.1.85 这台机器上使用 `docker info` 命令来查看集群中的节点的信息。 - -其中 info 也可以换成其他的 Docker 支持的命令。 -```bash -rio@085:~$ sudo docker -H 192.168.1.83:2376 info -Containers: 8 +```sh +$ docker -H 192.168.0.2:12375 info +Containers: 18 +Images: 36 +Role: primary Strategy: spread -Filters: affinity, health, constraint, port, dependency +Filters: health, port, dependency, affinity, constraint Nodes: 2 - sclu083: 192.168.1.83:2375 - └ Containers: 1 - └ Reserved CPUs: 0 / 2 - └ Reserved Memory: 0 B / 4.054 GiB - sclu084: 192.168.1.84:2375 - └ Containers: 7 - └ Reserved CPUs: 0 / 2 - └ Reserved Memory: 0 B / 4.053 GiB -``` -结果输出显示这个集群中只有两个节点,IP地址分别是 192.168.1.83 和 192.168.1.84,结果不对呀,我们明明把三台机器加入了这个集群,还有 124 这一台机器呢? -经过排查,发现是忘了修改 124 这台机器上面改 docker daemon 的监听方式,只要按照上面的步骤修改写 docker daemon 的监听方式就可以了。 - -在使用这个方法的时候,使用swarm create可能会因为网络的原因会出现类似于下面的这个问题: -```bash -rio@227:~$ sudo docker run --rm swarm create -[sudo] password for rio: -time="2015-05-19T12:59:26Z" level=fatal msg="Post https://discovery-stage.hub.docker.com/v1/clusters: dial tcp: i/o timeout" -``` - -### 使用文件 - -第二种方法相对于第一种方法要简单得多,也不会出现类似于上面的问题。 - -第一步:在 swarm 管理节点上新建一个文件,把要加入集群的机器 IP 地址和端口号写入文件中,本次试验就是要在83这台机器上面操作: -```bash -rio@083:~$ echo 192.168.1.83:2375 >> cluster -rio@083:~$ echo 192.168.1.84:2375 >> cluster -rio@083:~$ echo 192.168.1.124:2375 >> cluster -rio@083:~$ cat cluster -192.168.1.83:2375 -192.168.1.84:2375 -192.168.1.124:2375 -``` - -第二步:在083这台机器上面执行 `swarm manage` 这条命令: -```bash -rio@083:~$ sudo docker run -d -p 2376:2375 -v $(pwd)/cluster:/tmp/cluster swarm manage file:///tmp/cluster -364af1f25b776f99927b8ae26ca8db5a6fe8ab8cc1e4629a5a68b48951f598ad -``` -使用`docker ps`来查看有没有启动成功: -```bash -rio@083:~$ sudo docker ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -364af1f25b77 swarm:latest "/swarm manage file: About a minute ago Up About a minute 0.0.0.0:2376->2375/tcp happy_euclid -``` -可以看到,此时整个集群已经启动成功。 - -在使用这条命令的时候需要注意的是注意:这里一定要使用-v命令,因为cluster文件是在本机上面,启动的容器默认是访问不到的,所以要通过-v命令共享。 - -接下来的就可以在任何一台安装了docker的机器上面通过命令使用集群,同样的,在85这台机器上执行docker info命令查看集群的节点信息: -```bash -rio@s085:~$ sudo docker -H 192.168.1.83:2376 info -Containers: 9 -Strategy: spread -Filters: affinity, health, constraint, port, dependency -Nodes: 3 - atsgxxx: 192.168.1.227:2375 - └ Containers: 0 + Host-1: 192.168.0.2:2375 + └ Containers: 15 └ Reserved CPUs: 0 / 4 - └ Reserved Memory: 0 B / 2.052 GiB - sclu083: 192.168.1.83:2375 - └ Containers: 2 - └ Reserved CPUs: 0 / 2 - └ Reserved Memory: 0 B / 4.054 GiB - sclu084: 192.168.1.84:2375 - └ Containers: 7 - └ Reserved CPUs: 0 / 2 - └ Reserved Memory: 0 B / 4.053 GiB + └ Reserved Memory: 1 GiB / 4.053 GiB + └ Labels: executiondriver=native-0.2, kernelversion=3.16.0-43-generic, operatingsystem=Ubuntu 14.04.3 LTS, storagedriver=aufs + Host-2: 192.168.0.3:2375 + └ Containers: 3 + └ Reserved CPUs: 0 / 8 + └ Reserved Memory: 0 B / 16.46 GiB + └ Labels: executiondriver=native-0.2, kernelversion=3.16.0-30-generic, operatingsystem=Ubuntu 14.04.3 LTS, storagedriver=aufs +CPUs: 12 +Total Memory: 20.51 GiB +Name: 1e1ca8c4117b ``` +结果输出显示这个集群目前只有两个节点,地址分别是 `192.168.0.2` 和 `192.168.0.3`。 + +类似的,也可以通过 Compose 模板来启动多个服务。不过请注意,要想让服务分布到多个 Swarm 节点上,需要采用版本 2 的写法。 + +### 使用网络 +Swarm 为了支持跨主机的网络,默认采用了 `overlay` 网络类型,实现上通过 vxlan 来构建联通整个 Swarm 集群的网络。 + +首先,在集群中所有节点上,添加配置 Docker daemon 选项: + +``` +--cluster-store= --cluster-advertise= +``` + +以 consul 服务为例,可能类似: + +```sh +--cluster-store=consul://:8500 --cluster-advertise=192.168.0.3:2375 +``` + +之后重启 Docker 服务。 + +首先,创建一个网络。 + +```sh +$ docker -H 192.168.0.2:12375 network create swarm_network +``` + +查看网络,将看到一个 overlay 类型的网络。 + +```sh +$ docker -H 192.168.0.2:12375 network ls +NETWORK ID NAME DRIVER +6edf2d16ec97 swarm_network overlay +``` + +此时,所有添加到这个网络上的容器将自动被分配到集群中的节点上,并且彼此联通。 \ No newline at end of file