跳转到内容

数据持久化与备份

数据持久化与备份

本节介绍 Docker 环境中的数据持久化策略和自动备份方案。学习完成后,您将能够:

  • 理解 Docker 数据卷(Volume)的概念和作用
  • 配置容器数据持久化
  • 设计和实施自动备份策略
  • 向客户解释数据安全性和可靠性保障

默认情况下,容器删除后所有数据都会丢失。对于 IoT 系统,这意味着:

问题场景:
1. 容器崩溃重启 → 所有 Flow 配置丢失
2. 更新软件版本 → 历史数据全部清除
3. 服务器迁移 → 需要重建整个系统
价值点说明对客户的影响
配置保留重启后 Flow、仪表板、设置不变减少重复工作
数据安全传感器历史数据不会丢失业务数据可追溯
升级无忧更新容器版本数据不受影响降低维护风险
快速恢复故障后快速恢复服务减少停机时间

由 Docker 管理,存储在 /var/lib/docker/volumes/

Terminal window
# 创建卷
docker volume create nodered_data
# 使用卷
docker run -d \
--name nodered \
-v nodered_data:/data \
nodered/node-red:latest
# 查看卷信息
docker volume inspect nodered_data
# 列出所有卷
docker volume ls
# 删除卷(慎用!)
docker volume rm nodered_data

直接映射宿主机的目录:

Terminal window
# 使用绝对路径挂载
docker run -d \
--name mosquitto \
-v /opt/iot/mosquitto/config:/mosquitto/config \
-v /opt/iot/mosquitto/data:/mosquitto/data \
eclipse-mosquitto:2

数据存储在内存中,容器停止后自动清除:

Terminal window
docker run -d \
--name cache-service \
--tmpfs /cache:rw,noexec,nosuid,size=64m \
alpine
特性Named VolumeBind Mounttmpfs
管理方式Docker 自动管理用户手动管理内存存储
存储位置/var/lib/docker/volumes/手动指定路径内存
备份方式Docker 命令直接文件操作不需要
性能原生原生极快
持久性
适用场景数据库、配置文件开发调试缓存、临时数据
version: '3.8'
services:
mosquitto:
image: eclipse-mosquitto:2
volumes:
# Named Volumes 用于数据持久化
- mosquitto_data:/mosquitto/data
- mosquitto_log:/mosquitto/log
# Bind Mount 用于配置文件编辑
- ./mosquitto/config:/mosquitto/config
nodered:
image: nodered/node-red:latest
volumes:
- nodered_data:/data
influxdb:
image: influxdb:2
volumes:
- influxdb_data:/var/lib/influxdb2
- influxdb_config:/etc/influxdb2
grafana:
image: grafana/grafana:latest
volumes:
- grafana_data:/var/lib/grafana
volumes:
mosquitto_data:
mosquitto_log:
nodered_data:
influxdb_data:
influxdb_config:
grafana_data:
服务关键数据存储路径备份优先级
Node-REDFlows, 配置/data⭐⭐⭐
Mosquitto配置, 密码文件/mosquitto/config⭐⭐
InfluxDB时序数据库/var/lib/influxdb2⭐⭐⭐
GrafanaDashboard, Datasources/var/lib/grafana⭐⭐

创建自动备份脚本 backup-iot-stack.sh

