본문 바로가기
클라우드

레거시 환경을 클라우드로? "일단 올리면 된다"는 착각 🚀

by gasbugs 2026. 4. 14.

"서버 그대로 AWS에 올리면 되는 거 아닌가요?"
— 마이그레이션 현장에서 가장 많이 듣는 말이자, 가장 위험한 착각이다.


🎯 이 글에서 다루는 것

  • 레거시 앱 클라우드 이전 전, 반드시 해야 할 호환성 분석
  • AWS 마이그레이션 도구(MGN)가 커널 문제를 해결해주지 않는 이유
  • 컨테이너로 해결 가능한 케이스와 구체적인 Dockerfile 예제
  • KVM이 불가피한 케이스와 AWS Bare Metal 구성 방법
  • 판단 기준을 정리한 최종 의사결정 트리

📌 도입 — "올리는 것"과 "돌아가는 것"은 다르다

레거시 시스템 마이그레이션 프로젝트에서 흔히 벌어지는 일이 있다. AWS MGN(Application Migration Service)으로 서버를 통째로 복제해서 EC2에 올렸는데, 앱이 시작조차 안 되는 상황이다.

 

이유는 단순하다. 마이그레이션 도구는 이동 수단일 뿐이다. 디스크를 블록 단위로 복제해서 EC2에 붙여주는 역할이 전부다. 커널 2.x, 3.x 시절의 레거시 앱이 가진 호환성 문제는 옮긴 후에도 그대로 남는다.

 

심지어 MGN은 복제 과정에서 구버전 커널을 감지하면 자동으로 Nitro 호환 커널로 교체해버린다. /boot/vmlinuz-3.x 파일이 복제는 되지만, Nitro 하이퍼바이저가 요구하는 ENA(네트워크), NVMe(스토리지) 드라이버가 구버전 커널에 없기 때문이다. 결국 원본 커널로는 부팅이 불가능하다.

 

그래서 마이그레이션 전에 반드시 해야 할 작업이 있다. 호환성 분석이다.


🔍 핵심 질문 — "커널 종속"인가, "userspace 종속"인가

현장에서 "이 앱은 커널 3.x에서만 돌아요"라는 말을 들으면, 먼저 의심해야 한다. 실제로 커널 자체에 종속된 케이스는 생각보다 드물다. 대부분은 userspace 영역의 문제다.

"커널 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 같은 버전 심볼이 보인다면 userspace 종속이다. 이 경우 컨테이너로 해결 가능하다.


🐳 케이스 1 — userspace(glibc) 종속: 컨테이너로 해결

컨테이너의 핵심 구조를 이해하면 왜 이게 해결되는지 바로 보인다.

┌──────────────────────────────────┐
│  컨테이너 이미지 내부             │
│  ┌────────────────────────────┐  │
│  │  레거시 앱                  │  │
│  │  glibc 2.12 (구버전)        │  │  ← 이미지 안에 격리
│  │  필요한 .so 라이브러리들     │  │
│  └────────────────────────────┘  │
├──────────────────────────────────┤
│  호스트 커널 (5.x / 6.x)         │  ← glibc와 무관
└──────────────────────────────────┘

 

컨테이너는 커널만 공유하고, glibc를 포함한 모든 userspace 라이브러리는 이미지 안에 독립적으로 탑재된다. 호스트 커널이 6.x여도 컨테이너 내부의 glibc 2.12는 그대로 동작한다.

 

구버전 glibc base 이미지 선택 기준

 

Base Image glibc 버전  비고
centos:6 2.12 커널 2.6 시절 userspace
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 Bare Metal + KVM 중첩 가상화가 정석이다.

┌─────────────────────────────────┐
│      EC2 Bare Metal             │
│   (i3.metal, m5.metal 등)       │
│                                 │
│  ┌───────────────────────────┐  │
│  │  Host OS (Amazon Linux 2) │  │
│  │  KVM + QEMU               │  │
│  │  ┌─────────────────────┐  │  │
│  │  │  Guest VM            │  │  │
│  │  │  커널 3.x 직접 설치   │  │  │
│  │  │  레거시 앱 실행       │  │  │
│  │  └─────────────────────┘  │  │
│  └───────────────────────────┘  │
└─────────────────────────────────┘

 

일반 EC2(Nitro VM)는 커널 변경이 불가능하지만, Bare Metal은 하이퍼바이저 없이 하드웨어에 직접 접근하므로 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

 

단, Bare Metal 인스턴스는 비용이 상당하다.

인스턴스 스펙 온디맨드 비용
m5.metal 96 vCPU, 384GB 약 $5/hr
i3.metal 72 vCPU, 512GB 약 $4.99/hr

 

레거시 앱 하나를 위해 이 비용이 합리적인지 검토가 선행되어야 한다. 장기적으로는 앱 포팅이 더 경제적인 경우가 많다.


⚠️ 주의사항 — 흔한 실수들

1. strace/ldd 분석 없이 "KVM으로 가자" 결정 userspace 종속인데 VM을 구성하는 케이스가 의외로 많다. 반드시 분석 먼저다.

2. centos:6 베이스 이미지의 EOL 인식 부족 CentOS 6는 2020년 11월 EOL. 보안 패치가 없으므로 외부 노출 최소화, 내부망 운영 원칙 적용 필요.

3. glibc 버전 심볼 확인 생략 ldd만 보고 넘어가면 안 된다. objdump -p | grep GLIBC로 심볼 버전까지 확인해야 정확한 base 이미지 선택이 가능하다.

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이 불가피하지만, 그 경우에도 장기적으로는 앱 포팅이 정답임을 염두에 두어야 한다.