네트워크 네임스페이스는 Docker와 같은 컨테이너에서 네트워크 격리를 구현하는 데 사용됩니다. 간단한 호스트부터 시작하겠습니다. 이미 알고 있듯이 컨테이너는 네임스페이스를 사용하여 default 호스트와 분리됩니다.
그렇다면 네임스페이스란 무엇인가요? 호스트가 집이라면 네임스페이스는 각 자녀에게 할당하는 집 안의 방입니다. 이 방은 각 어린이에게 프라이버시를 제공하는 데 도움이 됩니다. 각 어린이는 자신의 방 안에 있는 것만 볼 수 있고 방 밖에서 일어나는 일은 볼 수 없습니다. 그 방만 생각한다면, 그들은 집에 사는 유일한 사람입니다. 그러나 부모는 집안의 모든 방과 집안의 다른 영역을 볼 수 있습니다. 원하는 경우 집안의 두 방을 연결할 수 있습니다. 컨테이너를 생성할 때 컨테이너가 격리되어 있는지 확인하고 호스트의 다른 프로세스나 다른 컨테이너를 볼 수 없도록 해야 합니다. 그래서 네임스페이스를 사용하여 호스트에 특별한 공간을 만듭니다. 컨테이너 안에서는 컨테이너는 자신이 실행하는 프로세스만 보고 자체 호스트에 있다고 생각합니다. 그러나 default 호스트는 컨테이너 내부에서 실행되는 프로세스를 포함하여 모든 프로세스를 볼 수 있습니다.
이것은 컨테이너 내에서 프로세스를 조회할 때 볼 수 있습니다. 프로세스 ID가 1인 단일 프로세스가 표시됩니다. default 호스트에서 동일한 프로세스를 루트 사용자로 나열하면 컨테이너 내부에서 실행 중인 프로세스와 함께 이번에는 다른 프로세스 ID를 사용하여 다른 모든 프로세스가 표시됩니다. 컨테이너 내부와 외부에서 서로 다른 프로세스 ID로 실행되는 동일한 프로세스입니다. 네임스페이스가 작동하는 방식입니다.
네트워킹과 관련하여 호스트에는 로컬 영역 네트워크에 연결하는 자체 인터페이스가 있습니다. 호스트에는 나머지 네트워크에 대한 정보가 포함된 자체 라우팅 및 ARP 테이블이 있습니다. 컨테이너에서 이러한 모든 세부 정보를 봉인하려고 합니다. 컨테이너가 생성되면 네트워크 네임스페이스를 생성하므로 호스트의 네트워크 관련 정보를 볼 수 없습니다. 네임스페이스 내에서 컨테이너는 자체 가상 인터페이스, 라우팅 및 ARP 테이블을 가질 수 있습니다. 컨테이너에는 자체 인터페이스가 있습니다.
Linux 호스트에서 새 네트워크 네임스페이스를 만들려면 ip netns add 커맨드를 실행합니다. 이 경우 두 개의 네트워크 네임스페이스를 생성합니다. 네트워크 네임스페이스를 조회하려면 ip netns 커맨드를 실행합니다.
내 호스트의 인터페이스를 조회하기 위해 ip link 커맨드를 실행합니다. 호스트에 루프백 인터페이스와 80 인터페이스가 있는 것을 확인했습니다. 이제 red 또는 blue 네임스페이스 내에서 동일한 커맨드를 어떻게 실행하나요? 커맨드 앞에 ip netns exec 커맨드를 붙인 다음 네임스페이스 이름(red)을 붙입니다. 이제 red 네임스페이스 내에서 ip link 커맨드가 실행됩니다. 이를 수행하는 또 다른 방법은 원래 ip link 커맨드에 -n 옵션을 추가하는 것입니다. 이 둘은 동일합니다. 두 번째는 더 간단하지만 네임스페이스 내에서 ip 커맨드를 실행하려는 경우에만 작동한다는 점을 기억하세요.
보시다시피 루프백 인터페이스만 나열되며 호스트에서 80 인터페이스는 볼 수 없습니다. 따라서 네임스페이스를 사용하여 컨테이너가 호스트 인터페이스를 보지 못하도록 성공적으로 방지했습니다.
ARP 테이블도 마찬가지입니다. 호스트에서 ARP 커맨드를 실행하면 항목 목록이 표시되지만 컨테이너 내부에서 실행하면 항목이 표시되지 않습니다.
라우팅 테이블도 마찬가지입니다.
현재로서는 이러한 네트워크 네임스페이스에는 네트워크 연결이 없고 자체 인터페이스가 없으며 underlying 호스트 네트워크를 볼 수 없습니다. 네임스페이스 자체 간의 연결 설정을 먼저 살펴보겠습니다. 케이블을 사용하여 두 개의 물리적 머신을 각 머신의 인터넷 인터페이스에 연결하는 것과 마찬가지로 가상 이더넷 쌍 또는 가상 케이블을 사용하여 두 개의 네임스페이스를 함께 연결할 수 있습니다. 흔히 파이프라고 부르지만 저는 양쪽 끝에 두 개의 인터페이스가 있는 가상 케이블이라고 부르고 싶습니다.
케이블을 생성하려면 유형을 veth로 설정하고 ip link at 커맨드를 실행하고 두 끝 veth red 및 veth blue를 지정합니다. 다음 단계는 각 인터페이스를 적절한 네임스페이스에 연결하는 것입니다. 그렇게 하려면 ip link set veth red netns red 커맨드를 사용하십시오. 마찬가지로 blue 인터페이스를 blue 네임스페이스에 연결합니다. 그런 다음 이러한 각 네임스페이스에 IP 주소를 할당할 수 있습니다. 일반적인 ip addr 커맨드를 사용하여 IP 주소를 할당하지만 각 네임스페이스 내에서 사용합니다. red 네임스페이스에 ip 192.168.15.1을 할당합니다. 그런 다음 blue 네임스페이스에 ip 192.168.15.2를 할당했습니다. 그런 다음 각 네임스페이스 내의 각 장치에 대해 ip link setup 커맨드를 사용하여 인터페이스를 불러옵니다. 링크가 작동하고 이제 네임스페이스가 서로 연결할 수 있습니다.
red 네임스페이스에서 ping을 시도하여 blue네임스페이스의 ARP 테이블을 보면 MAC 주소가 있는 192.168.15.2에서 blue 이웃을 식별하는 것을 볼 수 있습니다. 마찬가지로 blue 네임스페이스에 ARP 테이블을 나열하면 red 이웃으로 식별되는 것을 볼 수 있습니다. 이것을 호스트의 ARP 테이블과 비교하면 호스트 ARP 테이블은 우리가 생성한 이러한 새 네임스페이스에 대해 전혀 모르고 그 안에 생성한 인터페이스에 대해 전혀 모른다는 것을 알 수 있습니다.
이제 네임스페이스가 두 개뿐이었을 때는 효과가 있었습니다. 네임스페이스가 더 많으면 어떻게 해야 할까요? 그들 모두가 서로 의사 소통을 할 수 있게 하려면 어떻게 해야 할까요? 실제 세계에서와 마찬가지로 호스트 내부에 가상 네트워크를 만듭니다. 네트워크를 생성하려면 스위치가 필요하므로 가상 네트워크를 생성하려면 가상 스위치가 필요합니다. 따라서 호스트 내에 가상 스위치를 생성하고 여기에 네임스페이스를 연결합니다. 그러나 호스트 내에서 가상 스위치를 어떻게 생성하나요? Linux 브리지라고 하는 네이티브 솔루션과 open V switch 등 여러 가지 솔루션을 사용할 수 있습니다. 이 예에서는 Linux 브리지 옵션을 사용합니다.
내부 브리지 네트워크를 생성하기 위해 유형이 bridge로 설정된 ip link add 커맨드를 사용하여 호스트에 새 인터페이스를 추가합니다. 이름은 v-net-0입니다. 우리 호스트에 관한 한 그것은 80 인터페이스와 같은 또 다른 인터페이스일 뿐입니다. 다른 인터페이스와 함께 ip link 커맨드의 출력에 나타납니다. 현재 꺼져 있으므로 켜야 합니다. ip link setup 커맨드를 사용하여 켭니다.
이제 네임스페이스의 경우 이 인터페이스는 연결할 수 있는 스위치와 같습니다. 따라서 호스트를 위한 인터페이스이자 네임스페이스를 위한 스위치라고 생각하세요.
다음 단계는 네임스페이스를 이 새로운 가상 네트워크 스위치에 연결하는 것입니다. 이전에는 두 네임스페이스를 직접 연결하기를 원했기 때문에 한쪽 끝에 veth red 인터페이스가 있고 다른 쪽 끝에 blue 인터페이스가 있는 케이블 또는 eth 쌍을 만들었습니다. 이제 모든 네임스페이스를 브리지 네트워크에 연결합니다. 따라서 이를 위해서는 새로운 케이블이 필요합니다. 이전 케이블은 더 이상 의미가 없으므로 제거하겠습니다. ip link delete 커맨드를 사용하여 케이블을 삭제합니다. 한쪽 끝이 있는 링크를 삭제하면 다른 쪽 끝은 쌍이기 때문에 자동으로 삭제됩니다.
이제 네임스페이스를 브리지에 연결하는 새 케이블을 만들어 보겠습니다. ip link add 커맨드를 실행하고 이전과 같이 한쪽 끝에 veth red가 있는 쌍을 생성하지만 이번에는 다른 쪽 끝에 이름이 지정됩니다. 브리지 네트워크에 연결되는 이름은 veth-red-br입니다. 이 명명규칙은 red 네임스페이스와 관련된 인터페이스를 쉽게 식별하는 데 도움이 됩니다. 마찬가지로 blue 네임스페이스를 브리지 네트워크에 연결하는 케이블을 만듭니다.
이제 케이블이 준비되었으므로 네임스페이스에 연결할 차례입니다. 인터페이스의 한쪽 끝을 red 네임스페이스에 연결하려면 ip link set veth-red netns red 커맨드를 실행합니다. 다른 쪽 끝을 브리지 네트워크에 연결하려면 ip link set veth-red-br커맨드를 실행하고 v-net-0 네트워크로 이에 대한 마스터를 지정합니다. 동일한 절차에 따라 blue 네임스페이스와 브리지 네트워크에 blue 케이블을 연결합니다. 이제 이러한 링크에 대한 IP 주소를 설정하고 활성화하겠습니다. 192.168.15.1 및 192.168.15.2 으로, 이전에 사용했던 것과 동일한 IP 주소를 사용합니다. 그리고 마지막으로 장치를 켜세요.
이제 컨테이너는 네트워크를 통해 서로 도달할 수 있습니다. 따라서 동일한 절차에 따라 나머지 두 네임스페이스를 동일한 네트워크에 연결합니다.
이제 네 개의 네임스페이스가 모두 내부 브리지 네트워크에 연결되어 있으며 모두 서로 통신할 수 있습니다. 그들은 모든 IP 주소를 가지고 있습니다. 192.168.15.1, 2, 3, 4. 그리고 기억하세요. 우리 호스트는 내 호스트의 IP 192.168.1.2를 할당했습니다. 이러한 네임스페이스에서 이러한 인터페이스 중 하나에 도달하려고 하면 어떻게 될까요? 작동할까요? 아니요. 내 호스트는 한 네트워크에 있고 네임스페이스는 다른 네트워크에 있습니다. 하지만 내 호스트와 이러한 네임스페이스 간에 연결을 설정하고 싶다면 어떻게 해야 할까요? virt 스위치는 실제로 호스트의 네트워크 인터페이스라고 말한 것을 기억하세요. 따라서 호스트의 192.168.15 네트워크에 인터페이스가 있습니다. 이것은 단지 또 다른 인터페이스이기 때문에 우리가 해야 할 일은 IP 주소를 할당하여 이를 통해 네임스페이스에 도달할 수 있도록 하는 것입니다.
ip addr 커맨드를 실행하여 IP 192.168.15.5를 이 인터페이스로 설정합니다. 이제 로컬 호스트에서 red 네임스페이스를 ping할 수 있습니다. 이제 이 전체 네트워크는 여전히 비공개이며 호스트 내에서 제한된다는 점을 기억하세요. 네임스페이스 내에서 외부 세계에 도달할 수 없으며, 외부 세계의 누구도 내부에서 호스팅되는 서비스나 애플리케이션에 도달할 수 없습니다. 외부 세계로 통하는 유일한 문은 호스트의 이더넷 포트입니다.
그렇다면 이더넷 포트를 통해 회선 네트워크에 도달하도록 이 브리지를 구성하려면 어떻게 해야 할까요? 주소가 192.168.1.3인 line 네트워크에 다른 호스트가 연결되어 있다고 가정합니다. 내 네임스페이스 내에서 이 호스트에 도달하려면 어떻게 해야 합니까? ping을 시도하면 어떻게 됩니까? 내 네임스페이스에서 이 호스트를 사용하시겠습니까? blue 네임스페이스는 내가 현재 네트워크인 192.168.15와 다른 192.168.1에서 네트워크에 연결하려고 시도하고 있음을 확인합니다. 따라서 해당 네트워크를 찾는 방법을 알아보기 위해 라우팅 테이블을 살펴봅니다. 라우팅 테이블에는 다른 네트워크에 대한 정보가 없습니다. 그래서 네트워크에 연결할 수 없다는 메시지가 나타납니다. 따라서 외부 세계에 대한 관문이나 문을 제공하기 위해 라우팅 테이블에 항목을 추가해야 합니다.
그렇다면 그 게이트웨이를 어떻게 찾을 수 있을까요? 이전에 논의한 것처럼 도어 또는 게이트웨이는 다른 네트워크에 연결되는 로컬 네트워크의 시스템입니다. 그렇다면 192.168.15 네트워크인 blue 네임스페이스에 로컬인 네트워크에 하나의 인터페이스가 있고, 외부 LAN 네트워크에도 연결되는 시스템은 무엇입니까? 아래 logical view를 봅시다.
이것은 네임스페이스를 ping할 수 있도록 모든 네임스페이스가 있는 로컬 호스트입니다. 로컬 호스트에는 개인 네트워크를 연결하는 인터페이스가 있으므로 네임스페이스를 ping할 수 있습니다. 따라서 로컬 호스트는 두 네트워크를 함께 연결하는 게이트웨이입니다. 이제 blue 네임스페이스에 행 항목을 추가하여 192.168.15.5의 게이트웨이를 통해 모든 트래픽을 192.168.1 네트워크로 라우팅할 수 있습니다. 이제 호스트에는 두 개의 IP 주소가 있습니다. 하나는 1925.168.15.5의 브리지 네트워크에 있고 다른 하나는 192.168.1.2의 외부 네트워크에 있습니다. route에서 사용할 수 있습니까? 아니요. blue 네임스페이스는 192.168.15.5의 로컬 네트워크에 있는 게이트웨이에만 도달할 수 있기 때문입니다. default 게이트웨이는 route에 추가할 때 네임스페이스에서 연결할 수 있어야 합니다.
지금 ping을 시도하면 더 이상 네트워크에 연결할 수 없다는 메시지가 표시되지 않지만 여전히 ping에서 응답을 받지 못합니다. 무엇이 문제일까요? 우리는 이전 강의 중 하나에서 홈 네트워크에서 라우터를 통해 외부 인터넷에 도달하려고 시도한 것과 유사한 상황에 대해 이야기했습니다. 우리의 홈 네트워크에는 대상 네트워크가 알지 못하는 내부 사설 IP 주소가 있으므로 다시 연결할 수 없습니다. 이를 위해 자체 주소가 있는 자체 이름으로 LAN에 메시지를 보낼 수 있도록 여기에서 게이트웨이 역할을 하는 호스트에서 NAT 활성화가 필요합니다.
그렇다면 호스트에 NAT 기능을 추가하려면 어떻게 해야 할까요? IP 테이블을 사용하여 이를 수행해야 합니다. 포스트 라우팅 체인의 NAT IP 테이블에 새 rule을 추가하여 원본 네트워크에서 오는 모든 패킷의 보낸 사람 주소를 자체 IP 주소가 있는 192.168.15.0로 바꿉니다. 그렇게 하면 네트워크 외부에서 이러한 패킷을 받는 사람은 네임스페이스 내에서가 아니라 호스트에서 오는 것으로 생각할 것입니다. 지금 ping을 시도하면 외부 세계에 연결할 수 있음을 알 수 있습니다.
마지막으로 LAN이 인터넷에 연결되어 있다고 가정합니다. 네임스페이스가 인터넷에 연결되기를 원합니다. 그래서 blue 네임스페이스에서 8.8.8.8의 인터넷 서버에 ping을 시도합니다. 네트워크에 연결할 수 없다는 유사한 메시지가 표시됩니다. 이제 우리는 그 이유를 알고 있습니다. 우리는 라우팅 테이블을 보고 네트워크 192.168.1에 대한 route가 있지만 다른 route는 없음을 확인합니다. 이러한 네임스페이스는 호스트가 도달할 수 있는 모든 네트워크에 도달할 수 있으므로 외부 네트워크에 도달하려면 호스트와 대화한다고 간단히 말할 수 있습니다. 따라서 호스트를 지정하는 default 게이트웨이를 추가합니다. 이제 이러한 네임스페이스 내에서 외부 세계에 도달할 수 있어야 합니다.
이제 외부 세계에서 네임스페이스 내부로의 연결은 어떨까요? 예를 들어 blue 네임스페이스가 포트 80에서 웹 애플리케이션을 호스팅한다고 가정해 보겠습니다. 현재 네임스페이스는 내부 사설 네트워크에 있으며 외부 세계의 누구도 이에 대해 알지 못합니다. 호스트 자체에서만 액세스할 수 있습니다. 다른 네트워크에 있는 다른 호스트에서 네임스페이스의 사설 IP로 ping을 시도하면 해당 호스트가 이 사설 네트워크에 대해 모르기 때문에 분명히 연결할 수 없다는 것을 알 수 있습니다. 이러한 통신을 가능하게 하려면 두 가지 옵션이 있습니다. 이전 강의에서 본 두 가지 옵션입니다. 첫 번째는 개인 네트워크의 ID를 두 번째 호스트에 제공하는 것입니다. 따라서 기본적으로 두 번째 호스트에 ip route 항목을 추가하여 호스트에 네트워크 192.168.15가 192.168.1.2의 호스트를 통해 도달할 수 있음을 알려줍니다. 하지만 우리는 그렇게 하고 싶지 않습니다. 다른 옵션은 로컬 호스트의 포트 80으로 들어오는 모든 트래픽이 blue 네임스페이스에 할당된 IP의 포트 80으로 전달되도록 IP 테이블을 사용하여 포트 전달 롤을 추가하는 것입니다.
Docker의 기본 네트워킹 옵션으로 시작한 다음 네트워킹 네임스페이스에 대한 개념과 연결해 보겠습니다.
Docker가 설치된 서버인 단일 Docker 호스트부터 시작해 보겠습니다. eth0에 IP 주소 192.168.1.10으로 로컬 네트워크에 연결하는 인터넷 인터페이스가 있습니다. 컨테이너를 실행할 때 선택할 수 있는 네트워킹 옵션이 다릅니다.
먼저, none 네트워크를 살펴보겠습니다. 네트워크가 none인 경우 도커 컨테이너는 네트워크에 연결되지 않습니다. 컨테이너는 외부 세계에 도달할 수 없고, 외부 세계의 누구도 컨테이너에 도달할 수 없습니다. 여러 컨테이너에 있는 경우 네트워크의 일부가 되지 않고 모두 생성되어 서로 또는 외부와 통신할 수 없습니다.
다음은 호스트 네트워크입니다. 호스트 네트워크를 사용하면 컨테이너가 호스트 네트워크에 연결됩니다. 호스트와 컨테이너 간에는 네트워크 분리가 없습니다. 컨테이너의 포트 80에서 수신 대기하는 웹 애플리케이션을 배포하면 추가 포트 매핑을 수행하지 않고도 호스트의 포트 80에서 웹 애플리케이션을 사용할 수 있습니다. 동일한 포트에서 수신하는 동일한 컨테이너의 다른 인스턴스를 실행하려고 하면 호스트 네트워킹을 공유하기 때문에 작동하지 않으며 두 프로세스가 동일한 포트에서 동시에 수신할 수 없습니다.
세 번째 네트워킹 옵션은 브리지입니다. 이 경우 Docker 호스트 및 컨테이너가 연결되는 내부 전용 네트워크가 생성됩니다. 네트워크에는 기본적으로 주소 172.17.0.0이 있으며, 이 네트워크에 연결된 각 장치는 이 네트워크에서 자체 내부 전용 네트워크 주소를 얻습니다.
이 네트워크는 우리가 가장 관심을 갖고 있는 네트워크이므로 도커가 이 네트워크를 정확히 어떻게 만들고 관리하는지 자세히 살펴봅시다.
호스트에 Docker를 설치하면 기본적으로 Bridge라는 내부 전용 네트워크가 생성됩니다. Docker networks ls 명령을 실행하면 이를 확인할 수 있습니다. 이제 Docker는 네트워크를 Bridge라는 이름으로 부르지만 호스트에서는 네트워크가 Docker0이라는 이름으로 생성됩니다. 이는 IP 링크 명령의 출력에서 확인할 수 있습니다. 도커는 브리지로 설정된 유형으로 IP link add 명령을 실행하여 네임스페이스에서 강의에서 본 것과 유사한 기술을 내부적으로 사용합니다. 따라서 Docker networks 출력의 이름 브리지는 호스트의 이름 Docker0을 참조합니다. 그들은 같은 것입니다. 또한 인터페이스나 네트워크가 현재 중단되었다는 것을 유의해주세요.
브리지 네트워크는 호스트와의 인터페이스와 비슷하지만 호스트 내의 네임스페이스 또는 컨테이너로의 전환과 같다고 말했습니다. 따라서 호스트의 인터페이스 Docker0에는 IP 172.17.0.1이 할당됩니다. 이는 IP ADDR 명령의 출력에서 확인할 수 있습니다.
컨테이너가 생성될 때마다 Docker는 컨테이너에 대한 네트워크 네임스페이스를 생성합니다. 이전 강의에서 네트워크 네임스페이스를 만든 것처럼 말입니다. IP netns 명령을 실행하여 네임스페이스를 나열합니다. 도커가 만든 네임스페이스를 나열하는 IP netns 명령을 얻기 위해 수행해야 할 사소한 hack(?)이 있습니다. 자세한 내용은 이 강의의 리소스 섹션을 참조하세요. 네임스페이스의 이름은 B3165로 시작합니다. Docker inspect 명령 출력에서 각 컨테이너와 연결된 네임스페이스를 확인할 수 있습니다.
그렇다면 Docker는 컨테이너 또는 네트워크 네임스페이스를 브리지 네트워크에 어떻게 연결할까요? 컨테이너와 네트워크 네임스페이스는 동일한 것을 의미합니다. 내가 컨테이너라고 말할 때, 나는 Docker가 그 컨테이너에 대해 만든 네트워크 네임스페이스를 말하는 것입니다. 그렇다면 도커는 어떻게 컨테이너를 브릿지에 부착할까요?
우리가 전에 했던 것처럼, 이것은 양쪽 끝에 두 개의 인터페이스가 있는 가상 케이블을 만듭니다. 여기서 도커가 무엇을 만들어냈는지 알아봅시다. Docker 호스트에서 IP link 명령을 실행하면 로컬 브리지인 Docker0에 연결된 인터페이스의 한쪽 끝이 표시됩니다. 네임스페이스가 있는 -n 옵션을 사용하여 동일한 명령을 다시 실행하면 컨테이너 네임스페이스 내 인터페이스의 다른 쪽 끝이 나열됩니다. 또한 인터페이스는 네트워크 내에서 IP를 할당받습니다.
컨테이너의 네임스페이스 내에서 IP ADDR 명령을 실행하여 이 정보를 볼 수 있습니다. 컨테이너에 172.17.0.3이 할당됩니다. 컨테이너에 연결하여 컨테이너에 할당된 IP 주소를 확인할 수도 있습니다.
새 컨테이너가 생성될 때마다 동일한 절차가 수행됩니다. 도커는 네임스페이스를 만들고, 인터페이스 쌍을 만들고, 한쪽 끝을 컨테이너에 연결하고, 다른 쪽 끝을 브리지 네트워크에 연결합니다. 인터페이스 쌍은 번호를 사용하여 식별할 수 있습니다. 홀수와 짝수가 짝을 이룹니다. 9와 10, 7과 8,11과 12는 한 쌍입니다. 컨테이너는 이제 모두 네트워크의 일부입니다. 그들은 모두 서로 의사소통을 할 수 있습니다.
이제 포트 매핑을 살펴보겠습니다. 우리가 만든 컨테이너는 Nginx이므로 포트 80의 웹 애플리케이션 서비스 웹페이지입니다. 컨테이너가 호스트 내부의 전용 네트워크 내에 있으므로 동일한 네트워크에 있는 다른 컨테이너 또는 호스트 자체만 이 웹 페이지에 액세스할 수 있습니다.
포트 80의 Docker 호스트 내에서 용기의 IP를 사용하여 curl을 사용하여 웹 페이지에 액세스하려고 하면 웹 페이지가 표시됩니다. 호스트 외부에서 동일한 작업을 수행하려고 하면 웹 페이지를 볼 수 없습니다. 외부 사용자가 컨테이너에 호스팅된 응용프로그램에 액세스할 수 있도록 도커는 포트 게시 또는 포트 매핑 옵션을 제공합니다. 컨테이너를 실행할 때 Docker에게 Docker 호스트의 포트 8080을 컨테이너의 포트 80에 매핑하도록 지시합니다. 이렇게 하면 도커 호스트의 IP와 포트 8080을 사용하여 웹 애플리케이션에 액세스할 수 있습니다. 도커 호스트의 포트 8080에 대한 트래픽은 컨테이너의 포트 80으로 전달됩니다. 이제 모든 외부 사용자와 다른 애플리케이션 또는 서버가 이 URL을 사용하여 호스트에 배포된 애플리케이션에 액세스할 수 있습니다.
하지만 도커는 어떻게 할까요? 어떻게 한 포트에서 다른 포트로 트래픽을 전달합니까? 도커와 다른 모든 것들은 잠시 잊어버립시다. 요구 사항은 한 포트에서 들어오는 트래픽을 서버의 다른 포트로 전달하는 것입니다. 우리는 그것에 대해 우리의 선행 강의 중 하나에서 이야기했습니다. NAT은 이를 위한 NAT 규칙을 만듭니다. IP 테이블을 사용하여 NAT 테이블에 항목을 생성하여 대상 포트를 8080에서 80으로 변경하는 규칙을 사전 라우팅 체인에 추가합니다. 도커도 같은 방식으로 합니다. Docker는 Docker 체인에 규칙을 추가하고 컨테이너의 IP도 포함하도록 대상을 설정합니다.
IP 테이블에 규칙을 나열할 때 도커가 만드는 규칙을 볼 수 있습니다.
지금까지 네트워크 네임스페이스가 작동하는 방식, 예를 들어 시스템 내에서 격리된 네트워크 네임스페이스 환경을 만드는 방법, 브리지 네트워크를 통해 여러 개의 네임스페이스를 연결하는 방법, 양쪽 끝에 가상 인터페이스가 있는 가상 케이블이나 파이프를 만드는 방법, 그리고 각 엔드 투 엔드 네임스페이스와 브리지를 연결하는 방법을 살펴 보았습니다. 또한 IP를 할당하고 IP를 불러오는 방법과 함께 마지막으로 외부 통신을 위해 NAT 또는 IP 위장을 사용하도록 설정합니다. 그런 다음 Docker가 브리지 네트워킹 옵션에 대해 어떻게 수행했는지 확인했습니다. 그것은 다른 이름 패턴을 사용한다는 것을 제외하고는 거의 같은 방식이었습니다. 다른 컨테이너 솔루션들도 같은 방식으로 네트워킹 문제를 해결합니다.
Rocket이나 Mesos Container와 같이 컨테이너와 함께 작동하고 Kubernetes와 같이 컨테이너 간의 네트워킹을 구성해야 하는 다른 솔루션들도 마찬가지입니다.
모두가 사소한 차이를 가지고 유사한 접근 방식을 연구하고 최종적으로 식별함으로써 동일한 네트워킹 문제를 해결하려고 한다면, 왜 동일한 솔루션을 여러 번 코딩하고 개발할까요? 모두가 따를 수 있는 단일 표준 접근 방식을 만들어 보는 것은 어떨까요? 그래서 우리는 이 모든 아이디어를 다른 솔루션에서 가져와 그것의 모든 네트워킹 부분을 하나의 프로그램이나 코드로 옮깁니다. 그리고 이것이 브리지 네트워크를 위한 것이기 때문에, 우리는 그것을 브리지라고 부릅니다.
그래서 우리는 컨테이너를 브리지 네트워크에 연결하기 위해 필요한 모든 작업을 수행하는 프로그램이나 스크립트를 만들었습니다. 예를 들어 Bridge라는 이름을 사용하여 이 프로그램을 실행하고 특정 네트워크 namespace에 이 컨테이너를 추가하도록 지정할 수 있습니다. Bridge 프로그램은 컨테이너 런타임 환경이 이러한 작업에서 벗어나도록 나머지 부분을 처리합니다. 예를 들어, Rocket 또는 Kubernetes가 새 컨테이너를 만들 때 Bridge Program을 호출하고 컨테이너 ID와 네임스페이스를 전달하여 해당 컨테이너에 대한 네트워킹을 구성합니다.
그렇다면 만약 여러분이 새로운 네트워킹 유형을 위해 그런 프로그램을 만들고 싶다면 어떨까요? 만약 당신이 그렇게 한다면, 그것은 어떤 arguments와 커맨드를 지원해야 합니까? 작성한 프로그램이 현재 실행 시간에 맞게 작동하는지 어떻게 확인합니까? Kubernetes나 Rocket과 같은 컨테이너 실행 시간이 당신의 프로그램을 정확하게 호출할 것이라는 것을 어떻게 압니까? 그것이 우리가 정의해야 할 몇 가지 기준이 필요한 부분입니다. 프로그램이 어떻게 보여야 하는지, 컨테이너 실행 시간이 어떻게 실행되는지 정의하는 표준으로, 모든 사용자가 단일 표준 세트를 준수하고 실행 시간에 걸쳐 작동하는 솔루션을 개발할 수 있습니다.
여기서 컨테이너 네트워크 인터페이스가 등장합니다. CNI는 컨테이너 런타임 환경에서 네트워킹 문제를 해결하기 위해 프로그램을 개발하는 방법을 정의하는 표준의 집합입니다. 프로그램을 플러그인이라고 합니다. 이 경우, 우리가 언급한 Bridge 프로그램은 CNI를 위한 플러그인이다. CNI는 플러그인이 어떻게 개발되어야 하는지, 컨테이너 실행 시간이 어떻게 그것들을 호출해야 하는지를 정의합니다.
CNI는 컨테이너 실행 시간 및 플러그인에 대한 일련의 책임을 정의합니다. 컨테이너 실행 시간의 경우, CNI는 각 컨테이너에 대한 네트워크 namespace을 생성하도록 지정합니다. 그런 다음 컨테이너가 연결되어야 하는 네트워크를 식별해야 하며, 컨테이너 런타임은 add 커맨드를 사용하여 컨테이너를 생성할 때 플러그인을 호출해야 하며, del 커맨드를 사용하여 컨테이너를 삭제할 때 플러그인을 호출해야 합니다. 또한 JSON 파일을 사용하여 컨테이너 런타임 환경에서 네트워크 플러그인을 구성하는 방법도 지정합니다. 플러그인 측에서는 플러그인이 추가, del 및 check 커맨드라인 arguments를 지원해야 하며 컨테이너 및 네트워크 네임스페이스와 같은 매개 변수를 허용해야 한다고 정의합니다. 플러그인은 컨테이너가 네트워크의 다른 컨테이너에 도달하는 데 필요한 파드 및 관련 경로에 IP 주소를 할당해야 합니다. 마지막에 결과를 특정 형식으로 지정해야 합니다. 컨테이너 가동 시간과 플러그인이 이러한 표준을 준수하는 한, 그들은 모두 함께 조화롭게 살 수 있습니다. 모든 실행 시간은 모든 플러그인을 사용하여 작업할 수 있어야 합니다.
CNI에는 Bridge, VLAN, IP VLAN, MAC VLAN, 윈도우즈용 플러그인 및 Host Local 및 DHCP와 같은 IPAM 플러그인과 같은 이미 지원되는 플러그인 집합이 함께 제공됩니다. 타사 조직에서 사용할 수 있는 다른 플러그인도 있습니다. 예를 들어 Weeve, Flannel, Cilium, VMware NSX, Calico, Infoblox 등이 있습니다. 이러한 모든 컨테이너 런타임은 CNI 표준을 구현하므로 이러한 플러그인 중 하나라도 작동할 수 있습니다.
하지만 이 목록에 없는 것이 하나 있습니다. 도커입니다. 도커는 CNI를 구현하지 않습니다. 도커는 CNM이라는 자체 표준을 가지고 있는데, CNI와 유사하지만 약간의 차이가 있는 컨테이너 네트워킹 문제를 해결하는 것을 목표로 하는 또 다른 표준인 컨테이너 네트워크 모델을 의미합니다.