关键概念:
什么是 swarm:
一个 swarm 群集由多个 Docker 主机组成, 这些主机以群集模式运行, 并充当 managers 和 workers
给定的 Docker 主机可以是 manager 或 worker 这两种角色
创建服务时, 您可以定义其最佳状态(可用的副本数量, 网络和存储资源, 服务暴露给外部的端口等)
Docker 努力维持所需的状态. 例如, 如果工作节点变得不可用, Docker 将该节点上的容器调度到其他节点上运行
任务:
一个任务是一个运行的容器, 是一个 swarm 服务的一部分, 并通过 swarm manager 管理, 而不是一个独立的容器
群集服务相对于独立容器的一个主要优点是, 您可以修改服务的配置, 包括其连接的网络和卷, 而无需手动重新启动服务, Docker 将更新配置
当 Docker 以群集模式运行时, 您仍然可以在 swarm 节点上运行独立容器和群集服务
独立容器和群集服务之间的关键区别在于, 只有群集管理器可以管理群集, 而独立容器可以在任何守护程序上启动
与使用 Docker Compose 定义和运行容器的方式相同, 您可以定义和运行 swarm service stacks
节点:
一个节点是一个装有 Docker Engine 的主机, 要将应用程序部署到 swarm 请将服务定义提交给 manager 节点, manager 节点将任务分派给 work 节点
manager 节点维护群集状态所需的编排和集群管理功能. manager 节点选择单个 leader 来执行编排任务
worker 节点接收并执行从 manager 节点分派的任务
默认情况下 manager 节点还将作为 worker 节点运行, 但您可以将它们配置为仅作为 manager 节点
agent 程序在每个 worker 节点上运行, 并报告分配给它的任务
worker节点向 manager 节点通知其分配的任务和当前状态, 以便 manager 可以维持每个 worker 的期望状态
服务和任务:
服务是在 manager 或 worker 节点上执行的任务的定义. 它是 swarm 系统的中心, 是用户与 swarm 交互的主要根源
在创建服务时, 指定要使用的容器镜像以及在运行容器中执行的命令
在 replicated 服务模型中, swarm 管理器根据您在所需状态中设置的比例在节点之间分配特定数量的 replica 任务
负载均衡:
swarm 管理器使用入口负载均衡来发布可被外部主机访问的服务
swarm 管理器可以自动为发布的端口分配服务, 或者可以为服务发布端口
在发布端口时, 您可以指定任何未使用的端口, 如果您没有指定端口, swarm 管理器将为服务分配给一个在 30000-32767 范围内的端口
安装 swarm 的前提:
1、安装 docker
# 建议安装 docker 1.12 以上版本
https://docs.docker.com/install/linux/docker-ce/centos/#prerequisites
2、配置 docker 监听 TCP 2375端口
mkdir /etc/systemd/system/docker.service.d/
cat > /etc/systemd/system/docker.service.d/tcp.conf <<EOF
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375
EOF
3、重启 docker
systemctl daemon-reload
systemctl restart docker
创建 swarm 集群:
# 初始化 master 节点, 192.168.5.11 为 master 和其他节点进行通信的 IP
# 初始化完成后输出 docker swarm join --token ... 的一条命令, 在节点执行, 将节点加入 swarm 集群
docker swarm init --advertise-addr 192.168.5.11
# 查看 swarm 集群状态
docker info
# 查看和节点相关的信息
docker node ls
# 查看端口监听情况
ss -tunl
# docker swarm 需要监听的端口
# tcp/2377 # swarm 集群管理端口
# tcp/7946 udp/7946 # 节点间通信
# udp/4789 # 网络流量传输
节点加入集群:
# 将 master端 执行 docker swarm init 后输出的命令在 node 节点上运行即可
docker swarm join --token \
SWMTKN-1-4xim2s11yxwlb1rz4pvbm9fsivjfgh5bssspalpdku4p1uk806-baaerpzmlgena74kvzh5dif3a 192.168.5.11:2377
# 如果不小心忘记了, 可以使用此命令获取
docker swarm join-token worker
# 在 master 上运行此命令将看见 node 节点已经加入 swarm
docker node ls
swarm 集群基础操作:
# 在 maser 上运行此命令(对 swarm 集群的大多数操作都是在 master 上操作的, 下面的操作如无额外说明都是在 master 上执行)
docker service create --replicas 1 --name helloworld alpine ping docker.com
# docker service create 创建一个 swarm 服务
# --replicas 服务的副本数(一共有多少个容器在运行)
# --name 服务名称
# alpine ping docker.com 运行 alpine 镜像, 执行 ping docker.com 命令
# 查看服务
docker service ls
# 输出 helloworld 服务基础信息
docker service inspect --pretty helloworld
# 输出 helloworld 服务详细信息
docker service inspect helloworld
# 查看正在运行服务的节点, 在节点对应节点上运行 docker container ls 可以看见该容器在运行
docker service ps helloworld
# 将 helloworld 的副本数更改为 10
docker service scale helloworld=10
# 查看服务副本数量(查看 REPLICAS 列)
docker service ls
# 将 helloworld 的副本数更改为 5
docker service scale helloworld=5
# 查看服务副本数量, 这次发现 REPLICAS 为 5/5 (有可能是 10/5 这是因为虽然服务器已经减少副本的数量了, 但是 docker 还没有将容器删除, 出现这种情况多等待一段时间即可)
docker service ls
# 查看各个副本所在的 node 节点
docker service ps helloworld
# 删除该服务
docker service rm helloworld
swarm 滚动更新服务:
# 创建一个 redis 服务
docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6
# --update-delay 指定服务在更新时的延迟时间, 将时间表示为T, 秒数Ts, 分钟数Tm, 小时数Th. 所以 10m30s 表示延迟10分30秒
# --update-parallelism 默认情况下, 调度程序一次更新1个任务, 使用该参数指定同时更新的最大任务数
# 默认情况下, 对单个任务更新返回的状态为 RUNNING 时, 调度程序会继续更新下一个任务, 直到所有任务更新完成. 如果在更新返回 FAILED 则调度程序会暂停更新
# 可以使用 --update-failure-action 来控制 docker service create 或 docker service update 的行为
# --update-failure-action 可接受的值 pause(默认值, 暂停), continue(继续), rollback(回滚)
# 查看 redis 服务(这时 IMAGE 列的值为 redis:3.0.6)
docker service ls
# 更新 redis 服务(swarm 管理器将根据 UpdateConfig 策略将更新应用于节点)
docker service update --image redis:3.0.7 redis
# 查看 redis 服务(这时 IMAGE 列的值为 redis:3.0.7)
docker service ls
# 查看更新状态, 如果更新失败在 Message 列将显示和更新失败相关的内容
docker service inspect --pretty redis
# 重启暂停的更新任务
docker service update redis
# 查看服务更新信息(将看见所有的历史版本)
docker service ps redis
设置 swarm 节点状态:
# 当节点处于 Active 状态时(docker node ls 的 AVAILABILITY 列), swarm 管理器可以将任务分配给任何 ACTIVE 状态的节点
# 有时, 例如服务器维护, 需要将节点状态设置为 DRAIN
# DRAIN 状态阻止节点从 swarm 管理器接收新任务, 并且 swarm 管理器将停止此节点上运行的任务(一个任务通常就是一个容器), 将其上的任务分配给其他状态为 ACTIVE 的节点
# 查看节点(获取节点 NODE 名称)
docker node ls
# 将节点状态设置为 drain, docker-2 是我 docker 节点的名称
docker node update --availability drain docker-2
# 查看节点状态
docker node inspect --pretty docker-2 | grep Availability
# 查看 swarm 管理器将其任务的分配情况
docker service ps redis
# 将节点状态设置为 active
docker node update --availability active docker-2
# 查看节点状态
docker node inspect --pretty docker-2 | grep Availability
swarm 网络:
docker swarm 通过发布端口使得外部主机可以访问集群资源, 所有节点都参入到 ingress 路由网格
路由网格使得集群中每个节点都能够接收集群中已发布的服务端口的连接, 即使节点上没有运行该任务
路由网格将所有传入请求路由到发布端口的可用节点的可用容器上
docker 的路由网格在 Linux 上使用 iptables 实现
# 在新版本的 docker swarm 中, 使用 --publish 暴露端口, published 为暴露的端口(即宿主机端口), target 为容器端口
# 如果不指定 published 参数 docker swarm 会随机分配一个高编号的端口
docker service create --name my-web --publish published=8080,target=80 --replicas 2 nginx
# 在任何节点上访问 8080 端口时, docker 会将请求路由到活动容器(状态健康并且运行了该任务的容器)
# 在 swarm 节点本身上, 8080 端口实际上可能不受约束, 但路由网格知道如何路由流量并防止发生任何端口冲突
# 路由网格节点上的发布端口的所有地址(0.0.0.0:<port>), 对于外网地址, 该端口可以在外部访问, 对于其他 IP 地址只能在内部访问
访问测试:
# 查看容器所在的节点
docker service ps my-web
# 修改 node 2 节点上的 index.html
[root@docker-2 ~]# docker container exec -it 4a998a01a9d4 bash # 进入 my-web 的任务容器
root@4a998a01a9d4:/# echo "node2" > /usr/share/nginx/html/index.html # 修改页面内容
# 修改 node 3 节点上的 index.html
[root@docker-3 ~]# docker container exec -it f1aedec1c1db bash # 进入 my-web 的任务容器
root@f1aedec1c1db:/# echo "node3" > /usr/share/nginx/html/index.html # 修改页面内容
# 在任意节点访问, 路由网格会自动进行负载均衡
curl http://127.0.0.1:8080/
# 对现有的服务进行端口发布
docker service update --publish-add published=2222,target=22 my-web
# 查看已发布的端口
docker service inspect --format="{{json .Endpoint.Spec.Ports}}" my-web | python -m json.tool
默认情况下, docker swarm 发布的端口为 TCP 端口, 需要发布 UDP 的端口需要使用 protocol 参数设置
# 发布 TCP 端口
docker service create --name dns-cache --publish published=53,target=53 dns-cache
# 发布 TCP 和 UDP 端口
docker service create --name dns-cache --publish published=53,target=53 --publish published=53,target=53,protocol=udp dns-cache
# 发布 UDP 端口
docker service create --name dns-cache --publish published=53,target=53,protocol=udp dns-cache
绕过路由网格:
您可以绕过路由网格, 以便在访问给定节点上的绑定端口时, 始终访问在该节点上运行的服务实例, 这被称为 host 模式
host 和 ingress 的区别:
1、如果一个任务启动了两节点上的容器, 那么在 ingress 模式下, 不管访问那个 node 其都会对请求做负载均衡, 将请求负载到两个节点上的容器
2、在 host 模式中必须使用 IP 地址访问运行了该任务的节点, 其访问是和 IP 地址绑定的
3、在 host 模式中, 如果节点没有运行指定任务则不会简单指定端口, 或者是其他不同的任务在监听
4、在 host 模式中, 创建服务时不能指定 --replicas 选项
5、如果您希望在每个节点上运行多个服务任务(例如: 当您有5个节点但运行10个副本时), 则无法指定静态目标端口, Docker 会随机分配高编号端口
# 要绕过路由网格, 将 --publish 的 mode 设置为 host, mode 默认为 ingress
docker service create --name web --publish published=8000,target=80,mode=host --mode global nginx
原文:http://blog.51cto.com/hongchen99/2310378