MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

基于 Docker Swarm 的容器编排实战

2024-09-306.1k 阅读

1. Docker Swarm 基础概念

Docker Swarm 是 Docker 原生的容器编排工具,它使得在多个 Docker 主机上部署和管理容器变得更加容易。它将一组 Docker 主机变成一个单一的虚拟主机,在这个虚拟主机上,用户可以像在单个主机上一样管理容器。

1.1 节点类型

  • Manager 节点:负责管理集群的状态和任务调度。Manager 节点存储集群的状态信息,包括服务定义、节点列表以及任务的分配情况等。在生产环境中,通常会运行多个 Manager 节点以实现高可用性,它们之间通过 Raft 一致性算法来同步状态。
  • Worker 节点:负责运行实际的容器任务。Worker 节点从 Manager 节点接收任务分配,并在本地的 Docker 引擎上启动和管理容器。Worker 节点不参与集群管理决策,只专注于执行任务。

1.2 服务与任务

  • 服务(Service):是 Swarm 中部署和管理容器的基本单位。一个服务定义了运行容器的镜像、启动命令、资源限制等参数,并且可以指定运行的副本数量。例如,可以定义一个使用 Nginx 镜像的服务,并指定运行 3 个副本,Swarm 会确保在集群的节点上始终运行这 3 个 Nginx 容器。
  • 任务(Task):是服务的一个实例。当创建一个服务时,Swarm 会根据服务的定义创建相应数量的任务,并将这些任务分配到合适的节点上运行。每个任务都有自己的生命周期,包括创建、调度、运行、停止和删除等阶段。

2. 搭建 Docker Swarm 集群

在开始搭建 Docker Swarm 集群之前,确保已经在每台主机上安装了 Docker 引擎。以下步骤以三台主机为例进行说明,主机 IP 分别为 192.168.1.100192.168.1.101192.168.1.102

2.1 初始化 Manager 节点

在其中一台主机(例如 192.168.1.100)上执行以下命令初始化 Docker Swarm 集群:

docker swarm init --advertise-addr 192.168.1.100

执行上述命令后,会得到类似以下的输出:

Swarm initialized: current node (92x5f464z2279327127341) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-556233959703943349-479487563797461434 192.168.1.100:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

这个输出包含了两个重要信息:

  • Worker 节点加入命令:其他主机作为 Worker 节点加入集群时需要执行的命令。
  • Manager 节点加入命令:如果需要添加更多的 Manager 节点,可以通过 docker swarm join-token manager 命令获取加入命令。

2.2 添加 Worker 节点

在另外两台主机(192.168.1.101192.168.1.102)上执行上述获取到的 Worker 节点加入命令,例如:

docker swarm join \
--token SWMTKN-1-556233959703943349-479487563797461434 192.168.1.100:2377

执行成功后,在 Manager 节点上执行 docker node ls 命令,可以看到集群中的节点列表:

ID                           HOSTNAME            STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
92x5f464z2279327127341 *     manager1            Ready     Active         Leader           19.03.12
089c6a9e7d7f20776367387295   worker1             Ready     Active                          19.03.12
12c4f7e3c8a209876367387295   worker2             Ready     Active                          19.03.12

其中,带有 * 标记的是当前执行命令的节点,MANAGER STATUSLeader 的是集群的主 Manager 节点。

2.3 添加更多 Manager 节点

如果需要添加更多的 Manager 节点以实现高可用性,可以在 Manager 节点上执行以下命令获取 Manager 节点加入令牌:

docker swarm join-token manager

输出结果类似以下内容:

To add a manager to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-556233959703943349-479487563797461434 192.168.1.100:2377

在需要加入的主机上执行上述命令,即可将其添加为 Manager 节点。

3. 服务部署与管理

3.1 创建简单服务

以部署一个 Nginx 服务为例,在 Manager 节点上执行以下命令:

docker service create --name my-nginx --replicas 3 nginx

上述命令中:

  • --name my-nginx:指定服务的名称为 my-nginx
  • --replicas 3:指定运行 3 个副本。
  • nginx:指定使用的 Docker 镜像为官方 Nginx 镜像。

执行命令后,可以通过以下命令查看服务的状态:

docker service ls

输出类似以下内容:

ID                  NAME        MODE        REPLICAS    IMAGE       PORTS
f9f7f6e227932712734 my-nginx    replicated  3/3         nginx:latest

其中,REPLICAS 列显示了当前运行的副本数量和期望的副本数量,这里 3/3 表示 3 个副本都已成功运行。

3.2 扩展与收缩服务

如果需要增加或减少服务的副本数量,可以使用 docker service scale 命令。例如,将 my-nginx 服务的副本数量增加到 5:

