개발 노트

Docker localhost 연결 안 될 때 — 8081:8080 포트 매핑부터 확인했다

nocklock 2026. 9. 27. 20:30

localhost error

 

Spring Boot 프로젝트를 Docker로 실행했는데 localhost로 접속할 때 포트가 헷갈렸다.

http://localhost:8080
 

을 입력하면 됐다.

그런데 Docker를 사용하기 시작하니 갑자기 이런 형태가 등장했다.

 
docker run -p 8081:8080 my-spring-app
 

처음 봤을 때는 솔직히 숫자가 왜 두 개 필요한지 바로 와닿지 않았다.

8081도 포트고 8080도 포트인데,

도대체 어느 쪽으로 접속해야 하는 걸까?

직접 Docker로 Spring Boot를 실행해보고 나서야 이 구조가 조금씩 이해되기 시작했다.

먼저 localhost부터 다시 봤다

localhost는 인터넷에 있는 특정 서버의 이름이 아니다.

지금 프로그램이 실행되고 있는 자기 자신을 가리킨다.

내 PC에서 브라우저를 열고

http://localhost:8080
 

으로 들어간다면 내 PC의 8080 포트를 찾는다.

그런데 Docker 컨테이너 안에서 localhost라고 하면 이야기가 달라진다.

Docker 컨테이너 입장에서 localhost는 내 Windows PC가 아니라 그 컨테이너 자신이다.

Docker를 처음 사용할 때 이 부분이 꽤 헷갈렸다.

같은 localhost라는 글자인데 실행되는 위치에 따라 가리키는 대상이 달라지기 때문이다.

내가 먼저 만난 문제는 8080 포트 충돌이었다

당시 Spring Boot를 실행하려는데 이런 오류가 났다.

Port 8080 was already in use
 

당시 로컬 개발 중에는 8080 포트가 이미 사용 중이라 Spring Boot를 8081로 바꿔 실행한 적도 있었다.

 

그런데 Docker에서는 조금 다르게 처리할 수 있었다. 컨테이너 내부의 Spring Boot는 기본 포트인 8080으로 실행하고, 내 PC에서 접근하는 포트만 8081로 매핑했다.

 
docker run -p 8081:8080 my-spring-app
 

즉 이 경우에는

내 PC 8081 → Docker Container 8080
 

이 된다.

server.port=8081
 

그러면 로컬에서 접속하는 주소도 자연스럽게 바뀐다.

http://localhost:8081
 

여기까지는 어렵지 않았다.

 

당시 로컬에서 Spring Boot를 직접 실행할 때는 8080 포트가 이미 사용 중이라 애플리케이션 포트를 8081로 바꿔 실행한 적도 있었다.

server.port=8081

 

이 경우 Spring Boot 애플리케이션 자체가 8081 포트에서 실행되기 때문에 브라우저에서도

http://localhost:8081

 

로 접속한다.

그런데 Docker에서는 조금 다르게 처리할 수 있었다.

컨테이너 내부의 Spring Boot는 기본 포트인 8080을 그대로 사용하고, 내 PC에서 접근하는 포트만 8081로 매핑했다.

docker run -p 8081:8080 my-spring-app

즉 이 경우에는

내 PC 8081 → Docker Container 8080

 

이 된다.

로컬에서 Spring Boot 자체의 포트를 8081로 바꾸는 것과, Docker에서 호스트의 8081을 컨테이너의 8080에 연결하는 것은 서로 다른 방식이었다.

 

문제는 Docker를 사용하면서부터였다.

Docker의 8081:8080은 무슨 뜻일까

Docker 컨테이너를 실행할 때 이런 명령을 사용할 수 있다.

 
docker run -p 8081:8080 my-spring-app
 

처음에는

8081:8080
 

이 숫자 두 개가 꽤 헷갈렸다.

결론부터 말하면 나는 이렇게 이해하니까 가장 쉬웠다.

8081 → 내 PC에서 사용할 포트
8080 → Docker 컨테이너 내부 포트
 

즉,

내 PC의 8081
        ↓
Docker 컨테이너의 8080
 

으로 연결해주는 것이다.

그래서 브라우저에서는

http://localhost:8081
 

로 접속한다.

하지만 Docker 컨테이너 내부의 Spring Boot 애플리케이션은 여전히 8080에서 실행될 수 있다.

기존 Docker 배포를 하면서 내가 사용했던 구조도 이 방식이었다.

-p 앞뒤 순서를 반대로 생각하면 계속 헷갈린다

Docker의 포트 옵션은 다음 형태다.

 
-p 호스트포트:컨테이너포트
 

예를 들어

 
docker run -p 8081:8080 my-spring-app
 

이라면

Host        Container
8081   →    8080
 

이다.

내가 외부에서 접속하는 포트는 8081이다.

그래서

localhost:8080
 

이 아니라

localhost:8081
 

로 접속한다.

반대로

 
docker run -p 9000:8080 my-spring-app
 

이라고 하면 브라우저에서는

http://localhost:9000
 

으로 들어가면 된다.

컨테이너 내부 애플리케이션은 그대로 8080을 사용한다.

이걸 한 번 이해하고 나니까 Docker 포트 설정이 훨씬 덜 무서워졌다.

EXPOSE 8080을 적었다고 8080이 자동으로 열리는 건 아니었다

