Docker - 네트워크

문한성·2023년 4월 13일
0

공부

목록 보기
24/28
post-thumbnail

도커 네트워크 구조

기본적으로 도커를 호스트 운영체제에 설치하면 여러가지 네트워크 드라이버들이 설치되며 IP 주소를 순차적으로 할당하고 도커 컨테이너를 실행할 때 사용하고 싶은 네트워크 드라이버를 선택할 수 있습니다.

기본적으로 도커는 컨테이너에 172.17.0.x의 IP를 순차적으로 할당합니다. 확인해보기 위해 아래의 명령어로 컨테이너를 생성해줍니다.

docker run -it ubuntu:focal

그리고 컨테이너 내부에서 ifconfig 명령어로 컨테이너의 네트워크 인터페이스를 확인합니다.

위 스크린샷을 보면 lo 네트워크 인터페이스와 eth0 네트워크 인터페이스가 각각 172.17.0.1과 172.17.0.2가 할당된 것을 확인할 수 있습니다. 이 IP들은 내부 IP로 아무런 설정을 하지 않았다면 이 컨테이너는 외부에서 접근할 수 없으며 도커가 설치된 호스트 내부에서만 접근할 수 있습니다.

외부에 컨테이너 어플케이션을 노출하기 위해서는 eth0의 IP포트를 호스트의 IP와 포트에 바인딩해야 합니다.

외부와의 네트워크 연결은 컨테이너마다 eth0에 대응되는 veth라는 가상 네트워크 인터페이스를 호스트에 생성함으로써 이루어집니다. 그리고 각각의 IP 주소와 포트를 입력해 컨테이너를 외부에 노출 시킬 수 있습니다. veth는 도커 호스트에서 ifconfig 명령어를 입력하면 확인 가능합니다.

즉, eth0에 대응되는 vethXXXX이라는 이름의 veth interface와 브릿지 네트워크에 컨테이너의 interface가 바인딩되는 형태로 통신합니다.

veth 인터페이스는 사용자가 직접 생성할 필요는 없고 컨테이너가 생성될 때 도커 엔진이 자동으로 생성합니다. 도커 컨테이너가 실행될 때 네트워크 드라이버를 따로 지정하지 않으면 docker0라고 하는 브릿지 네트워크를 default로 사용합니다. 이 브릿지 네트워크의 역할은 veth와 호스트의 eth0의 다리 역할을 합니다.

veth란?

리눅스의 virtual ethernet interface, virtual eth를 의미. 랜카드에 연결된 실제 네트워크 인터페이스가 아니라 가상으로 생성한 네트워크 인터페이스 입니다. 일반적인 네트워크 인터페이스와는 달리 패킷을 전달받으면, 자신에게 연결된 다른 네트워크 인터페이스로 패킷을 보내주는 식으로 동작하기 때문에 항상 쌍(pair)로 생성해줘야 합니다. 한 쪽에서 다른 쪽으로 패킷을 전송할 수 있으며, 한 쪽이 다운된 경우 나머지 한 쪽도 정상적으로 기능하지 않는 것이 특징입니다. 도커에서는 실행중인 컨테이너 수 만큼 veth로 시작하는 인터페이스가 생성됩니다.

도커 컨테이너 Port를 외부에 노출

컨테이너 포트 연결 명령어

$ docker run -p [HOST IP:PORT]:[CONTAINER PORT] [CONTAINER NAME]

-p: publish 옵션. 호스트 ip 포트를 Container Port와 매핑시키는 역할을 합니다.

아래의 예제들로 포트연결을 해보겠습니다.

예제1. nginx 컨테이너의 80번 포트를 호스트의 모든 IP의 80번 포트와 연결하여 실행

$ docker run -d -p 80:80 nginx

위의 명령어는 호스트의 80번 포트와 컨테이너의 80번 포트를 연결합니다.

실행결과
0.0.0.0:80 -> 80/tcp -> 위의 실행결과에서 Port를 해석하면 모든 호스트 IP의 80번 포트는 컨테이너의 80번 포트로 매핑이 된다는 것을 의미합니다.

curl로 호스트의 80번 포트를 접근해보면 nginx가 출력되는 것을 확인할 수 있습니다.

예제2. nginx 컨테이너의 80번 포트를 호스트의 사용 가능한 포트와 연결하여 실행

$ docker run -d -p 80 nginx

위의 명령어처럼 80번 포트 하나만 지정을 하면 컨테이너 포트만 지정하는 역할을 합니다.

이렇게 되면, 컨테이너 80번 포트를 호스트의 사용가능한 포트를 랜덤으로 지정하여 연결하게 됩니다.

docker ps로 확인해본 결과 컨테이너의 80번 포트를 호스트의 49153포트로 자동으로 연결이 되었습니다.

마찬가지로 curl localhost:49153로 접근을하면 정상적으로 동작하고 curl localhost:80는 동작하지 않습니다.

예제3. nginx 컨테이너의 80번 포트를 호스트의 127.0.0.1 IP의 80번 포트와 연결하여 실행

