빌드노트
기본 bridge에서 컨테이너 IP는 되는데 이름은 안 풀릴 때
Docker 기본 bridge의 IP 통신과 컨테이너 이름 해석은 별개다. 같은 두 컨테이너의 IP 요청·이름 조회를 비교하고, 사용자 정의 bridge를 추가했을 때 이름으로 HTTP 응답을 받은 결과와 적용 명령을 설명한다.
앱 컨테이너에서 상대 컨테이너의 IP로 요청하면 응답하는데, 같은 포트에 컨테이너 이름으로 요청하면 주소를 찾지 못할 수 있다. 두 컨테이너가 Docker의 기본 bridge에만 붙어 있다면 먼저 네트워크 선택을 확인한다. 기본 bridge는 컨테이너 간 IP 통신을 지원하지만 컨테이너 이름의 자동 해석은 제공하지 않는다. 같은 사용자 정의 bridge에 연결하면 이름으로 서로를 찾을 수 있다. Docker bridge의 이름 해석 조건 (새 탭에서 열림)
docker ps에 이름이 보인다는 사실과 앱 안에서 그 이름이 IP로 풀린다는 사실은 다르다. 여기서는 이름을 상대 컨테이너의 IPv4 주소로 바꾸는 단계와, 그 주소의 HTTP 서버에 요청하는 단계를 나누어 확인한다.
우선 두 컨테이너가 붙은 네트워크를 본다
다음은 Docker CLI를 사용할 수 있는 PowerShell 7 터미널에서 실행하는 조회다. $app은 실패한 요청을 보내는 컨테이너, $api는 응답해야 하는 컨테이너의 실제 이름으로 바꾼다. 명령은 각 컨테이너의 이름과 연결된 네트워크를 한 줄씩 출력한다.
$app = '앱-컨테이너-이름'
$api = '서버-컨테이너-이름'
docker inspect --format '{{.Name}} {{json .NetworkSettings.Networks}}' $app $api
두 출력에 공통으로 있는 네트워크의 NetworkID가 같은지 보고, 그 네트워크에서 서버에 배정된 IPAddress를 읽는다. 양쪽에 기본 bridge만 있다면 이번 글의 비교 조건과 같다. 서로 다른 네트워크라면 먼저 두 컨테이너가 함께 통신할 네트워크를 정해야 한다. 드라이버가 bridge라는 것만으로 기본 네트워크라고 판단하지는 않는다. 사용자가 만든 네트워크도 같은 드라이버를 쓴다. 컨테이너 조회 명령 (새 탭에서 열림)
별도로 만든 실습에서는 Windows 11의 Docker Desktop 4.92.0, Linux 컨테이너용 Engine 29.8.0, 컨테이너 안의 Python 3.12.14를 사용했다. 새 클라이언트와 합성 HTTP 서버를 기본 bridge에 붙였다. 서버는 컨테이너 안의 0.0.0.0:8000에서 요청을 받았으며, 호스트 포트 공개와 수동 호스트 항목, --link 설정은 없었다. 두 컨테이너의 NetworkID는 같았고 서버 IP는 172.17.0.2였다.
IP 요청과 이름 조회를 같은 출발점에서 비교한다
아래 명령은 요청을 보내는 $app 컨테이너에 Python 3가 있을 때 사용할 수 있다. $ip에는 앞서 확인한 서버 IP를 넣는다. 코드의 8000은 서버가 컨테이너 안에서 실제로 듣는 HTTP 포트로, /는 조회해도 되는 경로로 맞춘다. 이 예제는 HTTP 서버용이며 HTTPS 서비스에 그대로 적용하지 않는다. 첫 요청은 IP 통신, 다음 줄은 이름 해석, 마지막 요청은 이름을 이용한 전체 경로를 확인한다.
$ip = '172.17.0.2'
$http = "import http.client,sys; c=http.client.HTTPConnection(sys.argv[1],8000,timeout=2); c.request('GET','/'); r=c.getresponse(); print(r.status,r.read().decode().strip()); c.close()"
docker exec $app python -c $http $ip
docker exec $app python -c "import socket,sys; print(socket.gethostbyname(sys.argv[1]))" $api
docker exec $app python -c $http $api
실습에서 IP 요청은 200 bridge-dns-ok를 출력했다. 이어서 서버 이름을 조회하자 socket.gaierror: [Errno -2] Name does not resolve가 나왔고, 이름으로 보낸 HTTP 요청도 같은 이름 해석 오류로 끝났다. 여기의 IP와 응답 본문은 실습 값이다. 자신의 서버 IP로 바꾸고 해당 서비스의 정상 상태 코드와 응답 내용을 확인한다.
이 비교에서 IP 요청 성공은 그 주소의 서버와 8000 포트까지 도달했다는 근거다. 이름 요청은 서버에 도착하기 전 주소를 구하는 단계에서 실패했다. 따라서 이 경우에는 서버 포트부터 바꾸기보다 기본 bridge의 이름 해석 조건을 살펴보는 것이 맞다. Python의 gethostbyname은 IPv4 이름 해석을 확인하는 함수이며, DNS 패킷 자체를 분석하는 명령은 아니다. Python의 IPv4 이름 해석 (새 탭에서 열림)
IP 요청도 실패하면 이번과 같은 원인이라고 결론 내릴 수 없다. 잘못 읽은 IP, 수신 포트, 서버 준비 상태와 bind 주소를 먼저 확인한다. 이름 조회는 성공하지만 요청이 거절되거나 시간 초과가 나도 연결 단계의 문제를 따로 봐야 한다. python 실행 파일을 찾지 못한 오류는 진단 도구가 없는 것이므로 네트워크 실패로 세지 않는다.
이름을 쓸 두 컨테이너를 같은 사용자 정의 bridge에 연결한다
기본 bridge에 컨테이너 이름 해석을 기대하며 IP를 고정하기보다, 두 컨테이너가 공유할 사용자 정의 bridge를 만든다. 다음 명령은 앞의 $app, $api를 유지한 채 실행 중인 컨테이너에 네트워크를 추가하는 예다. $network에는 아직 쓰지 않는 새 이름을 정하고, 생성과 각 연결이 성공했는지 확인한 뒤 다음 줄로 진행한다. 네트워크 생성 (새 탭에서 열림), 실행 중인 컨테이너 연결 (새 탭에서 열림)
$network = 'app-dns-net'
docker network create --driver bridge $network
docker network connect $network $app
docker network connect $network $api
실습에서도 같은 두 컨테이너를 그대로 두고 새 bridge에 추가 연결했다. 서버 프로세스, 컨테이너 이름과 포트는 바꾸지 않았다. 새 네트워크를 조회해 양쪽의 연결을 확인한 다음, 앞에서 실패했던 이름 조회와 HTTP 요청을 다시 실행했다.
docker network inspect $network --format '{{.Name}} driver={{.Driver}} {{range .Containers}}{{.Name}}={{.IPv4Address}} {{end}}'
docker exec $app python -c "import socket,sys; print(socket.gethostbyname(sys.argv[1]))" $api
docker exec $app python -c $http $api
network inspect에는 새 네트워크의 드라이버가 bridge로 나왔고 클라이언트와 서버의 IPv4Address는 각각 172.27.0.2/16, 172.27.0.3/16이었다. 이어서 서버 이름 조회는 172.27.0.3을, 이름으로 보낸 요청은 200 bridge-dns-ok를 출력했다. 이름이 새 네트워크에 배정된 서버 IP로 풀렸고 그 이름으로 실제 응답도 받았다. 네트워크 조회 명령 (새 탭에서 열림)
따로 별칭을 추가하지 않아도 컨테이너 이름으로 조회할 수 있었다. 사용자 정의 네트워크에서는 Docker의 내장 DNS를 사용한다는 문서 설명과 일치하며, 연결 뒤 클라이언트의 /etc/resolv.conf에서도 nameserver 127.0.0.11을 확인했다. 이 결과는 다른 인터넷 도메인의 DNS까지 정상이라는 뜻은 아니다. Docker의 DNS 서비스 (새 탭에서 열림)
network connect는 기존 연결을 없애는 명령이 아니다. 이번 비교에서도 기본 bridge 연결을 남긴 채 새 네트워크를 더했다. 이후에도 같은 구성을 쓰려면 컨테이너를 생성하는 배포 설정에 사용자 정의 네트워크를 반영한다. 새 docker run의 네트워크 선택은 --network 네트워크이름으로 지정할 수 있다. 이렇게 해야 컨테이너를 다시 만들 때 수동 연결이 빠지는 일을 피할 수 있다.
같은 사용자 정의 bridge의 컨테이너끼리 요청하는 데 호스트의 -p 포트 공개를 추가할 필요는 없다. 앱의 목적지는 상대 컨테이너 이름과 내부 수신 포트다. 이 실습은 한 Docker Engine 안의 Linux 컨테이너 간 IPv4 통신을 확인했다. 호스트나 외부 PC에서의 접속, 인터넷 DNS 전체 동작, IPv6와 여러 호스트 간 통신은 검증하지 않았다. Docker의 포트 공개 범위 (새 탭에서 열림)