1. Devops/

docker-swarm 教程:stack(堆栈式服务)及节点管理篇

·717 字·4 分钟· loading
docker devops
demo007x
作者
demo007x

docker-swarm 教程:stack(堆栈式服务)及节点管理篇
#

使用 Docker stack 部署服务到集群中

在集群模式下运行Docker Engine时,我们可以使用docker stack deploy将完整的应用程序堆栈部署到集群中。deploy命令以Compose文件的形式接受堆栈描述。

docker stack deploy命令支持“3.x”版本的任何Compose文件。

  1. swarm 集群模式下运行的Docker引擎。

    Note:如果在本地开发环境中尝试,您可以使用docker swarm init将引擎置于swarm模式。

    如果您已经有一个多节点群在运行,请记住,所有docker stackdocker service命令都必须从管理器节点运行。

  2. 确保使用Docker Compose的最新版本。

设置Docker镜像仓库
#

由于swarm 集群由多个Docker引擎组成,因此需要一个仓库才能向所有引擎分发镜像。可以使用Docker Hub或使用私有化的 Docker Hub。我们在使用之前先注册 Docker Hub 仓库服务。

  1. 在的集群上启动一个registry作为仓库服务:

     docker service create --name registry --publish published=5000,target=5000 registry:2
    
  2. 使用docker service ls检查其状态:

     docker service ls
    

    一旦它在REPLICAS下读取1/1,它就会运行。如果它读取0/1,它可能仍然在拉去图像。

  3. 我们使用 curl命令查看是否安装成功:

     curl http://localhost:5000/v2/
    

创建应用程序
#

本指南中使用的应用程序由一个Python应用程序组成,该应用程序在Redis实例中维护一个计数器,并在访问它时增加计数器。

  1. 为项目创建一个目录:

     mkdir stackdemo
     cd stackdemo
    
  2. 在项目目录中创建一个名为app.py的文件,并将其粘贴到:

    from 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)
    
  3. 创建一个名为requirements.txt的文件,并将这两行粘贴到:

    flask
    redis
    
  4. 创建一个名为Dockerfile的文件,并下面的内容复制到文件中:

    # syntax=docker/dockerfile:1
    FROM python:3.4-alpine
    ADD . /code
    WORKDIR /code
    RUN pip install -r requirements.txt
    CMD ["python", "app.py"]
    
  5. 创建一个名为docker-compose.yml的文件,把一下内容复制到文件中:

      services:
      web:
        image: 127.0.0.1:5000/stackdemo
        build: .
        ports:
          - "8000:8000"
      redis:
        image: redis:alpine
    

    web 应用程序的镜像是使用上面定义的 Dockerfile 构建的。它还标记了 127.0.0.1:5000 此前创建的注册表地址。这在将应用程序分发到集群时非常重要。

    使用Compose测试应用程序
    #

    1. 使用docker-compose up启动应用程序。这会构建Web应用程序图像,如果还没有Redis图像,则拉取它,并创建两个容器。

      我们会看到有关引擎处于swarm模式的警告。这是因为Compose没有利用群模式,而是将所有内容部署到单个节点。我们暂时忽略这一警告。

      $ 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
      
    2. 检查应用程序是否使用docker compose ps运行:

      docker-compose ps
      8000/tcp
      

      您可以使用curl localhost:8000 测试该应用程序:

      image-20230728090447366

    3. 关闭应用程序:

       docker-compose down --volumes
      

将生成的镜像推送到Docker 仓库
#

要将Web应用程序的镜像分发到群中,需要将其推送到之前设置的Hub。使用Compose 执行命令:

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(堆栈式服务) 部署服务到集群中
#

  1. 使用docker stack deploy创建堆栈:

     docker stack deploy --compose-file docker-compose.yml stackdemo
    

    最后一个参数是stack的名称。每个网络、卷和服务名称都以堆栈名称为前缀。

  2. 检查它是否与docker stack services stackdemo一起运行:

     docker stack services stackdemo
    

    image-20230805104643174

    和以前一样,你可以用curl http://localhost:8000测试应用程序:

    root@master:~/stackdemo# curl localhost:8000
    Hello World! I have been seen 3 times.
    

    因为有了Docker的内置路由,我们可以在端口8000上访问群中的任何节点,并路由到应用程序:

    root@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.
    
  3. 使用docker stack rm删除 stack:

     docker stack rm stackdemo
    
  4. 使用docker service rm 删除 registry

     docker service rm registry
    
  5. 如果我们只是在本地机器上测试东西,并希望让Docker引擎退出集群模式,请使用docker swarm leave

     docker swarm leave --force
    

将节点加入到集群
#

