Docker 环境下 MySQL 数据库备份与查看操作指南

前言

在使用 Docker 部署 MySQL 时,很多开发者习惯进入容器内部进行操作,然而这常常带来以下痛点:

  • 备份文件默认保存在容器内部,容器一旦停止或删除,备份随之丢失
  • 操作步骤繁琐,需要在容器内外反复切换终端
  • 不利于自动化脚本编写,手动操作易出错
  • 使用磁盘目录映射,要更加方便一些,但依然不够优雅

本文将系统介绍如何在 Docker 环境中安全、高效地备份和查看 MySQL 数据库,并提供”不进容器”的最佳实践方案,同时提供完整的自动化备份和恢复脚本。


一、备份操作

1.1 容器内部备份(不推荐但需了解)

如果你已经进入 MySQL 容器(docker exec -it mysql bash),备份流程如下:

1
2
3
4
5
6
7
8
# 备份单个数据库到容器内临时目录
mysqldump -u root -p密码 数据库名 > /tmp/backup.sql

# 备份所有数据库
mysqldump -u root -p密码 --all-databases > /tmp/all_backup.sql

# 备份并压缩
mysqldump -u root -p密码 数据库名 | gzip > /tmp/backup.sql.gz

关键问题:备份文件在容器内部,容器删除则文件丢失。

解决方法:将文件从容器复制到宿主机

1
2
# 在宿主机执行(另一个终端窗口)
docker cp 容器名或ID:/tmp/backup.sql /宿主机/目标路径/

完整工作流示例

1
2
3
4
5
6
7
8
# 1. 容器内备份
root@容器ID:/# mysqldump -u root -p123456 mydb > /tmp/mydb_backup.sql

# 2. 宿主机复制(新终端窗口)
$ docker cp mysql-container:/tmp/mydb_backup.sql ~/backups/

# 3. 清理容器临时文件
root@容器ID:/# rm /tmp/mydb_backup.sql

1.2 推荐方案:不进容器直接备份

直接在宿主机执行,一步到位:

1
2
3
4
5
6
7
8
# 备份单个数据库到宿主机
docker exec mysql-container mysqldump -u root -p密码 数据库名 > ~/backup.sql

# 备份所有数据库
docker exec mysql-container mysqldump -u root -p密码 --all-databases > ~/all_backup.sql

# 备份并压缩
docker exec mysql-container mysqldump -u root -p密码 数据库名 | gzip > ~/backup.sql.gz

为什么这是最佳实践?

  • ✅ 简单:单条命令完成备份
  • ✅ 安全:备份直接保存在宿主机
  • ✅ 自动化:易于集成到脚本和定时任务
  • ✅ 资源友好:不占用容器内磁盘空间

1.3 自动化备份脚本

对于生产环境,建议使用自动化备份脚本。以下是一个功能完整的双重备份脚本,可保存为 backup-mysql.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
#!/bin/bash
# MySQL 双重备份脚本
# 1. 完整备份所有数据库
# 2. 每个数据库单独备份
# 3. 保留最近3份备份

# ============ 配置区域 ============
CONTAINER_NAME="c_mysql" # MySQL容器名
MYSQL_USER="root" # MySQL用户名
MYSQL_PASSWORD="songjian" # MySQL密码
BACKUP_BASE_DIR="/root/songjian/mysql/backups" # 备份根目录
KEEP_BACKUPS=3 # 保留的备份份数
LOG_FILE="/root/songjian/mysql/backup-mysql.log" # 日志文件
# ==================================

# 创建必要的目录
mkdir -p $BACKUP_BASE_DIR
mkdir -p $(dirname $LOG_FILE)

# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

# 错误处理函数
error_exit() {
log "❌ 错误: $1"
exit 1
}

# 获取当前时间戳
BACKUP_TIME=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="$BACKUP_BASE_DIR/$BACKUP_TIME"

log "=========================================="
log "开始 MySQL 双重备份"
log "备份时间: $BACKUP_TIME"
log "备份目录: $BACKUP_DIR"
log "容器名称: $CONTAINER_NAME"
log "备份路径: $BACKUP_BASE_DIR"

# 检查容器是否运行
CONTAINER_STATUS=$(docker ps --filter "name=$CONTAINER_NAME" --format "{{.Names}}")

if [ -z "$CONTAINER_STATUS" ]; then
error_exit "容器 ${CONTAINER_NAME} 未运行!"
else
log "✅ 容器状态: 运行中 ($CONTAINER_NAME)"
fi