#!/bin/bash
# IoT Stack 自动备份脚本
# 使用方法: ./backup-iot-stack.sh [backup-dir]
BACKUP_DIR="${1:-/opt/backups/iot}"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_PATH="${BACKUP_DIR}/${TIMESTAMP}"
# 颜色定义
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
echo -e "${GREEN}=== IoT Stack Backup Script ===${NC}"
echo "Backup directory: ${BACKUP_PATH}"
# 创建备份目录
mkdir -p "${BACKUP_PATH}"
# 1. 备份 Node-RED Flows
echo -e "\n${YELLOW}[1/4] Backing up Node-RED...${NC}"
if docker ps --format '{{.Names}}' | grep -q "nodered"; then
docker cp nodered:/data/flows.json "${BACKUP_PATH}/nodered_flows.json"
docker cp nodered:/data/flows_cred.json "${BACKUP_PATH}/nodered_flows_cred.json" 2>/dev/null
docker cp nodered:/data/package.json "${BACKUP_PATH}/nodered_package.json" 2>/dev/null
echo -e "${GREEN}✓ Node-RED backup completed${NC}"
else
echo -e "${RED}✗ Node-RED container not found${NC}"
fi
# 2. 备份 Mosquitto 配置
echo -e "\n${YELLOW}[2/4] Backing up Mosquitto...${NC}"
if docker ps --format '{{.Names}}' | grep -q "mosquitto"; then
docker cp mosquitto:/mosquitto/config "${BACKUP_PATH}/mosquitto_config" 2>/dev/null
docker cp mosquitto:/mosquitto/data "${BACKUP_PATH}/mosquitto_data" 2>/dev/null
echo -e "${GREEN}✓ Mosquitto backup completed${NC}"
else
echo -e "${RED}✗ Mosquitto container not found${NC}"
fi
# 3. 备份 InfluxDB
echo -e "\n${YELLOW}[3/4] Backing up InfluxDB...${NC}"
if docker ps --format '{{.Names}}' | grep -q "influxdb"; then
docker exec influxdb influx backup \
/tmp/influxdb-backup \
--token "${INFLUX_TOKEN:-}"
docker cp influxdb:/tmp/influxdb-backup "${BACKUP_PATH}/influxdb_backup"
echo -e "${GREEN}✓ InfluxDB backup completed${NC}"
else
echo -e "${RED}✗ InfluxDB container not found${NC}"
fi
# 4. 备份 Grafana
echo -e "\n${YELLOW}[4/4] Backing up Grafana...${NC}"
if docker ps --format '{{.Names}}' | grep -q "grafana"; then
docker cp grafana:/var/lib/grafana/grafana.db "${BACKUP_PATH}/grafana.db" 2>/dev/null
echo -e "${GREEN}✓ Grafana backup completed${NC}"
else
echo -e "${RED}✗ Grafana container not found${NC}"
fi
# 创建备份摘要
{
echo "Backup Timestamp: ${TIMESTAMP}"
echo "Components:"
echo " - Node-RED: nodered_flows.json"
echo " - Mosquitto: mosquitto_config/"
echo " - InfluxDB: influxdb_backup/"
echo " - Grafana: grafana.db"
} > "${BACKUP_PATH}/backup_manifest.txt"
# 压缩备份
echo -e "\n${YELLOW}Compressing backup...${NC}"
cd "${BACKUP_DIR}"
tar -czf "iot-backup-${TIMESTAMP}.tar.gz" "${TIMESTAMP}"
rm -rf "${TIMESTAMP}"
echo -e "\n${GREEN}=== Backup Completed Successfully ===${NC}"
echo "Backup file: ${BACKUP_DIR}/iot-backup-${TIMESTAMP}.tar.gz"
echo "Size: $(du -h "${BACKUP_DIR}/iot-backup-${TIMESTAMP}.tar.gz" | cut -f1)"
Terminal window
# 编辑 crontab
crontab -e
# 每天凌晨 2:30 执行备份
30 2 * * * /opt/scripts/backup-iot-stack.sh >> /var/log/iot-backup.log 2>&1
# 每周日凌晨 3:00 执行完整备份
0 3 * * 0 /opt/scripts/backup-iot-stack.sh /opt/backups/iot-weekly
# 保留最近 30 天的备份(清理旧备份)
0 4 * * * find /opt/backups/iot -name "*.tar.gz" -mtime +30 -delete
备份目录结构:
/opt/backups/iot/
├── daily/ # 日备份,保留 7 天
│ ├── iot-backup-20260517.tar.gz
│ ├── iot-backup-20260518.tar.gz
│ └── ...
├── weekly/ # 周备份,保留 4 周
│ ├── iot-backup-202604-week1.tar.gz
│ └── ...
└── monthly/ # 月备份,保留 12 个月
└── iot-backup-202605.tar.gz
Terminal window
# 从备份恢复 Node-RED Flow
docker cp backup/nodered_flows.json nodered:/data/flows.json
# 重启 Node-RED 加载新 Flow
docker restart nodered
Terminal window
# 从备份恢复 InfluxDB
docker exec influxdb influx restore \
/tmp/influxdb-backup \
--token "${INFLUX_TOKEN:-}"
# 重启 InfluxDB
docker restart influxdb
#!/bin/bash
# IoT Stack 完整恢复脚本
# 使用方法: ./restore-iot-stack.sh <backup-file.tar.gz>
BACKUP_FILE=$1
if [ -z "$BACKUP_FILE" ]; then
echo "Usage: ./restore-iot-stack.sh <backup-file.tar.gz>"
exit 1
fi
# 解压备份
tar -xzf "$BACKUP_FILE" -C /tmp/restore
# 停止所有服务
docker-compose down
# 恢复 Node-RED
docker cp /tmp/restore/nodered_flows.json nodered:/data/
# 恢复 Mosquitto 配置
docker cp /tmp/restore/mosquitto_config mosquitto:/mosquitto/
# 恢复 Grafana
docker cp /tmp/restore/grafana.db grafana:/var/lib/grafana/
# 重启服务
docker-compose up -d
echo "Restore completed!"

A: 如果使用了 Volume,容器删除后数据仍然保留。重新创建容器并挂载相同的 Volume 即可恢复。

A: 备份文件包含敏感数据(密码、Token),建议加密存储:

Terminal window
# 加密备份
gpg --symmetric --cipher-algo AES256 iot-backup-20260518.tar.gz
# 解密备份
gpg --decrypt iot-backup-20260518.tar.gz.gpg > iot-backup-20260518.tar.gz

A: 备份不影响服务正常运行。但如果需要数据库一致性,建议在低峰期执行并暂停写入。

推荐做法:

  • 所有关键服务配置数据卷
  • 实施 3-2-1 备份策略(3 份备份、2 种介质、1 份异地)
  • 定期测试恢复流程
  • 监控备份日志和磁盘空间
  • 加密敏感数据备份

避免做法:

  • 不配置持久化直接使用容器
  • 仅有一份备份文件
  • 从不测试备份恢复
  • 备份文件与服务器共存
  • 忽视配置文件备份
  1. 数据持久化是容器化 IoT 系统的基石
  2. 使用 Named Volume 管理关键数据
  3. 自动备份脚本确保数据安全
  4. Cronjob 定时备份实现自动化
  5. 定期测试恢复流程确保可用性