diff --git a/SUMMARY.md b/SUMMARY.md index e3014c2..26e5530 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -88,7 +88,7 @@ * [实战 Django](compose/django.md) * [实战 Rails](compose/rails.md) * [实战 wordpress](compose/wordpress.md) -* [Docker 三剑客之 Machine 项目](machine/README.md) +* [Docker 三剑客之 Machine 项目](machine/README.md) * [安装](machine/install.md) * [使用](machine/usage.md) * [Docker 三剑客之 Docker Swarm](swarm/README.md) diff --git a/network/README.md b/network/README.md index 99228fe..55a4556 100644 --- a/network/README.md +++ b/network/README.md @@ -1,4 +1,5 @@ # Docker 中的网络功能介绍 + Docker 允许通过外部访问容器或容器互联的方式来提供网络服务。 Docker 在 1.13 版本引进了新的管理命令(management commands),在 Docker 1.13+ 推荐使用 `docker network` 子命令来管理 Docker 网络。 diff --git a/network/linking.md b/network/linking.md index 79efbe7..8d7380b 100644 --- a/network/linking.md +++ b/network/linking.md @@ -1,102 +1,63 @@ ## 容器互联 + +如果你之前有 `Docker` 使用经验,你可能已经习惯了使用 `--link` 参数来使容器互联。 + +随着 Docker 网络的完善,强烈建议大家将容器加入自定义的 Docker 网络来连接多个容器。 + 容器的连接(linking)系统是除了端口映射外,另一种跟容器中应用交互的方式。 该系统会在源和接收容器之间创建一个隧道,接收容器可以看到源容器指定的信息。 -### 自定义容器命名 -连接系统依据容器的名称来执行。因此,首先需要自定义一个好记的容器命名。 +### 新建网络 -虽然当创建容器的时候,系统默认会分配一个名字。自定义命名容器有2个好处: -* 自定义的命名,比较好记,比如一个web应用容器我们可以给它起名叫web -* 当要连接其他容器时候,可以作为一个有用的参考点,比如连接web容器到db容器 +下面先创建一个新的 Docker 网络。 -使用 `--name` 标记可以为容器自定义命名。 ```bash -$ docker run -d -P --name web training/webapp python app.py +$ docker network create -d bridge my-net ``` -使用 `docker ps` 来验证设定的命名。 +### 连接容器 + +创建一个容器并连接到新建的 `my-net` 网络 + ```bash -$ docker ps -l -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -aed84ee21bde training/webapp:latest python app.py 12 hours ago Up 2 seconds 0.0.0.0:49154->5000/tcp web +$ docker run -it --rm --name busybox1 --net my-net busybox sh ``` -也可以使用 `docker inspect` 来查看容器的名字 + +打开新的终端,再新建一个容器,加入 `my-net` 网络 + ```bash -$ docker inspect -f "{{ .Name }}" aed84ee21bde -/web +$ docker run -it --rm --name busybox2 --net my-net busybox sh ``` -注意:容器的名称是唯一的。如果已经命名了一个叫 web 的容器,当你要再次使用 web 这个名称的时候,需要先用`docker rm` 来删除之前创建的同名容器。 -在执行 `docker run` 的时候如果添加 `--rm` 标记,则容器在终止后会立刻删除。注意,`--rm` 和 `-d` 参数不能同时使用。 +再打开一个新的终端查看容器信息 -###容器互联 -使用 `--link` 参数可以让容器之间安全的进行交互。 - -下面先创建一个新的数据库容器。 ```bash -$ docker run -d --name db training/postgres +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +b47060aca56b busybox "sh" 11 minutes ago Up 11 minutes busybox2 +8720575823ec busybox "sh" 16 minutes ago Up 16 minutes busybox1 ``` -删除之前创建的 web 容器 + +下面通过 `ping` 来证明 `busybox1` 容器和 `busybox2` 容器建立了互联关系。 + +在 `busybox1` 容器输入以下命令 + ```bash -$ docker rm -f web +/ # ping busybox2 +PING busybox2 (172.19.0.3): 56 data bytes +64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.072 ms +64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.118 ms ``` -然后创建一个新的 web 容器,并将它连接到 db 容器 + +用 ping 来测试连接 `busybox2` 容器,它会解析成 172.19.0.3。 + +同理在 `busybox2` 容器执行 `ping busybox1`,也会成功连接到。 + ```bash -$ docker run -d -P --name web --link db:db training/webapp python app.py +/ # ping busybox1 +PING busybox1 (172.19.0.2): 56 data bytes +64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.064 ms +64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.143 ms ``` -此时,db 容器和 web 容器建立互联关系。 -`--link` 参数的格式为 `--link name:alias`,其中 `name` 是要链接的容器的名称,`alias` 是这个连接的别名。 - -使用 `docker ps` 来查看容器的连接 -```bash -$ docker ps -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -349169744e49 training/postgres:latest su postgres -c '/usr About a minute ago Up About a minute 5432/tcp db, web/db -aed84ee21bde training/webapp:latest python app.py 16 hours ago Up 2 minutes 0.0.0.0:49154->5000/tcp web -``` -可以看到自定义命名的容器,db 和 web,db 容器的 names 列有 db 也有 web/db。这表示 web 容器链接到 db 容器,web 容器将被允许访问 db 容器的信息。 - -Docker 在两个互联的容器之间创建了一个安全隧道,而且不用映射它们的端口到宿主主机上。在启动 db 容器的时候并没有使用 `-p` 和 `-P` 标记,从而避免了暴露数据库端口到外部网络上。 - -Docker 通过 2 种方式为容器公开连接信息: -* 环境变量 -* 更新 `/etc/hosts` 文件 - -使用 `env` 命令来查看 web 容器的环境变量 -```bash -$ docker run --rm --name web2 --link db:db training/webapp env -. . . -DB_NAME=/web2/db -DB_PORT=tcp://172.17.0.5:5432 -DB_PORT_5000_TCP=tcp://172.17.0.5:5432 -DB_PORT_5000_TCP_PROTO=tcp -DB_PORT_5000_TCP_PORT=5432 -DB_PORT_5000_TCP_ADDR=172.17.0.5 -. . . -``` -其中 DB_ 开头的环境变量是供 web 容器连接 db 容器使用,前缀采用大写的连接别名。 - -除了环境变量,Docker 还添加 host 信息到父容器的 `/etc/hosts` 的文件。下面是父容器 web 的 hosts 文件 -```bash -$ docker run -t -i --rm --link db:db training/webapp /bin/bash -root@aed84ee21bde:/opt/webapp# cat /etc/hosts -172.17.0.7 aed84ee21bde -. . . -172.17.0.5 db -``` -这里有 2 个 hosts,第一个是 web 容器,web 容器用 id 作为他的主机名,第二个是 db 容器的 ip 和主机名。 -可以在 web 容器中安装 ping 命令来测试跟db容器的连通。 -```bash -root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping -root@aed84ee21bde:/opt/webapp# ping db -PING db (172.17.0.5): 48 data bytes -56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms -56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms -56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms -``` -用 ping 来测试db容器,它会解析成 `172.17.0.5`。 -*注意*:官方的 ubuntu 镜像默认没有安装 ping,需要自行安装。 - -用户可以链接多个父容器到子容器,比如可以链接多个 web 到 db 容器上。 +这样,`busybox1` 容器和 `busybox2` 容器建立了互联关系。 diff --git a/network/port_mapping.md b/network/port_mapping.md index fa7a57b..0281754 100644 --- a/network/port_mapping.md +++ b/network/port_mapping.md @@ -1,16 +1,21 @@ ## 外部访问容器 + 容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 `-P` 或 `-p` 参数来指定端口映射。 -当使用 -P 标记时,Docker 会随机映射一个 `49000~49900` 的端口到内部容器开放的网络端口。 +当使用 `-P` 标记时,Docker 会随机映射一个 `49000~49900` 的端口到内部容器开放的网络端口。 使用 `docker ps` 可以看到,本地主机的 49155 被映射到了容器的 5000 端口。此时访问本机的 49155 端口即可访问容器内 web 应用提供的界面。 + ```bash $ docker run -d -P training/webapp python app.py + $ docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bc533791f3f5 training/webapp:latest python app.py 5 seconds ago Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morse ``` + 同样的,可以通过 `docker logs` 命令来查看应用的信息。 + ```bash $ docker logs -f nostalgic_morse * Running on http://0.0.0.0:5000/ @@ -18,40 +23,60 @@ $ docker logs -f nostalgic_morse 10.0.2.2 - - [23/May/2014 20:16:31] "GET /favicon.ico HTTP/1.1" 404 - ``` --p(小写的)则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 `ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort`。 +`-p` 则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 `ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort`。 ### 映射所有接口地址 + 使用 `hostPort:containerPort` 格式本地的 5000 端口映射到容器的 5000 端口,可以执行 + ```bash $ docker run -d -p 5000:5000 training/webapp python app.py ``` + 此时默认会绑定本地所有接口上的所有地址。 ### 映射到指定地址的指定端口 + 可以使用 `ip:hostPort:containerPort` 格式指定映射使用一个特定地址,比如 localhost 地址 127.0.0.1 + ```bash $ docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py ``` + ### 映射到指定地址的任意端口 + 使用 `ip::containerPort` 绑定 localhost 的任意端口到容器的 5000 端口,本地主机会自动分配一个端口。 + ```bash $ docker run -d -p 127.0.0.1::5000 training/webapp python app.py ``` -还可以使用 udp 标记来指定 udp 端口 + +还可以使用 `udp` 标记来指定 `udp` 端口 + ```bash $ docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py ``` + ### 查看映射端口配置 + 使用 `docker port` 来查看当前映射的端口配置,也可以查看到绑定的地址 + ```bash $ docker port nostalgic_morse 5000 127.0.0.1:49155. ``` + 注意: * 容器有自己的内部网络和 ip 地址(使用 `docker inspect` 可以获取所有的变量,Docker 还可以有一个可变的网络配置。) -* -p 标记可以多次使用来绑定多个端口 + +* `-p` 标记可以多次使用来绑定多个端口 例如 + ```bash -$ docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py +$ docker run -d \ + -p 5000:5000 \ + -p 3000:80 \ + training/webapp \ + python app.py ``` diff --git a/revision.md b/revision.md index d837f7e..2e0c606 100644 --- a/revision.md +++ b/revision.md @@ -6,13 +6,21 @@ * 0.9-rc2: 2017-12-10 + * 更新 `CoreOS` 章节 + * 增加 `Docker Cloud` 介绍 + * 增加 `Docker Store` 介绍 + * 0.9-rc1: 2017-11-30 * 根据最新版本(v17.09)修订内容 - * 完善 Compose 项目 - * 更新 Swarm 项目 - * 更新 Mesos 项目 - * 添加操作系统实战案例 + * 增加 Dockerfile `multistage builds` 多阶段构建 `Dcoker 17.05` 新增特性 + * 更新 `Docker 网络` 一节 + * 更新 `Docker Machine` 基于 0.13.0 版本 + * 更新 `Docker Compose` 基于 3.4 文件格式 + * 删除 Docker Swarm 相关内容,替换为 `Swarm mode` `Docker 1.12.0` 新增特性 + * 精简 `Docker Registry` 一节 + * 删除 `docker run` `--link` 参数 + * 替换 `docker run` `-v` 参数为 `--mount` * 0.8.0: 2017-01-08 diff --git a/swarm/README.md b/swarm/README.md index 790c39d..5518654 100644 --- a/swarm/README.md +++ b/swarm/README.md @@ -1,6 +1,7 @@ # Docker 三剑客之 Docker Swarm + Docker Swarm 是 Docker 官方三剑客项目之一,提供 Docker 容器集群服务,是 Docker 官方对容器云生态进行支持的核心方案。 使用它,用户可以将多个 Docker 主机封装为单个大型的虚拟 Docker 主机,快速打造一套容器云平台。 -本章将介绍 Swarm 项目的相关情况,以及如何进行安装和使用。最后还对 Swarm 的服务发现后端、调度器和过滤器等功能进行讲解。 +注意:Docker 1.12.0+ [Swarm mode](https://docs.docker.com/engine/swarm/) 已经内嵌入 Docker 引擎,成为了 docker 子命令 `docker swarm`,绝大多数用户已经开始使用 `Swarm mode`,Docker 引擎 API 已经删除 Docker Swarm。为避免大家混淆旧的 `Docker Swarm` 与新的 `Swarm mode`,旧的 `Docker Swarm` 内容已经删除,请查看 `Swarm mode` 一节。 diff --git a/swarm/_images/docker_swarm.png b/swarm/_images/docker_swarm.png deleted file mode 100644 index 1631913..0000000 Binary files a/swarm/_images/docker_swarm.png and /dev/null differ diff --git a/swarm/_images/swarm.png b/swarm/_images/swarm.png deleted file mode 100644 index 4af7b27..0000000 Binary files a/swarm/_images/swarm.png and /dev/null differ diff --git a/swarm/filter.md b/swarm/filter.md deleted file mode 100644 index ebb5f34..0000000 --- a/swarm/filter.md +++ /dev/null @@ -1,108 +0,0 @@ -## Swarm 中的过滤器 - -Swarm 的调度器可以按照指定调度策略自动分配容器到节点。但有些时候希望能对这些分配加以干预。比如说,让 IO 敏感的容器分配到安装了 SSD 的节点上;让计算敏感的容器分配到 CPU 核数多的机器上;让网络敏感的容器分配到高带宽的机房;让某些容器尽量放同一个节点……。 - -这可以通过过滤器(filter)来实现,目前支持 `Constraint`、`Affinity`、`Port`、`Dependency`、`Health` 等五种过滤器。 - -### Constraint 过滤器 -Constraint 过滤器是绑定到节点的键值对,相当于给节点添加标签。 - -可在启动 Docker 服务的时候指定,例如指定某个节点颜色为 `red`。 - -```bash -$ docker daemon --label color=red -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock -``` - -同样的,可以写在 Docker 服务的配置文件里面(以 Ubuntu 14.04 为例,是 `/etc/default/docker`)。 - -```bash -DOCKER_OPTS="--label color=red -H 0.0.0.0:2375 -H unix:///var/run/docker.sock" -``` - -使用 Swarm 启动容器的时候,采用 `-e constarint:key=value` 的形式,可以过滤选择出匹配条件的节点。 - -例如,我们将 `192.168.0.2` 节点打上红色标签,`192.168.0.3` 节点打上绿色标签。 - -然后,分别启动两个容器,指定使用过滤器分别为红色和绿色。 - -```bash -$ 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 -$ 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 -$ 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 过滤器 -Affinity 过滤器允许用户在启动一个容器的时候,让它分配到某个已有容器的节点上。 - -例如,下面我们将启动一个 nginx 容器,让它分配到已经运行某个 ubuntu 容器的节点上。 - -在 Constraint 过滤器的示例中,我们分别启动了两个 ubuntu 容器 `sick_galileo` 和 `compassionate_ritchie`,分别在 Host-2 和 Host-3 上。 - -现在启动一个 nginx 容器,让它跟容器 `sick_galileo` 放在一起,都放到 Host-2 节点上。可以通过 `-e affinity:container==` 参数来实现。 - -```bash -$ docker -H 192.168.0.2:12375 run -d -e affinity:container==sick_galileo nginx -``` - -然后启动一个 redis 容器,让它跟容器 `compassionate_ritchie` 放在一起,都放到 Host-3 节点上。 - -```bash -$ docker -H 192.168.0.2:12375 run -d -e affinity:container==compassionate_ritchie redis -``` - -查看所有容器运行情况。 - -```bash -$ 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 deleted file mode 100644 index fefb120..0000000 --- a/swarm/install.md +++ /dev/null @@ -1,81 +0,0 @@ -## 安装 Swarm -Swarm 安装有几种方式,可以基于 Docker Machine 来进行安装,也可以手动配置。为了能更容易理解 Swarm 的组件和更灵活的进行管理,推荐使用手动配置方式。 - -对于 Docker 1.12+ 版本,Swarm 相关命令已经原生嵌入到了 Docker engine 的支持,对于较低版本的 Docker,需要额外进行配置。 - -### 下载镜像 -Docker 官方已经提供了 Swarm 镜像使用,需要在所有被 Swarm 管理的 Docker 主机上下载该镜像。 - -```bash -$ docker pull swarm -``` - -可以使用下面的命令来查看 Swarm 版本,验证是否成功下载 Swarm 镜像。 - -```bash -$ docker run --rm swarm -v -swarm version 1.2.2 (34e3da3) -``` - -### 配置节点 -Docker 主机在加入 Swarm 集群前,需要进行一些简单配置,添加 Docker daemon 的网络监听。 - -例如,在启动 Docker daemon 的时候通过 `-H` 参数: - -```bash -$ 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 上略有不同)。 - -在文件的最后添加: - -```bash -DOCKER_OPTS="$DOCKER_OPTS -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock" -``` - -### 启动集群 -Docker 集群管理需要使用服务发现(Service Discover)功能,Swarm 支持以下的几种方式:DockerHub、本地文件、etcd、consul、zookeeper 和手动指定节点 IP 地址信息等。 - -除了手动指定外,这些方法原理上都是通过维护一套数据库机制,来管理集群中注册节点的 Docker daemon 的访问信息。 - -本地配置集群推荐使用 consul 作为服务发现后端。利用社区提供的 Docker 镜像,整个过程只需要三步即可完成。 - -#### 启动 Consul 服务后端 -启动 consul 服务容器,映射到主机的 8500 端口。 - -```bash -$ docker run -d -p 8500:8500 --name=consul progrium/consul -server -bootstrap -``` - -获取到本地主机的地址作为 consul 的服务地址:`:8500`。 - -#### 启动管理节点 -首先,启动一个主管理节点,映射到主机的 4000 端口,并获取所在主机地址为 ``。其中 4000 端口是 Swarm 管理器的默认监听端口,用户也可以指定映射为其它端口。 - -```bash -$ docker run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise :4000 consul://:8500 -``` - -为了提高高可用性,用户也可以启动从管理节点。假定获取所在主机地址为 ``。 - -```bash -$ docker run -d swarm manage -H :4000 --replication --advertise :4000 consul://:8500 -``` - -#### 启动工作节点 -需要在每个工作节点上启动 agent 服务。 - -获取节点的主机地址为 ``,并指定前面获取到的 consul 服务地址。 - -```bash -$ 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 deleted file mode 100644 index dbe7807..0000000 --- a/swarm/intro.md +++ /dev/null @@ -1,16 +0,0 @@ -## Swarm 简介 -![Docker Swarm](_images/docker_swarm.png) - -Docker Swarm 是 Docker 公司推出的官方容器集群平台,基于 Go 语言实现,代码开源在 [https://github.com/docker/swarm](https://github.com/docker/swarm)。目前,包括 Rackspace 等平台都采用了 Swarm,用户也很容易在 AWS 等公有云平台使用 Swarm。 - -Swarm 的前身是 Beam 项目和 libswarm 项目,首个正式版本(Swarm V1)在 2014 年 12 月初发布。为了提高可扩展性,2016 年 2 月对架构进行重新设计,推出了 V2 版本,支持超过 1K 个节点。最新的 Docker Engine 已经集成了 SwarmKit,加强了对 Swarm 的协作支持。 - -作为容器集群管理器,Swarm 最大的优势之一就是 100% 支持标准的 Docker API。各种基于标准 API 的工具比如 Compose、docker-py、各种管理软件,甚至 Docker 本身等都可以很容易的与 Swarm 进行集成。这大大方便了用户将原先基于单节点的系统移植到 Swarm 上。同时 Swarm 内置了对 Docker 网络插件的支持,用户可以很容易地部署跨主机的容器集群服务。 - -![Swarm 基本结构图](_images/swarm.png) - -上图是来自官方的 V1 结构图。可以看出,Swarm 是典型的 master-slave 结构,通过发现服务来选举 manager。manager 是中心管理节点,各个 node 上运行 agent 接受 manager 的统一管理。 - -在 V2 中,集群中会自动通过 Raft 协议分布式选举出 manager 节点,无需额外的发现服务支持,避免了单点瓶颈。同时,V2 中内置了基于 DNS 的负载均衡和对外部负载均衡机制的集成支持。 - -目前,Swarm V1 支持 Docker 版本为 1.6.0+,V2 支持 Docker 版本为 1.12.0+。本章将以 Swarm V1 为主进行介绍,并结合 V2 的部分最新特性。 diff --git a/swarm/scheduling.md b/swarm/scheduling.md deleted file mode 100644 index 072803e..0000000 --- a/swarm/scheduling.md +++ /dev/null @@ -1,73 +0,0 @@ -## Swarm 中的调度器 -调度是集群十分重要的功能,Swarm 目前支持三种调度策略:`spread`、`binpack` 和 `random`。 - -在执行`swarm manage`命令启动管理服务的时候,可以通过 `--strategy` 参数指定调度策略,默认的是 `spread`。 - -简单来说,这三种调度策略的优化目标如下: - -* `spread`:如果节点配置相同,选择一个正在运行的容器数量最少的那个节点,即尽量平摊容器到各个节点; -* `binpack`:跟 `spread` 相反,尽可能的把所有的容器放在一台节点上面运行,即尽量少用节点,避免容器碎片化。 -* `random`:直接随机分配,不考虑集群中节点的状态,方便进行测试使用。 - -### spread 调度策略 -仍然以之前创建好的集群为例,来演示下 spread 策略的行为。 - -在 `192.168.0.2` 节点启动管理服务,管理 token://946d65606f7c2f49766e4dddac5b4365 的集群。 - -```bash -$ docker run -d -p 12375:2375 swarm manage --strategy "spread" token://946d65606f7c2f49766e4dddac5b4365 -c6f25e6e6abbe45c8bcf75ac674f2b64d5f31a5c6070d64ba954a0309b197930 -``` - -列出集群中节点。 - -```bash -$ docker run --rm swarm list token://946d65606f7c2f49766e4dddac5b4365 -192.168.0.3:2375 -192.168.0.2:2375 -``` - -此时,两个节点上除了 swarm 外都没有运行其它容器。 - -启动一个 ubuntu 容器。 - -```bash -$ docker -H 192.168.0.2:12375 run -d ubuntu:14.04 ping 127.0.0.1 -bac3dfda5306181140fc959969d738549d607bc598390f57bdd432d86f16f069 -``` - -查看发现它实际上被调度到了 `192.168.0.3` 节点(当节点配置相同时候,初始节点随机选择)。 - -再次启动一个 ubuntu 容器。 - -```bash -$ docker -H 192.168.0.2:12375 run -d ubuntu:14.04 ping 127.0.0.1 -8247067ba3a31e0cb692a8373405f95920a10389ce3c2a07091408281695281c -``` - -查看它的位置,发现被调度到了另外一个节点:`192.168.0.2` 节点。 - -```bash -$ 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 容器,并查看它们的位置。 - -```bash -$ 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`)上运行的。 diff --git a/swarm/servicebackend.md b/swarm/servicebackend.md deleted file mode 100644 index 5e009ec..0000000 --- a/swarm/servicebackend.md +++ /dev/null @@ -1,97 +0,0 @@ -## 使用其它服务发现后端 - -Swarm 目前可以支持多种服务发现后端,这些后端功能上都是一致的,即维护属于某个集群的节点的信息。不同方案并无优劣之分,在实际使用时候,可以结合自身需求和环境限制进行选择,甚至自己定制其它方案。 - -使用中可以通过不同的路径来选择特定的服务发现后端机制。 - -* `token://`:使用 DockerHub 提供的服务,适用于可以访问公网情况; -* `file://path/to/file`:使用本地文件,需要手动管理; -* `consul:///`:使用 consul 服务,私有环境推荐; -* `etcd://,/`:使用 etcd 服务,私有环境推荐; -* `zk://,/`:使用 zookeeper 服务,私有环境推荐; -* `[nodes://],`:手动指定集群中节点的地址,方便进行服务测试。 - -### 使用文件 - -使用本地文件的方式十分简单,就是讲所有属于某个集群的节点的 Docker daemon 信息写入一个文件中,然后让 manager 从这个文件中直接读取相关信息。 - -首先,在 Swarm 管理节点(`192.168.0.2`)上新建一个文件,把要加入集群的机器的 Docker daemon 信息写入文件: - -```bash -$ tee /tmp/cluster_info <<-'EOF' -192.168.0.2:2375 -192.168.0.3:2375 -EOF -``` - -然后,本地执行 `swarm manage` 命令,并指定服务发现机制为本地文件,注意因为是容器方式运行 manager,需要将本地文件挂载到容器内。 - -```bash -$ docker run -d -p 12375:2375 -v /tmp/cluster_info:/tmp/cluster_info swarm manage file:///tmp/cluster_info -``` - -接下来就可以通过使用 Swarm 服务来进行管理了,例如使用 info 查看所有节点的信息。 - -```bash -$ 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 服务的命令为: - -```bash -$ docker run -d -p 8500:8500 --name=consul progrium/consul -server -bootstrap -``` - -之后创建 Swarm 的管理服务,指定使用 consul 服务,管理端口监听在本地的 4000 端口。 - -```bash -$ docker run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise :4000 consul://:8500 -``` - -Swarm 节点注册时候命令格式类似于: - -```bash -$ swarm join --advertise= consul:/// -``` - -对于 etcd 服务后端来说,节点注册时候命令格式类似于: - -```bash -$ swarm join --addr= etcd://,/ -``` -启动管理服务时候,格式类似于: - -```bash -$ 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 个地址。 diff --git a/swarm/summary.md b/swarm/summary.md deleted file mode 100644 index 12709a7..0000000 --- a/swarm/summary.md +++ /dev/null @@ -1,10 +0,0 @@ -## 本章小结 -本章笔者介绍了 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 deleted file mode 100644 index a4be583..0000000 --- a/swarm/usage.md +++ /dev/null @@ -1,181 +0,0 @@ -## 使用 Swarm -前面演示了基于 consul 服务发现后端来配置一个本地 Swarm 集群。其中,consul 也可以被替换为 etcd、zookeeper 等。 - -另外一个更方便的方式是直接使用 DockerHub 提供的免费服务发现后端。 - -下面使用这种方式来演示 Swarm 的主要操作,包括: - -* create:创建一个集群; -* list:列出集群中的节点; -* manage:管理一个集群; -* join:让节点加入到某个集群。 - -注意,使用 DockerHub 的服务发现后端,需要各个节点能通过公网访问到 DockerHub 的服务接口。 - -### 创建集群 id - -在任意一台安装了 Swarm 的机器上执行 `swarm create` 命令来在 DockerHub 服务上进行注册。 - -Swarm 会通过服务发现后端(此处为 DockerHub 提供)来获取一个唯一的由数字和字母组成的 token,用来标识要管理的集群。 - -```bash -$ docker run --rm swarm create -946d65606f7c2f49766e4dddac5b4365 -``` - -注意返回的字符串,这是集群的唯一 id,加入集群的各个节点将需要这个信息。 - -### 配置集群节点 - -在所有要加入集群的普通节点上面执行 `swarm join` 命令,表示把这台机器加入指定集群当中。 - -例如某台机器 IP 地址为 `192.168.0.2`,将其加入我们刚创建的 `946d65606f7c2f49766e4dddac5b4365` 集群,则可以通过: - -```bash -$ 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 服务必须要通过这个地址可以访问到该节点。* - -通过控制台可以看到,上述命令执行后,默认每隔 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` 端口。 - -```bash -$ docker run -d -p 12375:2375 swarm manage token://946d65606f7c2f49766e4dddac5b4365 -1e1ca8c4117b6b7271efc693f9685b4e907d8dc95324350392b21e94b3cffd18 -``` - -可以通过 `docker ps` 命令来查看启动的 swarm manager 服务容器。 - -```bash -$ 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 -``` - -命令如果执行成功会返回刚启动的 Swarm 容器的 ID,此时一个简单的 Swarm 集群就已经搭建起来了,包括一个普通节点和一个管理节点。 - -### 查看集群节点列表 - -集群启动成功以后,用户可以在任何一台节点上使用 `swarm list` 命令查看集群中的节点列表。例如 - -```bash -$ docker run --rm swarm list token://946d65606f7c2f49766e4dddac5b4365 -192.168.0.2:2375 -``` -显示正是之前用 `swarm join` 命令加入集群的节点的地址。 - -我们在另外一台节点 `192.168.0.3` 上同样使用 `swarm join` 命令新加入一个节点: -```bash -$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" -... -``` - -再次使用 `swarm list` 命令查看集群中的节点列表信息,可以看到新加入的节点: - -```bash -$ docker run --rm swarm list token://946d65606f7c2f49766e4dddac5b4365 -192.168.0.3:2375 -192.168.0.2:2375 -``` - -### 使用集群服务 -那么,怎么使用 Swarm 提供的服务呢? - -实际上,所有 Docker 客户端可以继续使用,只要指定使用 Swarm manager 服务的监听地址即可。 - -例如,manager 服务监听的地址为 `192.168.0.2:12375`,则可以通过指定 `-H 192.168.0.2:12375` 选项来继续使用 Docker 客户端,执行任意 Docker 命令,例如 `ps`、`info`、`run` 等等。 - -在任意节点上使用 `docker run` 来启动若干容器,例如 - -```bash -$docker -H 192.168.0.2:12375:12375 run -d ubuntu ping 127.0.0.1 -4c9bccbf86fb6e2243da58c1b15e9378fac362783a663426bbe7058eea84de46 -``` - -使用 `ps` 命令查看集群中正在运行的容器。 - -```bash -$ 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 -``` - -输出结果中显示目前集群中正在运行的容器(注意不包括 Swarm manager 服务容器),可以在不同节点上使用 `docker ps` 查看本地容器,发现这些容器实际上可能运行在集群中多个节点上(被 Swarm 调度策略进行分配)。 - -使用 info 查看所有节点的信息。 - -```bash -$ 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: 1e1ca8c4117b -``` -结果输出显示这个集群目前只有两个节点,地址分别是 `192.168.0.2` 和 `192.168.0.3`。 - -类似的,也可以通过 Compose 模板来启动多个服务。不过请注意,要想让服务分布到多个 Swarm 节点上,需要采用版本 2 的写法。 - -### 使用网络 -Swarm 为了支持跨主机的网络,默认采用了 `overlay` 网络类型,实现上通过 vxlan 来构建联通整个 Swarm 集群的网络。 - -首先,在集群中所有节点上,添加配置 Docker daemon 选项: - -``` ---cluster-store= --cluster-advertise= -``` - -以 consul 服务为例,可能类似: - -```bash ---cluster-store=consul://:8500 --cluster-advertise=192.168.0.3:2375 -``` - -之后重启 Docker 服务。 - -首先,创建一个网络。 - -```bash -$ docker -H 192.168.0.2:12375 network create swarm_network -``` - -查看网络,将看到一个 overlay 类型的网络。 - -```bash -$ docker -H 192.168.0.2:12375 network ls -NETWORK ID NAME DRIVER -6edf2d16ec97 swarm_network overlay -``` - -此时,所有添加到这个网络上的容器将自动被分配到集群中的节点上,并且彼此联通。