요약(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
'Dev Log (개발 문제 & 해결 기록) > Error & Fix (에러 해결 기록)' 카테고리의 다른 글
[오류로그 #1][502 #1] PR 머지 직후 502 Bad Gateway — application.yml 구성 붕괴 (2025-08-22) (1) | 2025.09.03 |
---|