docker service scale my-nginx=5

执行命令后,再次查看服务状态:

docker service ls

输出:

ID                  NAME        MODE        REPLICAS    IMAGE       PORTS
f9f7f6e227932712734 my-nginx    replicated  5/5         nginx:latest

可以看到副本数量已更新为 5。

如果要收缩服务,例如将副本数量减少到 2:

docker service scale my-nginx=2

3.3 更新服务

假设需要更新 my-nginx 服务使用的镜像版本,可以使用 docker service update 命令。首先,拉取最新的 Nginx 镜像:

docker pull nginx:latest

然后更新服务:

docker service update --image nginx:latest my-nginx

在更新过程中,Swarm 会采用滚动更新的方式,即逐步停止旧版本的容器并启动新版本的容器,以确保服务的可用性。可以通过 docker service ps my-nginx 命令查看更新过程中任务的状态。

3.4 服务网络

Docker Swarm 提供了多种网络模式,包括 overlay 网络和 bridge 网络。overlay 网络适用于跨节点的容器通信,而 bridge 网络主要用于同一节点内的容器通信。

创建 overlay 网络:

docker network create --driver overlay my-overlay

创建服务时,可以指定使用该网络:

docker service create --name my-nginx --replicas 3 --network my-overlay nginx

这样,在 my-overlay 网络中的容器可以通过服务名称进行通信,例如,在另一个容器中可以通过 my-nginx 这个名称访问 Nginx 服务,而无需关心具体的 IP 地址。

4. 服务发现与负载均衡

4.1 服务发现

在 Docker Swarm 中,服务发现是自动实现的。当一个服务创建后,集群中的其他容器可以通过服务名称来访问该服务,而无需知道具体的 IP 地址。例如,在一个 Python 应用容器中,可以通过以下代码访问 my-nginx 服务:

import requests

response = requests.get('http://my-nginx')
print(response.text)

Docker Swarm 会自动将 my-nginx 解析为实际运行 Nginx 服务的容器的 IP 地址。

4.2 负载均衡

Swarm 内置了负载均衡功能,对于暴露端口的服务,Swarm 会自动在所有运行该服务的副本之间进行负载均衡。例如,在创建 Nginx 服务时,可以将 Nginx 的 80 端口映射到主机的 8080 端口:

docker service create --name my-nginx --replicas 3 -p 8080:80 nginx

此时,外部请求发送到任意一个节点的 8080 端口,Swarm 会将请求负载均衡到运行 my-nginx 服务的各个副本上。

Swarm 使用的负载均衡算法是基于轮询(Round - Robin)的,它会依次将请求分配到各个可用的副本上,以实现负载的平均分配。

5. 持久化存储

在容器化应用中,数据的持久化是非常重要的。Docker Swarm 支持多种持久化存储方式,包括本地卷和分布式存储。

5.1 本地卷

创建一个使用本地卷的服务示例,以 MySQL 数据库为例:

docker service create --name my-mysql \
--mount type=volume,source=my-mysql-data,destination=/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=rootpassword \
-e MYSQL_DATABASE=mydb \
-e MYSQL_USER=myuser \
-e MYSQL_PASSWORD=mypassword \
mysql:5.7

上述命令中,--mount type=volume,source=my-mysql-data,destination=/var/lib/mysql 表示创建一个名为 my-mysql-data 的本地卷,并将其挂载到容器内的 /var/lib/mysql 目录,用于存储 MySQL 的数据文件。

5.2 分布式存储

对于跨节点的数据持久化需求,可以使用分布式存储解决方案,如 GlusterFS 或 Ceph。以 GlusterFS 为例,首先需要在各个节点上安装 GlusterFS 客户端,然后创建 GlusterFS 卷:

gluster volume create myglustervol replica 3 transport tcp 192.168.1.100:/var/gluster/data 192.168.1.101:/var/gluster/data 192.168.1.102:/var/gluster/data
gluster volume start myglustervol

接下来,在 Docker Swarm 中创建服务时,可以使用 GlusterFS 卷:

docker service create --name my-mysql \
--mount type=volume,source=myglustervol,destination=/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=rootpassword \
-e MYSQL_DATABASE=mydb \
-e MYSQL_USER=myuser \
-e MYSQL_PASSWORD=mypassword \
mysql:5.7

这样,MySQL 容器的数据会存储在 GlusterFS 卷上,实现了跨节点的数据持久化和高可用性。

6. 滚动更新与回滚策略

6.1 滚动更新策略

在更新服务时,可以指定滚动更新的策略,以控制更新的速度和对服务可用性的影响。例如,在更新 my-nginx 服务时,可以指定每次只更新一个副本,并且等待 5 秒确认更新成功后再继续更新下一个副本:

