프록시 호스트에 webserver를 적었는데 요청이 webserver 컨테이너에 닿지 않았다. 컨테이너는 떠 있었고, docker ps로 보면 Up 15 minutes 상태였다. 개발 중인 시스템에서 Nginx Proxy Manager(이하 NPM)가 외부 요청을 내부 웹서버로 넘기는 구조였는데, 그 연결 하나가 끊겨 있었다.
컨테이너 간 트래픽 전달은 Docker에서 가장 기본적인 영역이라 오히려 늦게 의심하게 된다. 컨테이너가 살아 있어도 같은 네트워크에 있지 않으면 서로의 이름을 모른다. 이 글은 두 컨테이너가 어느 네트워크에 붙어 있는지 확인한 데서 시작해, 이름으로 찾지 못한 이유와 네트워크를 다시 연결해 해결한 방법까지 정리한다.

두 컨테이너는 서로 다른 네트워크에 있었다
NPM은 리버스 프록시다. 어느 컨테이너에 트래픽을 넘길 수 있는지는 NPM과 대상 컨테이너가 어떤 네트워크에 할당되어 있는지로 정해진다. 두 컨테이너의 네트워크부터 확인했다.
docker ps | grep webserver
╰─❯
ae0f096ac981 httpd "httpd-foreground" 15 minutes ago Up 15 minutes 0.0.0.0:8888->80/tcp webserver
docker network ls
╰─❯
NETWORK ID NAME DRIVER SCOPE
ba99d5799e32 3vi-waf-npm_network bridge local
a2053532b62f bridge bridge local
1db1d050373f docker_default bridge local
8af1a1b95e98 host host local
b383f6e17a69 none null local
bbf73a74ebdb npm_network bridge local
docker inspect webserver | grep -A 10 "Networks"
╰─❯
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "a20535.....",
"EndpointID": "c587d6.....",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
docker inspect npm_core | grep -A 10 "Networks"
╰─❯
"Networks": {
"npm_network": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"npm_core",
"npm",
"4d521a92b175"
],
"NetworkID": "bbf73a.....",
webserver는 기본 bridge 네트워크(172.17.0.3)에, NPM(npm_core)은 npm_network라는 별도 네트워크에 붙어 있었다. 두 출력의 차이는 Aliases에도 보인다. **npm_network 쪽은 컨테이너 이름이 Aliases로 등록되어 있고, 기본 bridge 쪽 webserver는 **null이다.
이름으로 찾지 못한 이유는 네트워크 격리다
Docker는 네트워크 단위로 컨테이너를 격리한다. 같은 호스트에 있어도 서로 다른 bridge 네트워크에 속한 컨테이너끼리는 기본적으로 통신이 막혀 있다. 여기에 이름 해석 문제가 겹친다. 사용자 정의 네트워크(npm_network 같은)는 Docker의 내장 DNS가 컨테이너 이름과 Alias를 풀어주지만, 기본 bridge 네트워크는 컨테이너 이름 기반 이름 해석을 제공하지 않는다.
그래서 NPM 프록시 설정에 webserver라는 이름을 적어도 NPM 입장에서는 풀 수 없는 이름이었다. 설정이 틀린 게 아니라, NPM이 bridge 네트워크의 webserver를 볼 수 없는 구조였다.

호스트를 돌아가지 않고 같은 네트워크에 붙였다
길은 두 가지였다. webserver가 호스트에 열어 둔 8888 포트를 이용해 NPM이 host.docker.internal:8888로 호스트를 거쳐 들어가거나, webserver를 NPM과 같은 네트워크에 추가로 붙이는 것이다.
호스트 경유는 컨테이너 밖으로 나갔다가 다시 들어오는 경로라 호스트 포트 매핑에 의존한다. 같은 네트워크에 붙이면 NPM이 컨테이너 이름과 컨테이너 내부 포트(80)로 바로 접근한다. 후자를 골랐다.
# webserver를 NPM이 있는 npm_network에 추가로 연결한다 (기존 bridge 연결은 유지)
docker network connect npm_network webserver
docker network connect는 기존 연결을 끊지 않는다. 이 명령 이후 webserver는 bridge와 npm_network 두 네트워크에 동시에 연결된 상태가 됐다. npm_network 안에서 webserver라는 이름이 풀리기 시작했고, 프록시 설정이 트래픽을 webserver 컨테이너로 직접 라우팅할 수 있게 됐다.

적용 결과: curl 한 번으로 확인했다
재구성한 네트워크에서 프록시를 통해 요청을 보냈다.
curl http://test.local
# 결과: "It works!"
It works!는 httpd 기본 페이지다. NPM이 test.local로 들어온 요청을 webserver:80으로 넘겼다는 뜻이다.
| 상태 | webserver 네트워크 | NPM과의 직접 통신 | 프록시 호스트 | 설명 | Forward Port |
|---|---|---|---|---|---|
| 적용 전 | bridge | 불가능 | host.docker.internal 필요 | 호스트를 거쳐서 통신 | 8888 |
| 적용 후 | bridge + npm_network | 가능 | webserver (직접 접근) | 컨테이너 간 직접 통신 (권장) | 80 |
Forward Port가 8888에서 80으로 바뀐 점이 핵심이다. 호스트에 매핑된 포트가 아니라 컨테이너가 실제로 듣는 포트로 바로 간다.
아직 남은 문제
docker network connect는 실행 중인 컨테이너에 대한 일회성 조치다. 컨테이너를 지우고 다시 만들면 연결이 사라진다. 재생성 후에도 유지하려면docker run --network나 Compose 파일의networks에 npm_network를 명시해야 한다.**webserver는 여전히 **
0.0.0.0:8888->80/tcp로 호스트에 열려 있다. 프록시를 거치지 않는 경로가 남아 있다는 뜻이다. NPM 앞단에서만 받으려면 포트 매핑을 걷어내는 것을 검토할 만하다.기본 bridge 연결도 그대로 남아 있다. 다른 이유로 필요한지 확인하지 않았다면, 불필요한 연결은
docker network disconnect bridge webserver로 정리할 수 있다.
정리
컨테이너가 떠 있다는 것과 통신할 수 있다는 것은 다른 문제다. 먼저
docker inspect로 서로 어느 네트워크에 있는지 본다.기본 bridge 네트워크에서는 컨테이너 이름이 풀리지 않는다. 이름으로 부르려면 사용자 정의 네트워크에 함께 있어야 한다.
docker network connect로 기존 연결을 유지한 채 네트워크를 하나 더 붙일 수 있다. 프록시 호스트를host.docker.internal:8888에서webserver:80으로 바꿀 수 있었다.런타임에 붙인 연결은 컨테이너를 다시 만들면 사라진다. 정의 파일에 남겨야 끝난다.
설정 한 줄 차이로 생긴 단절이었지만, 덕분에 컨테이너 네트워크가 어떻게 격리되고 어떻게 이름을 푸는지를 확인할 수 있었다. 운영 단계에서도 네트워크 연결 점검과 구조 변경은 반복해서 필요할 것이다. 프록시가 대상을 못 찾을 때는 프록시 설정보다 네트워크부터 본다.
참고자료
Docker Docs: Networking overview — Docker 네트워크 드라이버와 컨테이너 간 통신의 기본 개념
Docker Docs: Bridge network driver — 기본 bridge와 사용자 정의 bridge의 차이(이름 해석, 격리)
Docker Docs: docker network connect — 실행 중인 컨테이너를 네트워크에 추가로 연결하는 명령