이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- Docker network와 port mapping은 Spring API 접근 경로를 어떻게 결정하는가?
localhost, container name, host port, container port를 어떻게 구분해야 하는가?- Nginx, firewall, Docker port mapping이 어긋날 때 어떤 장애 신호가 나타나는가?
개요
Docker network 문제는 서버는 떠 있는데 접속이 안 된다로 나타난다.
Spring container 안에서는 8080이 열려 있지만 host에는 publish되지 않았을 수 있다.
host에서는 8080이 열려 있지만 Nginx upstream은 다른 port를 바라볼 수 있다.
Compose 내부에서는 service name으로 접근해야 하는데 localhost를 써서 자기 자신을 바라볼 수도 있다.
Port Mapping 기본
Docker port mapping은 host port와 container port를 연결한다.
docker run -p 8080:8080 order-api:3f21a9c왼쪽 8080은 host port다.
오른쪽 8080은 container 내부 port다.
Spring server.port=8080은 container 내부 port를 의미한다.
host에서 접근하려면 port가 publish되어 있어야 한다.
docker ps --format "table {{.Names}}\t{{.Ports}}"EXPOSE와 Publish
Dockerfile의 EXPOSE 8080은 문서화에 가깝다.
외부 접근을 자동으로 열어주지 않는다.
실제 host port 공개는 -p 또는 Compose ports가 담당한다.
services:
app:
image: order-api:3f21a9c
ports:
- "8080:8080"EXPOSE만 있고 ports가 없으면 host에서 접근할 수 없을 수 있다.
localhost의 함정
container 안에서 localhost는 container 자기 자신이다.
Spring app container에서 localhost:5432를 DB로 쓰면 같은 container 안의 5432를 찾는다.
Compose에서는 DB service name을 써야 한다.
spring:
datasource:
url: jdbc:postgresql://db:5432/orderhost에서 접근할 때의 localhost와 container 내부의 localhost는 다르다.
이 차이를 모르면 DB 연결 실패나 외부 API 연결 실패를 잘못 해석한다.
Compose Network
Compose는 기본 network를 만들고 service name으로 DNS를 제공한다.
services:
app:
image: order-api:3f21a9c
depends_on:
- db
db:
image: postgres:16app container는 db:5432로 DB에 접근할 수 있다.
하지만 depends_on은 DB가 ready 상태라는 뜻이 아니다.
DB process가 떠도 schema migration이나 connection readiness는 별도 확인이 필요하다.
Nginx와 Docker
Nginx가 host에서 실행되고 Spring이 container로 실행되면 upstream은 host port를 바라본다.
location / {
proxy_pass http://127.0.0.1:8080;
}Nginx도 container라면 같은 Docker network 안에서 service name을 바라볼 수 있다.
proxy_pass http://order-api:8080;어느 쪽인지에 따라 upstream 주소가 달라진다.
Nginx 502가 발생하면 Spring container log에 요청이 들어왔는지 먼저 확인한다.
운영 체크리스트
- Spring
server.port와 container port가 일치하는가? - host port publish가 필요한 서비스에만 열려 있는가?
- Nginx/LB upstream이 host port와 container network 중 어디를 바라보는가?
- container 내부에서 DB나 Redis를
localhost로 바라보지 않는가? - Compose service name과 DNS가 문서화되어 있는가?
- firewall과 security group이 host port를 허용하는가?
- management port를 분리했다면 health check 경로가 맞는가?
장애 신호
- container 내부
curl localhost:8080은 성공하지만 hostcurl localhost:8080은 실패한다. - host에서는 성공하지만 외부에서는 timeout이 난다.
- Nginx 502가 늘고 Spring access log에는 요청이 없다.
- Spring app이 DB를
localhost로 바라봐 connection refused가 난다. docker psPorts 항목이 비어 있다.- host port 충돌로 container 시작이 실패한다.
- Compose 내부 service name을 해석하지 못한다.
안전한 완화 조치
network 문제는 안쪽에서 바깥쪽으로 확인한다.
- container 내부 Spring health 확인
- host에서 published port 확인
- Nginx upstream 확인
- firewall/security group 확인
- 외부 client 확인
docker exec order-api curl -fsS http://localhost:8080/actuator/health
curl -fsS http://127.0.0.1:8080/actuator/health
docker network inspect <network>임시로 모든 port를 열기보다 어느 경로가 막혔는지 좁힌다.
인프라 담당자와 공유할 자료
증상: 외부 502, host curl 127.0.0.1:8080 실패
container: order-api Up, internal health OK
docker ps Ports: 127.0.0.1:18080->8080/tcp
Nginx upstream: 127.0.0.1:8080
요청: upstream port를 18080으로 맞출지 container publish를 수정할지 확인port 문제는 Spring port, container port, host port, proxy port를 한 줄에 보여주는 것이 중요하다.
실전 팁
EXPOSE와ports를 혼동하지 않는다.localhost가 어느 실행 범위 기준인지 항상 확인한다.- Nginx가 host에 있는지 container network 안에 있는지 먼저 본다.
- port mapping은 release note나 compose 파일에 명시한다.
- host port를 넓게 열기보다 proxy 뒤로 숨기는 구성을 우선 검토한다.
위험 신호!
- Dockerfile에
EXPOSE가 있으니 외부 접근이 된다고 생각한다. - container 내부에서 DB URL을
localhost로 둔다. docker ps의 Ports 항목을 보지 않고 Nginx부터 수정한다.- host firewall과 Docker publish port를 따로 관리하지 않는다.
- management endpoint를 외부에 그대로 노출한다.
확인 질문
확인 질문
8080:8080port mapping에서 왼쪽과 오른쪽은 각각 무엇인가?
- 왼쪽은 host port이고 오른쪽은 container 내부 port다.
- container 안에서
localhost를 DB 주소로 쓰면 왜 문제가 될 수 있는가?
- container 안의
localhost는 그 container 자신이므로 별도 DB container나 host DB를 바라보지 않는다.- Nginx 502에서 Docker 쪽으로 먼저 확인할 것은 무엇인가?
- Spring container 내부 health, host port publish, Nginx upstream 주소와 port, Spring access log 도달 여부다.