容器技术-Docker swarm

本文聚焦容器平台技术,着重介绍Docker自带编排引擎Docker Swarm。涵盖其基本概念,如swarm、node、service等,还阐述了Swarm集群的部署、弹性设置、网络通信、更新回滚、存储、模式调整、健康检查、秘密管理及Stack定义等内容,为云计算相关学习提供参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

容器生态系统包含三个部分:

  1. 容器核心知识,包括架构、镜像、容器、网络和存储。

  2. 容器平台技术,包括容器编排引擎、容器管理平台和基于容器的 PaaS。

  3. 容器支持技术,包括多主机管理、跨主机网络方案、监控和日志管理。

     之前介绍过docker一些相关知识,有关容器核心技术和容器支持技术,下面来介绍下容器平台技术,这也是这几年最火的云计算相关的知识,如果学习了会大有裨益。容器编排引擎、容器管理平台和基于容器的 PaaS 在大规模生产部署中占有相当重要的位置。其中容器编排引擎是核心,而最重要的编排引擎则是 Kubernetes,这当然也是这个教程的重中之重

    本文只介绍docker自带的编排引擎docker swarm:


一、基本概念:

Docker Swarm 管理的是 Docker Host 集群。所以先来讨论一个重要的概念 - 集群化(Clustering)。

服务器集群由一组网络上相互连接的服务器组成,它们一起协同工作。一个集群和一堆服务器最显著的区别在于:

集群能够像 单个 系统那样工作,同时提供高可用、负载均衡和并行处理

1、swarm

swarm 运行 Docker Engine 的多个主机组成的集群。

没启动 swarm mode 时,Docker 执行的是容器命令;运行 swarm mode 后,Docker 增加了编排 service 的能力。

Docker 允许在同一个 Docker 主机上既运行 swarm service,又运行单独的容器。

2、node

swarm 中的每个 Docker Engine 都是一个 node,有两种类型的 node:manager 和 worker

为了向 swarm 中部署应用,我们需要在 manager node 上执行部署命令,manager node 会将部署任务拆解并分配给一个或多个 worker node 完成部署。

manager node 负责执行编排和集群管理工作,保持并维护 swarm 处于期望的状态。swarm 中如果有多个 manager node,它们会自动协商并选举出一个 leader 执行编排任务。

woker node 接受并执行由 manager node 派发的任务。默认配置下 manager node 同时也是一个 worker node,不过可以将其配置成 manager-only node,让其专职负责编排和集群管理工作。

work node 会定期向 manager node 报告自己的状态和它正在执行的任务的状态,这样 manager 就可以维护整个集群的状态。

3、service

service 定义了 worker node 上要执行的任务。swarm 的主要编排任务就是保证 service 处于期望的状态下。

二、部署swarm 集群

下面将三个节点进行集群,基于下面这三个节点:

swarm-manager 是 manager node,swarm-worker1 和 swarm-worker2 是 worker node

首先在swarm manager节点上创建swarm:docker swarm init --advertise-addr 192.168.2.101

--advertise-addr 指定与其他 node 通信的地址。

docker swarm init 输出告诉我们:

① swarm 创建成功,swarm-manager 成为 manager node。

② 添加 worker node 需要执行的命令。

③ 添加 manager node 需要执行的命令。

复制前面的 docker swarm join 命令,在 swarm-worker1 和 swarm-worker2 上执行,将它们添加到 swarm 中。

docker node ls 可以看到两个 worker node 已经添加进来了。

如果当时没有记录下 docker swarm init 提示的添加 worker 的完整命令,可以通过 docker swarm join-token worker 查看。

创建好了 Swarm 集群, 现在部署一个运行 httpd 镜像的 service,执行如下命令:

docker service create --name web_server httpd

通过 docker service ls 可以查看当前 swarm 中的 service。

REPLICAS 显示当前副本信息,0/1 的意思是 web_server 这个 service 期望的容器副本数量为 1,目前已经启动的副本数量为 1。命令 docker service ps 可以查看 service 每个副本的状态。

