本文目录导读:

这是一个关于Shell脚本配置容器迁移方案的详细指南,我将分步骤介绍如何编写脚本来实现容器(以Docker为例)的迁移,包括导出、传输、导入和启动流程。
核心迁移思路
容器迁移主要分为三个阶段:
- 源端: 停止容器 → 提交为镜像 → 导出为tar文件
- 传输: 将tar文件传输到目标服务器
- 目标端: 导入镜像 → 启动新容器
基础迁移脚本模板
单容器迁移脚本
#!/bin/bash
# 容器迁移脚本 - migrate_container.sh
# 配置变量
CONTAINER_NAME="myapp"
IMAGE_NAME="myapp-image"
IMAGE_TAG="migrated-$(date +%Y%m%d%H%M%S)"
TAR_FILE="${IMAGE_NAME}_${IMAGE_TAG}.tar"
TARGET_USER="root"
TARGET_HOST="192.168.1.100"
TARGET_PATH="/tmp/"
TARGET_DIR="/opt/containers"
# 错误处理函数
handle_error() {
echo "错误: $1"
exit 1
}
# 步骤1:验证源容器是否存在
echo "===== 步骤1: 验证源容器 ====="
if ! docker inspect "$CONTAINER_NAME" >/dev/null 2>&1; then
handle_error "容器 $CONTAINER_NAME 不存在"
fi
# 步骤2:停止容器
echo "===== 步骤2: 停止容器 ====="
docker stop "$CONTAINER_NAME" || echo "容器已经在停止状态"
# 步骤3:提交容器为镜像
echo "===== 步骤3: 提交镜像 ====="
docker commit "$CONTAINER_NAME" "${IMAGE_NAME}:${IMAGE_TAG}" || \
handle_error "镜像提交失败"
# 步骤4:导出镜像为文件
echo "===== 步骤4: 导出镜像 ====="
docker save -o "$TAR_FILE" "${IMAGE_NAME}:${IMAGE_TAG}" || \
handle_error "镜像导出失败"
# 步骤5:传输到目标服务器
echo "===== 步骤5: 传输镜像 ====="
scp "$TAR_FILE" "${TARGET_USER}@${TARGET_HOST}:${TARGET_PATH}" || \
handle_error "镜像传输失败"
# 步骤6:在目标服务器上执行导入和启动
echo "===== 步骤6: 远程执行导入 ====="
ssh "${TARGET_USER}@${TARGET_HOST}" "
# 创建目标目录
mkdir -p $TARGET_DIR
# 导入镜像
docker load -i ${TARGET_PATH}${TAR_FILE} || exit 1
# 重新创建容器(根据原始容器配置调整)
docker run -d \\
--name ${CONTAINER_NAME} \\
--restart unless-stopped \\
-p 8080:80 \\ # 修改为实际端口映射
${IMAGE_NAME}:${IMAGE_TAG}
# 清理tar文件
rm -f ${TARGET_PATH}${TAR_FILE}
" || handle_error "远程导入失败"
# 步骤7:清理本地临时文件
echo "===== 步骤7: 清理临时文件 ====="
rm -f "$TAR_FILE"
docker rmi "${IMAGE_NAME}:${IMAGE_TAG}"
echo "===== 迁移完成 ====="
echo "容器 $CONTAINER_NAME 已成功迁移到 $TARGET_HOST"
增强版迁移脚本(支持多容器和配置持久化)
#!/bin/bash
# 增强版容器迁移脚本 - advanced_migrate.sh
# 配置区 - 可修改为配置文件读取
CONFIG_FILE="migration.conf"
# 默认配置
declare -A CONTAINERS=(
["nginx-web"]="nginx:latest:80:80"
["mysql-db"]="mysql:8.0:3306:3306"
["redis-cache"]="redis:alpine:6379:6379"
)
TARGET_HOST="192.168.1.200"
TARGET_USER="root"
BACKUP_DIR="/tmp/container_backup_$(date +%Y%m%d_%H%M%S)"
TARGET_BASE_DIR="/opt/containers"
VOLUME_BACKUP_ENABLED=true
# 加载配置文件
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
fi
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# 函数:备份容器卷
backup_volumes() {
local container=$1
local backup_path=$2
log "备份卷数据: $container"
# 获取容器的挂载点信息
local volumes=$(docker inspect "$container" | jq -r '.[0].Mounts[] | select(.Type=="bind" or .Type=="volume") | .Source')
if [ -z "$volumes" ]; then
log "没有发现卷"
return 0
fi
# 使用临时容器来打包卷数据
docker run --rm \
--volumes-from "$container" \
-v "${backup_path}:/backup" \
alpine tar czf "/backup/${container}_volumes.tar.gz" \
/data 2>/dev/null || true
}
# 函数:迁移单个容器
migrate_container() {
local container=$1
local image=$2
local host_port=$3
local container_port=$4
local tar_file="${container}_$(date +%Y%m%d%H%M%S).tar"
log "开始迁移容器: $container"
# 停止并提交
docker stop "$container" 2>/dev/null
docker commit "$container" "${container}:migrated" || {
log "ERROR: 提交失败: $container"
return 1
}
# 导出
docker save -o "${BACKUP_DIR}/${tar_file}" "${container}:migrated" || {
log "ERROR: 导出失败: $container"
return 1
}
# 备份卷
if [ "$VOLUME_BACKUP_ENABLED" = true ]; then
backup_volumes "$container" "$BACKUP_DIR"
fi
# 传输到目标
scp "${BACKUP_DIR}/${tar_file}" "${TARGET_USER}@${TARGET_HOST}:${TARGET_BASE_DIR}/" || {
log "ERROR: 传输失败: $container"
return 1
}
# 远程导入和启动
ssh "${TARGET_USER}@${TARGET_HOST}" "
log() { echo \"[\$(date '+%Y-%m-%d %H:%M:%S')] \$1\"; }
log '加载镜像: ${container}'
docker load -i ${TARGET_BASE_DIR}/${tar_file}
# 创建卷目录
mkdir -p ${TARGET_BASE_DIR}/volumes/${container}
# 启动容器 - 这里需要根据实际情况调整参数
docker run -d \\
--name ${container} \\
--restart unless-stopped \\
-p ${host_port}:${container_port} \\
-v ${TARGET_BASE_DIR}/volumes/${container}:/data \\
${container}:migrated
# 清理
rm -f ${TARGET_BASE_DIR}/${tar_file}
" || {
log "ERROR: 远程执行失败: $container"
return 1
}
# 清理本地
rm -f "${BACKUP_DIR}/${tar_file}"
docker rmi "${container}:migrated" 2>/dev/null
log "迁移完成: $container"
return 0
}
# 主迁移流程
main() {
log "启动容器迁移流程"
# 创建本地备份目录
mkdir -p "$BACKUP_DIR"
# 创建目标目录
ssh "${TARGET_USER}@${TARGET_HOST}" "mkdir -p ${TARGET_BASE_DIR}/volumes"
# 遍历并迁移所有容器
for container in "${!CONTAINERS[@]}"; do
IFS=':' read -r image host_port container_port <<< "${CONTAINERS[$container]}"
migrate_container "$container" "$image" "$host_port" "$container_port"
done
# 清理备份目录
rm -rf "$BACKUP_DIR"
log "所有容器迁移完成"
}
# 执行主函数
main
高级配置与优化
配置文件示例 (migration.conf)
# migration.conf - 容器迁移配置文件
# 容器配置: [容器名]=镜像:主机端口:容器端口
CONTAINERS=(
["nginx-web"]="nginx:latest:80:80"
["mysql-db"]="mysql:8.0:3306:3306"
["redis-cache"]="redis:alpine:6379:6379"
)
# 目标服务器配置
TARGET_HOST="192.168.1.100"
TARGET_USER="root"
TARGET_BASE_DIR="/opt/containers"
# 迁移选项
VOLUME_BACKUP_ENABLED=true
KEEP_SOURCE_CONTAINER=false
COMPRESS_LEVEL=6 # gzip压缩级别 1-9
# 网络配置
NETWORK_MODE="bridge"
DEFAULT_DNS="8.8.8.8"
# 资源限制 (可选)
MEMORY_LIMIT="1g"
CPU_LIMIT="2"
并行迁移脚本
#!/bin/bash
# 并行迁移脚本 - parallel_migrate.sh
PARALLEL_LIMIT=3 # 并行执行数量
# 任务队列
declare -a TASKS
# 添加迁移任务
for container in "${!CONTAINERS[@]}"; do
TASKS+=("$container")
done
# 并行执行函数
run_parallel() {
local running=0
local index=0
while [ $index -lt ${#TASKS[@]} ]; do
if [ $running -lt $PARALLEL_LIMIT ]; then
migrate_container "${TASKS[$index]}" &
((running++))
((index++))
else
wait -n
((running--))
fi
done
# 等待所有任务完成
wait
}
# 执行并行迁移
run_parallel
故障恢复脚本
#!/bin/bash
# 故障恢复脚本 - rollback.sh
TARGET_HOST="192.168.1.100"
BACKUP_DIR="/opt/container_backups"
# 回滚到指定版本
rollback_to_version() {
local container=$1
local timestamp=$2
local tar_file="${container}_${timestamp}.tar"
ssh "$TARGET_HOST" "
# 停止并删除当前容器
docker stop $container 2>/dev/null
docker rm $container 2>/dev/null
# 加载备份镜像
docker load -i ${BACKUP_DIR}/${tar_file}
# 启动旧版本
docker run -d --name $container --restart unless-stopped \\
$(cat /opt/container_configs/${container}_config.txt) \\
${container}:${timestamp}
"
}
使用注意事项
- 数据一致性:确保在停止容器后提交,避免数据不一致
- 网络配置:注意检查目标服务器的网络环境和端口占用
- 资源限制:确认目标服务器有足够资源运行容器
- 日志保留:迁移过程详细记录日志,便于问题追踪
- 测试验证:生产环境迁移前务必在测试环境验证
安全性建议
- 使用SSH密钥认证而非密码
- 对传输的文件进行校验(MD5/SHA256)
- 敏感数据考虑加密传输
- 迁移后清理临时文件和中间镜像
这个脚本框架可以根据你的具体环境进行调整和扩展,记得在实际使用前充分测试,并根据需要添加错误处理和重试机制。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播