Skip to content

Commit a74d15d

Browse files
committed
fix: Optimize the backup function
1 parent f962b19 commit a74d15d

File tree

1 file changed

+206
-42
lines changed

1 file changed

+206
-42
lines changed

docker-backup.sh

Lines changed: 206 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -318,86 +318,250 @@ create_restore_script() {
318318

319319
log_info "创建恢复脚本..."
320320

321-
cat > "${backup_dir}/restore.sh" << 'EOF'
321+
cat > "${backup_dir}/restore.sh" << EOF
322322
#!/bin/bash
323323
324324
# Docker容器恢复脚本
325325
# 此脚本由docker-backup.sh自动生成
326326
327327
set -euo pipefail
328328
329-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
330-
CONTAINER_NAME=$(basename "$(dirname "${SCRIPT_DIR}")" | sed 's/_[0-9]*$//')
329+
# 颜色定义
330+
RED='\033[0;31m'
331+
GREEN='\033[0;32m'
332+
YELLOW='\033[1;33m'
333+
BLUE='\033[0;34m'
334+
NC='\033[0m'
335+
336+
log_info() { echo -e "\${BLUE}[INFO]\${NC} \$1"; }
337+
log_success() { echo -e "\${GREEN}[SUCCESS]\${NC} \$1"; }
338+
log_warning() { echo -e "\${YELLOW}[WARNING]\${NC} \$1"; }
339+
log_error() { echo -e "\${RED}[ERROR]\${NC} \$1" >&2; }
340+
341+
# 脚本目录和容器名称
342+
SCRIPT_DIR="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
343+
CONTAINER_NAME="${container_name}"
344+
CONFIG_FILE="\${SCRIPT_DIR}/config/container_inspect.json"
331345
332-
echo "开始恢复容器: ${CONTAINER_NAME}"
346+
log_info "开始恢复容器: \${CONTAINER_NAME}"
347+
348+
# 检查必需文件
349+
if [[ ! -f "\${CONFIG_FILE}" ]]; then
350+
log_error "配置文件不存在: \${CONFIG_FILE}"
351+
exit 1
352+
fi
353+
354+
# 检查jq工具
355+
if ! command -v jq >/dev/null 2>&1; then
356+
log_error "需要安装jq工具来解析配置文件"
357+
exit 1
358+
fi
333359
334360
# 检查Docker是否运行
335361
if ! docker info >/dev/null 2>&1; then
336-
echo "错误: Docker未运行或无法访问"
362+
log_error "Docker未运行或无法访问"
337363
exit 1
338364
fi
339365
340366
# 停止并删除现有容器(如果存在)
341-
if docker ps -a --format "{{.Names}}" | grep -q "^${CONTAINER_NAME}$"; then
342-
echo "停止并删除现有容器..."
343-
docker stop "${CONTAINER_NAME}" 2>/dev/null || true
344-
docker rm "${CONTAINER_NAME}" 2>/dev/null || true
367+
if docker ps -a --format "{{.Names}}" | grep -q "^\${CONTAINER_NAME}\$"; then
368+
log_warning "发现现有容器,正在停止并删除..."
369+
docker stop "\${CONTAINER_NAME}" 2>/dev/null || true
370+
docker rm "\${CONTAINER_NAME}" 2>/dev/null || true
371+
log_info "现有容器已删除"
345372
fi
346373
347374
# 恢复镜像(如果存在)
348-
if [[ -f "${SCRIPT_DIR}/${CONTAINER_NAME}_image.tar.gz" ]]; then
349-
echo "恢复Docker镜像..."
350-
gunzip -c "${SCRIPT_DIR}/${CONTAINER_NAME}_image.tar.gz" | docker load
375+
if [[ -f "\${SCRIPT_DIR}/\${CONTAINER_NAME}_image.tar.gz" ]]; then
376+
log_info "恢复Docker镜像..."
377+
if gunzip -c "\${SCRIPT_DIR}/\${CONTAINER_NAME}_image.tar.gz" | docker load; then
378+
log_success "镜像恢复成功"
379+
else
380+
log_warning "镜像恢复失败,将尝试从远程拉取"
381+
fi
351382
fi
352383
353384
# 恢复数据卷
354-
if [[ -d "${SCRIPT_DIR}/volumes" ]]; then
355-
echo "恢复数据卷..."
356-
for volume_file in "${SCRIPT_DIR}/volumes"/*.tar.gz; do
357-
if [[ -f "${volume_file}" ]]; then
358-
volume_name=$(basename "${volume_file}" .tar.gz)
359-
echo " 恢复数据卷: ${volume_name}"
385+
if [[ -d "\${SCRIPT_DIR}/volumes" ]]; then
386+
log_info "恢复数据卷..."
387+
for volume_file in "\${SCRIPT_DIR}/volumes"/*.tar.gz; do
388+
if [[ -f "\${volume_file}" ]]; then
389+
volume_name=\$(basename "\${volume_file}" .tar.gz)
390+
log_info " 恢复数据卷: \${volume_name}"
360391
361392
# 创建数据卷
362-
docker volume create "${volume_name}" >/dev/null 2>&1 || true
393+
docker volume create "\${volume_name}" >/dev/null 2>&1 || true
363394
364395
# 恢复数据
365-
docker run --rm -v "${volume_name}:/data" -v "${SCRIPT_DIR}/volumes:/backup" \
366-
alpine:latest tar -xzf "/backup/${volume_name}.tar.gz" -C /data
396+
if docker run --rm -v "\${volume_name}:/data" -v "\${SCRIPT_DIR}/volumes:/backup" \
397+
alpine:latest tar -xzf "/backup/\${volume_name}.tar.gz" -C /data 2>/dev/null; then
398+
log_success " 数据卷 '\${volume_name}' 恢复成功"
399+
else
400+
log_warning " 数据卷 '\${volume_name}' 恢复失败"
401+
fi
367402
fi
368403
done
369404
fi
370405
371406
# 恢复挂载点
372-
if [[ -d "${SCRIPT_DIR}/mounts" ]]; then
373-
echo "恢复挂载点..."
374-
for mount_dir in "${SCRIPT_DIR}/mounts"/mount_*; do
375-
if [[ -d "${mount_dir}" ]]; then
376-
mount_info="${mount_dir}/mount_info.json"
377-
if [[ -f "${mount_info}" ]]; then
378-
source_path=$(jq -r '.Source' "${mount_info}")
379-
380-
echo " 恢复挂载点: ${source_path}"
407+
if [[ -d "\${SCRIPT_DIR}/mounts" ]]; then
408+
log_info "恢复挂载点..."
409+
for mount_dir in "\${SCRIPT_DIR}/mounts"/mount_*; do
410+
if [[ -d "\${mount_dir}" ]]; then
411+
mount_info="\${mount_dir}/mount_info.json"
412+
if [[ -f "\${mount_info}" ]]; then
413+
source_path=\$(jq -r '.Source' "\${mount_info}" 2>/dev/null || echo "")
414+
destination=\$(jq -r '.Destination' "\${mount_info}" 2>/dev/null || echo "")
381415
382-
# 创建目录结构
383-
mkdir -p "$(dirname "${source_path}")"
384-
385-
# 恢复数据
386-
if [[ -f "${mount_dir}/data.tar.gz" ]]; then
387-
tar -xzf "${mount_dir}/data.tar.gz" -C "$(dirname "${source_path}")"
388-
elif [[ -f "${mount_dir}/data.file" ]]; then
389-
cp "${mount_dir}/data.file" "${source_path}"
416+
if [[ -n "\${source_path}" ]]; then
417+
log_info " 恢复挂载点: \${source_path} -> \${destination}"
418+
419+
# 创建目录结构
420+
mkdir -p "\$(dirname "\${source_path}")"
421+
422+
# 恢复数据
423+
if [[ -f "\${mount_dir}/data.tar.gz" ]]; then
424+
if tar -xzf "\${mount_dir}/data.tar.gz" -C "\$(dirname "\${source_path}")" 2>/dev/null; then
425+
log_success " 挂载点数据恢复成功: \${source_path}"
426+
else
427+
log_warning " 挂载点数据恢复失败: \${source_path}"
428+
fi
429+
elif [[ -f "\${mount_dir}/data.file" ]]; then
430+
if cp "\${mount_dir}/data.file" "\${source_path}" 2>/dev/null; then
431+
log_success " 挂载点文件恢复成功: \${source_path}"
432+
else
433+
log_warning " 挂载点文件恢复失败: \${source_path}"
434+
fi
435+
fi
390436
fi
391437
fi
392438
fi
393439
done
394440
fi
395441
396-
echo "数据恢复完成"
397-
echo "请使用以下命令检查配置并手动启动容器:"
398-
echo " docker inspect \$(cat ${SCRIPT_DIR}/config/container_inspect.json | jq -r '.[0].Config')"
399-
echo "或参考 ${SCRIPT_DIR}/config/ 目录中的配置文件"
442+
# 解析容器配置并重建容器
443+
log_info "解析容器配置并重建容器..."
444+
445+
# 获取镜像名称
446+
IMAGE=\$(jq -r '.[0].Config.Image' "\${CONFIG_FILE}")
447+
if [[ "\${IMAGE}" == "null" || -z "\${IMAGE}" ]]; then
448+
log_error "无法获取镜像名称"
449+
exit 1
450+
fi
451+
452+
log_info "容器镜像: \${IMAGE}"
453+
454+
# 尝试拉取镜像(如果本地没有)
455+
if ! docker image inspect "\${IMAGE}" >/dev/null 2>&1; then
456+
log_info "本地镜像不存在,尝试拉取: \${IMAGE}"
457+
if docker pull "\${IMAGE}"; then
458+
log_success "镜像拉取成功"
459+
else
460+
log_error "无法拉取镜像: \${IMAGE}"
461+
exit 1
462+
fi
463+
fi
464+
465+
# 构建docker run命令
466+
log_info "构建容器运行命令..."
467+
DOCKER_CMD="docker run -d --name \${CONTAINER_NAME}"
468+
469+
# 添加端口映射
470+
PORTS=\$(jq -r '.[0].NetworkSettings.Ports // {} | to_entries[] | select(.value != null) | "\(.key):\(.value[0].HostPort // "")"' "\${CONFIG_FILE}" 2>/dev/null || true)
471+
if [[ -n "\${PORTS}" ]]; then
472+
while IFS= read -r port_mapping; do
473+
if [[ -n "\${port_mapping}" ]]; then
474+
container_port=\$(echo "\${port_mapping}" | cut -d: -f1)
475+
host_port=\$(echo "\${port_mapping}" | cut -d: -f2)
476+
if [[ -n "\${host_port}" && "\${host_port}" != "null" ]]; then
477+
DOCKER_CMD="\${DOCKER_CMD} -p \${host_port}:\${container_port}"
478+
log_info " 添加端口映射: \${host_port}:\${container_port}"
479+
fi
480+
fi
481+
done <<< "\${PORTS}"
482+
fi
483+
484+
# 添加环境变量
485+
ENV_VARS=\$(jq -r '.[0].Config.Env[]?' "\${CONFIG_FILE}" 2>/dev/null || true)
486+
if [[ -n "\${ENV_VARS}" ]]; then
487+
while IFS= read -r env_var; do
488+
if [[ -n "\${env_var}" ]]; then
489+
DOCKER_CMD="\${DOCKER_CMD} -e '\${env_var}'"
490+
log_info " 添加环境变量: \${env_var}"
491+
fi
492+
done <<< "\${ENV_VARS}"
493+
fi
494+
495+
# 添加挂载点
496+
MOUNTS=\$(jq -c '.[0].Mounts[]?' "\${CONFIG_FILE}" 2>/dev/null || true)
497+
if [[ -n "\${MOUNTS}" ]]; then
498+
while IFS= read -r mount_info; do
499+
if [[ -n "\${mount_info}" ]]; then
500+
mount_type=\$(echo "\${mount_info}" | jq -r '.Type' 2>/dev/null || echo "")
501+
source=\$(echo "\${mount_info}" | jq -r '.Source' 2>/dev/null || echo "")
502+
destination=\$(echo "\${mount_info}" | jq -r '.Destination' 2>/dev/null || echo "")
503+
504+
if [[ "\${mount_type}" == "bind" && -n "\${source}" && -n "\${destination}" ]]; then
505+
DOCKER_CMD="\${DOCKER_CMD} -v \${source}:\${destination}"
506+
log_info " 添加绑定挂载: \${source}:\${destination}"
507+
elif [[ "\${mount_type}" == "volume" ]]; then
508+
volume_name=\$(echo "\${mount_info}" | jq -r '.Name' 2>/dev/null || echo "")
509+
if [[ -n "\${volume_name}" && -n "\${destination}" ]]; then
510+
DOCKER_CMD="\${DOCKER_CMD} -v \${volume_name}:\${destination}"
511+
log_info " 添加数据卷: \${volume_name}:\${destination}"
512+
fi
513+
fi
514+
fi
515+
done <<< "\${MOUNTS}"
516+
fi
517+
518+
# 添加工作目录
519+
WORKDIR=\$(jq -r '.[0].Config.WorkingDir' "\${CONFIG_FILE}" 2>/dev/null || echo "")
520+
if [[ -n "\${WORKDIR}" && "\${WORKDIR}" != "null" ]]; then
521+
DOCKER_CMD="\${DOCKER_CMD} -w \${WORKDIR}"
522+
log_info " 设置工作目录: \${WORKDIR}"
523+
fi
524+
525+
# 添加镜像
526+
DOCKER_CMD="\${DOCKER_CMD} \${IMAGE}"
527+
528+
# 添加启动命令
529+
CMD=\$(jq -r '.[0].Config.Cmd[]?' "\${CONFIG_FILE}" 2>/dev/null | tr '\n' ' ' || echo "")
530+
if [[ -n "\${CMD}" ]]; then
531+
DOCKER_CMD="\${DOCKER_CMD} \${CMD}"
532+
log_info " 添加启动命令: \${CMD}"
533+
fi
534+
535+
# 保存命令到文件
536+
echo "\${DOCKER_CMD}" > "\${SCRIPT_DIR}/docker_run_command.sh"
537+
chmod +x "\${SCRIPT_DIR}/docker_run_command.sh"
538+
539+
log_info "Docker运行命令已保存到: \${SCRIPT_DIR}/docker_run_command.sh"
540+
log_info "执行命令: \${DOCKER_CMD}"
541+
542+
# 执行容器创建
543+
log_info "正在启动容器..."
544+
if eval "\${DOCKER_CMD}"; then
545+
log_success "容器启动成功: \${CONTAINER_NAME}"
546+
547+
# 等待容器启动
548+
sleep 3
549+
550+
# 检查容器状态
551+
if docker ps --format "{{.Names}}" | grep -q "^\${CONTAINER_NAME}\$"; then
552+
log_success "容器正在运行"
553+
docker ps --filter "name=\${CONTAINER_NAME}" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
554+
else
555+
log_warning "容器可能未正常启动,请检查日志"
556+
log_info "查看日志: docker logs \${CONTAINER_NAME}"
557+
fi
558+
else
559+
log_error "容器启动失败"
560+
log_info "请检查生成的命令: \${SCRIPT_DIR}/docker_run_command.sh"
561+
exit 1
562+
fi
400563
564+
log_success "容器恢复完成!"
401565
EOF
402566

403567
chmod +x "${backup_dir}/restore.sh"

0 commit comments

Comments
 (0)