Develop

Docker 네트워킹 완벽 가이드 — 컨테이너 간 통신을 설정하는 방법

가상 컨테이너 통신망의 격리 구조를 해부하고, Docker Compose의 가상 DNS 해석 체계를 활용해 복잡한 포트 노출 없이 백엔드 앱과 DB를 안전하게 묶는 실무 네트워크 패킷 제어 방법론을 제시합니다.

Docker네트워킹Docker Compose컨테이너infra
Docker Compose에서 앱 컨테이너와 DB 컨테이너가 같은 네트워크로 연결된 구조 다이어그램
  • ·Docker의 기본 bridge 네트워크에서는 컨테이너 이름으로 다른 컨테이너에 DNS 접근이 불가능하고 IP로만 접근할 수 있다
  • ·Docker Compose가 생성하는 사용자 정의 네트워크에서는 서비스 이름이 DNS 이름으로 동작해 이름으로 컨테이너에 접근할 수 있다
  • ·ports로 호스트와 컨테이너 포트를 매핑하면 외부에서 접근 가능하고, expose는 같은 네트워크의 컨테이너에서만 접근 가능하다
  • ·Docker 네트워크 드라이버는 bridge, host, overlay, none 등이 있으며 용도에 따라 선택한다
도커를 처음 만지던 시절, Docker Compose로 Node.js API 서버와 PostgreSQL 데이터베이스 컨테이너를 함께 띄운 뒤, Node 앱 설정 파일의 DB 주소에 무심히 localhost:5432를 기입하고 켰는데 커넥션 타임아웃 에러를 얻어맞아 머리를 쥐어뜯었습니다. 한참을 헤맨 끝에야 도커 컨테이너 내부의 localhost는 호스트 PC가 아니라 '자기 자신 컨테이너 공간'을 뜻한다는 걸 깨달았습니다. 도커의 가상 네트워크 대역 메커니즘을 파헤치고, Compose의 내장 서비스 명칭(DNS) 링킹을 배워 postgresql://db:5432/ 형태로 매핑 주소를 교정하자마자 물 흐르듯 통신이 뚫리던 희열은 지금도 생생한 실무 거름이 되었습니다.

1. 가상 브릿지와 내장 DNS

Docker 브릿지 네트워크 격리 메커니즘과 컨테이너 가상 DNS 해석 원리

도커 데몬이 켜지면 호스트 OS 단에 가상의 네트워크 스위치 역할을 하는 docker0 브릿지가 개설됩니다. 컨테이너들은 이 브릿지에 물리 가상 이더넷 카드를 하나씩 꼽아 격리된 IP를 할당받아 살아갑니다. 기본 브릿지 넷에 매칭된 컨테이너끼리는 불행히도 유동적으로 변하는 가상 IP 주소로만 직통 통신해야 해서 불편하죠. 하지만 사용자가 명시적으로 네트워크 공간을 커스텀 정의하여 묶어두면, 도커 내장 DNS 서버가 상주하여 컨테이너 이름(예: web-server, mysql-db)을 IP 주소로 번역 매핑해 주므로, 정적 호스트 이름 기반의 영속성 있는 상호 접속 환경이 안전하게 성립됩니다.

2. 포트 바인딩과 expose의 보안 경계

Docker Compose ports 외부 포털 개방과 expose 내부 격리용 포트 제어 기법

도커 컴포즈 YAML 설정을 매만질 때 포트를 가두고 여는 보안 경계 구분이 매우 중요합니다. ports 설정은 호스트 OS의 실제 네트워크 포트와 가상 컨테이너 포트를 통과 링킹시켜 외부 공인 인터넷 유저들의 통신 패킷을 안쪽으로 유입시키죠. 반면 expose 지시어는 외부 포털로는 포트를 전혀 개방하지 않고, 오직 동일한 도커 가상 네트워크 망에 묶인 컨테이너 동료들 사이에서만 통로를 개방하는 방패막 역할을 합니다. 해커들이 외부에서 포트 스캔으로 DB에 무단 침투하는 걸 완벽히 원천 차단하기 위해, 백엔드 DB 컨테이너는 ports를 철저히 닫고 expose만 매핑해 두는 것이 클라우드 보안 아키텍처의 철칙입니다.

# docker-compose.yml
services:
  app:
    build: .
    ports:
      - '3000:3000'
    environment:
      DATABASE_URL: postgresql://user:pass@db:5432/mydb
    depends_on:
      - db
    networks:
      - app-network

  db:
    image: postgres:16-alpine
    expose:
      - '5432'
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Docker 네트워크 디버깅과 컨테이너 간 통신 문제를 해결하는 방법

컴포즈 가동 중 네트워크 트러블이 생기면 docker network inspect 명령어로 IP 배치와 컨테이너 바인딩 로그를 확인해야 합니다. 특정 컨테이너 쉘에 docker exec -it로 진입해 ping이나 curl 요청을 던지는 유틸리티 진단법을 통해 DNS 도메인 링킹 통신 문제를 수월하게 헤쳐 나갈 수 있습니다.

3. 네트워크 세그멘테이션

프로덕션 환경을 방어하는 Docker 네트워크 세그멘테이션 분리 격리 노하우

단일 가상 네트워크 통로에 웹서버, API, DB, Redis, 배치 워커를 몰아두는 것은 보안 세그멘테이션 관점에서 안일한 아키텍처입니다. 만약 웹서버 하나가 해킹으로 털리면 해커가 동일 넷 상의 DB 컨테이너로 손쉽게 가로채기 침투를 감행할 수 있기 때문입니다. 이를 방어하기 위해 외부 패킷을 받는 Nginx 리버스 프록시와 웹 앱이 노는 frontend-net, 그리고 웹 앱과 DB/Redis만 격리 통신하는 backend-net으로 네트워크 존을 물리적으로 분할 매핑해야 합니다. DB는 바깥쪽 네트워크 인터페이스 자체가 물리 차단되어 한결 안전한 요새화가 완성됩니다.

자주 묻는 질문

서로 다른 docker-compose.yml 파일로 띄운 독립된 컨테이너끼리도 통신이 가능한가요?+

네, 충분히 가능합니다. 한쪽 컴포즈 파일에서 네트워크 드라이버 설정을 external: true 로 지정하여 외부에서 미리 만들어둔 글로벌 가상 브릿지 넷(docker network create shared-net)을 상속 참조하게 세팅해 두면, 별개 파일로 기동 중인 서비스 컨테이너들끼리도 이름 기반으로 거침없이 통신을 개시합니다.

docker-compose up으로 기동 시 데이터베이스 컨테이너가 켜지기도 전에 백엔드 앱이 먼저 켜져서 DB 연결 실패 에러로 터집니다.+

단순히 depends_on: [db] 설정만 걸어두면 도커는 db 컨테이너의 '프로세스가 시작된 시점'만 보고 바로 앱을 켜버리기 때문입니다. DB 커널이 내부 부팅을 끝마칠 때까지 대기하려면 db 쪽에 healthcheck 설정을 추가하고, 앱 쪽에는 depends_on: { db: { condition: service_healthy } } 조건을 가미해 주시면 정교하게 부팅 타이밍을 맞출 수 있습니다.

관련 글