三、弹性

部署了只有一个副本的 Service,不过对于 web 服务,我们通常会运行多个实例。这样可以负载均衡,同时也能提供高可用。

swarm 要实现这个目标非常简单,增加 service 的副本数就可以了。在 swarm-manager 上执行如下命令:

docker service scale web_server=5

也可以在创建服务的时候使用 --replicas=5

docker service create --name web_server --replicas=5 httpd

副本数增加到 5,通过 docker service ls 和 docker service ps 查看副本的详细信息。

475.png

默认配置下 manager node 也是 worker node,所以 swarm-manager 上也运行了副本。如果不希望在 manager 上运行 service,可以执行如下命令:

docker node update --availability drain swarm-manager

通过 docker node ls 查看各节点现在的状态:

477.png

Drain 表示 swarm-manager 已经不负责运行 service,之前 swarm-manager 运行的那个副本会如何处理呢?用 docker service ps 查看一下:

478.png

四、网络通信

如果想将端口映射到host,使用--publish-add 8080:80

docker service update --publish-add 8080:80 web_server

或者创建的时候使用。

容器的网络与 --publish-add 之前已经大不一样了,现在有两块网卡,每块网卡连接不同的 Docker 网络

1、eth0 连接的是一个 overlay 类型的网络,名字为 ingress,其作用是让运行在不同主机上的容器可以相互通信。

2、eth1 连接的是一个 bridge 类型的网络,名字为 docker_gwbridge,其作用是让容器能够访问到外网。

ingress 网络是 swarm 创建时 Docker 为自动我们创建的,swarm 中的每个 node 都能使用 ingress

当我们访问任何节点的 8080 端口时,swarm 内部的 load balancer 会将请求转发给 web_server 其中的一个副本

微服务架构的应用由若干 service 组成。比如有运行 httpd 的 web 前端,有提供缓存的 memcached,有存放数据的 mysql,每一层都是 swarm 的一个 service,每个 service 运行了若干容器。在这样的架构中,service 之间是必然要通信的。怎样实现呢?那就得依靠服务发现了。

要使用服务发现,需要相互通信的 service 必须属于同一个 overlay 网络,所以我们先得创建一个新的 overlay 网络。

docker network create --driver overlay myapp_net

部署一个 web 服务,并将其挂载到新创建的 overlay 网络。

docker service create --name my_web --replicas=3 --network myapp_net httpd

部署一个 util 服务用于测试,挂载到同一个 overlay 网络。

docker service create --name util --network myapp_net busybox sleep 10000000

那么从一个容器就能ping通另外一个容器了。

五、更新和回滚:

下面我们将部署三副本的服务,镜像使用 httpd:2.2.31,然后将其更新到 httpd:2.2.32。

创建服务:

docker service create --name my_web --replicas=3 httpd:2.2.31

将 service 更新到 httpd:2.2.32:

docker service update --image httpd:2.2.32 my_web

默认配置下,Swarm 一次只更新一个副本,并且两个副本之间没有等待时间。我们可以通过 --update-parallelism 设置并行更新的副本数目,通过 --update-delay 指定滚动更新的间隔时间。

比如执行如下命令:

docker service update --replicas 6 --update-parallelism 2 --update-delay 1m30s my_web

service 增加到六个副本,每次更新两个副本,间隔时间一分半钟。

docker service inspect 查看 service 的当前配置。

Swarm 还有个方便的功能是回滚,如果更新后效果不理想,可以通过 --rollback 快速恢复到更新之前的状态。

docker service update --rollback my_web

六、存储:

volume 不依赖 Docker 主机和容器,生命周期由 storage provider 管理,volume 的高可用和数据有效性也全权由 provider 负责,Docker 只管使用。

Rex-Ray 是开源的容器存储管理解决方案。支持主流的容器编排引擎 Docker Swarm、 Kubernetes 和 Mesos,为容器集群提供自动化的存储编排功能。

