本篇教程会介绍如何使用docker swarm进行容器的编排与分发friendlyhello:v4,这一服务可以通过浏览器访问,获取当前节点的Hostname,最终效果如下:

STEP 1: 创建虚拟机
为了模拟集群环境,我们创建3个虚拟机,1个作为manager节点、另外2个则是worker节点,我自己的mac是8g内存,虽然有些捉急,但3个vm还是撑得住的:
$ docker-machine create manager
$ docker-machine create worker-1
$ docker-machine create worker-2

然后分别进入这三台虚拟机(请开三个terminal来操作):
$ docker-machine ssh manager
$ docker-machine ssh worker-1
$ docker-machine ssh worker-2

STEP 2: 初始化集群
首先确认一下每个vm的IP:
$ ifconfig
例如,我现在三个ip分别是:
- manager: 192.168.99.112
- worker-1: 192.168.99.113
- worker-2: 192.168.99.114
然后在manager里,执行:
$ docker swarm init --addvertise-addr <你的manager节点的ip>
# 我自己的命令:
$ docker swarm init --addvertise-addr 192.168.99.112
完成后,复制输出的加入swarm集群的命令,在两个worker里分别执行一下,最后效果如下就说明成功了:

STEP 3: 创建friendlyhello:v4服务
我们先在当前目录下直接创建两个文件,app.py Dockerfile,并加入如下代码:
-
app.py
from flask import Flask from redis import Redis, RedisError import os import socket # Connect to Redis redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2) app = Flask(__name__) @app.route("/") def hello(): try: visits = redis.incr("counter") except RedisError: visits = "<i>cannot connect to Redis, counter disabled</i>" html = "<b>HostName:</b> {host_name}<br/>" \ "<b>Hostname:</b> {hostname}<br/>" \ "<b>Visits:</b> {visits}" return html.format(host_name=os.getenv("HOSTNAME", "UNKNOWN"), hostname=socket.gethostname(), visits=visits) if __name__ == "__main__": app.run(host='0.0.0.0', port=5000) -
Dockerfile
FROM python:3.7-slim WORKDIR /app COPY . /app RUN pip install flask redis -i https://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com EXPOSE 5000 CMD ["python", "app.py"]
接着构建image:
$ docker build -t friendlyhello:v4 .

然后通过docker service create来创建服务,--replicas 3参数表示创建3个副本:
$ docker service create --replicas 3 -p 5000:5000 --name friendly friendlyhello:v4

成功以后,我们就可以看到这一服务的task们了:
$ docker service ps friendly

但是,我们发现只有manager节点的task启动了,2个worker节点都表示没有镜像,所以接下来我们就需要去做分发。
STEP 4: 快速分发镜像到所有节点
我们先缩个容:
$ docker service scale friendly=1

为了高效分发,我们不用docker hub,而是自己部署一个registry服务:
$ docker service create --name registry --publish 5555:5000 registry:2
看看成功了没:
$ docker service ps registry

OK,接下来我们来把friendlyhello:v4镜像给推送到registry,在此之前,我们先创建一个配置文件,加入配置,否则可能会出现https相关问题:
$ vi /etc/docker/daemon.json
写入:
{"insecure-registries": ["<你的manager的ip>:5555"]}
// 我的配置:
{"insecure-registries": ["192.168.99.112:555"]}

接着重启一下docker:
$ sudo /etc/init.d/docker restart
重启后,我们就可以重新打tag然后push到registry了:
$ docker tag friendlyhello:v4 <你的manager的ip>:5555/friendlyhello:v4
$ docker push <你的manager的ip>:5555/friendlyhello:v4
# 我的命令:
$ docker tag friendlyhello:v4 192.168.99.112:5555/friendlyhello:v4
$ docker push 192.168.99.112:5555/friendlyhello:v4

如果这里出现了奇奇怪怪的问题,试试等个几秒重新执行一下
接着,分别到worker-1和worker-2里,加入一个一样的daemon.json:
$ vi /etc/docker/daemon.json

别忘了添加完配置后重启一下
重启后,就可以pull下我们需要的那个镜像了:
$ docker pull 192.168.99.112:5555/friendlyhello:v4
$ docker tag 192.168.99.112:5555/friendlyhello:v4 friendlyhello:v4

如果又出现了奇奇怪怪的问题,可以试试在
manager节点再重新push一下
接着在manager节点扩容:
$ docker service scale friendly=3

这下3个节点的task就都成功跑起来了:
$ docker service ps friendly

可以通过浏览器访问看看:

部署是没什么问题了,不过我们还需要让它显示所使用的node的名字,这需要加入环境变量。
我们先关了现在的服务:
$ docker service rm friendly
再重新创建,同时加入新的参数:
$ docker service create --replicas 3 -p 5000:5000 --name friendly3 -e HOSTNAME="{{.Node.Hostname}}" --hostname="{{.Node.Hostname}}-{{.Node.ID}}-{{.Service.Name}}" friendlyhello:v4

再来访问看看:

STEP 5: 用Portainer可视化管理Swarm集群
回到manager节点,现在来通过docker stack部署Portainer:
$ curl -L https://downloads.portainer.io/portainer-agent-stack.yml -o portainer-agent-stack.yml
$ docker stack deploy --compose-file=portainer-agent-stack.yml portainer
完成后,我们可以通过:9000端口来访问Portainer:

这里有丰富的功能,可以方便我们可视化地操作swarm集群


