Docker Container는 기본적으로 Network가 단절된 상태로 올려지게 된다. 그렇기에 Dockerfile이나 Compose에서 “EXPOSE”, “PORTS” 들을 설정해주는 것이다.

여기서 하나의 의문이 든다. “Nginx도 하나의 컨테이너, Spring Boot Application도 하나의 컨테이너라면, Nginx에서 Reverse Proxy 설정으로 Spring Boot에 접근할 수 있도록 하려면 어떻게 해야하는가?”

이번 년도에 프로젝트 여러 개를 시작하면서 계속 들었던 의문이자 MSA 구축하면서 가장 공부하고 싶었던 부분이기도 하다.

이를 해결하기 위해 Docker Network를 공부해야 한다.

Docker Network

Docker Network는 초기에 존재하던 ‘–link’ 옵션을 대체하기 위해 만들어진 네트워크 모듈로서, Docker Daemon 안에 올라가있는 Container 간 연결할 수 있도록 돕는 논리적 네트워크이다.

Driver는 총 5개(None 미포함)를 제공하고 있으며 이 중 가장 많이 사용되는 Driver는 Bridge와 Host이다.

  • Bridge
    • Default Driver로서 각 컨테이너는 StandAlone으로 독자적인 실행이 가능하며 Communication으로서의 Network 연결이 필요할 때 사용한다. 흔히 집에서 사용하는 IPTIME과 동일한 역할을 한다.
  • Host
    • Docker에서의 Network Isolation을 제거, Host에서 직접 네트워크를 사용한다. Swarm에서 사용 가능하다.
  • Overlay
    • 위 2개가 Container 수준에서의 Communication을 논한다면, Overlay는 Docker Daemon을 연결하여(물리적으로서의 여러 대 서버) 통신할 수 있도록 한다.

필자의 경우, Bridge만을 사용하고 있으며 하나의 Network안에 Nginx를 설치, 유일하게 Port를 뚫어 내부 컨테이너들을 Reverse Proxy로 매칭시킨다.

기본적인 명령어

  1. docker network ls 현재 docker daemon에 등록되어있는 network 리스트를 보여준다. docker daemon 시작 시에 기본적으로 생성된 네트워크들을 볼 수 있으며 사용자 Custom 네트워크를 생성할 시 추가되어 보여진다.

  2. docker network inspect {name} network 별 상세정보를 확인 할 수 있다. Name, Id 부터 시작하여 여러 설정 값, 등록되어있는 Container들의 정보를 알 수 있다.

  3. docker network create {name} network를 생성하는 명령어. ‘–help’로 여러 옵션을 확인 할 수 있다.
    gateway 주소는 임의대로 설정되며 위에서 언급했듯 특별한 설정이 없으면 Bridge Network로 만들어진다.

  • 주로 사용되는 option
    • ’–driver’ : network의 driver를 지정할 수 있다.
    • ’–subnet’ : network IP subnet을 직접 지정해줄 수 있다.
    • ’–ip-range’ : network 내 할당 가능한(Allocate) 범위를 지정할 수 있다. Subnet은 CIDR, 네트워크 대역을 지정하는것이고 ip-range는 실제 할당이 되는 ip 범위를 지정하는 것이다.
  1. docker network rm {name} network를 삭제하는 명령어.

Container 연결

이번 포스트에서 실질적으로 얘기하고싶은 섹션이다.
사용자가 직접 생성한 Network에 Container가 올리고자 할 때 어떤 명령어를 넣어야 하는지, 어떤 옵션을 고려해야 하는지 확인해본다.

  1. 기본적인 docker network 연결
    • 이미 Container가 올려져 있고, network 또한 미리 생성되어있을 때 사용하는 명령어이다.
    • docker network connect {name} {container}

  • Container를 새로 올리고자 하 때 Network 추가옵션을 넣는 명령어
    • docker run -d … –network {name} …

  • 가장 기본적으로 Container에 Network 연결이 가능한 방법이지만, 일일히 명령어를 쳐야하는 귀찮음과 컨테이너가 많아질수록 관리하기 다소 어렵다는 단점을 가지고 있다.
  • IP는 network에 설정되어있는 Gateway IP/Subnet에 따라 임의설정된다. (컨테이너 간 IP 연결을 하려면 추가설정이 필요하다는 말…)
  1. docker-compose에서 network 연결 필자는 docker-compose 파일에서 network를 설정했다.
    실제 서버에서 Nginx 컨테이너를 올리는 docker-compose 파일이다.
version: '3.8'
services:
  nginx_proxy:
    container_name: nginx
    hostname: nginx
    image: nginx:1.0
    ports:
      - "80:80"
      - "8080:8080"

......

    networks:
      msa: # msa라는 network에 등록한다.
        ipv4_address: 172.18.1.2 # ip4 address를 고정한다.
    restart: unless-stopped

networks:
  msa:
    external: true

    ......

위 설정파일을 보면, 마지막에 networks 값이 보인다. docker-compose는 이미 존재해있는 docker network 객체를 실행 시에 알아보지 못한다. 그렇기 때문에 ‘msa’라는 network가 외부(external)에 존재한다는 것을 명시해주어야 한다.
→ 이 설정을 모른 상태에서 compose로 network 연결하려니 도저히 성공하지를 못해서 정말 많이 찾아봤던 기억이 있다.

Spring Application API를 만들고 Port EXPOSE를 한다고 해서 모든 컨테이너가 API를 날릴 수 있는게 아니었다. 같은 네트워크 안에 있어야 가능한 일이었다.

이를 응용하면 여러가지 형태의 네트워크를 구성할 수 있다. Nginx같이 Host 네트워크와 직접적으로 통신하는 컨테이너는 DMZ 역할을 하는 네트워크와 내부망 역할을 하는 네트워크에 모두 연결되어 통로 역할을 부여할 수도 있으며, DB 네트워크를 별도로 생성하여 허용된 Container만 접속이 가능하도록 설정이 가능하다.

Written on April 23, 2022