Docker/Kubernets 정리 7

윤석주·2023년 4월 6일
0

docker

목록 보기
8/10

Containers & Networks

이번 포스팅에선 컨테이너에서의 네트워킹과 관련된 내용을 다루려고 합니다. 네트워킹에선 크게 3가지의 케이스와 관련된 내용을 살펴볼 예정입니다.

Case 1: Container to WWW Communication

우리가 만든 컨테이너 안에는 어플리케이션이 동작하고 있습니다. 이 어플리케이션이 어떤 API를 사용해야한다고 가정해봅시다. 네이버나 카카오처럼 WWW의 어딘가에 존재하는 API겠죠?

이런 API는 우리가 관리하는것이 아니라 특정 API사이트에서 관리하고 있을 겁니다. 이곳으로 GET, POST 등의 HTTP request를 보내야 하는 것이죠. 이는 어플리케이션 개발시 흔히 나타나는 패턴입니다.

우리의 어플리케이션은 컨테이너 내부에서 실행되고 있습니다. 이 말은 컨테이너의 내부에서 컨테이너의 외부(외부 API)로 HTTP 통신이 가능해야 한다는 것 입니다.

우리가 살펴볼 첫 번째 케이스는 컨태이너 내부와 외부의 네트워킹입니다.

Case 2: Container to Local Host Machine Communication

Dockerized app의 두 번째 커뮤니케이션 케이스는 호스트머신과의 커뮤니케이션입니다. 예를 들면 도커 없이 호스트 머신에서 동작하고 있는 DB접근 등이 있을 수 있습니다. 두 번째 케이스는 컨테이너 내부와 호스트 머신간의 네트워킹입니다.

Case 3: Container to Container Communication

세 번째 케이스는 컨테이너와 컨테이너간의 네트워킹입니다. 예를 들어 위에서 말한 호스트머신의 데이터베이스를 Dockerized app으로 컨테이너를 띄워 생성했다고 가정해봅시다. 이제 우리의 어플리케이션은 다른 컨테이너 내부에 있는 DB에 접근해야 합니다. 이런 상황에선 컨테이너와 컨테이너간의 커뮤니케이션이 필요합니다.

지금까지는 컨테이너 하나에 하나의 어플리케이션만 가정했지만, 현실에선 여러 컨테이너간의 소통이 필요한 경우가 존재합니다. 세 번째 케이스는 컨테이너와 컨테이너간의 네트워킹입니다.

Creating a Container & Communicating to the Web

특정 어플리케이션을 컨테이너 안에서 실행하면서 fetch 등의 기능을 이용해 외부 API를 사용해야 한다고 가정해봅시다. 먼저 docker run 명령어를 통해 어플리케이션을 컨테이너 내부에 올려놓을겁니다. 예를 들면 아래와 같은 명령어를 이용할겁니다.

docker run --name favorites -d --rm -p 3000:3000 favorites-node

dockerized된 어플리케이션에서 request를 보내는 것은 포트만 제대로 바인딩한다면 별도의 설정이 없어도 잘 동작합니다. 즉, HTTP request는 dockerized되지 않은 어플리케이션과 동일하게 사용가능합니다.

Making Container to Host Communication Work

dockerized된 어플리케이션에서 localhost에 접속하려고 하면 에러가 발생합니다. host machine과 커뮤니케이션 하기 위해선 localhost를 사용하면 안됩니다. 대신 host.docker.internal를 사용합니다.

이 특별한 도메인은 도커가 판별할 수 있으며 Docker container 내부에서 보이는 host machine의 IP주소로 해석합니다.

host machine에 DB 인스턴스등을 올려놓고 테스트를 진행해보면 localhost는 접근할 수 없지만 host.docker.internal은 정상적으로 동작하는 것을 확인할 수 있을겁니다.

Container to Container Communication

이제 Container와 Container사이의 커뮤니케이션을 살펴보겠습니다. 두 개의 컨테이너에 각각 어플리케이션과 어플리케이션에서 접근하려는 데이터베이스 인스턴스가 떠 있는 경우를 가정해봅시다.

