数据备份与恢复 #

数据备份概述 #

为什么需要备份? #

text
┌─────────────────────────────────────────────────────┐
│                   数据备份的重要性                   │
├─────────────────────────────────────────────────────┤
│                                                     │
│  1. 防止数据丢失                                    │
│  2. 灾难恢复                                        │
│  3. 数据迁移                                        │
│  4. 版本回滚                                        │
│  5. 合规要求                                        │
│                                                     │
└─────────────────────────────────────────────────────┘

备份类型 #

类型 说明 频率
全量备份 备份所有数据 每周
增量备份 备份变化的数据 每天
差异备份 备份与上次全量备份的差异 每天

数据卷备份 #

备份单个数据卷 #

bash
# 使用临时容器备份数据卷
docker run --rm \
  -v myvolume:/source:ro \
  -v $(pwd)/backup:/backup \
  alpine tar czf /backup/myvolume-$(date +%Y%m%d).tar.gz -C /source .

# 备份到标准输出
docker run --rm \
  -v myvolume:/source:ro \
  alpine tar czf - -C /source . > myvolume-backup.tar.gz

# 使用压缩
docker run --rm \
  -v myvolume:/source:ro \
  -v $(pwd)/backup:/backup \
  alpine tar cjf /backup/myvolume.tar.bz2 -C /source .

备份多个数据卷 #

bash
#!/bin/bash
# backup-volumes.sh

BACKUP_DIR="/backup/volumes"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR

for volume in $(docker volume ls -q); do
    echo "Backing up volume: $volume"
    docker run --rm \
        -v $volume:/source:ro \
        -v $BACKUP_DIR:/backup \
        alpine tar czf /backup/${volume}-${DATE}.tar.gz -C /source .
done

echo "Backup completed!"

备份容器数据 #

bash
# 备份运行中容器的数据
docker run --rm \
  --volumes-from mycontainer \
  -v $(pwd)/backup:/backup \
  alpine tar czf /backup/container-data.tar.gz /app/data

# 备份特定目录
docker run --rm \
  --volumes-from mycontainer \
  -v $(pwd)/backup:/backup \
  alpine tar czf /backup/mysql-data.tar.gz /var/lib/mysql

数据恢复 #

恢复数据卷 #

bash
# 创建新数据卷
docker volume create restored-volume

# 恢复数据
docker run --rm \
  -v restored-volume:/target \
  -v $(pwd)/backup:/backup \
  alpine sh -c "cd /target && tar xzf /backup/myvolume-backup.tar.gz"

# 恢复到现有数据卷(会覆盖)
docker run --rm \
  -v myvolume:/target \
  -v $(pwd)/backup:/backup \
  alpine sh -c "cd /target && tar xzf /backup/myvolume-backup.tar.gz"

从标准输入恢复 #

bash
# 从标准输入恢复
cat myvolume-backup.tar.gz | docker run --rm -i \
  -v myvolume:/target \
  alpine sh -c "cd /target && tar xzf -"

恢复到容器 #

bash
# 恢复数据到运行中的容器
docker run --rm \
  --volumes-from mycontainer \
  -v $(pwd)/backup:/backup \
  alpine tar xzf /backup/container-data.tar.gz -C /

数据库备份 #

MySQL备份 #

bash
# 使用mysqldump备份
docker exec my-mysql mysqldump -u root -proot --all-databases > mysql-backup.sql

# 备份特定数据库
docker exec my-mysql mysqldump -u root -proot mydb > mydb-backup.sql

# 使用压缩
docker exec my-mysql mysqldump -u root -proot --all-databases | gzip > mysql-backup.sql.gz

# 恢复MySQL
cat mysql-backup.sql | docker exec -i my-mysql mysql -u root -proot

# 恢复压缩备份
gunzip < mysql-backup.sql.gz | docker exec -i my-mysql mysql -u root -proot

PostgreSQL备份 #

bash
# 使用pg_dump备份
docker exec my-postgres pg_dump -U postgres mydb > postgres-backup.sql

# 备份所有数据库
docker exec my-postgres pg_dumpall -U postgres > postgres-all-backup.sql

# 使用压缩
docker exec my-postgres pg_dump -U postgres mydb | gzip > postgres-backup.sql.gz

# 恢复PostgreSQL
cat postgres-backup.sql | docker exec -i my-postgres psql -U postgres

# 恢复压缩备份
gunzip < postgres-backup.sql.gz | docker exec -i my-postgres psql -U postgres

MongoDB备份 #

bash
# 使用mongodump备份
docker exec my-mongo mongodump --archive > mongo-backup.archive

# 备份特定数据库
docker exec my-mongo mongodump --db mydb --archive > mydb-backup.archive

# 使用压缩
docker exec my-mongo mongodump --archive | gzip > mongo-backup.archive.gz

# 恢复MongoDB
cat mongo-backup.archive | docker exec -i my-mongo mongorestore --archive

# 恢复压缩备份
gunzip < mongo-backup.archive.gz | docker exec -i my-mongo mongorestore --archive

Redis备份 #

bash
# 触发RDB快照
docker exec my-redis redis-cli BGSAVE

# 复制RDB文件
docker cp my-redis:/data/dump.rdb ./redis-backup-$(date +%Y%m%d).rdb

# 恢复Redis
docker cp ./redis-backup.rdb my-redis:/data/dump.rdb
docker restart my-redis

自动化备份 #

定时备份脚本 #

bash
#!/bin/bash
# auto-backup.sh

BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份数据卷
echo "Backing up volumes..."
for volume in $(docker volume ls -q); do
    docker run --rm \
        -v $volume:/source:ro \
        -v $BACKUP_DIR:/backup \
        alpine tar czf /backup/${volume}-${DATE}.tar.gz -C /source .
done

# 备份MySQL
echo "Backing up MySQL..."
docker exec my-mysql mysqldump -u root -proot --all-databases | gzip > $BACKUP_DIR/mysql-${DATE}.sql.gz

# 备份PostgreSQL
echo "Backing up PostgreSQL..."
docker exec my-postgres pg_dumpall -U postgres | gzip > $BACKUP_DIR/postgres-${DATE}.sql.gz

# 清理旧备份
echo "Cleaning old backups..."
find $BACKUP_DIR -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
find $BACKUP_DIR -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete

echo "Backup completed at $(date)"

Cron定时任务 #

bash
# 编辑crontab
crontab -e

# 每天凌晨2点执行备份
0 2 * * * /path/to/auto-backup.sh >> /var/log/docker-backup.log 2>&1

# 每周日凌晨3点执行全量备份
0 3 * * 0 /path/to/full-backup.sh >> /var/log/docker-backup.log 2>&1

# 每小时执行增量备份
0 * * * * /path/to/incremental-backup.sh >> /var/log/docker-backup.log 2>&1

远程备份 #

备份到S3 #

bash
#!/bin/bash
# backup-to-s3.sh

BACKUP_DIR="/tmp/backup"
S3_BUCKET="s3://my-backup-bucket/docker"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR

# 备份数据卷
for volume in $(docker volume ls -q); do
    docker run --rm \
        -v $volume:/source:ro \
        -v $BACKUP_DIR:/backup \
        alpine tar czf /backup/${volume}-${DATE}.tar.gz -C /source .
done

# 上传到S3
aws s3 sync $BACKUP_DIR $S3_BUCKET/$DATE/

# 清理本地备份
rm -rf $BACKUP_DIR

echo "Backup uploaded to S3: $S3_BUCKET/$DATE/"

备份到远程服务器 #

bash
#!/bin/bash
# backup-to-remote.sh

REMOTE_HOST="backup.example.com"
REMOTE_DIR="/backup/docker"
DATE=$(date +%Y%m%d_%H%M%S)

# 备份并传输
docker run --rm \
  -v myvolume:/source:ro \
  alpine tar czf - -C /source . | \
  ssh $REMOTE_HOST "cat > $REMOTE_DIR/myvolume-${DATE}.tar.gz"

# 或使用rsync
docker run --rm \
  -v myvolume:/source:ro \
  -v $(pwd):/backup \
  alpine tar czf /backup/myvolume-${DATE}.tar.gz -C /source .

rsync -avz $(pwd)/myvolume-${DATE}.tar.gz $REMOTE_HOST:$REMOTE_DIR/

数据迁移 #

迁移数据卷 #

bash
# 源主机: 导出数据卷
docker run --rm \
  -v source-volume:/source:ro \
  -v $(pwd):/backup \
  alpine tar czf /backup/volume.tar.gz -C /source .

# 传输文件到目标主机
scp volume.tar.gz target-host:/tmp/

# 目标主机: 导入数据卷
docker volume create target-volume
docker run --rm \
  -v target-volume:/target \
  -v /tmp:/backup \
  alpine tar xzf /backup/volume.tar.gz -C /target

迁移容器 #

bash
# 导出容器
docker export mycontainer > container.tar

# 传输并导入
scp container.tar target-host:/tmp/
docker import /tmp/container.tar myimage:v1.0

# 运行新容器
docker run -d --name new-container myimage:v1.0

迁移整个Docker环境 #

bash
#!/bin/bash
# migrate-docker.sh

# 导出所有镜像
docker save $(docker images -q) -o all-images.tar

# 导出所有数据卷
for volume in $(docker volume ls -q); do
    docker run --rm \
        -v $volume:/source:ro \
        -v $(pwd):/backup \
        alpine tar czf /backup/${volume}.tar.gz -C /source .
done

# 导出容器配置
for container in $(docker ps -aq); do
    docker inspect $container > ${container}.json
done

# 打包传输
tar czf docker-migration.tar.gz *.tar *.json

备份验证 #

验证备份完整性 #

bash
#!/bin/bash
# verify-backup.sh

BACKUP_FILE=$1

# 验证tar文件
if tar tzf $BACKUP_FILE > /dev/null 2>&1; then
    echo "Backup is valid: $BACKUP_FILE"
    exit 0
else
    echo "Backup is corrupted: $BACKUP_FILE"
    exit 1
fi

测试恢复 #

bash
#!/bin/bash
# test-restore.sh

BACKUP_FILE=$1
TEST_VOLUME="test-restore-$(date +%s)"

# 创建测试卷
docker volume create $TEST_VOLUME

# 恢复数据
docker run --rm \
  -v $TEST_VOLUME:/target \
  -v $(pwd):/backup \
  alpine tar xzf /backup/$BACKUP_FILE -C /target

# 验证数据
docker run --rm \
  -v $TEST_VOLUME:/data \
  alpine ls -la /data

# 清理
docker volume rm $TEST_VOLUME

小结 #

本节学习了Docker数据的备份和恢复:

  • 数据卷备份方法
  • 数据恢复操作
  • 数据库备份策略
  • 自动化备份配置
  • 远程备份方案
  • 数据迁移方法

下一步 #

接下来,让我们学习 网络基础,了解Docker网络的基本概念。