Dockerfile에는 이런 설정도 있었다.

 
EXPOSE 8080
 

처음에는 이것만 적으면 내 컴퓨터에서도 8080으로 바로 접속할 수 있는 줄 알았다.

그런데 EXPOSE는 실제 포트를 외부에 자동으로 열어주는 명령이라기보다,

이 컨테이너의 애플리케이션이 이 포트를 사용한다

는 정보를 표현하는 것에 가깝다.

실제로 호스트와 컨테이너를 연결하려면 실행할 때

 
docker run -p 8081:8080 my-spring-app
 

처럼 포트 매핑을 해줘야 한다.

이 차이도 Docker를 직접 실행해보기 전에는 잘 와닿지 않았다.

그러면 Docker에서 localhost는 왜 자주 문제가 될까

Docker를 사용하기 전에는 대부분 내 PC 하나만 생각하면 된다.

브라우저
Spring Boot
DB
기타 프로그램
 

이 모두 내 컴퓨터에서 돌아간다.

그래서 localhost라는 주소를 써도 크게 신경 쓸 일이 없다.

Docker를 사용하면 경계가 하나 더 생긴다.

내 PC
│
├─ 브라우저
│
└─ Docker Container
      └─ Spring Boot
 

여기서 중요한 건

내 PC와 Docker 컨테이너는 같은 localhost가 아니라는 것이다.

컨테이너 안에서

localhost
 

를 호출하면 기본적으로 컨테이너 자신을 찾는다.

따라서 Docker 안의 애플리케이션이 다른 서비스에 접속해야 한다면

그 localhost가 누구 기준의 localhost인가?

부터 확인해야 한다.

이 질문 하나만 해도 연결 문제를 볼 때 범위가 꽤 줄어든다.

로컬에서는 됐는데 Railway에서는 또 달랐다

Docker를 로컬에서 실행한 뒤 실제 배포는 Railway로 했다.

여기서 또 하나 달라진 게 포트였다.

로컬에서는 내가 직접

8080
8081
 

같은 포트를 정해서 사용할 수 있었다.

하지만 클라우드 환경에서는 플랫폼이 사용할 포트를 환경변수로 전달하는 경우가 있다.

그래서 Spring Boot에서는 이렇게 설정했다.

 
server.port=${PORT:8080}
 

이 설정은

PORT 환경변수가 있다
→ 그 값 사용

PORT 환경변수가 없다
→ 8080 사용
 

이라는 의미다.

덕분에 로컬과 배포 환경을 따로 하드코딩하지 않아도 됐다. 내가 Railway 배포 때 사용한 방식도 이것이었다.

localhost에서 외부 URL로 바뀌니까 그제야 배포가 실감났다

Docker와 Railway 배포가 끝난 뒤에는 드디어

localhost
 

가 아닌 실제 외부 URL이 생겼다.

PC에서도 접속해보고 휴대폰에서도 열어봤다.

그리고 내 컴퓨터에서 Spring Boot를 실행하지 않았는데도 서비스가 열렸다.

이때가 Docker를 공부하면서 가장 이해가 잘 됐던 순간이었다.

이미지, 컨테이너, 레이어 같은 용어를 먼저 공부할 때는 꽤 추상적이었다.

그런데 직접

내 PC에서 실행
↓
Docker로 실행
↓
외부 서버에서 실행
↓
외부 URL로 접속
 

을 해보니까 Docker가 왜 필요한지 조금씩 보이기 시작했다.

Docker localhost 연결이 안 된다면 나는 이 순서로 볼 것 같다

다시 같은 문제가 생긴다면 우선 이걸 확인할 것 같다.

1. Spring Boot가 실제로 어느 포트에서 실행되고 있는가?

2. docker run의 -p 설정은 어떻게 되어 있는가?

3. 호스트 포트와 컨테이너 포트를 반대로 생각하고 있지는 않은가?

4. 접속할 때 컨테이너 포트가 아니라
   호스트 포트로 접속하고 있는가?

5. localhost가 현재 누구 기준의 localhost인가?

6. 클라우드라면 PORT 환경변수가 따로 주어지는가?
 

Docker를 처음 사용할 때는 모든 게 Docker 문제처럼 보였다.

그런데 직접 하나씩 뜯어보니 대부분은

어디에서 실행되고 있고, 어느 포트를 보고 있는가

의 문제였다.

나는 특히

8081:8080
 

을 직접 사용해보면서 이 개념이 확실히 잡혔다.

내 PC 8081 → Docker 8080
 

이 한 줄을 이해하고 나니 localhost와 Docker 포트가 훨씬 덜 헷갈렸다.


같이 읽으면 좋은 글

Spring Boot를 Docker로 실제 배포하면서 막혔던 전체 과정

Windows와 WSL에서 시작해서 Docker 이미지를 만들고 Railway에 올리기까지의 과정은 이 글에 따로 정리했다.

- Spring Boot Docker 배포 방법 — Windows/WSL부터 Railway까지 직접 해보며 막힌 것들

localhost를 벗어나 실제 서비스로 만들면서 느꼈던 것

같은 경험을 해결 방법이 아니라 개발 과정과 생각 중심으로 적은 RE:개발자 글이다.

-localhost를 지웠더니 진짜 서비스가 됐다 | RE:개발자 #12