本篇教程会介绍如何使用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 = "cannot connect to Redis, counter disabled" html = "HostName: {host_name}
" \ "Hostname: {hostname}
" \ "Visits: {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集群