我们在首次创建集群时,将单个Docker引擎置于集群模式。要充分利用群模式,我们可以将节点添加到集群中:

  • 添加worker 节点会增加容量。当将服务部署到集群时,引擎会在可用节点上安排任务,无论它们是工作节点还是管理器节点。当将工作节点添加到集群中时,会增加集群的规模,以便在不影响 Manager 的情况下处理任务。
  • Manager 节点增加了容错性。Manager 节点为集群执行编排和集群管理功能。在 Manager 节点中,单个领导者节点执行编排任务。如果一个Manager节点下降,剩余的 worker 节点将选择一个新的领导者,并恢复编排和维护蜂群状态。默认情况下,管理器节点也运行任务。

Docker Engine根据给我们提供给docker swarm join命令的join-token加入集群。节点仅在连接时使用令牌。

添加 worker 节点
#

要检索连接命令,包括工作节点的连接令牌,请在Manager 节点上运行以下命令:

docker swarm join-token worker

从 worker节点的输出中运行命令以加入集群:

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算法共享数据,因此必须有奇数的管理器。只要超过一半的管理器节点的法定人数可用,群群就可以继续运行。

要检索包括管理器节点的连接令牌在内的连接命令,请在管理器节点上运行以下命令:

 docker swarm join-token manager

从新管理器节点上的输出运行命令,在要加入集群的节点中执行输出的命令,将其加入集群:

 docker swarm join \
  --token SWMTKN-1-61ztec5kyafptydic6jfc1i33t37flcl4nuipzcusor96k7kby-5vy9t8u35tuqm7vh67lrz9xp6 \
  172.16.95.137:2377

管理集群中的节点
#

作为集群管理生命周期的一部分,我们可能需要查看或者管理集群相关的节点:

要查看群中的节点列表,请从管理器节点运行docker node ls

 docker node ls

202307301737058.png

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标志,以人类可读格式打印结果。例如:

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可用性:

 docker node update --availability drain node1

添加或删除标签元数据
#

节点标签提供了一种灵活的节点组织方法。我们可以在服务约束中使用节点标签。在创建服务时应用约束,以限制调度器为服务分配任务的节点。

在管理器节点上运行docker node update --label-add,将标签元数据添加到节点。--label-add标志支持<key><key>=<value>对。

为要添加的每个节点标签传递一次--label-add标志:

 docker node update --label-add foo --label-add bar=baz node1

我们使用docker节点更新为节点设置的标签仅适用于群中的节点实体。不要将它们与dockerd 的docker守护进程标签混淆。

因此,节点标签可用于将关键任务限制为满足特定要求的节点。例如,仅在需要运行特殊工作负载的机器上进行调度。

然而,引擎标签仍然有用,因为一些不影响容器安全编排的功能可能最好以分散的方式设置。例如,引擎可以有一个标签来指示它具有某种类型的磁盘设备,这可能与安全没有直接关系。这些标签更容易被集群编排器所“信任”。

提升或降级节点
#

我们可以将工作节点提升为管理器角色。当管理器节点不可用或您想让管理器脱机进行维护时,这很有用。同样可以将管理器节点降级为worker角色。

注意:无论我们是提升或降级节点的原因是什么,都必须始终在集群中保持经理节点的法定人数。

要提升节点或一组节点,请从管理器节点运行docker node promote

 docker node promote node1 node2

要降级节点或节点集,请从管理器节点运行docker node demote

 docker node demote node1 node2

docker node promotedocker node demotedocker node update --role managerdocker node update --role worker的简单命令。

在swarm节点上安装插件
#

如果我们的集群服务依赖于一个或多个插件,这些插件需要在可能部署该服务的每个节点上可用。我们可以在每个节点上手动安装插件或脚本安装。还可以使用Docker API以类似于全局服务的方式部署插件,方法是指定aPluginSpec而不是ContainerSpec。

离开集群
#

如果我们不在使用集群的运行模式,在 manager 节点上运行docker swarm leave命令,将集群中删除。

例如,将manager节点从执行一下命令即可:

 docker swarm leave

当一个manager离开集群时,Docker引擎将停止以集群模式运行。编排器不再将任务调度到节点。

如果节点是管理器节点,我们将收到有关维护法定人数的警告。要覆盖警告,请传递--force标志。如果最后一个管理器节点离开群,群将变得不可用,需要您采取灾难恢复措施。

节点离开集群后,可以在管理器节点上运行docker node rm命令,从节点列表中删除节点。

例如:

 docker node rm node2

注意: 如果工作节点没有退出集群模式,在管理节点上是无法将管理节点移除的。或者可以使用 -f 参数, 强制将工作节点下线。

备注:
#

compose V3 https://docs.docker.com/compose/compose-file/compose-file-v3/

Related

docker-swarm 教程:服务管理篇
docker devops
docker-swarm 教程:服务管理篇
docker-swarm 教程:部署篇
docker devops
docker-swarm 教程:部署篇
生产环境中使用Docker的最佳实践
docker devops
近几年Docker的使用不断增长📈,上至公司团队,下至普通开发者。 但是并不是每个团队(或者个人)在使用 Docker 的时候都能做到 Docker 的最佳实践 👀, 本文将从以下几个方面来聊聊 Docker 工程化实践中的最佳方案.