빠른 비교
docker run --name web -d -p 8080:80 nginx:alpine갈리는 기준
어떤 네트워크 선택을 먼저 떠올리면 되나
| 상황 | 먼저 떠올릴 선택 |
|---|---|
| 호스트에서 컨테이너 서비스 접근 | -p 호스트:컨테이너 |
| 로컬에서만 접근 제한 | 127.0.0.1:호스트:컨테이너 |
| 컨테이너끼리 내부 통신 | 같은 bridge 네트워크 |
| DB를 외부에 숨기고 싶다 | -p 없이 내부 네트워크만 사용 |
-p 포트 매핑이 iptables 규칙으로 구현되는 방식
-p 8080:80은 "호스트의 8080 포트로 들어온 트래픽을 컨테이너의 80 포트로 전달하라"는 규칙이다. Linux에서 Docker는 이 매핑을 iptables NAT 규칙으로 구현한다. 호스트가 패킷을 받으면 DNAT(Destination NAT)으로 목적지를 컨테이너 IP:80으로 바꿔서 전달한다.
# 포트 매핑 확인
docker port web
# 여러 포트 동시 매핑
docker run -d \
-p 8080:80 \
-p 8443:443 \
nginx:alpine
# 호스트 포트 랜덤 지정 (사용 가능한 포트를 자동 할당)
docker run -d -p 80 nginx:alpine
docker port $(docker ps -lq)0.0.0.0 바인딩 vs 127.0.0.1 바인딩 보안 차이
-p 8080:80은 기본적으로 0.0.0.0:8080에 바인딩된다. 이는 모든 네트워크 인터페이스에서 접근 가능함을 의미하고, 외부 인터넷에서도 접근이 된다. 로컬에서만 접근해야 하는 서비스는 127.0.0.1:8080:80으로 제한해야 한다.
# 모든 인터페이스에 바인딩 (외부 접근 허용)
docker run -d -p 8080:80 nginx:alpine
# localhost에서만 접근 가능 (보안 강화)
docker run -d -p 127.0.0.1:8080:80 nginx:alpine
# DB는 외부에 열지 않고 내부 네트워크만 사용
docker run -d --name db --network app-net postgres:17
# -p 옵션 없음 → 호스트에서는 직접 접근 불가EXPOSE가 문서 역할만 하고 실제 포트를 열지 않는 이유
Dockerfile의 EXPOSE는 이 컨테이너가 어떤 포트를 사용한다고 문서화하는 메타데이터다. 실제로 호스트에 포트를 열지 않는다. 포트를 열려면 docker run -p를 사용해야 한다. EXPOSE는 이미지 사용자에게 포트 정보를 알리는 관례적 선언이다.
# EXPOSE만으로는 호스트에서 접근 불가
EXPOSE 3000# EXPOSE만 있는 이미지를 실행해도 외부 접근 안 됨
docker run -d my-app # EXPOSE 3000
# 실제로 열려면 -p 필요
docker run -d -p 3000:3000 my-appbridge 네트워크에서 컨테이너 간 통신 방식
사용자 정의 bridge 네트워크에서는 같은 네트워크의 컨테이너끼리 포트를 공개하지 않고도 내부적으로 통신한다. app이 db의 5432 포트에 접근할 때 -p는 필요 없다. 포트 공개는 외부(호스트 또는 인터넷)에서 접근할 때만 필요하다.
docker network create app-net
# db는 외부에 포트를 열지 않음
docker run -d --name db --network app-net postgres:17
# api는 db에 내부 통신 가능, 외부에는 3000 포트만 공개
docker run -d --name api \
--network app-net \
-p 3000:3000 \
my-api
# api 컨테이너 안에서: psql -h db -p 5432 (성공)포트 공개와 내부 통신은 해결하는 범위가 다르다
-p는 호스트와 외부 클라이언트가 컨테이너에 들어오게 하는 설정이고, bridge 네트워크는 컨테이너끼리 서로 찾고 통신하게 하는 설정입니다. 컨테이너 간 통신만 필요한 DB나 Redis에 -p를 붙이는 건 보통 불필요한 외부 노출입니다.
# 외부에서 브라우저로 접근해야 하는 웹 앱
docker run -d --name web -p 8080:80 --network app-net nginx:alpine
# api만 접근하면 되는 DB
docker run -d --name db --network app-net postgres:17체크포인트
| 상황 | 적합한 선택 |
|---|---|
| 외부에서 컨테이너 서비스에 접근 | -p 호스트포트:컨테이너포트 |
| 로컬에서만 접근하도록 제한 | -p 127.0.0.1:포트:포트 |
| 컨테이너 간 내부 통신 | 같은 네트워크 + 포트 공개 불필요 |
| DB, 캐시를 외부로부터 격리 | -p 없이 사용자 정의 네트워크만 사용 |
주의할 점
-p 8080:80은 기본적으로 모든 네트워크 인터페이스에 바인딩되어 외부 접근이 허용된다. DB나 내부 관리 서비스는 -p 없이 내부 네트워크만 사용하거나, 반드시 127.0.0.1로 바인딩 범위를 제한해야 의도치 않은 외부 노출을 막을 수 있다.
docker run -d --name db -p 5432:5432 postgres:17
# 사실은 api 컨테이너만 써야 하는 DB인데 호스트 전체에 노출됨참고 링크
2 sources