# 创建本次备份目录
mkdir -p $BACKUP_DIR/all_databases
mkdir -p $BACKUP_DIR/separate_databases
mkdir -p $BACKUP_DIR/logs

# 1. 备份所有数据库(完整备份)
log "1. 开始完整备份所有数据库..."
ALL_BACKUP_FILE="$BACKUP_DIR/all_databases/full_backup.sql.gz"

# 测试 MySQL 连接
log "测试 MySQL 连接..."
if ! docker exec $CONTAINER_NAME mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e "SELECT 1" >/dev/null 2>&1; then
error_exit "无法连接到 MySQL 数据库,请检查用户名和密码"
else
log "✅ MySQL 连接测试成功"
fi

# 执行完整备份
docker exec $CONTAINER_NAME mysqldump -u$MYSQL_USER -p$MYSQL_PASSWORD \
--all-databases \
--single-transaction \
--routines \
--events \
--triggers \
--set-gtid-purged=OFF 2>> "$BACKUP_DIR/logs/full_backup.log" | gzip > $ALL_BACKUP_FILE

if [ $? -eq 0 ] && [ -s $ALL_BACKUP_FILE ]; then
SIZE=$(du -h $ALL_BACKUP_FILE | cut -f1)
log " ✅ 完整备份成功: $(basename $ALL_BACKUP_FILE) ($SIZE)"
else
# 尝试不使用 --set-gtid-purged 参数
log "⚠️ 第一次备份失败,尝试不使用 GTID 参数..."
docker exec $CONTAINER_NAME mysqldump -u$MYSQL_USER -p$MYSQL_PASSWORD \
--all-databases \
--single-transaction \
--routines \
--events \
--triggers 2>> "$BACKUP_DIR/logs/full_backup_alt.log" | gzip > $ALL_BACKUP_FILE

if [ $? -eq 0 ] && [ -s $ALL_BACKUP_FILE ]; then
SIZE=$(du -h $ALL_BACKUP_FILE | cut -f1)
log " ✅ 完整备份成功(备选方案): $(basename $ALL_BACKUP_FILE) ($SIZE)"
else
error_exit "完整备份失败!"
fi
fi

# 2. 获取所有数据库列表
log "2. 获取数据库列表..."
DATABASES=$(docker exec $CONTAINER_NAME mysql -u$MYSQL_USER -p$MYSQL_PASSWORD \
--skip-column-names \
-e "SHOW DATABASES;" 2>> "$BACKUP_DIR/logs/db_list.log")

if [ $? -ne 0 ]; then
error_exit "获取数据库列表失败!"
fi

# 过滤掉系统数据库
FILTERED_DATABASES=""
for DB in $DATABASES; do
case $DB in
information_schema|performance_schema|sys|mysql)
log " 跳过系统数据库: $DB"
;;
*)
FILTERED_DATABASES="$FILTERED_DATABASES $DB"
;;
esac
done

# 重新赋值
DATABASES=$FILTERED_DATABASES
DB_COUNT=$(echo "$DATABASES" | wc -w)

log " 找到 $DB_COUNT 个用户数据库需要单独备份"

# 如果没有数据库,只备份完整备份
if [ $DB_COUNT -eq 0 ]; then
log "⚠️ 没有找到用户数据库,只保留完整备份"

# 创建备份摘要
cat > "$BACKUP_DIR/backup_summary.txt" << EOF
备份摘要
========
备份时间: $(date)
备份编号: $BACKUP_TIME
备份目录: $BACKUP_DIR
容器名称: $CONTAINER_NAME

备份内容:
1. 完整备份: $ALL_BACKUP_FILE
大小: $(du -h $ALL_BACKUP_FILE | cut -f1)

2. 单独数据库备份: 0 个 (没有找到用户数据库)

备份统计:
数据库总数: 0
完整备份: 成功
单独备份: 跳过
EOF

# 清理旧备份
cleanup_old_backups
exit 0
fi

log " 需要备份的数据库: $DATABASES"

# 3. 逐个备份每个数据库
SUCCESS_COUNT=0
FAIL_COUNT=0
FAILED_DBS=""
log "3. 开始逐个数据库备份..."

for DB in $DATABASES; do
log " 备份数据库: $DB"
DB_BACKUP_FILE="$BACKUP_DIR/separate_databases/${DB}.sql.gz"

