「サーバーをそのまま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 종속 ← 진짜 커널 문제 (희귀)
└─────────────────────────────────┘
これを区別する最も速い方法は、以下の2つのコマンドだ。
# アプリが使用する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
# レガシーOSイメージで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/hr |
| i3.metal | 72 vCPU, 512GB | 約$4.99/hr |
レガシーアプリ一つにこの費用が合理的か、事前に検討が必要だ。長期的にはアプリのポーティングの方が経済的な場合が多い。
⚠️ 注意事項 — よくある間違い
1. strace/ldd分析なしに「KVMで行こう」と決定 ユーザースペース依存なのにVMを構成するケースが意外と多い。必ず分析が先だ。
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) 검토 △
🏁 まとめ
レガシーマイグレーションの核心は、分析なしの移行はないということだ。
「カーネルバージョンが合致しなければならない」という言葉を聞いたら、すぐにVM構成に進まず、straceとlddで依存の性質をまず把握すべきだ。実際にコンテナで解決できるケースの方がはるかに多く、コストと運用負担もはるかに軽い。
カーネルモジュールや削除されたsyscallが必要な真のカーネル依存ケースであればKVMは避けられないが、その場合でも長期的にはアプリのポーティングが正解であることを念頭に置くべきだ。

コメントを残す