最近因为工作的原因,需要用到 Docker,并且搭建 Docker Cluster(集群),然后首先学习了一下 Docker Swarm,这里做一下记录。

#准备工作 由于是在本机模拟集群,所以我采用的是 Vagrant 和 VirtualBox 创建虚拟机来模拟集群。 假设本机已经装好了 Vagrant。
##制作基础镜像 本次模拟我采用的虚拟机系统是 Ubuntu 14.04,本来是应该通过下面命令完成的 ```bash vagrant init ubuntu/trusty64; vagrant up --provider virtualbox ``` 但是因为国内的这网络状况,从 hashicorp 基本是很难拉下 box,虽然一个 box 也就几百兆,所以选择手动从 hashicorp 下载 box,下载地址是 [ubuntu/trusty64 ](https://atlas.hashicorp.com/ubuntu/boxes/trusty64),现在在页面就有 box 的真实下载地址了(以前是没有的)。

下载好 box 后,然后就是把基础镜像初始化,并且在此基础上做一些准备工作,
添加下载的 box 作为基础镜像,在此基础镜像上替换 ubuntu 源为国内镜像,并且安装 Docker,然后设置 Docker 的 registry mirror 为阿里云的加速。

vagrant box add --name ubuntu-base ./yourbox.box
vagrant init ubuntu-base # 初始化 Vagrantfile
vagrant up # 启动虚拟机

启动虚拟机后,通过 vagrant ssh 登录到虚拟机里,替换 apt-get 镜像为清华源,然后通过阿里云的 Docker-Engine 加速来安装 Docker。

curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -
sudo usermod -aG docker vagrant # 添加 vagrant 用户到 docker 管理组里

安装好之后,在阿里云 Docker 控制台找到自己的 Docker Hub 加速地址,类似于https://XXXXXX.mirror.aliyuncs.com,然后通过下面的命令替换 register-mirror

echo "DOCKER_OPTS=\"\$DOCKER_OPTS --registry-mirror=https://ade5ipeh.mirror.aliyuncs.com\"" | sudo tee -a /etc/default/docker 
echo "DOCKER_OPTS=\"\$DOCKER_OPTS -H 0.0.0.0:2375 -H unix:///var/run/docker.sock\"" | sudo tee -a /etc/default/docker # 这里的作用是添加一个 2375 的端口作为 docker manager 的 socket 端口
sudo service docker restart

本来是打算制作一个基础镜像,然后在此基础上,复制4个出来,然而这里有个巨坑的地方在,复制的镜像,跟原镜像一模一样,这样就导致后面通过 Swarm 创建集群的时候,节点 join 的时候会出现错误,level=error msg="ID duplicated",而 Docker 有一个唯一 ID,这个 ID 是保存在 /etc/docker/key.json 里在。所以需要做以下操作

# https://github.com/docker/docker/issues/13278
sudo rm /etc/docker/key.json

然后可以通过 docker -H :2375 info 测试一下 Docker 是否正常工作,然后运行一个容器测试 docker -H :2375 run hello-world

##初始化多台虚拟机 然后是打包基础镜像 ```bash vagrant package --output ubuntu-docker.box vagrant box add --name ubuntu-docker-base ./ubuntu-docker.box ``` 然后创建一个 `Vagrantfile`,内容如下 ```ruby Vagrant.configure("2") do |config| config.vm.synced_folder ".", "/vagrant", disabled: true config.vm.define :cluster0 do| cluster0_config| cluster0_config.vm.box = 'ubuntu-docker-base' cluster0_config.vm.hostname = 'cluster0' cluster0_config.vm.network "private_network", ip: "11.11.11.100" end

config.vm.define :cluster1 do| cluster1_config|
cluster1_config.vm.box = 'ubuntu-docker-base'
cluster1_config.vm.hostname = 'cluster1'
cluster1_config.vm.network "private_network", ip: "11.11.11.101"
end

config.vm.define :cluster2 do| cluster2_config|
cluster2_config.vm.box = 'ubuntu-docker-base'
cluster2_config.vm.hostname = 'cluster2'
cluster2_config.vm.network "private_network", ip: "11.11.11.102"
end

config.vm.define :cluster3 do| cluster3_config|
cluster3_config.vm.box = 'ubuntu-docker-base'
cluster3_config.vm.hostname = 'cluster3'
cluster3_config.vm.network "private_network", ip: "11.11.11.103"
end

config.vm.define :cluster4 do| cluster4_config|
cluster4_config.vm.box = 'ubuntu-docker-base'
cluster4_config.vm.hostname = 'cluster4'
cluster4_config.vm.network "private_network", ip: "11.11.11.104"
end
end

这个配置文件的作用是基于 `ubuntu-docker-base` 这个基础 box,创建了5个虚拟机,并且设置了 `hostname` 和独立的内网 IP(为了互相能访问)。
<div id="docker-swarm"></div>
#Docker Swarm
<div id="discovery"></div>
##发现服务
发现服务的作用是让 swarm manage 知道有新的节点加入进来了,Docker Swarm 有提供下列这几种发现服务的支持

* Docker Hub
* key/value store
    * Consul
    * Etcd
    * ZooKeeper
* A static file or list of nodes
<div id="discovery-docker-hub"></div>
###基于 Docker Hub 的发现服务
**使用 Docker Hub 作为发现服务是不推荐作为生产环境使用的**

现在假设使用虚拟机中的其中三台,使用情况如下