docker exec $CONTAINER_NAME mysqldump -u$MYSQL_USER -p$MYSQL_PASSWORD \
--single-transaction \
--routines \
--events \
--triggers \
$DB 2>> "$BACKUP_DIR/logs/${DB}.log" | gzip > $DB_BACKUP_FILE

if [ $? -eq 0 ] && [ -s $DB_BACKUP_FILE ]; then
SIZE=$(du -h $DB_BACKUP_FILE | cut -f1)
log " ✅ 成功 ($SIZE)"
((SUCCESS_COUNT++))
else
log " ❌ 失败,尝试简单备份..."
# 尝试简化备份
docker exec $CONTAINER_NAME mysqldump -u$MYSQL_USER -p$MYSQL_PASSWORD \
$DB 2>> "$BACKUP_DIR/logs/${DB}_simple.log" | gzip > $DB_BACKUP_FILE

if [ $? -eq 0 ] && [ -s $DB_BACKUP_FILE ]; then
SIZE=$(du -h $DB_BACKUP_FILE | cut -f1)
log " ✅ 成功(简单模式) ($SIZE)"
((SUCCESS_COUNT++))
else
log " ❌❌ 备份失败"
rm -f $DB_BACKUP_FILE
FAILED_DBS="$FAILED_DBS $DB"
((FAIL_COUNT++))
fi
fi
done

log " 数据库单独备份完成: 成功 $SUCCESS_COUNT 个, 失败 $FAIL_COUNT 个"
if [ $FAIL_COUNT -gt 0 ]; then
log " 失败的数据库: $FAILED_DBS"
fi

# 4. 创建备份摘要
log "4. 生成备份摘要..."
SUMMARY_FILE="$BACKUP_DIR/backup_summary.txt"
cat > $SUMMARY_FILE << EOF
备份摘要
========
备份时间: $(date)
备份编号: $BACKUP_TIME
备份目录: $BACKUP_DIR
容器名称: $CONTAINER_NAME
MySQL 用户: $MYSQL_USER

备份内容:
1. 完整备份: $ALL_BACKUP_FILE
大小: $(du -h $ALL_BACKUP_FILE | cut -f1)

2. 单独数据库备份 ($SUCCESS_COUNT 个):
EOF

# 添加每个数据库的备份信息
for DB in $DATABASES; do
FILE="$BACKUP_DIR/separate_databases/${DB}.sql.gz"
if [ -f "$FILE" ]; then
SIZE=$(du -h "$FILE" 2>/dev/null | cut -f1 || echo "未知")
echo " - $DB: $SIZE" >> $SUMMARY_FILE
fi
done

cat >> $SUMMARY_FILE << EOF

备份统计:
数据库总数: $DB_COUNT
成功备份: $SUCCESS_COUNT
备份失败: $FAIL_COUNT
EOF

if [ -n "$FAILED_DBS" ]; then
echo " 失败列表: $FAILED_DBS" >> $SUMMARY_FILE
fi

cat >> $SUMMARY_FILE << EOF
日志文件: $BACKUP_DIR/logs/

生成时间: $(date)
EOF

