“服务器直接搬到AWS上不就行了吗?”
— 这是在迁移现场最常听到,也是最危险的误解。
>
🎯 本文涵盖内容
- 传统应用程序迁移到云端前,必须进行的兼容性分析
- AWS迁移工具(MGN)无法解决内核问题的原因
- 可通过容器解决的案例及具体的Dockerfile示例
- KVM不可避免的案例及AWS裸金属配置方法
- 整理判断标准的最终决策树
📌 引言 — “搬上去”和“能运行”是两回事
在传统系统迁移项目中,经常会发生这样的情况:使用AWS MGN (Application Migration Service) 将整个服务器复制到EC2上,但应用程序甚至无法启动。
原因很简单。迁移工具仅仅是一种搬运手段。它的全部作用就是以块为单位复制磁盘并将其附加到EC2。内核2.x、3.x时代的传统应用程序所固有的兼容性问题在迁移后依然存在。
更甚者,MGN在复制过程中如果检测到旧版本内核,会自动替换为Nitro兼容内核。虽然/boot/vmlinuz-3.x文件被复制了,但Nitro管理程序所需的ENA(网络)、NVMe(存储)驱动程序在旧版本内核中不存在。最终,使用原始内核启动变得不可能。
因此,在迁移之前,有一项必须完成的工作:兼容性分析。

