본 프로젝트의 핵심 목적은 직접 개발한 Dockerfile 정적 분석 및 자동 경량화 CLI 도구(imgadvisor)의 산출물이 실제 운영 환경의 가혹 조건에서도 실효성 있는 성능 개선을 만들어내는지 검증하는 것이다.
[CLI 도구 소개: imgadvisor]
imgadvisor는 Dockerfile을 정적으로 분석하여 최적화 포인트를 도출하는 자체 개발 CLI 도구다.
$ imgadvisor recommend -f Dockerfile : 최적화 가능한 레이어 및 안티패턴 진단$ imgadvisor validate -f Dockerfile --optimized [파일명] : 분석 결과를 바탕으로 멀티 스테이지 빌드 등이 적용된 경량화 Dockerfile 자동 생성일반적인 최적화 프로젝트는 "이미지 용량을 줄였다"는 선에서 마무리된다. 하지만 실제 프로덕션 환경에서 이미지 크기 감소가 무중단 배포나 장애 복구 시의 빠른 기동(Startup)을 보장하지는 않는다. 따라서 본 실험은 CLI가 자동 생성한 최적화 결과물을 극단적인 CPU 자원 경합(Contention) 상황에 노출시켜, 단순한 용량 축소가 런타임 성능에 미치는 영향을 커널 레벨에서 디버깅하는 실무형 트러블슈팅 과정으로 기획되었다.
단순히 time docker run으로 측정하는 E2E 지표만으로는 "왜 느려졌는지" 근본 원인을 규명할 수 없다. 따라서 컨테이너 기동 과정에서의 병목을 추적하기 위해 커널 레벨의 지표를 직접 추출하는 자체 프로파일링 쉘 스크립트(measure_host_pressure.sh)를 구현했다.
| 항목 | 내용 |
|---|---|
| 호스트 환경 | VMware VM (Docker Swarm Manager Node) |
| vCPU / RAM | 4코어 (nproc=4) / 3.8GiB (여유 3.0GiB 확인) |
| OS / 커널 | Ubuntu, Kernel 6.8.0-106-generic |
| 부하 도구 | stress-ng --cpu 4 --cpu-method matrixprod --timeout 60s |
| 애플리케이션 | Flask (app.py) + Gunicorn WSGI 서버 |
[핵심 측정 지표 추출 원리]
cat /sys/fs/cgroup/.../cpu.pressurecpu.stat의 wait_sum 필드가 커널 버전에 따라 미지원되는 이슈가 있어, 대안으로 PSI(Pressure Stall Information)의 some total 값을 추출. 이는 프로세스가 CPU 할당을 기다린 누적 시간(μs)을 의미함.grep nr_switches /proc/$PID/sched본 실험은 시스템 복원력(Resilience) 검증을 위해 두 가지 핵심 운영 시나리오를 모사했다.
이를 위해 호스트 가용 CPU를 강제 고갈시킨 상태에서 Baseline(679MB) 이미지와 Optimized(179MB) 이미지의 기동 속도를 비교했다. (모두 Gunicorn Worker 2개로 통일)
프로파일링 스크립트를 구축하는 과정에서 겪은 주요 문제와 해결 과정은 다음과 같다.
① 백그라운드 부하 프로세스(stress-ng) 강제 종료 현상
& 기호가 유실되거나 파싱 에러 발생.PID를 파일에 기록하여 제어하도록 수정.② 문맥 전환(ctx_switches) 지표 누락 문제
/proc/$PID/sched에서 조회한 nr_switches 값이 지속적으로 0에 가깝게 도출됨.CMD flask run ...)으로 작성되어, 컨테이너의 PID 1이 Gunicorn이 아닌 /bin/sh에 할당됨. 이로 인해 실제 워커 프로세스의 문맥 전환이 측정되지 않음.["gunicorn", "-w", "2", ...]으로 통일하여 PID 추적 대상을 명확히 함. 동시에 누적값 오염을 막기 위해 컨테이너 시작 시점(스냅샷)과 /ready 응답 후의 차이값(Delta)만 기록하도록 로직 개선.5회 반복 교차 측정(캐시 삭제 포함)을 통해 도출된 지표는 다음과 같다.
| 측정 지표 | Baseline (679MB) | Optimized (179MB) | 증감 |
|---|---|---|---|
| Startup Time 평균 | 2429.2 ms | 2980.6 ms | ❌ +551.4 ms (+22.7%) 악화 |
| Kernel Wait Time 평균 | 195.0 ms | 318.0 ms | ❌ +123.0 ms (+63.1%) 악화 |
| Context Switches 평균 | 331.2 회 | 415.0 회 | ❌ +83.8 회 (+25.3%) 증가 |
결과 요약: imgadvisor를 통해 이미지 크기를 679MB에서 179MB로 무려 73% 감소시켰으나, Baseline 대비 기동 속도(+22.7%), 커널 대기 시간(+63.1%), 문맥 전환(+25.3%) 모두 심각하게 악화되었다. 가벼워진 용량(I/O 이득)이 런타임 오버헤드(CPU 비용)에 잡아먹힌 '최적화의 역설'이 발생했다.
본 성능 저하는 프로젝트의 실패가 아니라, "정적 분석 기반의 이미지 경량화가 곧바로 Startup 성능 최적화로 이어지지 않는다" 는 실무적 맹점을 입증한 결과다.
[핵심 가설: Python .pyc 컴파일 오버헤드]
python:3.11 풀 이미지 내부에는 numpy, pandas 등 무거운 C 확장 기반 패키지들의 표준 라이브러리가 바이트코드(.pyc) 형태로 사전 컴파일되어 저장되어 있다.python:3.11-slim 이미지는 용량 감소를 위해 내부 .pyc 파일을 모두 제거한 상태다. 격리된 가상환경(venv) 패키지들은 처음 import 시 메모리상에서 실시간으로 JIT 컴파일을 수행해야 한다..py 소스를 읽어 컴파일을 시도하면서, 이미 포화된 Run-Queue에 막대한 추가 부하를 발생시켰고 이것이 kernel_wait_ms 폭증으로 직결되었다.(한계점 인식) 현재 도구는 docker inspect State.Pid를 통해 Gunicorn Master 프로세스를 추적하므로 지표의 정밀도에 한계가 있다. 향후 grep 'gunicorn.*worker'를 통해 실제 연산을 수행하는 Worker PID를 직접 추적하도록 보완이 필요하다.
본 프로파일링 결과를 바탕으로, 실무 환경에서 Python 애플리케이션 컨테이너를 최적화할 때 반드시 고려해야 할 가이드라인을 도출했다.
.pyc 사전 컴파일 적용RUN python -m compileall /opt/venv/lib /app 명령어를 주입하여 런타임 오버헤드를 빌드 타임으로 전가해야 한다.numpy, pandas, scikit-learn 등을 다수 포함하는 환경에서는 Slim 이미지를 통한 I/O 대역폭 확보보다 런타임 초기화 오버헤드(CPU 자원 소비)가 더 클 수 있음을 인지하고 트레이드오프를 계산해야 한다.단순한 'Dockerfile 파서' 수준인 현재의 CLI 알고리즘을 '지능형 배포 최적화 도구'로 고도화할 계획이다.
app.py, requirements.txt 등을 참조하여 실행될 애플리케이션의 런타임 특성(Python 등)을 동적으로 감지한다..pyc 강제 생성 명령어를 최적화된 Dockerfile에 자동 주입하도록 로직을 개선한다. 이를 통해 트래픽 폭주 상황에서도 즉각적인 Scale-out 골든타임을 보장하는 완성도 높은 도구로 발전시킬 예정이다.