# 5. 清理旧备份函数
cleanup_old_backups() {
log "5. 清理旧备份(保留最近 $KEEP_BACKUPS 份)..."
BACKUP_LIST=($(ls -dt $BACKUP_BASE_DIR/20* 2>/dev/null))
BACKUP_COUNT=${#BACKUP_LIST[@]}

if [ $BACKUP_COUNT -gt $KEEP_BACKUPS ]; then
TO_DELETE_COUNT=$((BACKUP_COUNT - KEEP_BACKUPS))
log " 发现 $BACKUP_COUNT 份备份,需要删除 $TO_DELETE_COUNT 份旧备份"

for ((i=KEEP_BACKUPS; i<BACKUP_COUNT; i++)); do
OLD_BACKUP=${BACKUP_LIST[$i]}
OLD_BACKUP_NAME=$(basename "$OLD_BACKUP")
log " 删除旧备份: $OLD_BACKUP_NAME"
rm -rf "$OLD_BACKUP"

# 记录删除操作
echo "删除备份: $OLD_BACKUP_NAME ($(date))" >> "$BACKUP_DIR/logs/cleanup.log"
done
else
log " 当前有 $BACKUP_COUNT 份备份,无需清理(最多保留 $KEEP_BACKUPS 份)"
fi
}

# 执行清理
cleanup_old_backups

# 6. 计算总大小
TOTAL_SIZE=$(du -sh $BACKUP_DIR 2>/dev/null | cut -f1 || echo "0B")
REMAINING_SIZE=$(du -sh $BACKUP_BASE_DIR 2>/dev/null | cut -f1 || echo "0B")
BACKUP_LIST_CURRENT=($(ls -dt $BACKUP_BASE_DIR/20* 2>/dev/null))
CURRENT_BACKUP_COUNT=${#BACKUP_LIST_CURRENT[@]}

log "6. 备份完成统计"
log " 本次备份大小: $TOTAL_SIZE"
log " 总备份占用: $REMAINING_SIZE"
log " 当前保留备份: $CURRENT_BACKUP_COUNT 份"
log " 备份目录: $BACKUP_BASE_DIR"
log " 备份日志: $LOG_FILE"

# 生成最终报告
log "=========================================="
log "✅ MySQL 双重备份完成!"
log " 备份编号: $BACKUP_TIME"
log " 完整备份: $(basename $ALL_BACKUP_FILE)"
log " 单独备份: $SUCCESS_COUNT 个数据库"
log " 保留备份: $CURRENT_BACKUP_COUNT/$KEEP_BACKUPS 份"

# 输出摘要
echo ""
echo "===== 备份摘要 ====="
cat $SUMMARY_FILE

设置定时任务

1
2
3
4
5
# 编辑 crontab
crontab -e

# 添加以下行(每隔2天的凌晨2点执行)
0 2 */2 * * /bin/bash /root/songjian/mysql/backup-mysql.sh

二、查看操作(不进容器)

无需进入容器,直接在宿主机通过 docker exec 调用 MySQL 客户端。

2.1 查看数据库信息

1
2
3
4
5
# 查看所有数据库
docker exec mysql-container mysql -u root -p123456 -e "SHOW DATABASES;"

# 查看当前使用的数据库
docker exec mysql-container mysql -u root -p123456 -e "SELECT DATABASE();"

2.2 查看表结构

1
2
3
4
5
6
7
8
# 查看指定数据库的所有表
docker exec mysql-container mysql -u root -p123456 mydb -e "SHOW TABLES;"

# 查看表结构
docker exec mysql-container mysql -u root -p123456 mydb -e "DESC 表名;"

# 查看建表语句
docker exec mysql-container mysql -u root -p123456 mydb -e "SHOW CREATE TABLE 表名;"

2.3 数据查询

1
2
3
4
5
6
7
8
# 查询数据(限制5条)
docker exec mysql-container mysql -u root -p123456 mydb -e "SELECT * FROM users LIMIT 5;"

# 查询记录数
docker exec mysql-container mysql -u root -p123456 mydb -e "SELECT COUNT(*) FROM users;"

# 带条件的查询
docker exec mysql-container mysql -u root -p123456 mydb -e "SELECT id, name FROM users WHERE status=1;"

2.4 交互式模式

如需连续执行多条 SQL 命令,使用交互式模式:

1
2
# 进入 MySQL 交互命令行
docker exec -it mysql-container mysql -u root -p

输入密码后,进入 mysql> 提示符,可执行任何 SQL 命令:

1
2
3
4
USE mydb;
SHOW TABLES;
SELECT * FROM users;
EXIT; -- 退出

三、恢复操作

3.1 手动恢复

1
2
3
4
5
# 恢复完整备份
zcat backup.sql.gz | docker exec -i mysql-container mysql -u root -p密码

# 恢复单个数据库
zcat database.sql.gz | docker exec -i mysql-container mysql -u root -p密码 数据库名

3.2 交互式恢复脚本

对于复杂的恢复需求,可以使用以下交互式恢复脚本,保存为 interactive-restore.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#!/bin/bash
# 交互式 MySQL 恢复脚本

CONTAINER_NAME="c_mysql"
MYSQL_USER="root"
MYSQL_PASSWORD="songjian"
BACKUP_BASE_DIR="/root/songjian/mysql/backups"

# 声明数组变量
declare -a BACKUP_PATHS

# 显示菜单
show_menu() {
clear
echo "========================================"
echo " MySQL 数据库恢复工具"
echo "========================================"
echo ""

# 列出备份
echo "可用的备份:"
echo "序号 | 备份目录 | 大小"
echo "----|---------|-----"

local backups=($(ls -dt $BACKUP_BASE_DIR/20* 2>/dev/null))
local count=1

for backup in "${backups[@]}"; do
if [ -d "$backup" ]; then
local backup_name=$(basename "$backup")
local backup_size=$(du -sh "$backup" 2>/dev/null | cut -f1 || echo "未知")
printf "%-4s | %-15s | %s\n" "$count" "$backup_name" "$backup_size"

# 存储备份路径
BACKUP_PATHS[$count]="$backup"
((count++))
fi
done

if [ $count -eq 1 ]; then
echo "未找到任何备份"
fi

echo ""
echo "========================================"
echo "0. 退出"
echo "========================================"
echo ""
}

# 显示备份摘要
show_backup_summary() {
local backup_path="$1"
if [ -f "$backup_path/backup_summary.txt" ]; then
cat "$backup_path/backup_summary.txt"
fi
}

# 恢复完整备份
restore_full_backup() {
local backup_path="$1"
echo ""
echo "⚠️ 警告: 这将覆盖所有现有数据库!"
read -p "确认恢复完整备份? (y/N): " confirm
if [[ "$confirm" =~ ^[Yy]$ ]]; then
echo "开始恢复完整备份..."
zcat "$backup_path/all_databases/full_backup.sql.gz" | \
docker exec -i $CONTAINER_NAME mysql -u$MYSQL_USER -p$MYSQL_PASSWORD
if [ $? -eq 0 ]; then
echo "✅ 完整备份恢复成功!"
else
echo "❌ 恢复失败!"
fi
else
echo "操作已取消"
fi
}

# 恢复单个数据库
restore_single_database() {
local backup_path="$1"

# 列出可恢复的数据库
echo ""
echo "可恢复的数据库:"

# 检查是否有单独的数据库备份
if [ ! -d "$backup_path/separate_databases" ]; then
echo "没有单独的数据库备份目录"
return
fi

# 获取数据库文件列表
local db_files=("$backup_path/separate_databases"/*.sql.gz)
if [ ${#db_files[@]} -eq 0 ] || [ ! -f "${db_files[0]}" ]; then
echo "没有单独的数据库备份文件"
return
fi

# 显示数据库列表
local db_count=1
declare -a DB_NAMES

for db_file in "${db_files[@]}"; do
if [ -f "$db_file" ]; then
local db_name=$(basename "$db_file" .sql.gz)
local size=$(du -h "$db_file" 2>/dev/null | cut -f1 || echo "未知")
echo "$db_count. $db_name ($size)"
DB_NAMES[$db_count]="$db_name"
((db_count++))
fi
done

echo ""
read -p "请选择数据库序号 (0取消): " db_choice

if [[ "$db_choice" =~ ^[0-9]+$ ]] && [ "$db_choice" -ge 1 ] && [ "$db_choice" -lt $db_count ]; then
local DB_NAME="${DB_NAMES[$db_choice]}"

echo ""
echo "⚠️ 警告: 这将覆盖数据库 $DB_NAME!"
read -p "确认恢复数据库 $DB_NAME? (y/N): " confirm

if [[ "$confirm" =~ ^[Yy]$ ]]; then
echo "开始恢复数据库 $DB_NAME..."

# 删除现有数据库
docker exec $CONTAINER_NAME mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e "DROP DATABASE IF EXISTS \`$DB_NAME\`;" 2>/dev/null

# 创建数据库
docker exec $CONTAINER_NAME mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e "CREATE DATABASE \`$DB_NAME\`;" 2>/dev/null

if [ $? -ne 0 ]; then
echo "❌ 创建数据库失败!"
return
fi

# 恢复数据库
zcat "$backup_path/separate_databases/${DB_NAME}.sql.gz" | \
docker exec -i $CONTAINER_NAME mysql -u$MYSQL_USER -p$MYSQL_PASSWORD "$DB_NAME"

if [ $? -eq 0 ]; then
echo "✅ 数据库 $DB_NAME 恢复成功!"

# 验证恢复结果
echo "验证恢复结果..."
local table_count=$(docker exec $CONTAINER_NAME mysql -u$MYSQL_USER -p$MYSQL_PASSWORD --skip-column-names -e "USE \`$DB_NAME\`; SHOW TABLES;" 2>/dev/null | wc -l)
if [ $? -eq 0 ]; then
echo "✅ 数据库 $DB_NAME 包含 $table_count 个表"
fi
else
echo "❌ 恢复失败!"
fi
else
echo "操作已取消"
fi
elif [ "$db_choice" = "0" ]; then
echo "操作已取消"
else
echo "无效的选择"
fi
}

# 检查容器状态
check_container() {
if ! docker ps --filter "name=$CONTAINER_NAME" --format "{{.Names}}" | grep -q "^${CONTAINER_NAME}$"; then
echo "❌ 错误: 容器 $CONTAINER_NAME 未运行!"
return 1
fi

# 测试 MySQL 连接
if ! docker exec $CONTAINER_NAME mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e "SELECT 1" >/dev/null 2>&1; then
echo "❌ 错误: 无法连接到 MySQL 数据库,请检查用户名和密码"
return 1
fi

return 0
}

# 主循环
main() {
# 检查容器状态
if ! check_container; then
exit 1
fi

while true; do
show_menu

read -p "请选择备份序号 (0退出): " choice

if [ "$choice" = "0" ]; then
echo "退出恢复工具"
exit 0
fi

if [ -z "${BACKUP_PATHS[$choice]}" ]; then
echo "无效的选择,请重试"
read -p "按 Enter 继续..."
continue
fi

local SELECTED_BACKUP="${BACKUP_PATHS[$choice]}"
local BACKUP_NAME=$(basename "$SELECTED_BACKUP")

echo ""
echo "已选择备份: $BACKUP_NAME"
echo ""

# 显示备份摘要
show_backup_summary "$SELECTED_BACKUP"

echo ""
echo "恢复选项:"
echo "1. 恢复完整备份 (覆盖所有数据库)"
echo "2. 恢复单个数据库"
echo "3. 返回上级菜单"
echo ""

read -p "请选择恢复选项: " restore_option

case $restore_option in
1)
restore_full_backup "$SELECTED_BACKUP"
;;
2)
restore_single_database "$SELECTED_BACKUP"
;;
3)
continue
;;
*)
echo "无效的选项"
;;
esac

echo ""
read -p "按 Enter 继续..."
done
}

# 执行主程序
main "$@"

使用方式

1
2
3
4
5
# 1. 给执行权限
chmod +x interactive-restore.sh

# 2. 运行脚本
./interactive-restore.sh

四、参数说明与安全提示

4.1 常用参数

参数 说明 示例
-u 用户名 -u root
-p 密码(注意无空格) -p123456
-e 执行 SQL 语句 -e "SHOW DATABASES;"
-it 交互式终端 -it

4.2 安全建议

  1. 密码安全:避免在命令行明文显示密码

    1
    2
    3
    4
    5
    6
    # 方式1:手动输入(推荐)
    docker exec -it mysql-container mysql -u root -p

    # 方式2:使用环境变量
    export MYSQL_PWD=your_password
    docker exec mysql-container mysql -u root -e "SHOW DATABASES;"
  2. 容器状态:确保容器正在运行

    1
    docker ps | grep mysql
  3. 权限控制:使用最小权限账户进行操作

  4. 定期测试恢复:定期验证备份文件的可用性


五、快速测试指南

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 测试备份功能
docker exec mysql-container mysqldump -u root -p123456 --all-databases > /tmp/test_backup.sql

# 2. 验证备份文件
ls -lh /tmp/test_backup.sql
head -n 5 /tmp/test_backup.sql

# 3. 测试查询功能
docker exec mysql-container mysql -u root -p123456 -e "SHOW DATABASES;"

# 4. 测试恢复功能
./interactive-restore.sh

# 5. 清理测试文件
rm /tmp/test_backup.sql

六、总结与建议

核心原则:尽量不进容器

场景 推荐操作 命令示例
手动备份 宿主机直接执行 docker exec mysql容器 mysqldump -u 用户 -p密码 数据库 > 备份.sql
已进容器 备份到 /tmp/ 后复制 容器内备份 → docker cp 复制 → 清理临时文件
自动化备份 使用备份脚本 + crontab backup-mysql.sh + 定时任务
日常查看 宿主机查询 docker exec mysql容器 mysql -u 用户 -p密码 -e "SQL语句"
数据恢复 使用恢复脚本 ./interactive-restore.sh

最佳实践

  1. 自动化备份:使用提供的 backup-mysql.sh 脚本实现定时双重备份
  2. 交互式恢复:使用 interactive-restore.sh 脚本安全恢复数据
  3. 定期验证:至少每月测试一次备份文件的恢复流程
  4. 版本控制:对备份和恢复脚本进行版本管理
  5. 监控告警:监控备份任务的执行状态和磁盘空间

提示:所有命令中的容器名、用户名、密码、数据库名请替换为你的实际值。对于生产环境,建议将备份脚本化并定期测试恢复流程。

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

0%