docker-swarm 教程:stack(堆栈式服务)及节点管理篇
使用 Docker stack 部署服务到集群中
在集群模式下运行Docker Engine时,我们可以使用docker stack deploy将完整的应用程序堆栈部署到集群中。deploy命令以Compose文件的形式接受堆栈描述。
docker stack deploy命令支持"3.x"版本的任何Compose文件。
-
在
swarm集群模式下运行的Docker引擎。Note:如果在本地开发环境中尝试,您可以使用
docker swarm init将引擎置于swarm模式。如果您已经有一个多节点群在运行,请记住,所有
docker stack和docker service命令都必须从管理器节点运行。 -
确保使用
Docker Compose的最新版本。
设置Docker镜像仓库
由于swarm 集群由多个Docker引擎组成,因此需要一个仓库才能向所有引擎分发镜像。可以使用Docker Hub或使用私有化的 Docker Hub。我们在使用之前先注册 Docker Hub 仓库服务。
-
在的集群上启动一个
registry作为仓库服务:shdocker service create --name registry --publish published=5000,target=5000 registry:2 -
使用
docker service ls检查其状态:bashdocker service ls一旦它在
REPLICAS下读取1/1,它就会运行。如果它读取0/1,它可能仍然在拉去图像。 -
我们使用
curl命令查看是否安装成功:bashcurl http://localhost:5000/v2/
创建应用程序
本指南中使用的应用程序由一个Python应用程序组成,该应用程序在Redis实例中维护一个计数器,并在访问它时增加计数器。
-
为项目创建一个目录:
shmkdir stackdemo cd stackdemo -
在项目目录中创建一个名为
app.py的文件,并将其粘贴到:pythonfrom flask import Flask from redis import Redis app = Flask(__name__) redis = Redis(host='redis', port=6379) @app.route('/') def hello(): count = redis.incr('hits') return 'Hello World! I have been seen {} times.\n'.format(count) if __name__ == "__main__": app.run(host="0.0.0.0", port=8000, debug=True) -
创建一个名为
requirements.txt的文件,并将这两行粘贴到:shflask redis -
创建一个名为
Dockerfile的文件,并下面的内容复制到文件中:sh# syntax=docker/dockerfile:1 FROM python:3.4-alpine ADD . /code WORKDIR /code RUN pip install -r requirements.txt CMD ["python", "app.py"] -
创建一个名为
docker-compose.yml的文件,把一下内容复制到文件中:commonlispservices: web: image: 127.0.0.1:5000/stackdemo build: . ports: - "8000:8000" redis: image: redis:alpineweb 应用程序的镜像是使用上面定义的 Dockerfile 构建的。它还标记了
127.0.0.1:5000此前创建的注册表地址。这在将应用程序分发到集群时非常重要。使用Compose测试应用程序
-
使用
docker-compose up启动应用程序。这会构建Web应用程序图像,如果还没有Redis图像,则拉取它,并创建两个容器。我们会看到有关引擎处于swarm模式的警告。这是因为Compose没有利用群模式,而是将所有内容部署到单个节点。我们暂时忽略这一警告。
shell$ docker compose up -d [+] Running 8/8 ! web Warning 0.0s ✔ redis 6 layers [⣿⣿⣿⣿⣿⣿] 0B/0B Pulled 9.9s ✔ 31e352740f53 Already exists 0.0s ✔ 029a81f05585 Already exists 0.0s ✔ 7aaf69037d81 Already exists 0.0s ✔ 2bfe6b931134 Pull complete 3.9s ✔ 9528a9e21ebd Pull complete 3.9s ✔ d9b99dbdfe9d Pull complete 4.0s [+] Building 26.9s (11/11) FINISHED ✔ Network stackdemo_default Created 0.1s ✔ Container stackdemo-web-1 Started 0.6s ✔ Container stackdemo-redis-1 Started -
检查应用程序是否使用
docker compose ps运行:bashdocker-compose ps 8000/tcp您可以使用
curl localhost:8000测试该应用程序:
-
关闭应用程序:
bashdocker-compose down --volumes
-
将生成的镜像推送到Docker 仓库
要将Web应用程序的镜像分发到群中,需要将其推送到之前设置的Hub。使用Compose 执行命令:
shell
root@master:~/stackdemo# docker compose push
[+] Pushing 9/9
✔ redis Skipped 0.0s
✔ Pushing web: df94dc998b6a Pushed 1.0s
✔ Pushing web: 5f70bf18a086 Pushed 0.1s
✔ Pushing web: ba8c6053b4d9 Pushed 0.1s
✔ Pushing web: 62de8bcc470a Pushed 1.3s
✔ Pushing web: 58026b9b6bf1 Pushed 0.1s
✔ Pushing web: fbe16fc07f0d Pushed 3.7s
✔ Pushing web: aabe8fddede5 Pushed 1.3s
✔ Pushing web: bcf2f368fe23 Pushed 1.3s
使用 stack(堆栈式服务) 部署服务到集群中
-
使用
docker stack deploy创建堆栈:shdocker stack deploy --compose-file docker-compose.yml stackdemo最后一个参数是stack的名称。每个网络、卷和服务名称都以堆栈名称为前缀。
-
检查它是否与
docker stack services stackdemo一起运行:bashdocker stack services stackdemo
和以前一样,你可以用
curl http://localhost:8000测试应用程序:shroot@master:~/stackdemo# curl localhost:8000 Hello World! I have been seen 3 times.因为有了Docker的内置路由,我们可以在端口8000上访问群中的任何节点,并路由到应用程序:
shroot@master:~/stackdemo# curl localhost:8000 Hello World! I have been seen 3 times. root@master:~/stackdemo# curl node1:8000 Hello World! I have been seen 4 times. root@master:~/stackdemo# curl node2:8000 Hello World! I have been seen 5 times. root@master:~/stackdemo# curl node1:8000 Hello World! I have been seen 6 times. root@master:~/stackdemo# curl master:8000 Hello World! I have been seen 7 times. -
使用
docker stack rm删除 stack:shdocker stack rm stackdemo -
使用
docker service rm删除registry:shdocker service rm registry -
如果我们只是在本地机器上测试东西,并希望让Docker引擎退出集群模式,请使用
docker swarm leave:shdocker swarm leave --force
将节点加入到集群
我们在首次创建集群时,将单个Docker引擎置于集群模式。要充分利用群模式,我们可以将节点添加到集群中:
- 添加worker 节点会增加容量。当将服务部署到集群时,引擎会在可用节点上安排任务,无论它们是工作节点还是管理器节点。当将工作节点添加到集群中时,会增加集群的规模,以便在不影响
Manager的情况下处理任务。 - Manager 节点增加了容错性。Manager 节点为集群执行编排和集群管理功能。在 Manager 节点中,单个领导者节点执行编排任务。如果一个Manager节点下降,剩余的 worker 节点将选择一个新的领导者,并恢复编排和维护蜂群状态。默认情况下,管理器节点也运行任务。
Docker Engine根据给我们提供给docker swarm join命令的join-token加入集群。节点仅在连接时使用令牌。
添加 worker 节点
要检索连接命令,包括工作节点的连接令牌,请在Manager 节点上运行以下命令:
bash
docker swarm join-token worker
从 worker节点的输出中运行命令以加入集群:
bash
docker swarm join --token SWMTKN-1-5ajtwjsdm7cpp59kcjf7ixfxy1h32jdesk9608or97cn6soszp-cp3mvw0r4d6edoqeu81b8x4tv 172.16.95.137:2377
docker swarm join命令执行以下操作:
- 将当前节点上的Docker引擎切换到集群模式。
- 从
Manager请求TLS证书。 - 用机器主机名命名节点
- 根据群令牌将当前节点加入到管理器监听地址的集群中。
- 将当前节点设置为
Active可用性,这意味着它可以从调度器接收任务。 - 将
ingress覆盖网络扩展到当前节点。
作为 Manager 加入
当我们运行docker swarm join并传递管理器令牌时,Docker Engine会切换到与worker相同的swarm模式。Manager 节点也参与了Raft 共识算法。新节点应该是Reachable,但现有的管理器仍然是群组Leader。
Docker建议每个集群三个或五个管理器节点来实现高可用性。由于群模式管理器节点使用Raft算法共享数据,因此必须有奇数的管理器。只要超过一半的管理器节点的法定人数可用,群群就可以继续运行。
要检索包括管理器节点的连接令牌在内的连接命令,请在管理器节点上运行以下命令:
bash
docker swarm join-token manager
从新管理器节点上的输出运行命令,在要加入集群的节点中执行输出的命令,将其加入集群:
sh
docker swarm join \
--token SWMTKN-1-61ztec5kyafptydic6jfc1i33t37flcl4nuipzcusor96k7kby-5vy9t8u35tuqm7vh67lrz9xp6 \
172.16.95.137:2377
管理集群中的节点
作为集群管理生命周期的一部分,我们可能需要查看或者管理集群相关的节点:
要查看群中的节点列表,请从管理器节点运行docker node ls:
bash
root@master:~/stackdemo# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
bbyi6evg0of1o64y6hc0j3249 * master Ready Active Leader 24.0.5
e30b3jr5pvphsgveap2ix7iox node1 Ready Active 24.0.5
los6oy5vh63wxwouqqg4akfis node2 Ready Active 24.0.5
AVAILABILITY列显示调度器是否可以将任务分配给节点:
Active意味着调度器可以将任务分配给节点。Pause意味着调度程序不会向节点分配新任务,但现有任务仍在运行。Drain意味着调度程序不会向节点分配新任务。调度器关闭任何现有任务,并将其调度到可用节点上。
MANAGER STATUS列显示了节点参与raft共识:
- 没有值表示不参与群管理的工作节点。
Leader意味着节点是主要管理器节点,为集群做出所有群管理和编排决策。Reachable意味着该节点是参与Raft共识法定人数的经理节点。如果领导者节点不可用,该节点有资格当选为新领导者。Unavailable意味着节点是一个无法与其他管理器通信的管理器。如果管理器节点不可用,您应该将新的管理器节点加入群中,或者将工作节点提升为管理器。
检查单个节点
我们可以在管理器节点上运行docker node inspect <NODE-ID>,以查看单个节点的详细信息。输出默认为JSON格式,也可以使用--pretty标志,以人类可读格式打印结果。例如:
bash
root@master:~/stackdemo# docker node inspect node1 --pretty
ID: e30b3jr5pvphsgveap2ix7iox
Hostname: node1
Joined at: 2023-07-30 09:36:17.102762431 +0000 utc
Status:
State: Ready
Availability: Active
Address: 172.16.95.138
Platform:
Operating System: linux
Architecture: x86_64
Resources:
CPUs: 2
Memory: 3.787GiB
Plugins:
Log: awslogs, fluentd, gcplogs, gelf, journald, json-file, local, logentries, splunk, syslog
Network: bridge, host, ipvlan, macvlan, null, overlay
Volume: local
Engine Version: 24.0.5
TLS Info:
TrustRoot:
-----BEGIN CERTIFICATE-----
MIIBazCCARCgAwIBAgIUBlxRrNPgy/kl03zsCmm3j00RwkswCgYIKoZIzj0EAwIw
EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMjMwNzMwMDkxMTAwWhcNNDMwNzI1MDkx
MTAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABEQX/beGrkwslJG0TBj+zbXdbJBwNb+cNW8K9G7+V5E/f4cQvzF/gQL1iq32
Ufo7Lzv8ZEUCecS32yn0r4PkjfujQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
Af8EBTADAQH/MB0GA1UdDgQWBBRKG3DDP17uQWKMOyfH7XcyxE7qIDAKBggqhkjO
PQQDAgNJADBGAiEA8LovRl7fp9N1eOmeMWv0HwYHbTN+KkGRgLoY//vZ1PYCIQD/
GI+X5fv8QiyfuRopsxVuvIjl9CRFUZFYb44jH9p0Ew==
-----END CERTIFICATE-----
Issuer Subject: MBMxETAPBgNVBAMTCHN3YXJtLWNh
Issuer Public Key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERBf9t4auTCyUkbRMGP7Ntd1skHA1v5w1bwr0bv5XkT9/hxC/MX+BAvWKrfZR+jsvO/xkRQJ5xLfbKfSvg+SN+w==
root@master:~/stackdemo#
更新一个节点
更改节点可用性
当我们遇到了以下的问题的时候可以更新节点的可用性来管理我们的集群中的节点:
- 耗尽管理器节点,使其仅执行群管理任务,并且无法进行任务分配。
- 耗尽一个节点,以便可以将其取下进行维护。
- 暂停一个节点,使其无法接收新任务。
- 恢复不可用或暂停的节点可用性状态。
例如,将管理器节点更改为Drain可用性:
sh
docker node update --availability drain node1
添加或删除标签元数据
节点标签提供了一种灵活的节点组织方法。我们可以在服务约束中使用节点标签。在创建服务时应用约束,以限制调度器为服务分配任务的节点。
在管理器节点上运行docker node update --label-add,将标签元数据添加到节点。--label-add标志支持<key>或<key>=<value>对。
为要添加的每个节点标签传递一次--label-add标志:
sh
docker node update --label-add foo --label-add bar=baz node1
我们使用docker节点更新为节点设置的标签仅适用于群中的节点实体。不要将它们与dockerd 的docker守护进程标签混淆。
因此,节点标签可用于将关键任务限制为满足特定要求的节点。例如,仅在需要运行特殊工作负载的机器上进行调度。
然而,引擎标签仍然有用,因为一些不影响容器安全编排的功能可能最好以分散的方式设置。例如,引擎可以有一个标签来指示它具有某种类型的磁盘设备,这可能与安全没有直接关系。这些标签更容易被集群编排器所"信任"。
提升或降级节点
我们可以将工作节点提升为管理器角色。当管理器节点不可用或您想让管理器脱机进行维护时,这很有用。同样可以将管理器节点降级为worker角色。
注意:无论我们是提升或降级节点的原因是什么,都必须始终在集群中保持经理节点的法定人数。
要提升节点或一组节点,请从管理器节点运行docker node promote:
bash
docker node promote node1 node2
要降级节点或节点集,请从管理器节点运行docker node demote:
bash
docker node demote node1 node2
docker node promote和docker node demote是docker node update --role manager和docker node update --role worker的简单命令。
在swarm节点上安装插件
如果我们的集群服务依赖于一个或多个插件,这些插件需要在可能部署该服务的每个节点上可用。我们可以在每个节点上手动安装插件或脚本安装。还可以使用Docker API以类似于全局服务的方式部署插件,方法是指定aPluginSpec而不是ContainerSpec。
离开集群
如果我们不在使用集群的运行模式,在 manager 节点上运行docker swarm leave命令,将集群中删除。
例如,将manager节点从执行一下命令即可:
bash
docker swarm leave
当一个manager离开集群时,Docker引擎将停止以集群模式运行。编排器不再将任务调度到节点。
如果节点是管理器节点,我们将收到有关维护法定人数的警告。要覆盖警告,请传递--force标志。如果最后一个管理器节点离开群,群将变得不可用,需要您采取灾难恢复措施。
节点离开集群后,可以在管理器节点上运行docker node rm命令,从节点列表中删除节点。
例如:
sh
docker node rm node2
注意: 如果工作节点没有退出集群模式,在管理节点上是无法将管理节点移除的。或者可以使用 -f 参数, 强制将工作节点下线。