前言
这篇文章介绍Docker生态中的常被提到的Engine、Machine和Swarm,大家以了解为主,工作需要再深入。
Engine
Docker Engine其实就是我们常说的「Docker」,它是一个C/S模型(Client/Server)的应用,包含如下组件:
Daemon。守护进程,属于C/S中的Server(
dockerd
)REST API。Daemon向外暴露的REST 接口
CLI。向外暴露的命令行接口(Command Line API:
docker
)
客户端访问服务端的方式有三种:
使用命令行工具,如
docker run
、docker ps
等等直接通过调用REST API,如发送一个
curl
请求通过脚本直接和Daemon交互
用户通过Docker CLI向Docker Daemon发送REST API请求。Daemon创建和管理Docker objects(对象),如:
images。镜像
containers。容器
networks。网络
volumes。数据卷
Machine
在没有Machine之前,Docker的安装流程非常复杂,首先需要登录到相应的主机上,根据官方的安装和配置指南来安装Docker,而且不同的操作系统的安装步骤也不同。
Machine是一个简化Docker Engine安装和管理的命令行工具,这样通过一个简单的命令即可在相应的平台上安装Docker,如本地(macOS、Linux和Windows)、虚拟化平台(VirtualBox、macOS xhyve等),公有云(AWS、Azure、Digital Ocean等)等。使用Machine可以启动、审查、停止和重新启动托管的宿主机、升级 Docker 客户端和守护程序、并配置 Docker 客户端与宿主机通信。
通过图示可以看出来,Machine是管理本地/远程带有Docker Engine的主机的工具, docker-machine create
创建的「machine」包含了Daemon和REST API这2部分,Machine自己包含CLI。
我大概演示一下使用Machine的方法:
创建machine。
docker-machine create--driver virtualboxdefault
,这就会可以创建一个叫做default
的「机器」,它是Virtualbox类型的,所以可以在Virtualbox管理器里面看到这个虚拟机。连接到machine。
eval"$(docker-machine env default)"
,其实就是做了对应的环境变量设置使用Docker CLI。之后就可以使用
docker ps
等命令查看和管理这个主机里面的镜像/容器等内容了
Swarm Mode
Docker Swarm是Docker 官方的集群管理和编排工具,可以将多个Docker主机封装为单个大型的虚拟Docker主机,成为一个容器平台。从 Docker1.12.0+
开始 SwarmMode
已经内嵌入 Docker Engine,成为子命令 docker swarm
可以直接使用。
SwarmMode
主要特性如下:
具有容错能力的去中心化设计
服务发现。可以做到Docker集群中节点的动态加入和退出的感知,支持主流的etcd、consul和zookeeper。
负载均衡。让资源分配负载,以达到最优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载。
动态伸缩。服务在判断监测指标超出所设定的上下限时,会按照你的设置触发扩容或缩容。
滚动更新(Rolling updates)。可以实现「零停机时间部署」,下节我们还会再说。
安全传输。集群中的每个节点都执行TLS的相互认证和加密,以确保自己与所有其他节点之间的通信安全。
确保期望状态。Swarm会在后台进行轮训检查,确保实际状态能够满足期望状态的要求。
Swarm 是使用SwarmKit构建的 Docker 引擎内置(原生)的集群管理和编排工具。它包含如下三个重要概念: 节点、服务和任务,我们挨个看。
节点(Node)
运行 Docker 的主机可以主动初始化一个 Swarm 集群或者加入一个已存在的 Swarm 集群,这样这个运行 Docker 的主机就成为一个 Swarm 集群的节点。节点分为管理 (manager) 节点和工作 (worker) 节点。
管理节点用于 Swarm 集群的管理,管理节点分发工作单元(称为Task「任务」)到工作节点。docker swarm
命令基本只能在管理节点执行(节点退出集群命令 docker swarm leave
可以在工作节点执行)。一个 Swarm 集群可以有多个管理节点,但只有一个管理节点可以成为领导(leader, 通过Raft协议实现)。管理节点还要通过leader执行维护集群所需状态所需的编排和集群管理任务。
工作节点接收并执行从管理节点分派的任务。默认情况下,管理器节点也作为工作节点运行服务(Service),但是你可以将它们配置为专门运行管理器任务,并且只运行管理器节点。代理在每个工作节点上运行,并报告分配给它的任务。工作节点通知管理节点其分配任务的当前状态,以便管理器可以维护每个工作的所需状态。
任务(Task)
任务是Swarm中的最小的调度单位,任务携带Docker容器和在容器中运行的命令。管理节点根据服务中设置的副本(Replicas)数量将任务分配给工作节点。一旦任务被分配给一个节点,它就不能移动到另一个节点。它只能在指定的节点上运行或失败
任务是这么调度的:
服务(Service)
服务是指一组任务的集合,它定义了任务的属性,是Swarm系统的中心结构:
服务有两种模式:
Replicated services。按照一定规则在各个工作节点上运行指定个数的任务
Global services。每个可用节点上运行一个任务
PS: 两种模式通过 docker service create
的 --mode
参数指定。
基本用法
我们创建一个最小的 Swarm 集群,包含一个管理节点和两个工作节点。创建Docker 主机使用Docker Machine:
# 管理节点
❯ docker-machine create -d virtualbox manager # 创建管理节点,名字为manager
❯ docker-machine ssh manager # 登录到管理节点
docker@manager:~$ /sbin/ifconfig eth1 | grep 'inet addr' | cut -d: -f2 | awk '{print $1}'
192.168.99.104 # 获得IP
docker@manager:~$ docker swarm init --advertise-addr 192.168.99.104 # 在管理节点初始化一个Swarm集群,另外Docker主机有多个网卡,所以有多个IP,必须使用 --advertise-addr 指定IP
Swarm initialized: current node (k8cdrnrylrkxpsk4qoyybwpca) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-2gfzia6yrk172e8352jxpolevjr9gx1a9xu95hg0ibkhqat52p-d6j79273adew38s5mzmewgwoo 192.168.99.104:2377 # 记住这句命令
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
❯ docker-machine create -d virtualbox worker1 # 创建工作节点,名字worker1
❯ docker-machine ssh worker1
docker@worker1:~$ docker swarm join --token SWMTKN-1-2gfzia6yrk172e8352jxpolevjr9gx1a9xu95hg0ibkhqat52p-d6j79273adew38s5mzmewgwoo 192.168.99.104:2377 # 从上面直接粘贴来
This node joined a swarm as a worker.
❯ docker-machine create -d virtualbox worker2 # 创建工作节点,名字worker2
❯ docker-machine ssh worker2
docker@worker2:~$ docker swarm join --token SWMTKN-1-2gfzia6yrk172e8352jxpolevjr9gx1a9xu95hg0ibkhqat52p-d6j79273adew38s5mzmewgwoo 192.168.99.104:2377
This node joined a swarm as a worker.
这样集群就做好了,在管理节点看一下状态:
❯ docker-machine ssh manager
docker@manager:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
k8cdrnrylrkxpsk4qoyybwpca * manager Ready Active Leader 18.09.9
puzrum9ixbt6holgfk5d8aokl worker1 Ready Active 18.09.9
sqwpb00zh5fp9z2o6r7vnebbt worker2 Ready Active 18.09.9
然后部署Nginx(只能在管理节点运行):
docker@manager:~$ docker service create --replicas 3 -p 80:80 --name nginx nginx:1.17.4-alpine # 创建服务,三个副本,服务监听在80端口
pydkv5ffwfqiv1aua1ylmwhum
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Service converged
docker@manager:~$ docker service ls # 查看当前Swarm集群运行的服务
ID NAME MODE REPLICAS IMAGE PORTS
pydkv5ffwfqi nginx replicated 3/3 nginx:1.17.4-alpine *:80->80/tcp
# 现在我们使用浏览器,输入任意节点IP(如管理节点的192.168.99.104),都能看到nginx默认页面
docker@manager:~$ docker service logs nginx # 查看Nginx服务的日志
... # 省略输出
docker@manager:~$ docker service scale nginx=5 # 业务高峰期时,扩展服务运行的容器数量
nginx scaled to 5
overall progress: 5 out of 5 tasks
1/5: running [==================================================>]
2/5: running [==================================================>]
3/5: running [==================================================>]
4/5: running [==================================================>]
5/5: running [==================================================>]
verify: Service converged
docker@manager:~$ docker service ps nginx # 查看服务详情
i6xkgnneqbbq nginx.1 nginx:1.17.4-alpine worker2 Running Running 4 minutes ago
f517ogp705ne nginx.2 nginx:1.17.4-alpine manager Running Running 5 minutes ago
... # 省略输出
docker@manager:~$ docker service scale nginx=2 # 业务平稳期时,减少服务运行的容器数量
在Swarm集群中使用Compose文件
在第一篇中我使用 docker-compose.yml
一次配置、启动多个容器,在Swarm集群中也可以使用compose文件来配置、启动多个服务。在上一小节中,使用 docker service create
一次只能部署一个服务(Nginx),使用 docker-compose.yml
可以一次启动多个关联的服务。还是拿lyanna项目的docker-compose.yml体验一下,不过需要修改配置项,添加deploy(如mode和副本数等项),也要去掉一些stack不支持的项(如build、restart等):
version: '3'
services:
db:
image: mysql
environment:
MYSQL_DATABASE: 'test'
MYSQL_USER: 'root'
MYSQL_PASSWORD: ''
MYSQL_ROOT_PASSWORD: ''
MYSQL_ALLOW_EMPTY_PASSWORD: 'true'
volumes:
- my-datavolume:/var/lib/mysql
deploy:
placement:
constraints: [node.role == manager]
redis:
image: redis:alpine
deploy:
mode: replicated
replicas: 3
memcached:
image: memcached:1.5-alpine
deploy:
mode: replicated
replicas: 3
web:
image: 127.0.0.1:5000/lyanna-app
build: .
ports:
- '8000:8000'
volumes:
- .:/app
- ./local_settings.py.tmpl:/app/local_settings.py
depends_on:
- db
- redis
- memcached
environment:
PYTHONPATH: $PYTHONPATH:/usr/local/src/aiomcache:/usr/local/src/tortoise:/usr/local/src/arq:/usr/local/src
command: sh -c './setup.sh && python app.py'
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
stop_grace_period: 1m30s
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
volumes:
my-datavolume:
其中有3个需要着重说明的点:
visualizer服务提供一个可视化页面,可以从浏览器中很直观的查看集群中各个服务的运行节点,一会会感受到
db/redis/memcached/visualizer这几项都添加了deploy项,
mode
指服务模式,replicas
指副本数,placement
可以限定满足条件的Node,而避免在不合适的Node进行部署,这里限制db/visualizer都要在管理节点上web加了image项,是一个注册服务的API地址,下面会看到如何注册和推送镜像上去
接着部署:
❯ eval "$(docker-machine env manager)" # 本机切换到管理主机
❯ git clone https://github.com/dongweiming/lyanna # 下载lyanna项目源码,如果原来已经clone了不用再做
❯ cd lyanna
❯ docker service create --name registry --publish published=5000,target=5000 registry:2 # 创建注册服务(名字叫registry),启动在5000端口上
❯ docker-compose -f docker-compose.swarm.yml build # 用Compose的方式启动,这个过程会构建lyanna-app镜像
❯ docker-compose -f docker-compose.swarm.yml push # 把lyanna-app推送给本地的注册服务
❯ docker stack deploy -c docker-compose.swarm.yml lyanna # 部署服务
Ignoring unsupported options: build
Creating network lyanna_default
Creating service lyanna_web
Creating service lyanna_visualizer
Creating service lyanna_db
Creating service lyanna_redis
Creating service lyanna_memcached
现在在浏览器输入 任一节点IP:8080
即可看到各节点运行状态,类似如下效果:
可以看到:
db、visualizer限定在管理节点manager
redis/memcached由于副本数和节点数一致,所以每个节点都有一个
web和registry由于负载平衡的作用分配到了2个工作节点上,让服务整体看起来比较均衡
在浏览器新的标签页输入 任一节点IP:8000
即可看到lyanna博客效果!
延伸阅读
https://docs.docker.com/engine/docker-overview/
https://www.docker.com/products/container-runtime
https://docs.docker.com/machine/
https://docs.docker.com/engine/swarm/key-concepts/
https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/
https://docs.docker.com/engine/swarm/stack-deploy/