docker-compose를 이용해서 로컬에서 stage 환경과 유사한 개발환경을 제공하는 프로젝트를 진행하면서 docker-compose up 명령을 2번이상 수행하게 되었을 때(docker-compose 의 수정사항으로 compose를 업데이트 하는경우) 컨테이너끼리의 컨테이너명으로는 통신이 불가능한 현상이 발생했고, 이를 해결하기 위해 리서치한 내용을 정리했다.
공식문서에서 크게 6가지 분류로 설명하고있다. 각 네트워크의 종류와 간략한 설명은 아래와 같다.
해당 오류를 직면하고, 관련 경험이 없다보니 많이 해맸고, 운이 좋게도 이것저것 시도해보다가 각 컨테이너의 네트워크 드라이버를 bridge
로 명시해주어 해결할 수 있었지만 이게 왜 내가 원하는대로 동작하는지 알 수 없었다.
나에게 그런 오류가 발생했던 이유는 docker의 기본 네트워크 드라이버중 Bridge
네트워크 드라이버에 함정이 있었기 때문이었다.
docker 공식문서에 network 페이지에는 의심갈만한 내용이 없지만, Bridge
네트워크를 사용하는 튜토리얼 페이지와 use Bridge network
페이지에서 특이한 내용이 있었다. 두 내용의 설명방법은 다르지만 같은 부분은 기본으로 제공되는 bridge
와 사용자가 정의한 bridge
를 구분해서 설명하고 있었다.
그리고 그 내용은 요것이었다.
User-defined bridges provide automatic DNS resolution between containers.
컨테이너이름으로 해당 컨테이너와 통신하는 기능은 automatic DNS resolution
이 제공되어 가능한 기능이었고, 컨테이너에 네트워크를 명시하지 않아서 할당되는 기본 Bridge
네트워크는 이 기능을 제공하지 않았고, 사용자가 정의하여 추가된 Bridge
네트워크는 이 기능을 제공한다는 것이다....
이때까지 docker-compose를 실행할때에 있어서 항상 컨테이너명으로 통신하도록 사용했다. 한 서비스가 다른 서비스와 통신을하기위한 엔트포인트도 모두 컨테이너명:포트
로 정의시켜놨었고, 잘 동작했었다.
하지만 도커의 문서대로라면 내가 생성하지 않은Bridge
네트워크를 사용하면 컨테이너명으로는 통신이 애초에 불가능해야했다.
그래서 docker-compose 공식문서의 network 파트를 살펴봤다.
By default Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.
컴포즈는 기본적으로 실행시키는 앱에 대해 단일 네트워크를 생성한다고 한다. 그래서 컨테이너명을 통해 통신이 가능하다.
이 내용또한 같은 문서에 존재했다.
If you make a configuration change to a service and run docker-compose up to update it, the old container is removed and the new one joins the network under a different IP address but the same name. Running containers can look up that name and connect to the new address, but the old address stops working.
If any containers have connections open to the old container, they are closed. It is a container’s responsibility to detect this condition, look up the name again and reconnect.
컨테이너가 업데이트 될 때, IP주소와 컨테이너이름의 연결은 컨테이너의 책임이다
그랬다. 공식문서에 너무나 친절이 내가 왜 불가능한지 다 적혀있었다.
컴포즈로 실행시 서비스 디스커버리는 제공하지 않았고, 난 기본으로 제공하는 Bridge 네트워크를 사용했기 때문에 컨테이너가 재실행될 때 변경된 IP와 컨테이너명의 연결이 불가능했었다.
정말 운좋게 내가 했던방법 Bridge 네트워크를 선언하고, 명시적으로 해당 네트워크 드라이버를 사용하도록 한게 올바른 해법이었다.
공식문서를 잘 읽도록 하자!