docker service create --name my_web \
       --publish 8080:80 \
       --mount "type=volume,volume-driver=rexray,source=web_data,target=/usr/local/apache2/htdocs" \
       httpd
  1. --mount 指定数据卷的 volume-driver 为 rexray

  2. source 指定数据卷的名字为 web_data,如果不存在,则会新建。

  3. target 指定将数据卷 mount 到每个副本容器的 /usr/local/apache2/htdocs,即存放静态页面的目录。

七、globalmode

Swarm 可以在 service 创建或运行过程中灵活地通过 --replicas 调整容器副本的数量,内部调度器则会根据当前集群的资源使用状况在不同 node 上启停容器,这就是 service 默认的 replicated mode。在此模式下,node 上运行的副本数有多有少,一般情况下,资源更丰富的 node 运行的副本数更多,反之亦然。

除了 replicated mode,service 还提供了一个 globalmode,其作用是强制在每个 node 上都运行一个且最多一个副本。

此模式特别适合需要运行 daemon 的集群环境。比如要收集所有容器的日志,就可以 global mode 创建 service,在所有 node 上都运行 gliderlabs/logspout 容器,即使之后有新的 node 加入,swarm 也会自动在新 node 上启动一个 gliderlabs/logspout 副本。

 

docker service create \

       --mode global \

       --name logspout \

       --mount type=bind,source=/var/run/docker.sock,destination=/var/run/docker.sock \

       gliderlabs/logspout

作为用户我们有没有可能精细控制 Service 的运行位置呢?

答案是:能,使用 label。

逻辑分两步:

1、为每个 node 定义 label。

2、设置 service 运行在指定 label 的 node 上。

label 可以灵活描述 node 的属性,其形式是 key=value,用户可以任意指定,例如将 swarm-worker1 作为测试环境,为其添加 label env=test

docker node update --label-add env=test swarm-worker1

对应的,将 swarm-worker2 作为生产环境,添加 label env=prod

docker node update --label-add env=prod swarm-worker2

现在部署 service 到测试环境:

docker service create \
      --constraint node.labels.env==test \
      --replicas 3 \
      --name my_web \
      --publish 8080:80 \
      httpd

545.png

--constraint node.labels.env==test 限制将 service 部署到 label=test 的 node,即 swarm-worker1。从部署结果看,三个副本全部都运行在 swarm-worker1 上。

更新 service,将其迁移到生产环境:

docker service update --constraint-rm node.labels.env==test my_web 
           docker service update --constraint-add node.labels.env==prod my_web

删除并添加新的 constraint,设置 node.labels.env==prod,最终所有副本都迁移到了 swarm-worker2

八、Health check配置:

下面我们通过例子来演示 Health Check 在 swarm 中的应用。

docker service create --name my_db \
       --health-cmd "curl --fail http://localhost:8091/pools || exit 1" \
       couchbase

--health-cmd Health Check 的命令,还有几个相关的参数:

1、--timeout 命令超时的时间,默认 30s。

2、--interval 命令执行的间隔时间,默认 30s。

3、--retries 命令失败重试的次数,默认为 3,如果 3 次都失败了则会将容器标记为 unhealthy。swarm 会销毁并重建 unhealthy 的副本。

九、secret

我们经常要向容器传递敏感信息,最常见的莫过于密码了。比如:

docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql

在启动 MySQL 容器时我们通过环境变量 MYSQL_ROOT_PASSWORD 设置了 MySQL 的管理员密码。不过密码是以明文的形式写在 docker run 命令中,有潜在的安全隐患。

为了解决这个问题,docker swarm 提供了 secret 机制,允许将敏感信息加密后保存到 secret 中,用户可以指定哪些容器可以使用此 secret。

如果使用 secret 启动 MySQL 容器,方法是:

1、在 swarm manager 中创建 secret my_secret_data,将密码保存其中。

