Docker Cluster with Swarm

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

准备工作

由于是在本机模拟集群,所以我采用的是 Vagrant 和 VirtualBox 创建虚拟机来模拟集群。 假设本机已经装好了 Vagrant。

制作基础镜像

本次模拟我采用的虚拟机系统是 Ubuntu 14.04,本来是应该通过下面命令完成的

vagrant init ubuntu/trusty64; vagrant up --provider virtualbox  

但是因为国内的这网络状况,从 hashicorp 基本是很难拉下 box,虽然一个 box 也就几百兆,所以选择手动从 hashicorp 下载 box,下载地址是 ubuntu/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

初始化多台虚拟机

然后是打包基础镜像

vagrant package --output ubuntu-docker.box  
vagrant box add --name ubuntu-docker-base ./ubuntu-docker.box  

然后创建一个 Vagrantfile,内容如下

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(为了互相能访问)。

Docker Swarm

发现服务

发现服务的作用是让 swarm manage 知道有新的节点加入进来了,Docker Swarm 有提供下列这几种发现服务的支持

  • Docker Hub
  • key/value store
    • Consul
    • Etcd
    • ZooKeeper
  • A static file or list of nodes

基于 Docker Hub 的发现服务

使用 Docker Hub 作为发现服务是不推荐作为生产环境使用的

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

hostname role IP
cluster0 manager 11.11.11.100
cluster1 node0 11.11.11.101
cluster2 node1 11.11.11.102

首先是通过 swarm 创建一个 token

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。

参考

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