$ docker run -d -p 127.0.0.1:80:80 nginx

위처럼 컨테이너의 IP까지 지정을 해주면 호스트의 해당 IP에 대해서만 포트(여기선 80번 포트)를 매핑하게 됩니다.

도커 네트워크 드라이버

도커 네트워크 종류

도커 네트워크 드라이버는 Native 드라이버와 Remote 드라이버로 나뉩니다.

Native Drivers -> Bridge, Host, None, Overlay를 사용.

Remote Drivers -> 써드파티 드라이버로 외부에서 잘 만들어진 드라이버를 사용.

네트워크 동작 방식에 따라 드라이버 분류

위 그림은 네트워크 드라이버를 단일 호스트, 다중 호스트로 분류를 한 그림입니다.

네트워크 드라이버는 단일 호스트에서 동작하는 네트워킹, 단일 호스트에서 동작하는 네트워킹이 있습니다.

단일 호스트 네트워크 드라이버 -> Bridge, Host, None 네트워크

다중 호스트 네트워크 드라이버 -> Overlay 네트워크

도커 네트워크 목록 확인

도커 네트워크 목록은 docker netork ls 명령어로 확인 가능합니다.

$ docker network ls

도커 네트워크 확인하기

$ docker network insepct [NETWORK ID or NAME]

도커 네트워크는 docker network inspect 명령어로 확인이 가능합니다.

도커 네트워크 생성하기

도커 네트워크는 docker network create 명령어로 생성할 수 있고, --driver 옵션으로 네트워크 드라이버를 지정할 수 있습니다.

// ex. docker network create --driver=bridge seunghwan-bridge
$ docker network create --driver=[NETWORK DRIVER] [DRIVER NAME]

네트워크 지정 후 컨테이너 실행

도커 네트워크는 docker run 명령어에 --network 옵션으로 네트워크를 지정할 수 있습니다.

$ docker run -d --network=[NETWORK DRIVER] [CONTAINER NAME]

Bridge 네트워크

포트를 연결해 Port를 외부에 노출하는 방식이 이 bridge 네트워크를 이용하는 방식입니다.

위에 있는 예제에서도 네트워크 드라이버를 지정해주지 않았으므로 default로 docker0라는 bridge 네트워크를 사용하고 있습니다.

그리고, 커스텀 bridge 네트워크를 생성해서 사용할 수도 있습니다.

bridge 네트워크를 확인해보면 docker0 브릿지 네트워크인 것을 확인할 수 있습니다.

IP 172.17.0.0을 사용하는 것을 확인할 수 있고 컨테이너를 네트워크 드라이버를 지정하지 않고 생성하면 해당 docker0 브릿지 네트워크를 사용합니다.

Host 네트워크

host 네트워크는 도커가 제공해주는 가상 네트워크(veth)를 사용하는 것이 아니라 직접 host 네트워크에 붙어서 사용하는 개념입니다.

그래서 host 네트워크를 사용할 경우에는 Port 바인딩을 하지 않더라도 host 네트워크를 사용하기 때문에 접속을 할수있게 됩니다.

$ docker run -d --network=host nginx

위 명령어로 호스트 네트워크 드라이버로 nginx를 실행시키면 포트 목록이 보이지 않는 것을 확인할 수 있습니다.

None 네트워크

none 네트워크 드라이버는 해당 컨테이너가 네트워크 기능이 필요없을 때, 혹은 커스텀 네트워킹을 사용해야되는 경우가 있을 때 드라이버를 none으로 설정하고 사용할 수 있습니다.

none 네트워크를 사용해서 컨테이너를 생성하면 외부와의 연결이 단절됩니다.

$ docker run --network none ubuntu:focal

container 네트워크

다른 컨테이너의 네트워크 네임스페이스 환경을 공유할 수 있습니다. 공유되는 속성은 내부 IP, MAC주소입니다.

컨테이너 2개를 생성해주는데 network_container_2가 network_container_1의 네트워크 환경을 공유하도록 설정해줍니다.

$ docker run -it -d -- name network_container_1 ubuntu:18.04
$ docker run -it -d --name network_container_2 --net container:network_container_1 ubuntu:18.04

사용자 정의 네트워크

내부 DNS 서버에 의해 이름 해결이 이루어진다.
내부 DNS 서버를 사용하면, link 기능과 같이 /etc/hosts/ 파일에 의존하지 않고 이름을 해결 할 수있다.
docker0에 연결된 컨테이너들은 ping을 할 때 IP만 가능하지만, 사용자 정의 네트워크에 연결된 컨테이너들은 컨테이너명뿐만 아니라 컨테이너 시작 시 지정한 --net-alias 옵션을 사용한 에일리어스 명칭으로도 통신이 가능하다.

# 컨테이너 구동 시킬 때 결합

docker run --network customNetwork --name container1 containerImage:1

# 컨테이너 구동 후 결합
docker network connect our-net one
profile
기록하고 공유하려고 노력하는 DevOps 엔지니어

0개의 댓글