echo "my-secret-pw" | docker secret create my_secret_data -

553.png

2、启动 MySQL service,并指定使用 secret my_secret_data

docker service create \
        --name mysql \
        --secret source=my_secret_data,target=mysql_root_password \
        -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" \
        mysql:latest

554.png

① source 指定容器使用 secret 后,secret 会被解密并存放到容器的文件系统中,默认位置为 /run/secrets/<secret_name>。--secret source=my_secret_data,target=mysql_root_password 的作用就是指定使用 secret my_secret_data,然后把器解密后的内容保存到容器 /run/secrets/mysql_root_password 文件中,文件名称 mysql_root_password 由 target 指定。

② 环境变量 MYSQL_ROOT_PASSWORD_FILE 指定从 /run/secrets/mysql_root_password 中读取并设置 MySQL 的管理员密码。

这里大家可能有这么两个疑问:

1、问:在第一步创建 secret 时,不也是使用了明文吗?这跟在环境变量中直接指定密码有什么不同呢?

答:在我们的例子中创建 secret 和使用 secret 是分开完成的,其好处是将密码和容器解耦合。secret 可以由专人(比如管理员)创建,而运行容器的用户只需使用 secret 而不需要知道 secret 的内容。也就是说,例子中的这两个步骤可以由不同的人在不同的时间完成。

2、问:secret 是以文件的形式 mount 到容器中,容器怎么知道去哪里读取 secret 呢?

答:这需要 image 的支持。如果 image 希望它部署出来的容器能够从 secret 中读取数据,那么此 image 就应该提供一种方式,让用户能够指定 secret 的位置。最常用的方法就是通过环境变量,Docker 的很多官方 image 都是采用这种方式。比如 MySQL 镜像同时提供了 MYSQL_ROOT_PASSWORD 和 MYSQL_ROOT_PASSWORD_FILE 两个环境变量。用户可以用 MYSQL_ROOT_PASSWORD 显示地设置管理员密码,也可以通过 MYSQL_ROOT_PASSWORD_FILE 指定 secret 路径。

只有当 secret 被指定的 service 使用是,Docker 才会将解密后的 secret 以文件的形式 mount 到容器中,默认的路径为/run/secrets/<secret_name>。例如在前面 MySQL 的例子中,我们可以在容器中查看 secret。

555.png

当容器停止运行,Docker 会 unmount secret,并从节点上清除。


十、Stack

什么是 stack ?
在回答这个问题之前我们先回忆一下前面部署 WordPress 应用的过程:

1、首先创建 secret。

2、然后创建 MySQL service,这是 WordPress 依赖的服务。

3、最后创建 WordPress service。

也就是说,这个应用包含了两个 service:MySQL 和 WordPress,它们之间有明确的依赖关系,必须先启动 MySQL。

为了保证这个依赖关系,我们控制了 docker secret 和 docker service 命令的执行顺序,只不过这个过程是手工完成的。

如果将前面 WordPress 用 stack 来定义,YAML 文件可以是这样:

562.png

YAML 是一种阅读性很强的文本格式,上面这个 stack 中定义了三种资源:service、secret 和 volume。

① services 定义了两个 service:db 和 wordpress

② secrets 定义了两个 secret:db_password 和 db_root_password,在 service db 和 wordpress 的定义中引用了这两个 secret。

③ volumes 定义了一个 volume:db_data,service db 使用了此 volume。

④ wordpress 通过 depends_on 指定自己依赖 db 这个 service。Docker 会保证当 db 正常运行后再启动 wordpress

可以在 YAML 中定义的元素远远不止这里看到的这几个,完整列表和使用方法可参考文档 https://docs.docker.com/compose/compose-file/

定义好了 stack YAML 文件,就可以通过 docker stack deploy 命令部署应用。564.png

docker stack rm 会将 stack 相关的所以资源清除干净。

参考文档:https://www.cnblogs.com/CloudMan6/p/7834113.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值