レガシー環境をクラウドへ?「とりあえず上げればいい」という誤解 🚀

「サーバーをそのまま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は避けられないが、その場合でも長期的にはアプリのポーティングが正解であることを念頭に置くべきだ。


Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です