Skip to content
VDS · Docker 및 컨테이너

Docker 네트워크와 포트 포워딩

컨테이너가 서로를 어떻게 보는지, 포트 게시가 단순 EXPOSE와 어떻게 다른지, Docker가 ufw 규칙을 우회하는 이유를 알아봐요.

업데이트 2026년 8월 23일

컨테이너 문제의 절반은 네트워크와 관련되어 있어요. 서비스가 데이터베이스에 접근하지 못하거나, 포트가 이미 사용 중이거나, 제어판이 갑자기 인터넷 전체에 노출되는 경우죠. 어떻게 작동하는지 하나씩 살펴볼게요.

세 가지 네트워크 유형

  • bridge — 기본값이에요. 컨테이너가 내부 주소를 받고 서로 통신하며, 호스트의 NAT를 통해 외부로 나가요.
  • host — 컨테이너가 호스트의 네트워크를 직접 사용해요. 포트 게시가 필요하지도 않고 작동하지도 않아요. 빠르지만 격리가 없어요. 컨테이너의 80번 포트가 곧 호스트의 80번 포트예요.
  • none — 네트워크가 전혀 없어요. 네트워크가 필요 없는 작업에 사용해요.

직접 만들거나 Compose가 만든 사용자 정의 네트워크는 기본 bridge와 중요한 차이가 하나 있어요. 바로 이름 확인이 작동한다는 점이에요. app 컨테이너가 db라는 이름으로 db 컨테이너에 접근할 수 있어요.

docker network create backend
docker network ls
docker network inspect backend

Compose에서는 이런 네트워크가 프로젝트마다 자동으로 생성돼요.

포트 게시

ports:
  - "127.0.0.1:8080:8080"   # accessible only from the machine itself
  - "80:80"                 # accessible to the whole internet

왼쪽은 호스트의 포트, 오른쪽은 컨테이너 내부의 포트예요. 이미지의 EXPOSE 지시문은 아무것도 게시하지 않아요. 애플리케이션이 어느 포트에서 수신 대기하는지에 대한 메모일 뿐이에요.

규칙은 간단해요. 외부에서 접근해야 하는 것만 게시하세요. 데이터베이스, 제어판, 내부 API는 127.0.0.1에 두고, 인증서가 있는 웹 서버가 이들을 외부에 노출해요.

Docker는 iptables 규칙을 스스로 작성하며, ufw가 관리하는 체인보다 먼저 작성해요. -p 8080:8080으로 게시된 포트는 ufw가 "deny"를 표시하더라도 인터넷에서 접근할 수 있어요. 방화벽에 의존하지 말고 포트를 127.0.0.1에 바인딩하세요.

컨테이너 간 통신

services:
  app:
    networks: [frontend, backend]
  db:
    networks: [backend]
  proxy:
    networks: [frontend]
    ports:
      - "80:80"
      - "443:443"

networks:
  frontend:
  backend:

여기서는 데이터베이스가 애플리케이션에서만 접근 가능하고, 웹 서버만 외부를 향해요. 어떤 스택에도 올바른 구성이에요.

컨테이너 내부에서는 서비스 이름으로 이웃을 참조하세요. postgres://db:5432/app. 컨테이너 내부의 localhost 주소는 호스트가 아니라 컨테이너 자신을 의미해요. latest 다음으로 흔한 실수죠.

호스트 자체에서 실행 중인 서비스에 컨테이너에서 접근하려면 host.docker.internal 이름을 사용하고 다음을 추가하세요.

extra_hosts:
  - "host.docker.internal:host-gateway"

진단

docker compose exec app ping -c2 db
docker compose exec app getent hosts db
sudo ss -tulpn | grep LISTEN
docker port <container>

ss는 포트가 실제로 어느 인터페이스에서 수신 대기하는지 보여줘요. 0.0.0.0:8080 — 외부에 열려 있음, 127.0.0.1:8080 — 열려 있지 않음.

흔한 실수

  • "포트가 이미 사용 중". 다른 컨테이너나 호스트 서비스가 점유하고 있어요. sudo ss -tulpn | grep :80으로 원인을 찾을 수 있어요.
  • 서로 다른 Compose 프로젝트의 컨테이너가 서로를 볼 수 없어요. 각 프로젝트에는 자체 네트워크가 있어요. networks: { shared: { external: true } }로 명시적으로 연결하세요.
  • 애플리케이션이 컨테이너 내부의 127.0.0.1에서 수신 대기해요. 그러면 게시해도 소용없어요. 컨테이너 외부에서 접근할 수 없어요. 애플리케이션이 0.0.0.0에서 수신 대기하도록 설정하세요.
  • 대역폭. 호스트당 최대 500 Mbps를 공유해요. 파일 배포는 다른 모든 것과 대역폭을 나눠 써요.