dockerized된 데이터베이스 인스턴스가 떠 있는 상황에 다음과 같은 명령어를 실행해봅시다.

docker container inspect ${db_container_name}

그러면 다음과 같은 내용을 확인할 수 있습니다.

{
  ...
  "Gateway": ...
  "GlobalIPv6Address": ...
  "GlobalIPv6PrefixLen": ...
  **"IPAddress": ...**
  ...
}

"NetworkSettings" 하위 항목에 "IPAddress"를 찾을 수 있을 겁니다. 여기서 표시되는 ip address가 container의 ip 주소이며 이 주소를 어플리케이션 코드 내부에서 사용하면 정상적으로 다른 컨테이너에 접근하는 것을 확인할 수 있습니다(포트 번호만 주의하면 됩니다).

Introducing Docker Networks

docker container inspect 명령어를 통해 다른 컨테이너와 커뮤니케이션하는 방법을 살펴봤지만, 편의성과 확장성 면에서 좋지 않다는 것을 금방 느꼈을 것이라 생각합니다.

컨테이너간의 Network를 생성하면 이런 문제를 해결할 수 있습니다. 여러대의 컨테이너가 있는 경우를 가정해봅시다.

도커는 위와 같은 상황에 여러 컨테이너를 하나의 네트워크로 묶어주는 기능을 제공합니다.

docker run --network 명령어를 사용하면 도커는 컨테이너가 서로 커뮤니케이션 할 수 있는 네트워크를 생성하며 위에서 직접 하던 IP look up과 resolving을 자동으로 실행해줍니다.

먼저, 컨테이너를 생성하기 전 네트워크를 생성합니다.

docker network create ${net_name}

위 명령어를 사용하면 Docker internal network를 생성할 수 있습니다.
이제 컨테이너를 다음과 같은 방법으로 실행합니다.

docker run -d --name ${container_name} --network ${net_name} ${image}

--network 옵션을 통해 우리가 생성한 Network를 사용하도록 할 수 있습니다. 이렇게 서로 같은 Internal Network로 묶인 컨테이너는 컨테이너명을 사용해 서로 커뮤니케이션 할 수 있습니다.

위에서 IPAddress로 하드코딩 되어있던 어플리케이션 코드를 컨테이너명으로 대체하여 적용해보면 다른 컨테이너에 잘 접근하는 것을 확인할 수 있습니다.

즉, 핵심은 다음과 같습니다.

  1. Docker Internal Network를 생성하여 컨테이너를 묶는다.
  2. Internal Network 내부의 컨테이너들은 컨테이너명을 통해 상호간 커뮤니케이션이 가능하다.

도커는 컨테이너를 생성한 환경에 대한 정보를 갖고 있기에, 다른 컨테이너에 보내는 request를 자동으로 바인딩하여 이러한 기능을 제공합니다.

도커 네트워크는 여러 종류의 Driver를 지원합니다. 기본 드라이버는 "bridge"라는 드라이버로 위에서 살펴봤던 내용을 지원합니다. (i.e. Containers can find each other by name if they are in the same Network)
드라이버는 --driver 옵션을 통해 세팅할 수 있습니다.
docker network create --driver ${driver_name} ${net_name}
도커는 아래와 같은 드라이버를 지원하며 일반적으로 bridge를 가장 많이 사용합니다.

  • host: For standalone containers, isolation between container and host system is removed (i.e. they share localhost as a network)
  • overlay: Multiple Docker daemons (i.e. Docker running on different machines) are able to connect with each other. Only works in "Swarm" mode which is a dated / almost deprecated way of connecting multiple containers
  • macvlan: You can set a custom MAC address to a container - this address can then be used for communication with that container
  • none: All networking is disabled
  • Third-party-plugins: You can install third-party plugins which then may add all kinds of behaviors and functionalities

출처

profile
웹 개발을 공부하고 있는 윤석주입니다.

0개의 댓글