Docker 컨테이너가 실행 중이라면, 왜 애플리케이션은 다운되었을까?
요약
본 가이드는 Docker 컨테이너가 '실행 중(Up)' 상태여도 애플리케이션 자체는 심각하게 오작동할 수 있음을 지적합니다. 단순히 재시작하는 대신, `docker logs`와 `docker inspect` 같은 전문적인 디버깅 도구를 사용하여 근본 원인을 체계적으로 파악하는 방법을 안내합니다.
핵심 포인트
- 컨테이너가 실행 중 = 애플리케이션이 건강함 이 아니다.
- 문제 해결의 첫 단계는 무작정 재시작이 아닌 로그 확인이다.
- `docker logs`를 활용하여 오류 메시지(Connection refused 등)를 찾아라.
- `docker inspect`로 상태, 종료 코드, 네트워크 설정을 심층 분석하라.
실제 DevOps 엔지니어처럼 Docker 컨테이너를 디버깅하는 실용적인 가이드.
이런 상황을 상상해 보세요.
Docker를 사용하여 애플리케이션을 배포했습니다. 모든 것이 완벽해 보입니다.
docker ps
출력:
CONTAINER ID IMAGE STATUS
a1b2c3d4 my-app:latest Up 10 minutes
컨테이너는 실행 중입니다. Docker는 문제가 없다고 보고합니다. 당신은 자신감을 느낍니다.
그러고 나서 누군가 메시지를 보냅니다:
"이봐, 애플리케이션이 다운됐어. 고칠 수 있어?"
당신은 컨테이너를 다시 확인합니다.
여전히 실행 중입니다.
재시작합니다.
여전히 고장났습니다.
이미지를 재구축합니다.
여전히 고장났습니다.
DevOps의 현실 세계에 오신 것을 환영합니다. 😅
실행 중인 컨테이너가 반드시 건강한 애플리케이션을 의미하는 것은 아닙니다.
무작위로 컨테이너를 재시작하는 대신, 엔지니어처럼 Docker 문제 해결 방법을 배워봅시다.
🧠 1. '실행 중'과 '건강함'의 차이 이해하기
Docker는 컨테이너의 메인 프로세스가 실행되고 있는지 여부는 알려줄 수 있습니다. 하지만 애플리케이션이 올바르게 작동하고 있음을 자동으로 보장할 수는 없습니다.
예를 들어, 다음과 같은 상황에서 컨테이너가 실행 중일 수 있습니다:
- 애플리케이션이 데이터베이스에 연결할 수 없는 경우.
- API가 HTTP 500 오류를 반환하는 경우.
- 애플리케이션이 잘못된 포트에서 리스닝하는 경우.
- 필요한 환경 변수가 누락된 경우.
- 애플리케이션 응답이 너무 느린 경우.
- 의존성(dependency)에 문제가 발생하여 충돌한 경우.
이렇게 생각해 보세요:
Docker container: RUNNING ✅
Application: BROKEN ❌
Database: UNREACHABLE ❌
...
DevOps 엔지니어로서 당신의 임무는 실제 실패가 어디에서 발생하고 있는지 발견하는 것입니다.
🔍 2. 로그부터 시작하기
절대로 무작위로 모든 것을 재시작하면서 시작해서는 안 됩니다. 먼저 조사해야 합니다.
애플리케이션 로그를 확인하세요:
docker logs my-app
실시간으로 로그 추적하기:
docker logs -f my-app
최신 100줄 보기:
docker logs --tail 100 my-app
타임스탬프 포함하기:
docker logs -t my-app
다음과 같은 오류를 찾으세요:
Connection refused
Database connection failed
Address already in use
...
전문가 팁: 로그는 근본 원인을 파악하는 가장 빠른 방법입니다. 무언가를 변경하기 전에 먼저 읽어보세요.**
🛠️ 3. 컨테이너 검사 (Inspect the Container)
때로는 문제가 로그에서 보이지 않을 수 있습니다.
컨테이너 구성을 검사하세요:
docker inspect my-app
상태를 확인하세요:
docker inspect -f '{{.State.Status}}' my-app
종료 코드를 확인하세요:
docker inspect -f '{{.State.ExitCode}}' my-app
Docker가 정상으로 보고하는지 확인하세요:
docker inspect -f '{{.State.Health.Status}}' my-app
참고: 마지막 명령어는 헬스 체크(health check)가 구성되어 있어야 합니다. 그렇지 않으면 Docker가 빈 값을 반환할 수 있습니다.
컨테이너를 검사하면 구성, 상태, 네트워크 설정, 마운트 등 다양한 런타임 세부 정보를 조사하는 데 도움이 됩니다.
🌐 4. 포트 매핑 확인 (Check Port Mapping)
애플리케이션이 컨테이너 내부의 8080 포트에서 리스닝하고 있을 수 있지만, 다른 포트를 노출했거나(exposed) 게시하는 것을 잊었을 수도 있습니다.
게시된 포트를 확인하세요:
docker port my-app
올바른 매핑으로 컨테이너를 시작하세요:
docker run -d \
--name my-app \
-p 8080:8080 \
...
매핑은 다음 패턴을 따릅니다:
-p HOST_PORT:CONTAINER_PORT
예시:
사용자 브라우저
|
v
...
기억하세요: 포트를 게시하는 것이 애플리케이션이 해당 포트에서 리스닝하도록 만드는 것은 아닙니다. 애플리케이션은 실제로 예상되는 인터페이스와 포트에서 리스닝하고 있어야 합니다.
💾 5. 컨테이너가 자원 부족 상태인지 확인 (Check Whether the Container Is Running Out of Resources)
애플리케이션은 메모리가 부족하거나 CPU 사용량에 어려움을 겪을 때 느려지거나 충돌할 수 있습니다.
자원 소비를 확인하세요:
docker stats
예시:
CONTAINER CPU % MEM USAGE / LIMIT
my-app 95% 480MiB / 512MiB
database 15% 300MiB / 1GiB
이 가상의 예시에서, my-app은 메모리 제한의 거의 모든 것을 소비하고 있습니다.
자원 제한을 변경하기 전에 더 깊이 조사하세요. 메모리 누수(memory leak), 과도한 트래픽 또는 비효율적인 애플리케이션 코드가 실제 문제일 수 있습니다.
유용한 명령어:
docker ps -a
docker system df
docker events
이 명령어들은 컨테이너 상태, Docker 디스크 사용량, 그리고 Docker 이벤트를 검사하는 데 도움을 줍니다.
주의사항: docker system prune -a를 일상적인 문제 해결 단계로 실행하는 것은 피하세요. 이는 여전히 필요할 수 있는 사용하지 않는 이미지 및 기타 리소스를 제거할 수 있습니다.
❤️ 6. Docker Health Check 추가하기
컨테이너 모니터링을 개선하는 한 가지 방법입니다.
Health check는 Docker가 애플리케이션이 정의된 검사에 응답하는지 주기적으로 테스트하도록 합니다.
예시 Dockerfile:
FROM nginx:alpine
COPY index.html /usr/share/nginx/html/index.html
...
이 예시는 가벼운 Nginx 이미지를 사용하며, 해당 HTTP 엔드포인트가 성공적으로 응답하는지 확인합니다.
Health 상태를 확인하려면:
docker ps
설정된 health check는 다음과 같은 상태를 보고할 수 있습니다:
starting
healthy
unhealthy
하지만 기억하세요. health check의 유용성은 정의하는 테스트에 달려 있습니다. 성공적인 HTTP 응답이 애플리케이션의 모든 기능이 작동하고 있음을 반드시 의미하지는 않습니다.
🔗 7. 네트워크 및 데이터베이스 문제 조사하기
애플리케이션이 PostgreSQL 데이터베이스에 의존한다고 가정해 봅시다.
애플리케이션 컨테이너는 실행 중이지만, 데이터베이스 연결은 계속 실패합니다.
먼저 Docker 네트워크를 검사하세요:
docker network ls
컨테이너가 사용하는 네트워크를 검사하세요:
docker network inspect my-network
두 서비스 모두 통신해야 한다면, 적절한 네트워크를 공유하는지 확인하세요.
Docker Compose를 사용하면 동일한 기본 네트워크에 있는 서비스들은 일반적으로 서비스 이름을 사용하여 서로 도달할 수 있습니다.
예시:
services:
app:
build: .
...
여기서 db는 데이터베이스 서비스 이름입니다.
주의사항: 이것은 학습 예제이며 운영 환경에 적합한 구성이 아닙니다. 하드코딩된 비밀번호 대신 시크릿(secrets)을 사용하고, 데이터베이스 데이터를 위해 영구 저장소(persistent storage)를 사용하며, 애플리케이션 레벨의 재시도 로직(retry logic)을 사용하세요. 또한, depends_on만으로는 PostgreSQL이 연결을 수락할 준비가 되었음을 보장하지 않습니다.
🧪 8. 자체 Docker 문제 해결 체크리스트 만들기
애플리케이션이 다운되었을 때는 다음 순서를 따르세요:
- 상태 확인:
docker ps -a - 로그 읽기:
docker logs my-app - 설정 검사:
docker inspect my-app - 리소스 사용량 확인:
docker stats - 포트 매핑 확인:
docker port my-app - 네트워크 조사:
docker network inspect my-network - 애플리케이션 엔드포인트 테스트:
curl또는 적절한 헬스 체크를 사용합니다. - 수정 적용: 발견된 증거에 기반하여 설정이나 코드를 변경합니다.
- 복구 확인: 관련 테스트를 반복하고 로그를 확인합니다.
목표는 단순히 오류가 사라지게 만드는 것이 아닙니다.
왜 발생했는지, 그리고 어떻게 다시 발생하지 않도록 할 것인지 이해하는 것입니다.
🚀 9. 더 나아가기: 컨테이너 모니터링 프로젝트 구축하기
이 지식을 포트폴리오 프로젝트로 만들고 싶으신가요?
다음 도구들을 사용하여 작은 Docker 모니터링 스택을 구축해 보세요:
- Docker Compose를 사용하여 서비스 실행.
- Prometheus를 사용하여 메트릭 수집.
- Grafana를 사용하여 성능 시각화.
- cAdvisor를 사용하여 컨테이너 리소스 메트릭 노출.
- **알림(Alerting)**을 설정하여 중요한 장애 발생 시 알림 받기.
간소화된 아키텍처:
Docker Containers
|
v
...
CPU 사용량, 메모리 소비량, 컨테이너 재시작 횟수, 애플리케이션 가용성 등을 추적하세요.
가상의 장애 상황 하나와 그 조사 과정, 근본 원인(root cause), 그리고 해결책을 문서화해 보세요. 이는 DevOps 인터뷰에서 논의할 수 있는 구체적인 프로젝트 경험이 됩니다.
🎯 최종 생각
Docker는 애플리케이션 패키징 및 실행을 쉽게 만들지만, 프로덕션 환경의 문제를 완전히 없애주지는 않습니다.
훌륭한 DevOps 엔지니어들은 컨테이너를 무작정 재시작하지 않습니다. 그들은 증거를 수집하고, 시스템 동작을 이해하며, 근본 원인을 파악하고, 해결책을 검증합니다.
다음에 누군가
도전 과제: Docker 컨테이너를 실행하고, 로그를 검사하며, 헬스 체크(health check)를 설정한 다음, 로컬 테스트 환경에서 의도적으로 실패를 발생시켜 보세요. 컨테이너를 즉시 재시작하지 않고 문제를 진단할 수 있나요?**
발견한 내용을 댓글로 공유해 주세요! 👇
📚 DevOps 역량 계속 쌓기
이러한 도구들을 학습하는 데 도움이 되는 체계적인 자료가 필요하다면, 제 가이드들을 살펴보세요:
- 🐳 Docker Mastery
- ☸️ CKA Complete Study Guide
- 🏗️ Terraform Associate (003) Exam Crash Course
- 🚀 DevOps Complete Pack
직접 구축하며 배우고, 안전한 실험실에서 무언가를 망가뜨려보고, 그것을 고치는 것에 더 능숙해지세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기