🔍 核心问题 — 是“内核依赖”还是“用户空间依赖”?
在现场听到“这个应用程序只能在内核3.x上运行”时,首先应该怀疑。实际上,真正依赖内核本身的案例比想象中要少。大多数是用户空间的问题。
"커널 3.x에서만 됩니다"
↓ 실제 원인 분석
┌─────────────────────────────────┐
│ glibc 버전 종속 ← 90% 이 케이스 (userspace)
│ .so 라이브러리 종속 ← userspace
│ 런타임 버전 종속 ← userspace
│ 실제 커널 syscall 종속 ← 진짜 커널 문제 (희귀)
└─────────────────────────────────┘
区分这一点的最快方法是以下两个命令。
# 追踪应用程序使用的syscall列表
strace -c ./legacy-app
# 检查应用程序链接的库和所需的glibc版本
ldd ./legacy-app
objdump -p ./legacy-app | grep GLIBC
如果ldd结果中出现GLIBC_2.12、GLIBC_2.17等版本符号,则表示是用户空间依赖。在这种情况下,可以通过容器解决。
🐳 案例1 — 用户空间(glibc)依赖:通过容器解决
理解容器的核心结构,就能立即明白为什么这可以解决问题。
┌──────────────────────────────────┐
│ 컨테이너 이미지 내부 │
│ ┌────────────────────────────┐ │
│ │ 레거시 앱 │ │
│ │ glibc 2.12 (구버전) │ │ ← 이미지 안에 격리
│ │ 필요한 .so 라이브러리들 │ │
│ └────────────────────────────┘ │
├──────────────────────────────────┤
│ 호스트 커널 (5.x / 6.x) │ ← glibc와 무관
└──────────────────────────────────┘
容器只共享内核,而包括glibc在内的所有用户空间库都独立地打包在镜像中。即使宿主内核是6.x,容器内部的glibc 2.12也能正常运行。
旧版本glibc基础镜像选择标准
| 基础镜像 | glibc版本 | 备注 |
| centos:6 | 2.12 | 内核2.6时代的用户空间 |
| centos:7 | 2.17 | 最常用的传统基础镜像 |
| ubuntu:14.04 | 2.19 | |
| ubuntu:16.04 | 2.23 | |
| debian:jessie | 2.19 |
###
实际示例 — 容器化glibc 2.12依赖应用程序
首先,检查应用程序所需的glibc版本。
objdump -p ./legacy-app | grep GLIBC
# 输出示例:
# GLIBC_2.12
# GLIBC_2.5
如果GLIBC_2.12是最大版本,则使用centos:6基础镜像。
# 容器化需要glibc 2.12环境的传统应用程序
FROM centos:6
# 安装必要的依赖库(根据应用程序调整)
RUN yum install -y
libstdc++
libgcc
openssl
&& yum clean all
# 复制应用程序二进制文件
COPY ./legacy-app /opt/app/legacy-app
RUN chmod +x /opt/app/legacy-app
# 如果有配置文件,一并复制
COPY ./config /opt/app/config
WORKDIR /opt/app
CMD ["./legacy-app"]
如果需要额外库 — 直接打包.so文件
如果应用程序直接依赖于无法通过包管理器安装的特定.so文件,也可以直接复制这些文件。
FROM centos:7
# 直接从现有服务器复制所需的.so文件
COPY ./libs/liblegacy.so.1.2.3 /usr/lib64/liblegacy.so.1.2.3
RUN ldconfig # 更新动态链接器缓存
COPY ./legacy-app /opt/app/legacy-app
RUN chmod +x /opt/app/legacy-app
CMD ["/opt/app/legacy-app"]
容器运行验证
# 构建镜像
docker build -t legacy-app:v1 .
# 在容器内部使用ldd检查库链接
docker run --rm legacy-app:v1 ldd /opt/app/legacy-app
# 实际运行测试
docker run --rm legacy-app:v1
# 使用strace检查syscall是否正常工作(调试时)
docker run --rm --cap-add SYS_PTRACE legacy-app:v1
strace -c /opt/app/legacy-app
直至AWS ECS部署
容器化完成后,将其上传到ECR并使用ECS进行部署。
# ECR登录
aws ecr get-login-password --region ap-northeast-2 |
docker login --username AWS
--password-stdin <account-id>.dkr.ecr.ap-northeast-2.amazonaws.com
# 标记并推送镜像
docker tag legacy-app:v1
<account-id>.dkr.ecr.ap-northeast-2.amazonaws.com/legacy-app:v1
docker push
<account-id>.dkr.ecr.ap-northeast-2.amazonaws.com/legacy-app:v1
🖥️ 案例2 — 真正的内核依赖:KVM不可避免的情况
以下情况无法通过容器解决。
- 需要直接加载内核模块(insmod)的应用程序
- 直接调用现代内核中已移除的syscall的应用程序
- 以内核版本特定方式硬编码访问/dev、/proc的应用程序
- 内核2.x依赖(Nitro管理程序本身要求4.x+驱动)
在这种情况下,EC2裸金属 + KVM嵌套虚拟化是标准做法。
┌─────────────────────────────────┐
│ EC2 Bare Metal │
│ (i3.metal, m5.metal 등) │
│ │
│ ┌───────────────────────────┐ │
│ │ Host OS (Amazon Linux 2) │ │
│ │ KVM + QEMU │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ Guest VM │ │ │
│ │ │ 커널 3.x 직접 설치 │ │ │
│ │ │ 레거시 앱 실행 │ │ │
│ │ └─────────────────────┘ │ │
│ └───────────────────────────┘ │
└─────────────────────────────────┘
普通EC2(Nitro VM)无法更改内核,但裸金属实例可以直接访问硬件而无需管理程序,因此可以直接运行KVM。
# 在Amazon Linux 2上安装KVM
yum install -y qemu-kvm libvirt libvirt-python libguestfs-tools
systemctl enable --now libvirtd
# 检查KVM支持
lscpu | grep Virtualization
# 使用传统操作系统镜像启动VM
qemu-system-x86_64
-enable-kvm
-m 4096
-cpu host
-drive file=/var/lib/libvirt/images/legacy.qcow2,format=qcow2
-net nic -net user
但是,裸金属实例的成本相当高。
| 实例 | 规格 | 按需费用 |
| m5.metal | 96 vCPU, 384GB | 约$5/小时 |
| i3.metal | 72 vCPU, 512GB | 约$4.99/小时 |
为了一个传统应用程序支付如此高的费用是否合理,需要事先进行评估。从长远来看,应用程序移植通常更经济。
⚠️ 注意事项 — 常见错误
1. 未经strace/ldd分析就决定“使用KVM” 令人惊讶的是,许多用户空间依赖的案例却配置了虚拟机。分析必须先行。
2. 对centos:6基础镜像EOL缺乏认识 CentOS 6已于2020年11月EOL。由于没有安全补丁,需要遵循最小化外部暴露、内部网络运行原则。
3. 忽略glibc版本符号检查 不能只看ldd。需要通过`objdump -p | grep GLIBC`来确认符号版本,才能准确选择基础镜像。
4. 误解AWS MGN能解决兼容性问题 MGN只是一个复制工具。兼容性问题仍然需要手动解决。
✅ 最终决策树
레거시 앱 클라우드 이전
↓
strace / ldd 분석
↓
userspace 종속?
(glibc, .so, 런타임)
↓ YES
컨테이너 (구버전 base 이미지) ✅
↓ NO
커널 모듈 / 제거된 syscall?
↓ YES
EC2 Bare Metal + KVM ✅
↓ NO
소스코드 있음?
↓ YES
재컴파일 / 포팅 (근본 해결) ✅
↓ NO
User-mode Linux (UML) 검토 △
🏁 总结
传统迁移的核心是没有分析就没有迁移。
当听到“内核版本必须匹配”时,不要立即转向虚拟机配置,而应首先使用strace和ldd来识别依赖的性质。实际上,容器能解决的案例要多得多,而且成本和运营负担也轻得多。
如果确实是需要内核模块或已移除syscall的真正内核依赖案例,KVM是不可避免的,但即使在这种情况下,也应牢记应用程序移植是长期的正确解决方案。

发表回复