适用人群:运维工程师、运维实习生、后端开发、系统学习人员
适配系统:CentOS 7/8/9、Ubuntu 18.04/20.04/22.04
核心架构:源机(生产服务器)→ 目标机(全新测试服务器),全程双机交互
在运维日常中,最危险的操作莫过于直接在生产环境上改配置、升级版本、调试代码。一次手滑的 rm -rf、一条写错目标库的 SQL、一个未验证的 Nginx 配置变更,都可能造成生产事故。因此,搭建一套与生产环境高度一致的测试环境,是生产运维的底线规范。
典型场景:
| 角色 | 说明 | 主机名示例 |
|---|---|---|
| 源机(生产服务器) | 正在对外提供业务的生产环境,严禁在源机上进行任何可能影响业务的实验操作 | prod-server |
| 目标机(测试服务器) | 全新搭建的测试环境,必须与生产网络隔离,禁止反向写入生产系统 | test-server |
在开始任何操作之前,以下几条红线必须刻在脑子里:
| 红线编号 | 规范内容 | 违规后果 |
|---|---|---|
| 红线1 | 测试机绝对不能通过任何方式(数据库主从、Nginx 反代、API 调用)反向写入生产环境 | 生产数据污染,业务异常,恢复极难 |
| 红线2 | 测试机 IP、主机名必须与生产机不同,严禁 IP 冲突 | 网络风暴、ARP 欺骗、生产断连 |
| 红线3 | 生产环境操作必须在停机窗口或有完整备份后执行 | 数据丢失、服务不可用 |
| 红线4 | 测试环境数据库必须脱敏或使用副本,不得包含真实用户隐私数据 | 合规风险、数据泄露 |
| 红线5 | 任何迁移操作前必须先做全量备份并校验备份完整性 | 数据无法恢复,事故等级升级 |
整个迁移搭建过程分为六大阶段,环环相扣:
展开代码前置检查 → 生产备份 → 系统/数据/服务迁移 → 测试机配置适配 → 服务验证 → 收尾归档
下面我们按照这个主线,先讲两台服务器通用的前置准备,再分别拆解物理机和虚拟机的迁移方案,最后重点展开 MySQL、Nginx、Tomcat 三大主流业务的详细迁移流程。
本节操作在两台服务器上都要执行,是后续所有迁移操作的基础保障。
展开代码# ============ 生产机:基础信息收集 ============ # 系统版本 cat /etc/os-release # CentOS 显示 centos,Ubuntu 显示 ubuntu cat /etc/redhat-release # CentOS 专用,显示具体小版本 # 内核版本 uname -r # CPU 信息 lscpu | grep -E "^CPU$s$|^Model name|^Architecture" # CPU核心数 nproc # 内存信息 free -h # 磁盘信息 lsblk -f # 查看磁盘分区和文件系统类型 df -h # 查看各分区使用情况 fdisk -l | grep "^Disk /" # 查看物理磁盘总容量 # 网卡与IP信息 ip addr show | grep -E "inet |link/ether" # 或使用旧命令 ifconfig -a
展开代码# ============ 测试机:基础信息收集 ============ # 执行与生产机同样的命令,对比输出 cat /etc/os-release uname -r free -h df -h
核心核对要点:
| 检查项 | 生产机 | 测试机要求 | 说明 |
|---|---|---|---|
| 系统版本 | CentOS 7.9 / Ubuntu 20.04 等 | 强烈建议同版本 | 不同发行版可能导致服务兼容性问题 |
| 内核版本 | 3.10 / 5.4 等 | 尽量相近 | 内核差异过大可能影响 Docker、特定内核模块 |
| CPU 架构 | x86_64 / aarch64 | 必须一致 | 二进制程序不能跨架构运行 |
| 内存大小 | 32G / 64G 等 | 可以等比例缩小 | 测试环境资源紧张时可降低规格,后续需调整服务内存参数 |
| 磁盘空间 | /data 500G 等 | 至少 >= 生产已用空间 × 1.2 | 留出缓冲空间,防止迁移后磁盘满 |
如果测试机硬件规格低于生产机(常见场景),后续必须调整以下内容:
innodb_buffer_pool_size-Xmx / -Xmsworker_connections展开代码# ============ 测试机:独立网络配置(示例) ============ # 假设生产机 IP 为 192.168.1.100 # 测试机 IP 规划为 192.168.2.100(不同网段或至少不同 IP) # CentOS:修改网卡配置 vim /etc/sysconfig/network-scripts/ifcfg-eth0 # 关键字段修改: # IPADDR=192.168.2.100 # 新IP,不能与生产重复 # GATEWAY=192.168.2.1 # 独立网关 # DNS1=192.168.2.1 # 独立DNS # BOOTPROTO=static # Ubuntu 18.04+:使用 netplan vim /etc/netplan/00-installer-config.yaml # network: # ethernets: # eth0: # addresses: # - 192.168.2.100/24 # gateway4: 192.168.2.1 # nameservers: # addresses: [192.168.2.1] # 应用网络配置 # CentOS systemctl restart network # Ubuntu netplan apply # 验证 ping -c 4 192.168.2.1 curl -I http://mirrors.aliyun.com # 测试外网连通性
测试机网络隔离原则:
| 停机类型 | 适用场景 | 数据一致性 | 业务影响 |
|---|---|---|---|
| 停机全量迁移 | MySQL 物理备份、整机打包、磁盘镜像 | 最高 | 业务中断,需要停机窗口 |
| 不停机增量同步 | Rsync + MySQL 主从/快照 | 较高 | 低影响,但最后切换瞬间有短暂中断 |
停机窗口选择规范:
展开代码# ============ 生产机:全量备份 ============ # 1. 创建备份目录 mkdir -p /backup/prod_$(date +%Y%m%d) cd /backup/prod_$(date +%Y%m%d) # 2. 备份关键系统配置文件 tar -czf etc_backup.tar.gz /etc tar -czf usr_local_backup.tar.gz /usr/local # 常见服务安装目录 tar -czf opt_backup.tar.gz /opt # 部分服务安装在这里 tar -czf home_backup.tar.gz /home # 用户数据 # 3. 备份 crontab 定时任务 crontab -l > crontab_root_backup.txt for user in $(cut -d: -f1 /etc/passwd); do crontab -u "$user" -l > "crontab_${user}_backup.txt" 2>/dev/null done # 4. 备份数据库(具体命令在 MySQL 章节展开) # 此处仅示意 mysqldump -u root -p --all-databases --single-transaction --routines --triggers \ > mysql_all_$(date +%Y%m%d).sql # 5. 备份服务配置文件(以 Nginx、Tomcat 为例) tar -czf nginx_conf_backup.tar.gz /etc/nginx /usr/local/nginx/conf tar -czf tomcat_backup.tar.gz /usr/local/tomcat # 6. 校验备份完整性 md5sum *.tar.gz *.sql > backup_md5_checksum.txt # 计算所有备份文件的 MD5 并记录,方便迁移后校验
备份校验:
展开代码# 查看备份文件大小,确认不是 0 字节 ls -lh /backup/prod_$(date +%Y%m%d)/ # 校验 MD5 md5sum -c backup_md5_checksum.txt # 测试解压一个文件,确认未损坏 tar -tzf etc_backup.tar.gz | head -20
展开代码# ============ 生产机与测试机通用 ============ # 关闭 SELinux(如果生产本身就是关闭的,测试机保持一致) # CentOS setenforce 0 sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config # 验证 getenforce # Ubuntu 默认没有 SELinux,使用 AppArmor # 如需关闭:systemctl stop apparmor && systemctl disable apparmor # 防火墙:测试机先清空规则,等迁移完成后再按需配置 # CentOS systemctl stop firewalld systemctl disable firewalld # Ubuntu ufw disable # 设置 root 密码(如果测试机还没设置) passwd root
场景:源机和目标机都是独立物理服务器,没有虚拟化层。这是传统数据中心最常见的架构。
在目标物理服务器上安装与生产机同版本的操作系统(CentOS 7.9 / Ubuntu 20.04 等),建议使用最小化安装 + 后续按需补充软件包。
展开代码# ============ 测试机:安装基础依赖 ============ # CentOS yum install -y vim wget curl net-tools lsof rsync tar gzip unzip \ openssh-clients ntpdate chrony screen tmux # Ubuntu apt update apt install -y vim wget curl net-tools lsof rsync tar gzip unzip \ openssh-client ntpdate chrony screen tmux # 同步时间 ntpdate ntp.aliyun.com # 设置时区 timedatectl set-timezone Asia/Shanghai
展开代码# ============ 生产机:打包数据目录 ============ # 打包 /data 目录(假设业务数据都在这) cd / tar -czf /backup/data_backup_$(date +%Y%m%d).tar.gz /data # 如果 /data 太大(几百G),建议用 rsync 直接推送到测试机 # rsync 方式(在测试机上执行,从生产机拉取) # ============ 测试机 ============ mkdir -p /data rsync -avzP --delete \ -e "ssh -p 22" \ root@生产机IP:/data/ \ /data/ # -a: 归档模式,保留权限、时间戳 # -v: 显示详细信息 # -z: 压缩传输 # -P: 显示进度,支持断点续传 # --delete: 删除目标端多余文件(保持严格一致)
展开代码# ============ 测试机:从生产机拉取配置 ============ # 同步 /etc 目录(谨慎,只同步必要的) rsync -avzP -e "ssh -p 22" root@生产机IP:/etc/nginx/ /etc/nginx/ rsync -avzP -e "ssh -p 22" root@生产机IP:/etc/my.cnf /etc/my.cnf # 同步 /usr/local 下的服务 rsync -avzP -e "ssh -p 22" root@生产机IP:/usr/local/tomcat/ /usr/local/tomcat/ rsync -avzP -e "ssh -p 22" root@生产机IP:/usr/local/nginx/ /usr/local/nginx/ # 同步 web 站点目录 rsync -avzP -e "ssh -p 22" root@生产机IP:/var/www/ /var/www/
展开代码# ============ 测试机:修改主机名 ============ hostnamectl set-hostname test-server # ============ 测试机:修改 hosts 文件 ============ vim /etc/hosts # 确保 127.0.0.1 指向 localhost,不要保留生产机的内部域名解析 127.0.0.1 localhost test-server # 删除或注释掉生产相关的内部域名解析 # ============ 测试机:修改服务配置中的 IP 和域名 ============ # 在生产机配置基础上,将所有 生产IP 替换为 测试机IP # 示例:Nginx sed -i 's/192.168.1.100/192.168.2.100/g' /etc/nginx/conf.d/*.conf # 示例:Tomcat 数据库连接 sed -i 's/192.168.1.100/192.168.2.100/g' /usr/local/tomcat/conf/server.xml
适用场景:需要把生产机的完整系统环境(包括操作系统本身、用户、安装的软件包、系统配置)一比一复制到测试机。 优点:真正的 1:1 克隆,环境一致度最高。 缺点:操作复杂,风险较高;要求两台机器硬件架构完全一致(尤其是磁盘设备名);CentOS 6.x 及更早的系统不建议此方式,grub 还原易出问题。
展开代码# ============ 生产机:整机打包(在救援模式或 LiveCD 下操作最安全) ============ # 注意事项: # 1. 必须排除 /proc /sys /dev /tmp /run /mnt /media /backup 等虚拟文件系统和备份目录 # 2. 如果 /home /var 是独立分区,分别打包 cd / tar -cvpzf /backup/full_system_backup.tar.gz \ --exclude=/proc \ --exclude=/sys \ --exclude=/dev \ --exclude=/tmp \ --exclude=/run \ --exclude=/mnt \ --exclude=/media \ --exclude=/backup \ --exclude=/lost+found \ / # 参数说明: # -c: 创建归档 # -v: 显示过程 # -p: 保留文件权限(关键!) # -z: gzip 压缩(数据量小时可用;几百G系统建议用 -j bzip2 或直接不压缩) # -f: 指定输出文件 # ============ 测试机:还原系统 ============ # 前置条件:测试机已安装同版本系统(或使用 LiveCD 启动) # 注意:还原会覆盖测试机现有系统文件! # 1. 将备份文件传输到测试机 scp root@生产机IP:/backup/full_system_backup.tar.gz /backup/ # 2. 解压还原 cd / tar -xvpzf /backup/full_system_backup.tar.gz -C / # 3. 重建被排除的目录 mkdir -p /proc /sys /dev /tmp /run /mnt /media chmod 1777 /tmp # 4. 修复 fstab(如果磁盘分区不同,必须修改) vim /etc/fstab # 根据测试机实际磁盘情况修改 UUID 或设备路径 # 查看测试机磁盘 UUID: blkid # 5. 重装 grub 引导(关键步骤,遗漏会导致无法启动) # CentOS 7/8/9 BIOS 引导 grub2-install /dev/sda grub2-mkconfig -o /boot/grub2/grub.cfg # CentOS 7/8/9 UEFI 引导 grub2-install --target=x86_64-efi --efi-directory=/boot/efi grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg # Ubuntu BIOS 引导 grub-install /dev/sda update-grub # Ubuntu UEFI 引导 grub-install --target=x86_64-efi --efi-directory=/boot/efi update-grub # 6. 重启测试 reboot
⚠️ 高风险警告:
sda 而测试机第一块盘是 nvme0n1,fstab 和 grub 必须手动修复,否则直接黑屏。predictable network interface names,换机器后网卡名大概率变化,启动后需进救援模式修改 /etc/sysconfig/network-scripts/。适用场景:只需要迁移业务数据目录,不关心系统底层环境,测试机已有同版本系统。 优点:最灵活,可增量同步,支持断点续传,对网络带宽要求低。 缺点:需要自己管理同步目录列表,容易漏掉隐藏目录或特殊文件。
展开代码# ============ 测试机执行:拉取生产机数据 ============ # 定义同步目录列表 # 根据实际业务调整 rsync -avzP --delete \ -e "ssh -p 22" \ --exclude='*.log' \ --exclude='*.pid' \ root@生产机IP:/data/ \ /data/ rsync -avzP --delete \ -e "ssh -p 22" \ root@生产机IP:/usr/local/tomcat/ \ /usr/local/tomcat/ rsync -avzP --delete \ -e "ssh -p 22" \ root@生产机IP:/etc/nginx/ \ /etc/nginx/ rsync -avzP --delete \ -e "ssh -p 22" \ root@生产机IP:/var/www/ \ /var/www/
展开代码# ============ 测试机:在正式切换前执行最后一次增量同步 ============ # 此时生产机可能仍有少量写入(如果是不停机方案) rsync -avzP --delete \ -e "ssh -p 22" \ root@生产机IP:/data/ \ /data/ # 第二次执行会跳过已存在且未变更的文件,仅同步差异部分
排错提示:
Permission denied,检查生产机 /etc/ssh/sshd_config 是否允许 root 远程登录(PermitRootLogin yes)。-W 参数跳过增量对比,直接全量传(适合首次同步)。--bwlimit=10000 限制为 10MB/s,避免打满生产网卡。场景:生产机和测试机都是虚拟机,运行在 KVM 或 VMware 虚拟化平台上。虚拟化环境下的迁移比物理机简单得多,核心是利用虚拟化平台的快照、克隆、镜像导出导入功能。
| 场景 | 特点 | 推荐方案 |
|---|---|---|
| 同宿主机 | 两台虚拟机跑在同一台物理宿主机上 | 原生克隆最方便,几分钟完成 |
| 跨宿主机 | 两台虚拟机在不同物理节点上 | 磁盘文件导出 + 导入,或使用共享存储 |
展开代码# ============ VMware 克隆操作步骤(vSphere Client 图形界面) ============ 1. 关闭测试所需的生产虚拟机(或在关机状态下做克隆) ⚠️ 如果生产机不能停机,可以先做快照,然后从快照克隆 2. 右键虚拟机 → 克隆 → 克隆到虚拟机 - 克隆类型:完整克隆(推荐,独立磁盘) - 虚拟机名称:test-server - 存放位置:选择与生产机不同的数据存储(防止 IO 争抢) 3. 克隆完成后,**不要直接开机**,先编辑虚拟机设置: - 网卡:连接到隔离网络(如 VM Network-Test),或先断开网络 - CPU/内存:可适当降低(测试环境资源可少一些) 4. 开机,进入系统后立即修改: - IP 地址(CentOS: /etc/sysconfig/network-scripts/ifcfg-eth0) - 主机名(hostnamectl set-hostname test-server) - 删除网卡 UUID(否则可能 IP 冲突)
展开代码# ============ KVM:使用 virt-clone 命令克隆 ============ # 1. 查看生产虚拟机列表 virsh list --all # 2. 确认生产虚拟机磁盘路径 virsh domblklist prod-server # 输出示例:vda /var/lib/libvirt/images/prod-server.qcow2 # 3. 关闭生产虚拟机(如果是生产环境,建议停机窗口内操作) virsh shutdown prod-server # 4. 克隆虚拟机 virt-clone \ --original prod-server \ --name test-server \ --file /var/lib/libvirt/images/test-server.qcow2 \ --auto-clone # --original: 源虚拟机名称 # --name: 新虚拟机名称 # --file: 新虚拟机的磁盘文件路径 # --auto-clone: 自动生成唯一标识(MAC、UUID) # 5. 克隆完成后,编辑测试虚拟机配置 virsh edit test-server # 修改网卡为隔离网络(如 virbr1 或 test-net) # 6. 启动测试虚拟机 virsh start test-server # 7. 进入控制台 virsh console test-server # 8. 进入系统后立即修改: hostnamectl set-hostname test-server # 修改 IP 地址 vim /etc/sysconfig/network-scripts/ifcfg-eth0 # 重启网络 systemctl restart network
适用场景:需要反复从生产环境克隆测试环境,或需要批量部署多套测试环境。
展开代码# ============ KVM:制作模板镜像 ============ # 1. 在生产虚拟机中执行清理(制作模板前必做) # 清理命令历史 history -c && > ~/.bash_history # 清理 SSH 密钥(模板部署后会自动生成新密钥) rm -f /etc/ssh/ssh_host_* # 清理日志 find /var/log -type f -exec truncate -s 0 {} \; # 清理网络配置中的 UUID 和持久化规则 > /etc/udev/rules.d/70-persistent-net.rules 2>/dev/null # 删除网卡 UUID(CentOS) sed -i '/^UUID=/d' /etc/sysconfig/network-scripts/ifcfg-eth0 # 2. 关机 poweroff # 3. 在宿主机上制作模板 cd /var/lib/libvirt/images/ cp prod-server.qcow2 template-prod-20240115.qcow2 # 可选:压缩模板以节省空间 qemu-img convert -O qcow2 -c template-prod-20240115.qcow2 template-prod-20240115-compressed.qcow2 # 4. 从模板部署新测试机 qemu-img create -f qcow2 \ -b /var/lib/libvirt/images/template-prod-20240115.qcow2 \ -F qcow2 \ /var/lib/libvirt/images/test-server.qcow2 # -b: 指定后端基础镜像(backing file) # -F: 基础镜像的格式 # 使用 backing file 的好处:新虚拟机只存储差异数据,节省空间 # 5. 创建虚拟机(使用 virt-install 导入现有磁盘) virt-install \ --name test-server \ --ram 4096 \ --vcpus 4 \ --disk path=/var/lib/libvirt/images/test-server.qcow2,format=qcow2 \ --import \ --network bridge=virbr1 \ --graphics none \ --console pty,target_type=serial
展开代码# ============ 源宿主机:导出虚拟机磁盘 ============ # VMware:导出为 OVF 模板 # 在 vCenter 中:虚拟机 → 模板 → 导出 OVF 模板 # 会生成 .ovf(配置描述)和 .vmdk(磁盘文件) # KVM:直接复制磁盘文件 # 先关机 virsh shutdown prod-server # 复制 qcow2 文件 scp /var/lib/libvirt/images/prod-server.qcow2 \ root@目标宿主机IP:/var/lib/libvirt/images/test-server.qcow2 # 同时导出虚拟机 XML 配置 virsh dumpxml prod-server > prod-server.xml scp prod-server.xml root@目标宿主机IP:/tmp/ # ============ 目标宿主机:导入虚拟机 ============ # 基于 XML 配置文件创建虚拟机(可能需要调整网络接口名称) virsh define /tmp/prod-server.xml # 如果网络接口不匹配,先编辑 XML virsh edit test-server # 启动 virsh start test-server
展开代码# ============ 测试虚拟机内部操作 ============ # 1. 查看当前网卡名称 ip link show # 克隆后网卡名称可能从 eth0 变成 ens34 或 eth1 # 2. CentOS:修复网卡配置 cd /etc/sysconfig/network-scripts/ # 查看配置文件 ls -la ifcfg-* # 如果网卡名变了,重命名配置文件 mv ifcfg-eth0 ifcfg-ens34 # 3. 编辑新配置文件 vim ifcfg-ens34 # 修改以下内容: # NAME=ens34 # DEVICE=ens34 # IPADDR=192.168.2.100 # 新IP # HWADDR= # 删除旧的MAC地址行,让系统自动识别 # UUID= # 删除UUID,重启后自动生成 # ONBOOT=yes # 4. 清空网卡持久化规则(如果存在) > /etc/udev/rules.d/70-persistent-net.rules 2>/dev/null # 5. Ubuntu:修改 netplan vim /etc/netplan/00-installer-config.yaml # 修改网卡名和IP netplan apply # 6. 重启网络或重启系统 systemctl restart network # CentOS # 或 reboot
这是生产环境搭建测试环境中最关键、也最容易出问题的环节。下面针对 MySQL、Nginx、Tomcat 三大主流业务,分别给出从备份到迁移、适配、校验、排错的完整流程。每种服务都区分物理机迁移和虚拟机迁移的差异点。
展开代码# ============ 生产机:MySQL 全量备份 ============ # 方式A:mysqldump 逻辑备份(推荐,兼容性好,可跨版本) mysqldump -u root -p \ --all-databases \ --single-transaction \ --routines \ --triggers \ --events \ --set-gtid-purged=OFF \ --master-data=2 \ > /backup/mysql_full_$(date +%Y%m%d).sql # 参数详解: # --all-databases: 备份所有库 # --single-transaction: 事务一致性备份,不锁表(InnoDB 适用) # --routines: 包含存储过程 # --triggers: 包含触发器 # --events: 包含定时事件 # --set-gtid-purged=OFF: 测试环境不需要 GTID,关闭避免导入报错 # --master-data=2: 记录 binlog 位置,注释形式写入备份文件 # 备份完成后检查文件 ls -lh /backup/mysql_full_*.sql head -50 /backup/mysql_full_*.sql # 确认内容正常 grep "CHANGE MASTER" /backup/mysql_full_*.sql # 确认 binlog 位置已记录 # 方式B:xtrabackup 物理备份(大库推荐,TB级也适用) # 需要先安装 percona-xtrabackup innobackupex --user=root --password=xxx --no-timestamp /backup/mysql_xtra_$(date +%Y%m%d) # 备份后需要 apply-log 才能用于恢复 innobackupex --apply-log /backup/mysql_xtra_$(date +%Y%m%d)
展开代码# 如果是不停机迁移,在主备份完成后、正式切换前,对每个库执行 flush 并记录 binlog 位点 mysql -u root -p -e "FLUSH TABLES WITH READ LOCK; SHOW MASTER STATUS;" # 记录下 File 和 Position,然后快速导出增量 # 解锁(在另一个会话中执行,或等增量导出完成后) mysql -u root -p -e "UNLOCK TABLES;"
展开代码# ============ 测试机:安装 MySQL ============ # 查看生产机 MySQL 版本 # 在生产机上:mysql -V # 假设生产机是 MySQL 8.0.35 # CentOS 7:安装 MySQL 8.0 yum install -y https://dev.mysql.com/get/mysql80-community-release-el7-7.noarch.rpm yum install -y mysql-community-server # CentOS 8/9:MySQL 8.0 dnf install -y mysql-server # Ubuntu 20.04/22.04:MySQL 8.0 apt update apt install -y mysql-server # 验证版本 mysql -V # 必须确保主版本号一致(如都是 8.0.x),小版本可以有差异
展开代码# ============ 测试机:导入 mysqldump 备份 ============ # 1. 从生产机获取备份文件 scp root@生产机IP:/backup/mysql_full_*.sql /backup/ # 2. 修改 MySQL 配置,加快导入速度 vim /etc/my.cnf # 在 [mysqld] 下临时加入: [mysqld] # 导入加速参数(导入完成后要改回来) innodb_flush_log_at_trx_commit = 2 sync_binlog = 0 max_allowed_packet = 256M # 3. 重启 MySQL systemctl restart mysqld # 4. 获取临时 root 密码并登录 # CentOS:安装时生成的临时密码 grep 'temporary password' /var/log/mysqld.log # Ubuntu:sudo mysql 可直接登录 # 5. 修改 root 密码(如果需要) mysql -u root -p ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewTestPass123!'; FLUSH PRIVILEGES; # 6. 导入备份 mysql -u root -p < /backup/mysql_full_20240115.sql # 大文件可能需要几小时,建议用 screen 包裹 screen -S mysql_import mysql -u root -p < /backup/mysql_full_20240115.sql # Ctrl+A D 退出 screen,稍后用 screen -r mysql_import 查看进度 # 7. 导入完成后,恢复 MySQL 配置 vim /etc/my.cnf # 去掉之前加的加速参数 systemctl restart mysqld
展开代码# ============ 测试机:修改 my.cnf 适配测试环境 ============ vim /etc/my.cnf # === 必须修改的配置 === [mysqld] # 监听地址(改为测试机IP或仅本地) bind-address = 0.0.0.0 # 如果需要远程连接 # 端口(如果测试机有端口冲突则修改) port = 3306 # 数据存储路径(如果测试机磁盘挂载不同,需要修改) datadir = /data/mysql # 日志路径 log-error = /var/log/mysql/error.log slow_query_log_file = /var/log/mysql/slow.log # === 测试环境优化(降低资源占用) === innodb_buffer_pool_size = 512M # 生产可能是 16G,测试机内存小就调低 innodb_log_file_size = 128M # 调小日志文件 max_connections = 100 # 测试环境不需要太多连接 # === 安全设置 === # 关闭 binlog(测试环境不需要主从同步) skip-log-bin # MySQL 8.0 # 或 # disable_log_bin # 部分版本 # 关闭主从同步相关 skip-slave-start # 关闭外网访问(如果可以的话) # bind-address = 127.0.0.1 # 应用配置 systemctl restart mysqld
展开代码# ============ 测试机:同步权限表 ============ # mysqldump 的 --all-databases 已包含 mysql.user 等权限表 # 但需要手动修改权限中的主机限制 mysql -u root -p -- 查看从生产机同步过来的用户 SELECT user, host FROM mysql.user; -- 更新 root 密码(测试机设置自己的密码) ALTER USER 'root'@'localhost' IDENTIFIED BY 'TestRootPass123!'; -- 如果应用连接用户是 'appuser'@'生产机IP',改为测试机IP -- 例如原来:appuser@'192.168.1.100' -- 改为:appuser@'192.168.2.100' 或 appuser@'%' RENAME USER 'appuser'@'192.168.1.100' TO 'appuser'@'192.168.2.100'; -- 或创建新用户 CREATE USER 'appuser'@'192.168.2.100' IDENTIFIED BY 'AppUserPass123!'; GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'192.168.2.100'; FLUSH PRIVILEGES;
展开代码# ============ 测试机:数据校验 ============ # 1. 库数量校验 mysql -u root -p -e "SELECT COUNT(*) AS db_count FROM information_schema.SCHEMATA;" # 2. 表数量校验(排除系统库) mysql -u root -p -e " SELECT TABLE_SCHEMA, COUNT(*) AS table_count FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema','sys') GROUP BY TABLE_SCHEMA;" # 3. 关键表行数校验 mysql -u root -p -e " SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'your_database' ORDER BY TABLE_ROWS DESC;" # 4. 字符集校验 mysql -u root -p -e " SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = 'your_database';"
| 报错信息 | 原因 | 解决方法 |
|---|---|---|
ERROR 1045: Access denied | 密码不对或权限表导入后 root 密码仍是生产机的 | 用 --skip-grant-tables 启动后重置密码 |
ERROR 2013: Lost connection | 导入超时,网络断开或 SQL 文件太大 | 增加 max_allowed_packet,用 screen 包裹 |
ERROR 1062: Duplicate entry | 导入时数据有重复(很少见) | 检查是否多次导入,清理库后重来 |
ERROR 1114: Table is full | 磁盘空间不足 | df -h 检查磁盘,清理或扩容 |
| 乱码 | 备份与导入字符集不一致 | 确保备份和导入都指定 --default-character-set=utf8mb4 |
InnoDB: Unable to lock ./ibdata1 | MySQL 已有实例在运行,数据目录被占用 | 确认之前的 MySQL 进程已关闭:pkill -9 mysqld |
启动失败,日志报 unknown variable | my.cnf 中某些参数版本不兼容 | 逐个注释可疑参数,最小化配置启动 |
展开代码# ============ 生产机:Nginx 数据备份 ============ # 1. 获取 Nginx 安装方式和路径 nginx -V 2>&1 | grep "configure arguments" # 或 which nginx # 2. 备份 Nginx 主目录(编译安装通常在 /usr/local/nginx) tar -czf /backup/nginx_usr_local_$(date +%Y%m%d).tar.gz /usr/local/nginx # 3. 备份 Nginx 配置文件(yum/apt 安装的在 /etc/nginx) tar -czf /backup/nginx_etc_$(date +%Y%m%d).tar.gz /etc/nginx # 4. 备份站点目录 tar -czf /backup/nginx_www_$(date +%Y%m%d).tar.gz /var/www /usr/share/nginx/html # 5. 备份 SSL 证书 tar -czf /backup/nginx_ssl_$(date +%Y%m%d).tar.gz /etc/ssl/certs /etc/ssl/private /etc/pki/nginx # 6. 备份 Nginx 日志(可选,测试环境一般不需要历史日志) # tar -czf /backup/nginx_logs_$(date +%Y%m%d).tar.gz /var/log/nginx # 7. 收集关键信息 nginx -v > /backup/nginx_version.txt nginx -V 2>&1 > /backup/nginx_compile_info.txt ls -la /usr/local/nginx/ > /backup/nginx_dir_structure.txt
展开代码# ============ 测试机:安装 Nginx ============ # 先查看生产机的 Nginx 版本和安装方式 # 生产机上:nginx -v # === 方式A:yum/apt 安装(生产也是 yum/apt 安装时选用) === # CentOS yum install -y nginx # Ubuntu apt install -y nginx # === 方式B:编译安装(生产是编译安装时选用) === # 先获取生产机的编译参数 # 生产机上:nginx -V # 输出示例:--prefix=/usr/local/nginx --with-http_ssl_module ... # 测试机上下载同版本源码 wget http://nginx.org/download/nginx-1.24.0.tar.gz tar -xzf nginx-1.24.0.tar.gz cd nginx-1.24.0 # 安装编译依赖 # CentOS yum install -y gcc pcre-devel zlib-devel openssl-devel make # Ubuntu apt install -y build-essential libpcre3-dev zlib1g-dev libssl-dev # 用生产机同样的参数编译 ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module make -j$(nproc) make install
展开代码# ============ 测试机:迁移 Nginx 配置 ============ # 1. 从生产机拉取配置 scp root@生产机IP:/backup/nginx_etc_*.tar.gz /tmp/ tar -xzf /tmp/nginx_etc_*.tar.gz -C /tmp/ # 或直接用 rsync rsync -avzP -e "ssh" root@生产机IP:/etc/nginx/ /etc/nginx/ # 2. 迁移站点文件 rsync -avzP -e "ssh" root@生产机IP:/var/www/ /var/www/ # 3. 迁移 SSL 证书 rsync -avzP -e "ssh" root@生产机IP:/etc/ssl/ /etc/ssl/ # ============ 测试机:修改 Nginx 配置(核心适配步骤) ============ # 4. 全局替换 IP 和域名 # 将生产 IP 替换为测试机 IP grep -r "192.168.1.100" /etc/nginx/ # 确认后批量替换 find /etc/nginx/ -type f -name "*.conf" -exec sed -i 's/192\.168\.1\.100/192.168.2.100/g' {} + # 5. 修改 server_name(如果测试环境用不同域名) vim /etc/nginx/conf.d/default.conf # 修改: # server_name test.example.com; # 测试域名 # 或直接监听 IP: # server_name 192.168.2.100; # 6. 修改反向代理后端地址(如果有) vim /etc/nginx/conf.d/upstream.conf # 修改 upstream 中的后端 IP: # upstream backend { # server 192.168.2.101:8080; # 指向测试环境 Tomcat # server 192.168.2.102:8080; # 测试环境第二个 Tomcat 节点 # } # 7. 修改日志路径(可选,保持默认也可) # access_log /var/log/nginx/test-access.log; # error_log /var/log/nginx/test-error.log; # 8. 测试环境优化:开启调试日志,便于排查问题 error_log /var/log/nginx/error.log debug; # 生产是 warn 或 error # 生产环境可能有防盗链、IP白名单限制,测试环境先关闭 # 注释掉以下类似的配置: # valid_referers none blocked *.example.com; # allow 192.168.1.0/24; deny all;
展开代码# ============ 测试机:Nginx 配置校验 ============ # 1. 检查配置文件语法 nginx -t # 期望输出:nginx: configuration file /etc/nginx/nginx.conf test is successful # 如果报错,根据提示逐行排查,常见错误: # - "unknown directive":缺少编译模块,重新编译加入对应模块 # - "open() failed":文件路径不存在,检查站点目录和日志目录 # - "bind() to 0.0.0.0:80 failed":端口被占用 # 2. 检查端口占用 lsof -i :80 # 如果被占用,先杀掉或用其他端口 # 修改 listen 端口: # listen 8080; # 测试机用 8080 避免冲突 # 3. 启动 Nginx systemctl start nginx systemctl status nginx # 4. 验证监听端口 ss -tlnp | grep nginx # 期望看到 80 或 443 端口被 nginx 监听 # 5. curl 测试 curl -I http://127.0.0.1 # 期望返回 HTTP/1.1 200 OK 或 301/302 # 6. 设置为开机自启 systemctl enable nginx
| 症状 | 可能原因 | 排查命令 |
|---|---|---|
nginx -t 报语法错误 | 配置文件格式错误,缺少分号或大括号 | 仔细检查报错行及上一行 |
| 启动后 80 端口没有监听 | 端口被占用或权限不足 | lsof -i :80,用 netstat -tlnp |
| 访问网站 502 Bad Gateway | 反向代理后端服务没启动 | 检查后端 Tomcat/PHP 状态 |
| 访问网站 403 Forbidden | 站点目录权限不足 | ls -la /var/www/,确保 nginx 用户可读 |
| SSL 证书错误 | 证书域名不匹配或过期 | openssl x509 -in /path/cert.pem -noout -dates |
| 静态资源 404 | root 路径配置错误 | 检查配置文件中的 root 指令路径 |
展开代码# ============ 生产机:Tomcat 数据备份 ============ # 1. 定位 Tomcat 安装目录 ps aux | grep tomcat | grep -v grep # 或 find / -name "catalina.sh" 2>/dev/null # 2. 查看 JDK 版本和路径 java -version echo $JAVA_HOME which java # 3. 备份整个 Tomcat 目录 TOMCAT_HOME="/usr/local/tomcat" # 根据实际路径修改 tar -czf /backup/tomcat_full_$(date +%Y%m%d).tar.gz $TOMCAT_HOME # 4. 单独备份配置文件(方便单独迁移配置) tar -czf /backup/tomcat_conf_$(date +%Y%m%d).tar.gz \ $TOMCAT_HOME/conf/server.xml \ $TOMCAT_HOME/conf/context.xml \ $TOMCAT_HOME/conf/web.xml \ $TOMCAT_HOME/bin/setenv.sh \ $TOMCAT_HOME/conf/Catalina/ # 5. 备份 webapps(业务项目) tar -czf /backup/tomcat_webapps_$(date +%Y%m%d).tar.gz $TOMCAT_HOME/webapps/ # 6. 备份自定义环境变量和启动脚本 cat $TOMCAT_HOME/bin/setenv.sh > /backup/tomcat_setenv.sh # 或查看 catalina.sh 中的 JAVA_OPTS grep "JAVA_OPTS" $TOMCAT_HOME/bin/catalina.sh > /backup/tomcat_java_opts.txt # 7. 记录 JVM 参数(关键!) jps -lv | grep tomcat > /backup/tomcat_jvm_args.txt # 或 ps aux | grep tomcat | grep -v grep > /backup/tomcat_process.txt
展开代码# ============ 测试机:安装与生产机同版本 JDK ============ # 先确定生产机 JDK 版本和类型 # 生产机上:java -version # 示例输出: # openjdk version "11.0.21" 2024-01-16 LTS # OpenJDK Runtime Environment (build 11.0.21+9-post-Ubuntu-0ubuntu120.04) # OpenJDK 64-Bit Server VM (build 11.0.21+9-post-Ubuntu-0ubuntu120.04, mixed mode) # === CentOS 安装 JDK 11 === yum install -y java-11-openjdk-devel # === Ubuntu 安装 JDK 11 === apt install -y openjdk-11-jdk # === 如果需要 Oracle JDK(生产用 Oracle JDK 时) === # 下载同版本的 Oracle JDK tar.gz 包,手动解压 tar -xzf jdk-11.0.21_linux-x64_bin.tar.gz -C /usr/local/ # 设置环境变量 echo 'export JAVA_HOME=/usr/local/jdk-11.0.21' >> /etc/profile echo 'export PATH=$JAVA_HOME/bin:$PATH' >> /etc/profile source /etc/profile # 验证 java -version javac -version
展开代码# ============ 测试机:部署 Tomcat ============ # 1. 获取生产机 Tomcat 版本 # 生产机上:cat $TOMCAT_HOME/RELEASE-NOTES | head # 或看目录名:ls /usr/local/ | grep tomcat # 2. 如果生产用的是官方二进制包,在测试机下载同版本 wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.83/bin/apache-tomcat-9.0.83.tar.gz tar -xzf apache-tomcat-9.0.83.tar.gz -C /usr/local/ ln -s /usr/local/apache-tomcat-9.0.83 /usr/local/tomcat # 3. 从生产机拉取备份的配置文件 scp root@生产机IP:/backup/tomcat_conf_*.tar.gz /tmp/ tar -xzf /tmp/tomcat_conf_*.tar.gz -C /tmp/ # 覆盖测试机的默认配置 cp /tmp/usr/local/tomcat/conf/server.xml /usr/local/tomcat/conf/ cp /tmp/usr/local/tomcat/conf/context.xml /usr/local/tomcat/conf/ # 4. 从生产机拉取 webapps(业务项目) scp root@生产机IP:/backup/tomcat_webapps_*.tar.gz /tmp/ tar -xzf /tmp/tomcat_webapps_*.tar.gz -C /tmp/ cp -r /tmp/usr/local/tomcat/webapps/* /usr/local/tomcat/webapps/ # 5. 同步 setenv.sh(JVM 参数) scp root@生产机IP:/backup/tomcat_setenv.sh /usr/local/tomcat/bin/setenv.sh chmod +x /usr/local/tomcat/bin/setenv.sh
展开代码# ============ 测试机:修改 server.xml ============ vim /usr/local/tomcat/conf/server.xml # === 修改 1:服务端口 === # 关闭端口(如果测试机有多个 Tomcat 实例,需要改成不同的端口) <Server port="8005" shutdown="SHUTDOWN"> # 改为(如果冲突):<Server port="8006" shutdown="SHUTDOWN"> # === 修改 2:HTTP 连接器端口 === <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> # 如果 8080 被占用,改为:port="8081" # === 修改 3:AJP 连接器(如果不用可以注释掉) === # <Connector protocol="AJP/1.3" port="8009" redirectPort="8443" /> # === 修改 4:日志输出路径(可选) === # 在 Host 标签内,修改 AccessLogValve 的 directory: <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> # ============ 修改项目数据库连接配置 ============ # 根据项目类型,连接配置可能在以下位置: # - src/main/resources/application.properties(Spring Boot) # - WEB-INF/classes/jdbc.properties # - context.xml 中的 Resource 标签 # 示例:修改 Spring Boot 项目的数据库连接 vim /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/application.properties # 修改: # spring.datasource.url=jdbc:mysql://192.168.2.100:3306/testdb?useSSL=false # spring.datasource.username=appuser # spring.datasource.password=TestPass123! # ============ 修改 JVM 参数适配测试环境 ============ vim /usr/local/tomcat/bin/setenv.sh # 生产环境的 JVM 参数可能是这样的: # export CATALINA_OPTS="-Xms8g -Xmx8g -XX:MaxMetaspaceSize=512m ..." # 测试机内存小,需要调低: export JAVA_OPTS="-Xms1g -Xmx2g -XX:MaxMetaspaceSize=256m" export CATALINA_OPTS="-Xms1g -Xmx2g -XX:MaxMetaspaceSize=256m" # 如果测试环境不需要 GC 日志和 JMX 监控,注释掉相关参数 # -Xlog:gc*:file=/path/gc.log → 注释掉
展开代码# ============ 测试机:Tomcat 启动 ============ # 1. 赋权 chown -R root:root /usr/local/tomcat chmod +x /usr/local/tomcat/bin/*.sh # 生产环境一般用 tomcat 用户运行,测试机可简化 # useradd -r -s /sbin/nologin tomcat # chown -R tomcat:tomcat /usr/local/tomcat # 2. 手动启动(前台启动,方便看日志) /usr/local/tomcat/bin/catalina.sh run # 看到 "Server startup in XXXX ms" 表示启动成功 # Ctrl+C 停止 # 3. 后台启动 /usr/local/tomcat/bin/startup.sh # 4. 检查进程 ps aux | grep tomcat | grep -v grep # 5. 检查端口 ss -tlnp | grep java # 确认 8080 端口在监听 # 6. 访问测试 curl -I http://127.0.0.1:8080 # 期望返回 HTTP/1.1 200 或 302 # 7. 查看启动日志 tail -f /usr/local/tomcat/logs/catalina.out
| 报错信息 | 原因 | 解决方法 |
|---|---|---|
java.net.BindException: Address already in use | 端口被占用 | 改端口或杀掉占用进程 lsof -i :8080 |
Error: Could not find or load main class | JDK 版本不对或 JAVA_HOME 未设置 | echo $JAVA_HOME,java -version 确认 |
java.lang.OutOfMemoryError: Java heap space | JVM 内存不足 | 增大 -Xmx,或排查是否有内存泄漏 |
java.lang.OutOfMemoryError: Metaspace | 类加载过多 | 增大 -XX:MaxMetaspaceSize |
Caused by: java.sql.SQLException: Access denied | 数据库连接密码错误 | 检查应用配置文件中的数据库密码 |
Caused by: java.net.ConnectException: Connection refused | 数据库没启动或 IP 不对 | 检查 MySQL 状态和连接 IP |
SEVERE: Error listenerStart | 项目启动失败 | 查看 logs/localhost.xxxx.log 详细错误 |
| WAR 包没有自动解压 | Tomcat 权限不足 | chown -R tomcat:tomcat /usr/local/tomcat |
Too many open files | 文件描述符限制太小 | ulimit -n 65535,修改 /etc/security/limits.conf |
实际生产环境中,常有生产是物理机、测试用虚拟机的场景(预算有限,测试环境跑在虚拟化平台上)。这里给出快速适配方案。
这是最常见的交叉场景。测试环境跑在 KVM/VMware 上,需要把物理机的系统+数据迁移到虚拟机中。
推荐方案:
展开代码# ============ 物理机:全量备份 ============ # 按照第三部分方式2的 Tar 整机打包,或 rsync 数据同步 # ============ 物理机:使用 P2V 工具(推荐) ============ # VMware:使用 VMware vCenter Converter Standalone # 直接将物理机在线转换为虚拟机,支持热迁移 # KVM:使用 virt-p2v # 在物理机上用 LiveCD 启动 virt-p2v,通过网络将物理机转换为 KVM 虚拟机 # ============ 手动方式:物理机备份 + 虚拟机还原 ============ # 1. 物理机做全量备份(tar 整机打包) # 2. 创建虚拟机,安装同版本基础系统 # 3. 将备份文件 scp 到虚拟机,解压还原 # 4. 修复 grub、fstab(虚拟机磁盘通常是 /dev/vda 或 /dev/sda) # 5. 重装内核(物理机内核可能缺少 virtio 驱动) yum install -y kernel # 或 apt install linux-image-generic # 6. 安装虚拟化驱动 # KVM:yum install -y qemu-guest-agent # VMware:安装 open-vm-tools 或 VMware Tools
关键差异注意:
/dev/sda,虚拟机 /dev/vda(KVM virtio)e1000e / igb,虚拟机 virtio_net / vmxnet3较少见(测试环境反而用物理机),但场景存在。本质是 V2P(Virtual to Physical)迁移。
核心步骤:
vda,物理机是 sda,必须修改 fstab 和 grub展开代码# ============ 测试机:收尾配置 ============ # 1. 修改主机名 hostnamectl set-hostname test-server # 2. 修改 /etc/hosts vim /etc/hosts # 确保不包含生产环境的内部域名解析 # 127.0.0.1 localhost test-server # 3. 关闭生产环境的定时任务 crontab -l # 查看当前 crontab crontab -r # 清空 root 的 crontab # 或逐条注释:crontab -e,在每条前面加 # # 4. 调整日志轮转策略 vim /etc/logrotate.d/nginx # 测试环境可缩短保留周期:rotate 7 → rotate 3 # 5. 关闭不需要的服务 systemctl disable --now postfix # 邮件服务,测试环境一般不需要 systemctl disable --now rpcbind # NFS 客户端,如果不连生产 NFS # 6. 配置防火墙 # 测试环境防火墙可以宽松一些,但至少保证基本安全 # CentOS systemctl start firewalld firewall-cmd --permanent --add-port=8080/tcp # Tomcat firewall-cmd --permanent --add-port=80/tcp # Nginx firewall-cmd --permanent --add-port=3306/tcp # MySQL(如果需要远程连接) firewall-cmd --reload
展开代码# ============ 测试机:全服务验证 ============ # 1. MySQL 验证 systemctl status mysqld mysql -u root -p -e "SELECT VERSION(); SHOW DATABASES;" # 确认库表完整、数据可查询 # 2. Nginx 验证 systemctl status nginx nginx -t curl -I http://127.0.0.1:80 # 确认返回状态码、server 头信息 # 3. Tomcat 验证 ps aux | grep tomcat curl -I http://127.0.0.1:8080 # 确认应用首页能正常访问 # 4. 端口监听总览 ss -tlnp # 确认 3306、80、8080 等关键端口都在监听 # 5. 资源使用检查 free -h df -h top -bn1 | head -20
展开代码# ============ 文件级校验(如果是从备份还原) ============ # 在生产机上计算关键文件的 MD5,在测试机上对比 # 生产机: md5sum /etc/nginx/nginx.conf > /tmp/nginx_md5_prod.txt # 测试机(注意 IP 已修改,所以校验前排除含 IP 的文件): md5sum /etc/nginx/nginx.conf > /tmp/nginx_md5_test.txt # ============ 数据库级校验 ============ # 按 5.1.7 节的方法核对库表数量和行数
展开代码# 模拟真实业务调用链路 # 1. Nginx → Tomcat(HTTP 请求链路) curl -v http://192.168.2.100/api/health # 应用健康检查接口 # 2. Tomcat → MySQL(数据库读写链路) curl -X POST http://192.168.2.100/api/login \ -d '{"username":"test","password":"test123"}' # 观察返回是否正常(200 OK),日志中是否有数据库查询记录
| 序号 | 绝对禁止的操作 | 原因 |
|---|---|---|
| 1 | 在测试机上配置指向生产数据库的连接 | 测试脚本可能误写生产数据 |
| 2 | 测试机使用生产机 IP 或主机名 | IP 冲突导致生产断网 |
| 3 | 在生产高峰期执行 tar / rsync / dd 等大量 I/O 操作 | 影响生产业务性能 |
| 4 | 把生产机 SSH 私钥复制到测试机 | 测试机被攻破则生产机也沦陷 |
| 5 | 在测试机上启用生产环境的定时任务 | 定时任务可能向生产 API 发起请求 |
| 6 | 不经验证直接在生产上执行测试环境验证过的脚本 | 测试和生产的 IP/路径/权限可能不同 |
展开代码# ============ 回滚方案文档模板 ============ # 1. 备份存放位置:/backup/prod_20240115/ # 2. 回滚操作步骤: # a) 停止测试机所有服务 # b) 确认生产机当前状态正常 # c) 如需从备份恢复生产数据: # - MySQL:mysql -u root -p < /backup/mysql_full_20240115.sql # - 文件:rsync -avzP /backup/data/ /data/ # d) 重启生产服务,验证业务正常 # 3. 回滚责任人:张三(电话 138xxxx) # 4. 预估回滚时间:30 分钟
| 高危操作 | 后果 | 规避方法 |
|---|---|---|
| 测试机 MySQL 配置了生产机的 master-host | 测试机变成生产库的从库,可能同步异常 | 迁移后立即注释 replicate-*、master-host 等主从参数 |
| Nginx 反代配置未修改后端 IP | 测试环境访问时流量打到生产后端 | 全局搜索生产 IP,逐一替换 |
| Tomcat 项目中的定时任务自动启动 | 测试机向生产 API 发数据 | 检查 @Scheduled 注解、Quartz 配置 |
| 忘记修改 /etc/fstab | 虚拟机/物理机启动时挂载失败,进入救援模式 | 迁移后立即检查并修正 fstab |
| 对比维度 | 物理机迁移 | 虚拟机迁移 |
|---|---|---|
| 操作难度 | 高:需要手动处理硬件差异、驱动、grub | 低:克隆、镜像导出导入即可 |
| 耗时 | 长:重装系统 2h+,数据同步数小时到数天 | 短:克隆几分钟到半小时 |
| 数据安全性 | 依赖人工操作,容易遗漏 | 快照/克隆可保证完整一致性 |
| 灵活性 | 需要两台相同或相似硬件 | 可以灵活调整 CPU、内存、磁盘规格 |
| 磁盘设备统一性 | /dev/sda、/dev/nvme0n1因机器而异 | /dev/vda(KVM)或 /dev/sda(VMware),较统一 |
| 网卡适配难度 | 高:网卡名称经常变化 | 中:MAC 地址变化但驱动通用 |
| 回滚便捷性 | 差:只能手动恢复 | 好:快照秒级回滚 |
| 服务 | 物理机迁移要点 | 虚拟机迁移要点 |
|---|---|---|
| MySQL | 数据量大时用 xtrabackup 物理备份效率更高 | 可直接挂载磁盘快照到测试虚拟机,省去备份导入时间 |
| Nginx | 配置文件中的 IP、域名需全局替换 | 同物理机,且注意虚拟机网卡名称不影响 Nginx |
| Tomcat | JVM 参数需根据测试机实际内存调整 | 虚拟化环境可热添加内存,调参更灵活 |
| 场景 | 推荐方案 |
|---|---|
| 生产=物理机,测试=物理机 | 系统重装 + 数据同步(方式1),或 rsync(方式3) |
| 生产=虚拟机,测试=虚拟机(同宿主机) | 原生克隆(最快最省事) |
| 生产=虚拟机,测试=虚拟机(跨宿主机) | 磁盘导出导入 + 模板部署 |
| 生产=物理机,测试=虚拟机 | P2V 工具 或 tar + rsync 手动迁移 |
| 需要反复刷新测试数据 | 使用虚拟机模板 + backing file(增量磁盘),每次还原到基线 |
展开代码# === 信息收集 === uname -r && cat /etc/os-release && free -h && df -h && ip addr # === 备份 === tar -czf backup.tar.gz /target/dir --exclude=/proc --exclude=/sys mysqldump -u root -p --all-databases --single-transaction > all.sql # === 传输 === rsync -avzP -e "ssh" root@源IP:/path/ /dest/path/ scp root@源IP:/backup/file.tar.gz /backup/ # === 网络修改 === hostnamectl set-hostname new-name vim /etc/sysconfig/network-scripts/ifcfg-eth0 # CentOS vim /etc/netplan/00-installer-config.yaml # Ubuntu sed -i 's/旧IP/新IP/g' /etc/hosts # === 校验 === md5sum file.tar.gz md5sum -c checksum.txt
展开代码# 备份 mysqldump -u root -p --all-databases --single-transaction --routines --triggers > dump.sql # 导入 mysql -u root -p < dump.sql # 查看版本 mysql -V # 查看库表 mysql -u root -p -e "SHOW DATABASES;" # 修改配置 vim /etc/my.cnf → systemctl restart mysqld # 密码重置(--skip-grant-tables 模式) systemctl stop mysqld mysqld --skip-grant-tables & mysql -u root FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewPass123!'; # 数据校验 mysql -u root -p -e " SELECT TABLE_SCHEMA, COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('mysql','sys','information_schema','performance_schema') GROUP BY TABLE_SCHEMA;"
展开代码# 版本 nginx -v # 语法检查 nginx -t # 启动/重启/重载 systemctl start nginx systemctl restart nginx nginx -s reload # 配置搜索 grep -r "关键词" /etc/nginx/ # 批量替换 IP find /etc/nginx/ -name "*.conf" -exec sed -i 's/旧IP/新IP/g' {} + # 端口检查 ss -tlnp | grep nginx # 访问测试 curl -I http://127.0.0.1
展开代码# 查看进程和 JVM 参数 ps aux | grep tomcat jps -lv # 启动/停止 /usr/local/tomcat/bin/startup.sh /usr/local/tomcat/bin/shutdown.sh # 前台启动(排错用) /usr/local/tomcat/bin/catalina.sh run # 查看端口 ss -tlnp | grep java # 实时日志 tail -f /usr/local/tomcat/logs/catalina.out # 修改 JVM 参数 vim /usr/local/tomcat/bin/setenv.sh # 项目部署 cp app.war /usr/local/tomcat/webapps/
展开代码□ 生产机:信息收集(系统版本、内核、CPU、内存、磁盘、IP) □ 生产机:全量备份(系统配置、数据库、Nginx、Tomcat) □ 生产机:备份 MD5 校验 □ 测试机:安装同版本操作系统 □ 测试机:配置独立 IP,网络隔离 □ 测试机:安装 JDK、MySQL、Nginx、Tomcat(版本对齐) □ 测试机:导入数据库备份 □ 测试机:迁移配置文件,修改 IP/域名/端口 □ 测试机:启动 MySQL → Nginx → Tomcat □ 测试机:端口监听检查(ss -tlnp) □ 测试机:curl 验证各服务响应 □ 测试机:数据库数据校验 □ 测试机:修改主机名、hosts、关闭生产定时任务 □ 测试机:配置防火墙、设置开机自启 □ 生产机:确认业务不受影响 □ 归档:备份文件、操作记录、配置变更日志
全文总结:从生产环境搭建测试环境,本质上是一次数据迁移 + 配置适配 + 风险管控的工程实践。物理机架构需要对硬件差异有清晰的认知和手动处理能力;虚拟机架构则可以充分利用克隆和快照的便利性。无论哪种架构,MySQL、Nginx、Tomcat 的迁移都必须遵循 "备份→迁移→适配→校验→优化→验证" 的完整链路。最重要的是:永远不要在生产环境上进行未经验证的操作,永远在手边保留一份完整的回滚方案。
本文作者:zzz
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!