본문 바로가기
Dev Log (개발 문제 & 해결 기록)/Error & Fix (에러 해결 기록)

[오류로그 #2][S2#1] 8080 포트 충돌로 앱 기동 실패 — 중복기동 점검 체크리스트

by Dev.후크리 2025. 9. 5.
요약(Summary)

 

신규 컨테이너 실행 직후 Address already in use 오류(S2),

애플리케이션 단일 노드 영향, 
원인은 동일 서버에서 기존 프로세스가 8080 포트를 이미 점유 중이어서 기동 실패.

 


환경(Context)

 

 

  • STACK: Spring Boot 3.3.x, Java 21, AWS EC2(Ubuntu 22.04), Docker, Nginx(RevProxy), GitHub Actions
  • 배포 흐름: GitHub → Actions 빌드/푸시 → DockerHub → EC2 Docker run → Nginx 리버스 프록시
  • 특징: EC2 단일 노드에서 systemd(Spring Boot jar)와 Docker 컨테이너 기동 가능 → 포트 충돌 가능성

 

flowchart LR
Client --> Nginx --> App(Spring Boot:8080) --> RDS[(MySQL)]

 

 


증상 & 로그(Symptoms & Logs)

 

 

컨테이너 실행 시 로그 예시:

2025-09-04T13:15:22 ERROR [main] o.a.coyote.http11.Http11NioProtocol :
Failed to start protocol handler for "http-nio-8080"
java.net.BindException: Address already in use: bind

 

포트 상태 확인 예시:

ss -lntp | grep 8080
LISTEN 0  100 0.0.0.0:8080  0.0.0.0:*  users:(("java",pid=12345,fd=100))

 

 


가상 타임라인(Timeline)

 

 

— 신규 컨테이너 실행 시 Address already in use: bind 발생

— docker logs 확인, 포트 바인딩 실패 로그 확인

— ss -lntp | grep 8080 실행 → 기존 프로세스(PID=12345) 포트 점유 확인

— 중복 기동(systemd 서비스 + Docker 컨테이너) 가설 수립

— 기존 프로세스 종료 후 컨테이너 재기동 → 정상 실행

— Swagger/헬스체크 응답 확인, 사건 종료

 

 


근본 원인(Root Cause Analysis)
  • 표면 원인: EC2 서버에서 8080 포트를 이미 점유 중인 프로세스 존재 → 신규 컨테이너 바인딩 실패
  • 근본 원인: systemd 서비스(Spring Boot jar 실행)가 자동 기동 설정된 상태에서 Docker 컨테이너를 추가로 띄움 → 중복 기동 충돌
  • 카테고리: 운영 환경 관리 / 중복 기동 방지

 


재현하기(Reproduction)

 

전제: EC2 Ubuntu 환경, Spring Boot jar를 systemd로 등록한 상태 + Docker 컨테이너 기동 시도

 

# 1) 포트 점유 상태 확인
ss -lntp | grep 8080

# 2) 컨테이너 실행
docker run -d -p 8080:8080 myapp:latest

# 3) 로그 확인
docker logs <container_id>

 

예상 결과: Address already in use 오류 발생 → 앱 기동 실패


해결(Resolution) & 롤백 전략(Rollback)

 

실행 절차:

- 포트 점유 프로세스 확인

ss -lntp | grep 8080
kill -9 <PID>

 

- 불필요 컨테이너 종료

docker ps
docker stop <container_id>

 

- 컨테이너 재기동 → 정상 실행

 

롤백 전략:

  • 만약 잘못 종료 시 GitHub Actions를 통한 이전 정상 이미지 재배포
  • systemd 기동 유지해야 할 경우 → Docker 포트 매핑을 -p 8081:8080 등으로 조정

왜 이게 통했나(Why it worked)

 

  • 리눅스 커널은 동일 포트에 대해 단일 프로세스만 소켓 바인딩을 허용.
  • 기존 프로세스를 종료하자 소켓이 해제되어 신규 컨테이너가 8080 포트를 정상적으로 점유할 수 있었음.

검증(Verification) & 스모크 테스트)

 

# 포트 상태
ss -lntp | grep 8080

# 컨테이너 로그
docker logs app

# API 헬스체크
curl -i http://localhost:8080/actuator/health

 

Swagger /swagger-ui/index.html 응답 정상.
애플리케이션 메트릭(5xx, 재시작 횟수) 정상화 확인.


재발 방지(Prevention) 체크리스트

 

 

  • 정책
    • 운영 서버는 systemd 기동 금지, Docker 컨테이너만 단일 관리
    • 포트 정책: 운영 환경에서는 8080 단일 할당
  • 도구/자동화
    • 배포 전 ss -lntp 실행하는 헬스체크 스크립트 포함
    • GitHub Actions 워크플로우에 포트 충돌 감지 스텝 추가
  • 리뷰 포인트
    • GHA/Dockerfile diff 리뷰 시 포트 매핑 변경 여부 확인
    • server.port 설정과 Nginx 업스트림 포트 일치 검증
  • 모니터링/알림
    • 애플리케이션 기동 실패 로그 수집 후 알림
    • 컨테이너 재시작 횟수 모니터링

 


부록(Playbooks / Snippets)

 

# 포트 점유 확인
ss -lntp | grep 8080

# 특정 PID 종료
kill -9 <PID>   # 시스템 영향 주의 필요

 


메타데이터(Metadata)
  • RACI
    • R(실행): Backend 온콜
    • A(책임): SRE/플랫폼
    • C(협의): 프론트엔드, 기획
    • I(통지): PO, 운영지원
  • 관련 파일(Related Files)
    • /etc/systemd/system/app.service
    • Dockerfile
    • .github/workflows/deploy.yml
    • src/main/resources/application-prod.yml
  • 링크: (내부 링크 예정) — 사건 티켓, 배포 로그, 대시보드
  • TAGS: #AWS #Docker #SpringBoot #Port #Nginx #CI_CD