<table>
<tr>
<th>hostname</th>
<th>role</th>
<th>IP</th>
</tr>
<tr>
<td>cluster0</td>
<td>manager</td>
<td>11.11.11.100</td>
</tr>
<tr>
<td>cluster1</td>
<td>node0</td>
<td>11.11.11.101</td>
</tr>
<tr>
<td>cluster2</td>
<td>node1</td>
<td>11.11.11.102</td>
</tr>
</table>

首先是通过 swarm 创建一个 token
```bash
docker -H 11.11.11.100 run --rm swarm create

因为我用的是虚拟机,我并不想每次都 ssh 到虚拟机里去操作,这样很麻烦,然后可以在本机(Macbook)上使用 docker 的 -H 参数指定 docker 使用的 dockerd 的服务。

通过上述命令,可以拿到一个 token,假设为 cd26cb761cb03e2ed8c0a25effda322c,然后分别执行下面的操作

# cluster0
docker -H 11.11.11.100 run -d -p 4000:4000 swarm manage -H :4000 token://cd26cb761cb03e2ed8c0a25effda322c
# cluster1
docker -H 11.11.11.101 run -d swarm join --addr=11.11.11.101:2375 token://cd26cb761cb03e2ed8c0a25effda322c
# cluster2
docker -H 11.11.11.102 run -d swarm join --addr=11.11.11.102:2375 token://cd26cb761cb03e2ed8c0a25effda322c

通过上述操作后,理论上已经在 cluster0 上建立了一个 swarm manage 的服务,在 cluster1cluster2 两个节点上分别建立了 swarm node,可以通过 docker -H 11.11.11.100:4000 info 查看 swarm 的信息,理论上可以看到下列的信息

Containers: 4
 Running: 2
 Paused: 0
 Stopped: 2
Images: 4
Server Version: swarm/1.2.4
Role: primary
Strategy: spread
Filters: health, port, containerslots, dependency, affinity, constraint
Nodes: 2
 cluster1: 11.11.11.101:2375
  └ ID: JSLI:JY6O:6GZI:LXRT:RQJ5:NZXN:FBMU:XUEB:CTSR:PEPU:ORVH:2A4T
  └ Status: Healthy
  └ Containers: 2 (1 Running, 0 Paused, 1 Stopped)
  └ Reserved CPUs: 0 / 1
  └ Reserved Memory: 0 B / 514.5 MiB
  └ Labels: kernelversion=3.13.0-93-generic, operatingsystem=Ubuntu 14.04.5 LTS, storagedriver=aufs
  └ UpdatedAt: 2016-08-05T18:39:49Z
  └ ServerVersion: 1.12.0
 cluster2: 11.11.11.102:2375
  └ ID: 2HZ6:6ZKW:S7XZ:LLTW:BQTS:YHFO:ELXC:6ZKM:4HHL:C6UO:IHE5:IG34
  └ Status: Healthy
  └ Containers: 2 (1 Running, 0 Paused, 1 Stopped)
  └ Reserved CPUs: 0 / 1
  └ Reserved Memory: 0 B / 514.5 MiB
  └ Labels: kernelversion=3.13.0-93-generic, operatingsystem=Ubuntu 14.04.5 LTS, storagedriver=aufs
  └ UpdatedAt: 2016-08-05T18:40:01Z
  └ ServerVersion: 1.12.0
Plugins:
 Volume:
 Network:
Swarm:
 NodeID:
 Is Manager: false
 Node Address:
Security Options:
Kernel Version: 3.13.0-93-generic
Operating System: linux
Architecture: amd64
CPUs: 2
Total Memory: 1.005 GiB
Name: b7b4f78090ac
Docker Root Dir:
Debug Mode (client): false
Debug Mode (server): false

通过 docker -H 11.11.11.100:4000 run -P -d nginx 可以在集群里运行一个 nginx 的容器,然后通过 docker -H 11.11.11.100:4000 ps 可以看到集群里的正在运行的容器,里面可以看到 nginx 具体是跑在哪一个容器里面在。

###使用 Consul 做发现服务
hostname role IP
cluster0 consul 11.11.11.100
cluster1 manager0 11.11.11.101
cluster2 manager1 11.11.11.102
cluster3 node0 11.11.11.103
cluster4 node1 11.11.11.104

可以通过 vagrant destory 销毁所有的虚拟机(本机就是可以这么任性,随便搞),然后再通过 vagrant up 来再次启动虚拟机。

然后顺序执行下列操作来创建集群

# cluster0
docker -H 11.11.11.100 run -d -p 8500:8500 --name=consul progrium/consul -server -bootstrap
# cluster1
docker -H 11.11.11.101 run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise 11.11.11.101:4000 consul://11.11.11.100:8500
# cluster2
docker -H 11.11.11.102 run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise 11.11.11.102:4000 consul://11.11.11.100:8500
# cluster3
docker -H 11.11.11.103 run -d swarm join --advertise=11.11.11.103:2375 consul://11.11.11.100:8500
# cluster4
docker -H 11.11.11.104 run -d swarm join --advertise=11.11.11.104:2375 consul://11.11.11.100:8500

可以通过 http://11.11.11.100:8500 进入 consul 提供的一个 Web 界面来查看 consul 的一些信息,Swarm 是通过使用 consul 的 key/value 来做发现服务的,所以在 consul 的 key/value 里是可以看到 swarm manage 的 leader 和 swarm node 的信息。

通过上述多节点的 manager,实现了 swarm manage 的高可用,如果干掉 manage leader,会发现 leader 自动切换到了另一个 manager。

#参考 没有下列的这些文章或者服务的帮助,我是无法完成上述这些操作的,特此感谢