docker service update \
--image nginx:latest \
--update-delay 5s \
--update-parallelism 1 \
my-nginx
  • --update-delay 5s:指定每个副本更新之间的延迟时间为 5 秒。
  • --update-parallelism 1:指定每次只更新一个副本。

通过这种方式,可以在更新过程中密切观察每个副本的运行状态,确保更新不会对服务造成严重影响。

6.2 回滚策略

如果在更新过程中发现问题,可以随时回滚到上一个版本。执行以下命令回滚 my-nginx 服务:

docker service rollback my-nginx

回滚过程同样采用滚动的方式,逐步将容器恢复到上一个版本的状态。在回滚过程中,也可以通过 docker service ps my-nginx 命令查看任务的状态。

7. 安全与认证

7.1 节点认证

Docker Swarm 使用 TLS(Transport Layer Security)进行节点之间的通信加密和认证。在初始化 Swarm 集群时,会自动生成自签名的 TLS 证书,用于节点之间的身份验证和数据加密。

如果需要使用自定义的证书,可以在初始化 Swarm 集群时通过 --tls 相关参数指定证书文件的路径。例如:

docker swarm init \
--advertise-addr 192.168.1.100 \
--tls \
--tlscacert /path/to/ca.crt \
--tlscert /path/to/server.crt \
--tlskey /path/to/server.key

这样,在节点加入集群时,会使用指定的证书进行认证。

7.2 服务认证

对于服务之间的通信安全,可以使用服务网格(如 Istio)来实现更细粒度的认证和授权。Istio 可以在容器之间建立安全的通信通道,并提供基于策略的访问控制。

以 Istio 为例,首先需要在 Swarm 集群上安装 Istio,然后将服务部署到 Istio 服务网格中。例如,对于 my-nginx 服务,可以通过 Istio 的配置文件启用认证和授权:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: istio-system
spec:
  mtls:
    mode: STRICT

上述配置表示在 Istio 服务网格中启用严格的 mTLS(Mutual Transport Layer Security)认证,确保服务之间的通信是安全加密的。

8. 监控与日志管理

8.1 监控

可以使用 Prometheus 和 Grafana 对 Docker Swarm 集群进行监控。首先,需要部署 Prometheus 来收集集群的指标数据,例如节点资源使用情况、容器运行状态等。可以通过 Docker 镜像部署 Prometheus:

docker service create --name prometheus \
--mount type=bind,source=/path/to/prometheus.yml,destination=/etc/prometheus/prometheus.yml \
prom/prometheus

prometheus.yml 配置文件中,需要配置对 Swarm 集群的监控目标:

scrape_configs:
  - job_name:'swarm'
    static_configs:
      - targets: ['192.168.1.100:9323', '192.168.1.101:9323', '192.168.1.102:9323']

这里的 9323 端口是 Docker Swarm 暴露的监控端口。

然后,部署 Grafana 用于可视化监控数据:

docker service create --name grafana \
--mount type=bind,source=/path/to/grafana.ini,destination=/etc/grafana/grafana.ini \
--mount type=bind,source=/path/to/provisioning,destination=/etc/grafana/provisioning \
--publish 3000:3000 \
grafana/grafana

通过 Grafana 可以创建各种仪表盘,展示集群的性能指标、服务运行状态等信息。

8.2 日志管理

Docker Swarm 支持多种日志驱动,如 json - filesyslogfluentd 等。以 fluentd 为例,首先需要部署 fluentd 服务:

docker service create --name fluentd \
--mount type=bind,source=/path/to/fluentd.conf,destination=/fluentd/etc/fluentd.conf \
fluent/fluentd

fluentd.conf 配置文件中,配置接收 Docker 容器日志的源和日志存储的目标,例如:

<source>
  @type forward
  port 24224
  bind 0.0.0.0
</source>

<match **>
  @type file
  path /var/log/docker/%{tag}.log
</match>

然后,在创建服务时指定使用 fluentd 日志驱动:

docker service create --name my-nginx \
--log-driver fluentd \
--log-opt fluentd-address=192.168.1.100:24224 \
nginx

这样,my-nginx 服务的日志会发送到 fluentd 服务,由 fluentd 进行存储和管理。

通过上述对 Docker Swarm 的详细介绍和实战操作,可以看到 Docker Swarm 在容器编排方面提供了强大而灵活的功能,能够满足不同规模和复杂度的后端开发需求。无论是简单的应用部署,还是复杂的分布式系统构建,Docker Swarm 都能提供有效的解决方案。在实际应用中,需要根据具体的业务场景和需求,合理地配置和使用 Docker Swarm 的各项功能,以实现高效、可靠和安全的容器化应用部署与管理。