学习目标
通过本章学习,您将能够:
- 掌握节点角色管理和转换方法
- 学会集群扩容和缩容操作
- 了解节点故障检测和处理机制
- 掌握集群备份和恢复策略
- 学会集群健康监控和维护
1. 节点角色管理
1.1 节点角色概述
管理节点(Manager Node)
# 管理节点职责
- 集群状态管理
- 服务编排和调度
- API 端点提供
- Raft 共识算法参与
- 工作节点管理
# 管理节点特点
- 默认也可运行容器任务
- 参与 Raft 共识决策
- 存储集群状态信息
- 提供 Swarm API 接口
工作节点(Worker Node)
# 工作节点职责
- 运行容器任务
- 接收管理节点指令
- 报告节点状态
- 执行健康检查
# 工作节点特点
- 专注于任务执行
- 不参与集群决策
- 资源消耗较低
- 可大规模扩展
1.2 节点角色转换
工作节点提升为管理节点
# 查看当前节点状态
docker node ls
# 提升工作节点为管理节点
docker node promote <worker-node-id>
# 批量提升多个节点
docker node promote node1 node2 node3
# 验证提升结果
docker node ls
管理节点降级为工作节点
# 降级管理节点为工作节点
docker node demote <manager-node-id>
# 批量降级多个节点
docker node demote node1 node2
# 注意:不能降级最后一个管理节点
# 确保至少保留一个管理节点
角色转换最佳实践
# 管理节点数量建议
# 1 个:仅测试环境
# 3 个:小型生产环境(推荐奇数)
# 5 个:中型生产环境
# 7 个:大型生产环境(最大推荐)
# 转换前检查
docker node ls --filter role=manager
docker info --format '{{.Swarm.Managers}}'
# 确保 Raft 仲裁
# 仲裁数 = (N/2) + 1
# 3 个管理节点:仲裁数 = 2
# 5 个管理节点:仲裁数 = 3
1.3 节点可用性管理
节点可用性状态
# Active:活跃状态,接受新任务
# Pause:暂停状态,不接受新任务但保持现有任务
# Drain:排空状态,不接受新任务且迁移现有任务
设置节点可用性
# 设置节点为活跃状态
docker node update --availability active <node-id>
# 设置节点为暂停状态
docker node update --availability pause <node-id>
# 设置节点为排空状态
docker node update --availability drain <node-id>
# 查看节点可用性
docker node ls --format "table {{.ID}}\t{{.Hostname}}\t{{.Status}}\t{{.Availability}}"
节点维护操作
# 维护前排空节点
docker node update --availability drain <node-id>
# 等待任务迁移完成
docker node ps <node-id>
# 执行维护操作(系统更新、硬件维护等)
# ...
# 维护完成后恢复节点
docker node update --availability active <node-id>
2. 集群扩容操作
2.1 水平扩容
添加工作节点
# 在管理节点获取加入令牌
docker swarm join-token worker
# 在新节点执行加入命令
docker swarm join --token <worker-token> <manager-ip>:2377
# 验证节点加入
docker node ls
添加管理节点
# 获取管理节点加入令牌
docker swarm join-token manager
# 在新节点执行加入命令
docker swarm join --token <manager-token> <manager-ip>:2377
# 验证管理节点加入
docker node ls --filter role=manager
批量节点添加脚本
#!/bin/bash
# add-workers.sh
# 配置参数
MANAGER_IP="192.168.1.100"
WORKER_IPS=("192.168.1.101" "192.168.1.102" "192.168.1.103")
# 获取工作节点令牌
WORKER_TOKEN=$(docker swarm join-token worker -q)
# 批量添加工作节点
for ip in "${WORKER_IPS[@]}"; do
echo "Adding worker node: $ip"
ssh root@$ip "docker swarm join --token $WORKER_TOKEN $MANAGER_IP:2377"
if [ $? -eq 0 ]; then
echo "Successfully added worker: $ip"
else
echo "Failed to add worker: $ip"
fi
done
# 验证结果
docker node ls
2.2 垂直扩容
节点资源升级
# 1. 排空节点
docker node update --availability drain <node-id>
# 2. 等待任务迁移
while [ $(docker node ps <node-id> --filter desired-state=running -q | wc -l) -gt 0 ]; do
echo "Waiting for tasks to migrate..."
sleep 10
done
# 3. 停止节点服务
ssh <node-ip> "sudo systemctl stop docker"
# 4. 升级硬件资源(CPU、内存、存储)
# ...
# 5. 重启节点服务
ssh <node-ip> "sudo systemctl start docker"
# 6. 恢复节点可用性
docker node update --availability active <node-id>
存储扩容
# 检查当前存储使用情况
docker system df
docker system df -v
# 清理未使用的资源
docker system prune -a
# 扩展存储卷(具体方法依赖于存储类型)
# LVM 扩容示例
sudo lvextend -L +50G /dev/mapper/docker-pool
sudo resize2fs /dev/mapper/docker-pool
2.3 扩容策略规划
容量规划
# 监控指标收集
docker stats --no-stream
docker system events --filter type=container
# 资源使用分析
#!/bin/bash
# resource-analysis.sh
echo "=== Node Resource Usage ==="
docker node ls --format "table {{.Hostname}}\t{{.Status}}\t{{.Availability}}"
echo "\n=== Service Resource Usage ==="
docker service ls --format "table {{.Name}}\t{{.Replicas}}\t{{.Image}}"
echo "\n=== System Resource Usage ==="
docker system df
echo "\n=== Container Resource Usage ==="
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
自动扩容触发器
# 基于 CPU 使用率的扩容脚本
#!/bin/bash
# auto-scale.sh
CPU_THRESHOLD=80
MEM_THRESHOLD=80
# 检查集群资源使用率
CPU_USAGE=$(docker stats --no-stream --format "{{.CPUPerc}}" | sed 's/%//' | awk '{sum+=$1} END {print sum/NR}')
MEM_USAGE=$(docker stats --no-stream --format "{{.MemPerc}}" | sed 's/%//' | awk '{sum+=$1} END {print sum/NR}')
if (( $(echo "$CPU_USAGE > $CPU_THRESHOLD" | bc -l) )); then
echo "CPU usage ($CPU_USAGE%) exceeds threshold ($CPU_THRESHOLD%)"
# 触发扩容操作
./add-worker-node.sh
fi
if (( $(echo "$MEM_USAGE > $MEM_THRESHOLD" | bc -l) )); then
echo "Memory usage ($MEM_USAGE%) exceeds threshold ($MEM_THRESHOLD%)"
# 触发扩容操作
./add-worker-node.sh
fi
3. 集群缩容操作
3.1 安全缩容流程
工作节点移除
# 1. 排空节点任务
docker node update --availability drain <node-id>
# 2. 等待任务迁移完成
docker node ps <node-id> --filter desired-state=running
# 3. 在目标节点离开集群
ssh <node-ip> "docker swarm leave"
# 4. 在管理节点移除节点
docker node rm <node-id>
# 5. 验证移除结果
docker node ls
管理节点移除
# 1. 确保有足够的管理节点维持仲裁
docker node ls --filter role=manager
# 2. 降级管理节点为工作节点
docker node demote <manager-node-id>
# 3. 按工作节点移除流程操作
docker node update --availability drain <node-id>
ssh <node-ip> "docker swarm leave"
docker node rm <node-id>
强制移除节点
# 当节点无法正常通信时使用
docker node rm --force <node-id>
# 注意:强制移除可能导致数据丢失
# 仅在节点永久故障时使用
3.2 批量缩容脚本
#!/bin/bash
# remove-workers.sh
# 要移除的节点列表
NODES_TO_REMOVE=("worker3" "worker4" "worker5")
for node in "${NODES_TO_REMOVE[@]}"; do
echo "Removing node: $node"
# 获取节点 ID
NODE_ID=$(docker node ls --filter name=$node --format "{{.ID}}")
if [ -z "$NODE_ID" ]; then
echo "Node $node not found"
continue
fi
# 排空节点
echo "Draining node $node..."
docker node update --availability drain $NODE_ID
# 等待任务迁移
while [ $(docker node ps $NODE_ID --filter desired-state=running -q | wc -l) -gt 0 ]; do
echo "Waiting for tasks to migrate from $node..."
sleep 10
done
# 获取节点 IP
NODE_IP=$(docker node inspect $NODE_ID --format '{{.Status.Addr}}')
# 节点离开集群
echo "Node $node leaving swarm..."
ssh root@$NODE_IP "docker swarm leave" || echo "Failed to leave swarm on $node"
# 移除节点
echo "Removing node $node from cluster..."
docker node rm $NODE_ID
echo "Successfully removed node: $node"
done
echo "Cluster scaling down completed"
docker node ls
3.3 缩容后优化
资源重新分配
# 检查服务分布
docker service ps <service-name>
# 重新平衡服务
docker service update --force <service-name>
# 检查网络配置
docker network ls
docker network inspect ingress
存储清理
# 清理未使用的卷
docker volume prune
# 清理未使用的网络
docker network prune
# 清理未使用的镜像
docker image prune -a
# 系统整体清理
docker system prune -a --volumes
4. 节点故障处理
4.1 故障检测机制
健康检查配置
# 节点健康检查间隔
docker swarm update --task-history-limit 5
# 查看节点状态
docker node ls
docker node inspect <node-id> --format '{{.Status}}'
故障检测脚本
#!/bin/bash
# health-check.sh
echo "=== Swarm Cluster Health Check ==="
echo "Timestamp: $(date)"
# 检查集群状态
echo "\n1. Cluster Status:"
docker info --format '{{.Swarm.LocalNodeState}}'
# 检查节点状态
echo "\n2. Node Status:"
docker node ls --format "table {{.Hostname}}\t{{.Status}}\t{{.Availability}}\t{{.ManagerStatus}}"
# 检查不健康的节点
echo "\n3. Unhealthy Nodes:"
docker node ls --filter status=down
# 检查服务状态
echo "\n4. Service Status:"
docker service ls --format "table {{.Name}}\t{{.Replicas}}\t{{.Image}}"
# 检查失败的任务
echo "\n5. Failed Tasks:"
docker service ps --filter desired-state=running --filter current-state=failed --no-trunc
# 检查网络状态
echo "\n6. Network Status:"
docker network ls --filter driver=overlay
# 资源使用情况
echo "\n7. Resource Usage:"
docker system df
4.2 常见故障处理
节点离线处理
# 检查离线节点
docker node ls --filter status=down
# 尝试重新连接
# 在离线节点上执行
sudo systemctl restart docker
# 如果节点无法恢复,强制移除
docker node rm --force <offline-node-id>
管理节点故障
# 检查管理节点状态
docker node ls --filter role=manager
# 如果失去仲裁,在剩余管理节点上执行
docker swarm init --force-new-cluster
# 重新添加管理节点
docker swarm join-token manager
# 在新节点执行加入命令
网络故障处理
# 检查网络连通性
docker network ls
docker network inspect ingress
# 重建 ingress 网络
docker network rm ingress
docker network create \
--driver overlay \
--ingress \
--subnet=10.255.0.0/16 \
--gateway=10.255.0.1 \
ingress
4.3 故障恢复策略
自动故障转移
# 服务自动重启配置
docker service create \
--name web \
--replicas 3 \
--restart-condition on-failure \
--restart-max-attempts 3 \
--restart-delay 10s \
nginx
数据恢复
# 备份集群状态
docker run --rm -v /var/lib/docker/swarm:/backup alpine tar czf /backup/swarm-backup.tar.gz /backup
# 恢复集群状态
docker swarm init --force-new-cluster
# 恢复备份数据到 /var/lib/docker/swarm/
5. 集群备份与恢复
5.1 备份策略
集群状态备份
#!/bin/bash
# backup-swarm.sh
BACKUP_DIR="/backup/swarm/$(date +%Y%m%d_%H%M%S)"
mkdir -p $BACKUP_DIR
echo "Starting Swarm cluster backup..."
# 1. 备份集群配置
echo "Backing up cluster configuration..."
docker info --format '{{json .Swarm}}' > $BACKUP_DIR/cluster-info.json
# 2. 备份节点信息
echo "Backing up node information..."
docker node ls --format '{{json .}}' > $BACKUP_DIR/nodes.json
# 3. 备份服务配置
echo "Backing up service configurations..."
mkdir -p $BACKUP_DIR/services
for service in $(docker service ls --format '{{.Name}}'); do
docker service inspect $service > $BACKUP_DIR/services/$service.json
done
# 4. 备份网络配置
echo "Backing up network configurations..."
mkdir -p $BACKUP_DIR/networks
for network in $(docker network ls --filter driver=overlay --format '{{.Name}}'); do
docker network inspect $network > $BACKUP_DIR/networks/$network.json
done
# 5. 备份密钥和配置
echo "Backing up secrets and configs..."
mkdir -p $BACKUP_DIR/secrets $BACKUP_DIR/configs
docker secret ls --format '{{.Name}}' | xargs -I {} docker secret inspect {} > $BACKUP_DIR/secrets/{}.json 2>/dev/null
docker config ls --format '{{.Name}}' | xargs -I {} docker config inspect {} > $BACKUP_DIR/configs/{}.json 2>/dev/null
# 6. 备份 Swarm 数据目录
echo "Backing up Swarm data directory..."
sudo tar czf $BACKUP_DIR/swarm-data.tar.gz -C /var/lib/docker swarm
echo "Backup completed: $BACKUP_DIR"
定期备份配置
# 添加到 crontab
# 每天凌晨 2 点执行备份
0 2 * * * /opt/scripts/backup-swarm.sh
# 每周日凌晨 1 点清理旧备份(保留 30 天)
0 1 * * 0 find /backup/swarm -type d -mtime +30 -exec rm -rf {} \;
5.2 恢复策略
完整集群恢复
#!/bin/bash
# restore-swarm.sh
BACKUP_DIR="$1"
if [ -z "$BACKUP_DIR" ]; then
echo "Usage: $0 <backup-directory>"
exit 1
fi
echo "Starting Swarm cluster restore from: $BACKUP_DIR"
# 1. 停止 Docker 服务
echo "Stopping Docker service..."
sudo systemctl stop docker
# 2. 清理现有 Swarm 数据
echo "Cleaning existing Swarm data..."
sudo rm -rf /var/lib/docker/swarm
# 3. 恢复 Swarm 数据
echo "Restoring Swarm data..."
sudo tar xzf $BACKUP_DIR/swarm-data.tar.gz -C /var/lib/docker/
# 4. 启动 Docker 服务
echo "Starting Docker service..."
sudo systemctl start docker
# 5. 强制重新初始化集群
echo "Force reinitializing cluster..."
docker swarm init --force-new-cluster
# 6. 恢复服务
echo "Restoring services..."
for service_file in $BACKUP_DIR/services/*.json; do
if [ -f "$service_file" ]; then
service_name=$(basename "$service_file" .json)
echo "Restoring service: $service_name"
# 这里需要根据备份的服务配置重新创建服务
# 具体实现依赖于服务配置格式
fi
done
echo "Restore completed"
echo "Please verify cluster status and re-add nodes if necessary"
部分恢复操作
# 恢复单个服务
docker service create --name restored-service \
$(cat backup/services/service-name.json | jq -r '.Spec')
# 恢复网络配置
docker network create \
--driver overlay \
$(cat backup/networks/network-name.json | jq -r '.Options')
# 恢复密钥
echo "secret-content" | docker secret create restored-secret -
5.3 灾难恢复计划
恢复优先级
# 1. 核心基础设施服务(优先级:高)
- 服务发现
- 负载均衡
- 数据库服务
# 2. 应用服务(优先级:中)
- Web 应用
- API 服务
- 缓存服务
# 3. 辅助服务(优先级:低)
- 监控服务
- 日志服务
- 备份服务
恢复时间目标(RTO)
# 定义恢复时间目标
RTO_CRITICAL=15min # 关键服务
RTO_IMPORTANT=1hour # 重要服务
RTO_NORMAL=4hours # 普通服务
# 恢复点目标(RPO)
RPO_CRITICAL=5min # 关键数据
RPO_IMPORTANT=1hour # 重要数据
RPO_NORMAL=24hours # 普通数据
6. 集群监控与维护
6.1 监控指标
集群级别监控
#!/bin/bash
# cluster-metrics.sh
echo "=== Cluster Metrics ==="
echo "Timestamp: $(date)"
# 节点数量统计
echo "\nNode Count:"
echo "Total: $(docker node ls | wc -l)"
echo "Managers: $(docker node ls --filter role=manager | wc -l)"
echo "Workers: $(docker node ls --filter role=worker | wc -l)"
echo "Active: $(docker node ls --filter status=ready | wc -l)"
echo "Down: $(docker node ls --filter status=down | wc -l)"
# 服务统计
echo "\nService Count:"
echo "Total: $(docker service ls | wc -l)"
echo "Running: $(docker service ls --filter mode=replicated | wc -l)"
# 任务统计
echo "\nTask Statistics:"
echo "Running: $(docker service ps --filter desired-state=running | wc -l)"
echo "Failed: $(docker service ps --filter desired-state=failed | wc -l)"
# 资源使用
echo "\nResource Usage:"
docker system df --format "table {{.Type}}\t{{.Total}}\t{{.Active}}\t{{.Size}}\t{{.Reclaimable}}"
节点级别监控
#!/bin/bash
# node-metrics.sh
for node in $(docker node ls --format '{{.Hostname}}'); do
echo "=== Node: $node ==="
# 节点基本信息
docker node inspect $node --format '
Status: {{.Status.State}}
Availability: {{.Spec.Availability}}
Role: {{.Spec.Role}}
Engine Version: {{.Description.Engine.EngineVersion}}
OS: {{.Description.Platform.OS}}
Architecture: {{.Description.Platform.Architecture}}
CPUs: {{.Description.Resources.NanoCPUs}}
Memory: {{.Description.Resources.MemoryBytes}}'
# 运行的任务数量
echo "Running Tasks: $(docker node ps $node --filter desired-state=running | wc -l)"
echo "---"
done
6.2 自动化维护
定期清理脚本
#!/bin/bash
# maintenance.sh
echo "Starting automated maintenance..."
# 1. 清理未使用的资源
echo "Cleaning unused resources..."
docker system prune -f
# 2. 清理旧的任务历史
echo "Cleaning old task history..."
docker swarm update --task-history-limit 3
# 3. 检查服务健康状态
echo "Checking service health..."
for service in $(docker service ls --format '{{.Name}}'); do
replicas=$(docker service ls --filter name=$service --format '{{.Replicas}}')
if [[ $replicas == *"0/"* ]]; then
echo "WARNING: Service $service has no running replicas"
fi
done
# 4. 检查节点状态
echo "Checking node status..."
down_nodes=$(docker node ls --filter status=down --format '{{.Hostname}}')
if [ ! -z "$down_nodes" ]; then
echo "WARNING: Down nodes detected: $down_nodes"
fi
# 5. 生成维护报告
echo "Generating maintenance report..."
REPORT_FILE="/var/log/swarm-maintenance-$(date +%Y%m%d).log"
{
echo "Maintenance Report - $(date)"
echo "================================"
docker node ls
echo ""
docker service ls
echo ""
docker system df
} > $REPORT_FILE
echo "Maintenance completed. Report saved to: $REPORT_FILE"
健康检查自动化
#!/bin/bash
# health-monitor.sh
SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"
EMAIL_RECIPIENT="admin@example.com"
# 检查集群健康状态
check_cluster_health() {
local issues=()
# 检查管理节点数量
manager_count=$(docker node ls --filter role=manager --filter status=ready | wc -l)
if [ $manager_count -lt 3 ]; then
issues+=("Insufficient manager nodes: $manager_count")
fi
# 检查离线节点
down_nodes=$(docker node ls --filter status=down --format '{{.Hostname}}')
if [ ! -z "$down_nodes" ]; then
issues+=("Down nodes: $down_nodes")
fi
# 检查失败的服务
failed_services=$(docker service ps --filter desired-state=running --filter current-state=failed --format '{{.Name}}')
if [ ! -z "$failed_services" ]; then
issues+=("Failed services: $failed_services")
fi
# 发送告警
if [ ${#issues[@]} -gt 0 ]; then
alert_message="Swarm Cluster Issues Detected:\n$(printf '%s\n' "${issues[@]}")"
# 发送 Slack 通知
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"$alert_message\"}" \
$SLACK_WEBHOOK
# 发送邮件通知
echo -e "$alert_message" | mail -s "Swarm Cluster Alert" $EMAIL_RECIPIENT
fi
}
# 每 5 分钟检查一次
while true; do
check_cluster_health
sleep 300
done
7. 实践练习
练习 1:节点角色管理
目标:练习节点角色转换和可用性管理
# 1. 查看当前集群状态
docker node ls
# 2. 提升一个工作节点为管理节点
docker node promote <worker-node>
# 3. 设置一个节点为维护模式
docker node update --availability drain <node-id>
# 4. 观察任务迁移过程
docker service ps <service-name>
# 5. 恢复节点可用性
docker node update --availability active <node-id>
# 6. 降级管理节点
docker node demote <manager-node>
练习 2:集群扩容缩容
目标:练习集群的动态扩容和缩容
# 1. 准备扩容脚本
cat > add-node.sh << 'EOF'
#!/bin/bash
NEW_NODE_IP="$1"
WORKER_TOKEN=$(docker swarm join-token worker -q)
MANAGER_IP=$(docker info --format '{{.Swarm.NodeAddr}}')
ssh root@$NEW_NODE_IP "docker swarm join --token $WORKER_TOKEN $MANAGER_IP:2377"
EOF
chmod +x add-node.sh
# 2. 添加新节点
./add-node.sh 192.168.1.104
# 3. 验证节点加入
docker node ls
# 4. 创建测试服务验证负载分布
docker service create --name test-lb --replicas 4 --publish 8080:80 nginx
docker service ps test-lb
# 5. 移除节点
docker node update --availability drain <node-id>
docker node rm <node-id>
# 6. 清理测试服务
docker service rm test-lb
练习 3:故障模拟与恢复
目标:模拟节点故障并练习恢复操作
# 1. 创建测试服务
docker service create --name fault-test --replicas 3 --publish 8081:80 nginx
# 2. 模拟节点故障(在工作节点上执行)
sudo systemctl stop docker
# 3. 观察服务自动恢复
docker service ps fault-test
# 4. 恢复故障节点
sudo systemctl start docker
# 5. 验证节点重新加入
docker node ls
# 6. 清理测试环境
docker service rm fault-test
8. 本章总结
关键要点
节点管理
- 理解管理节点和工作节点的角色差异
- 掌握节点角色转换和可用性控制
- 合理规划管理节点数量保证高可用
集群扩容
- 支持水平扩容(添加节点)和垂直扩容(升级资源)
- 制定合理的扩容策略和触发条件
- 实现自动化扩容脚本
集群缩容
- 遵循安全缩容流程避免服务中断
- 正确处理管理节点的移除
- 缩容后进行资源优化
故障处理
- 建立完善的故障检测机制
- 掌握常见故障的处理方法
- 制定故障恢复策略
备份恢复
- 定期备份集群状态和配置
- 制定灾难恢复计划
- 验证备份的有效性
最佳实践
- 预防为主:建立完善的监控和告警机制
- 自动化运维:使用脚本自动化常见的运维操作
- 文档记录:详细记录集群配置和操作流程
- 定期演练:定期进行故障恢复演练
- 渐进式操作:重要操作先在测试环境验证
下一步学习
在下一章中,我们将学习服务部署与管理,包括:
- 服务创建和配置
- 服务更新和回滚
- 服务扩缩容
- 服务约束和调度策略
检查清单: - [ ] 理解节点角色和管理方法 - [ ] 掌握集群扩容缩容操作 - [ ] 学会故障检测和处理 - [ ] 建立备份恢复机制 - [ ] 实现自动化监控维护