새소식

Recent Study/udemy - CKA with Practice Tests

Section 9 : Networking

  • -

1. Prerequisite - Switching Routing

Network란 무엇일까요? 컴퓨터 A,B가 있고 노트북과 데스크톱, 클라우드 VM이 있는데 시스템 A가 어떻게 B와 연결되나요? 스위치에 연결하면 스위치는 두 시스템을 포함하는 네트워크를 만들어줍니다. 스위치에 연결하기 위해 각 호스트에 인터페이스가 필요합니다. 물리적이거나 가상으로요.

 

 

위 명령을 통해 호스트의 인터페이스를 확인할 수 있고, 예로 Eth0이란 이름의 인터페이스를 볼 수 있습니다. 스위치에 연결할 때 사용할 것이에요. ip addr 명령으로 링크가 올라가고, IP 주소가 할당되면 이제 컴퓨터는 스위치를 통해 서로 통신할 수 있습니다. 스위치를 통해 동일한 네트워크 상에서만 통신할 수 있고, 다른 네트워크로 패킷을 주고 받을 수 없죠.

 

 

라우터는 두 네트워크를 함께 연결하는 데 도움이 되는 장치입니다. 2개의 개별 네트워크에 연결되므로, 각 네트워크에 하나씩 2개의 IP가 할당됩니다. 만약 시스템 B -> 시스템 C로 패킷을 보낼 때 네트워크에서 패킷을 보낼 위치를 어떻게 알 수 있을까요? 라우터는 네트워크의 장치일 뿐이고, 이를 위해 gateway 또는 route로 시스템을 구성합니다. 시스템의 기존 라우팅 configuration을 보려면

> route 명령을 통해 알 수 있습니다.

 

 

routing table이 작성된 라우터가 게이트웨이입니다. 만약 라우팅에 대한 정보가 없다면, > ip route add 192.168.2.0/24 via 192.168.1.1 명령으로 도달할 수 있도록 지정이 가능합니다. 인터넷에는 다양한 네트워크가 있습니다. 동일한 라우터 IP 주소를 라우팅 테이블에 추가하는 대신, 경로를 모르는 네트워크에 대해 이 라우터를 Default 게이트웨이로 사용할 수 있습니다. 이는 기존 네트워크 외부의 네트워크에 대한 모든 요청이 특정 라우터로 이동합니다.

 

이번에는 Linux 호스트를 라우터로 설정하는 방법을 알아보겠습니다. 

 

 

위는 A와 C가 대화할 수 있는 환경을 초기 환경을 구성한 것 입니다. 하지만 우리는 여전히 어떤 응답도 받지 못합니다. default로 Linux에서는 패킷이 한 인터페이스에서 다음 인터페이스로 전달되지 않습니다. 예를 들어 호스트 B의 eth0에서 수신된 패킷은 eth1을 통해 다른 곳으로 전달되지 않습니다. 보안상의 이유 때문입니다. 예를 들어 eth0이 개인 네트워크에 연결되어 있고 eth1이 공용 네트워크에 연결되어 있는 경우, 명시적으로 허용하지 않는 한 공용 네트워크의 어느 누구도 개인 네트워크로 메시지를 쉽게 보낼 수 없습니다.

 

그러나 지금 예제의 경우 둘 다 사설 네트워크이고 둘 사이의 통신을 가능하게 하는 것이 안전하다는 것을 알고 있으므로 호스트 B가 한 네트워크에서 다른 네트워크로 패킷을 전달하도록 허용할 수 있습니다. 호스트가 인터페이스 간에 패킷을 전달할 수 있는지 여부는 파일 proc/sys/net/ipv4/ip_forward에서 이 시스템의 설정에 따라 결정됩니다. default로 이 파일의 값은 0으로 설정되어 있으며, 이는 전달이 없음을 의미합니다. 이것을 1로 설정하면 핑이 통과하는 것을 볼 수 있습니다. 이제 이 값을 설정하는 것만으로는 재부팅 후에도 변경 사항이 지속되지 않는다는 점을 기억하십시오. 변경사항이 재부팅 후에도 지속되기 위해서는 etc/sys/control.conf파일 에서 동일한 값을 수정해야 합니다.

 

마지막으로 명령어 정리를 해보겠습니다.

> ip link (호스트에서 인터페이스를 나열하는 것)

> ip addr (해당 인터페이스에 할당된 IP주소 확인)

> ip addr add 192.168.1.10/24 dev eth0 (인터페이스에서 IP 주소를 설정하는데 사용)

> ip route (라우팅 테이블을 보는데 사용)

> ip route add 192.168.1.0/24 via 192.168.2.1 (테이블에 항목을 추가하는데 사용)

> cat /proc/sys/net/ipv4/ip_forward (호스트에서 IP 포워딩이 가능한지 확인하는 명령)

 

 

2. DNS

 

 

위에서 IP 주소 대신 db를 사용해 ping 하는 과정에서 문제가 생겼습니다. 기본적으로 시스템 A에게 db라는 호스트를 인식하지 못하는 것이기 때문에 etc/hosts 파일에 항목을 추가하여 수행할 수 있습니다. 그렇다면 db에 대한 ping이 올바른 IP로 전송되고 성공합니다. 또한 etc/hosts 파일에서 원하는만큼 서버에 대한 이름을 가질 수 있고, 호스트 A에서 이름으로 다른 호스트를 참조할 때마다 ping 커맨드나 SSH 커맨드를 통해 또는 이 시스템 내 애플리케이션이나 tool을 통해 호스트는 해당 호스트의 IP 주소를 찾기 위해 etc/hosts를 찾아갑니다. 이를 name resolution이라고 합니다.

 

소수의 시스템으로 구성된 소규모 네트워크 내에서 etc/hosts 파일의 항목을 쉽게 사용할 수 있습니다. 각 시스템에서 모두 다른 시스템을 지정합니다. 과거에는 그렇게 했습니다. 환경이 커지면 이러한 파일과 항목을 관리하는 것이 너무 어려워집니다. 서버 중 하나의 IP가 변경되면 모든 호스트에서 항목을 수정해야 합니다. 따라서 이 모든 항목을 중앙에서 관리할 단일 서버를 두기로 결정했습니다. 우리는 그것을 DNS 서버라고 부릅니다. 자체 etc/hosts 파일 대신 호스트 이름을 IP 주소로 확인해야 하는 경우에 모든 호스트가 해당 서버를 조회하도록 지정합니다.

 

 

 

모든 호스트에 "nameserver", 192.168.100이 configuration 되면 호스트가 알지 못하는 이름을 발견할 때마다(해당 호스트 이름이 update 되거나 생성되었을 때) DNS 서버에서 조회합니다. etc/hosts 파일과 DNS에 각각 하나씩 항목이 있으면 어떻게 될까요? 순서는 바뀔 수 있습니다. 순서는 etc/nsswitch.conf 파일의 항목으로 정의됩니다.따라서 모든 호스트 이름에 대해 호스트는 먼저 etc/hosts 파일을 살펴보고 찾을 수 없으면 DNS 서버를 찾는다는 의미입니다. 목록에 없는 서버에 ping을 시도하면 그 경우에는 실패합니다.

 

 

끝에 www와 .com이 있는 이 이름은 무엇입니까? 도메인 네임이라고 하며 호스트에 대해 했던 것처럼 공용 인터넷에서 기억할 수 있는 이름으로 IP가 변환하는 방식입니다. 이제 점으로 구분된 이 형식을 사용하는 이유는 유사한 항목을 함께 그룹화하기 위한 것입니다. 도메인 이름의 마지막 부분인 .coms, .nets, .edu, .org 등은 웹사이트의 의도를 나타내는 최상위 도메인입니다. 상업용 또는 일반용 .com, 네트워크용 .net, 교육 기관용 .edu, 비영리 기관용 .org.

 

Google의 경우 점은 루트입니다. 그것이 모든 것이 시작되는 곳입니다. .com은 최상위 도메인입니다. Google은 Google에 할당된 도메인 이름이고 www는 하위 도메인입니다. 하위 도메인은 Google에서 항목을 추가로 그룹화하는 데 도움이 됩니다. 예를 들어 Google의 지도 서비스는 maps.google.com에서 사용할 수 있습니다. 따라서 map은 하위 도메인입니다. Google의 스토리지 서비스는 drive.google.com에서 사용할 수 있습니다. 모바일 앱은 apps.google.com에서 사용할 수 있습니다. Google의 이메일 서비스는 mail.google.com에서 사용할 수 있습니다. 필요에 따라 이들 각각을 많은 하위 도메인으로 추가로 나눌 수 있습니다. 따라서 트리 구조가 형성되는 것을 볼 수 있습니다.

 

조직 내에서 이러한 도메인 이름(예: apps.google.com)에 도달하려고 하면 요청이 먼저 조직의 내부 DNS 서버에 도달합니다. 앱이나 Google이 누구인지 모르기 때문에 요청을 인터넷으로 전달합니다. 인터넷에서 apps.google.com을 제공하는 서버의 IP 주소는 여러 DNS 서버의 도움을 받아 확인할 수 있습니다. route DNS 서버는 요청을 보고 .com를 제공하는 DNS 서버를 가리킵니다. .com DNS 서버는 우리의 요청을 보고 우리를 Google에 전달합니다. 그리고 Google의 DNS 서버는 앱의 애플리케이션을 제공하는 서버의 IP를 제공합니다. 향후의 모든 확인 속도를 높이기 위해 조직의 DNS 서버는 일정 시간(일반적으로 몇 초에서 최대 몇 분) 동안 이 IP를 캐싱하도록 선택할 수 있습니다. 이렇게 하면 매번 전체 프로세스를 다시 거칠 필요가 없습니다.

 

 

마지막은 Record 유형에 대한 설명입니다. DNS 서버에 저장된 기록은 어떻게 되나요? 호스트 이름을 위해 IP를 저장합니다. 그것을 A레코드라고 합니다. 호스트 이름으로 IPv6를 저장한 건 AAAA레코드죠. 한 이름과 다른 이름에 매핑한 것은 CNAME 레코드라고 합니다. 예로 음식 배달 서비스와 같이 동일한 애플리케이션에 대한 여러 별칭이 있을 수 있는데, CNAME 레코드가 사용되는 것 입니다. 이름과 이름의 매핑이라고 이해하면 됩니다.

 

ping 이외에 nslookup 같은 다른 툴이 있습니다. nslookup을 사용해 DNS 서버에서 호스트 이름을 쿼리할 수 있습니다. 하지만 nslookup은 etc/hosts 파일 항목을 고려하지 않습니다. 따라서 웹 애플리케이션에 대한 로컬 etc/hosts 파일에 항목을 추가하고, 해당 웹 애플리케이션에 대해 nslookup을 시도하면 찾을 수 없죠. nslookup은 DNS 서버만 쿼리합니다.

 

 

3. NETWORK NAMESPACES

네임스페이스는 호스트가 집이라면 네임스페이스는 각 자녀에게 할당하는 집의 방입니다. 이 방은 프라이버시를 제공하고, 자녀는 방 안에 있는것만 볼 수 있고, 밖은 볼 수 없습니다. 하지마 부모는 집안의 모든 방과 다른 영역을 볼 수 있습니다. 컨테이너를 생성할 때 격리되었는지 확인하고, 호스트의 다른 프로세스나 다른 컨테이너를 볼 수 없도록 해야 합니다. 그래서 네임스페이스를 통해 호스트에 특별한 공간을 만듭니다. 컨테이너 안에서 컨테이너는 자신이 실행하는 프로세스만 보고, 자체 호스트에 있다고 생각합니다. 하지만 default 호스트 컨테이너 내부에서 실행되는 프로세스를 포함해 모든 것을 볼 수 있습니다.

 

 

네트워킹에 관해선 호스트는 로컬 지역 네트워크에 연결하는 고유 인터페이스가 있습니다. 호스트는 고유의 라우팅, ARP 테이블이 있고, 나머지 네트워크에 대한 정보도 가지고 있습니다. 컨테이너가 생성되면, 그것을 위한 네트워크 네임스페이스를 생성합니다. 그래서 호스트의 네트워크 관련 정보에 대한 표시 유형을 가지지 않죠.

 

네임스페이스 내에서 컨테이너는 고유의 가상 인터페이스 테이블과 ARP 테이블을 가질 수 있습니다. 컨테이너는 고유한 인터페이스가 있는 것이죠.

 

 

Linux 호스트에 새 네트워크 네임스페이스를 만들려면, 2가지 명령을 실행하세요. 위 경우에는 2개의 네트워크 네임스페이스를 생성하죠.

> ip nets add 명령을 실행하면 됩니다. 본인 호스트의 인터페이스를 조회하기 위해 > ip link 명령을 실행합니다. 위에서는 LOOPBACK 인터페이스와 eth0 인터페이스가 있는 것을 볼 수 있죠.

 

그렇다면 red, blue 네임스페이스에서 명령 실행은 어떻게 할까요? 위처럼 커맨드 앞에 ip netns exec를 붙인 후 실행할 네임스페이스(red)를 붙이면 됩니다. 그러면 red 네임스페이스 내에서 ip link 커맨드가 실행됩니다. 그 아래 명령어는 같은 의미를 뜻합니다.

 

 

Virtual Cable

현재로서는 이러한 네트워크 네임스페이스에는 네트워크 연결이 없고, 자체 인터페이스가 없으며 underlying 호스트 네트워크를 볼 수 없습니다. 케이블을 사용하여 2개의 물리적 머신을 각 머신의 인터넷 인터페이스에 연결하는 것과 마찬가지로 가상 이더넷 쌍 또는 가상 케이블을 사용하여 2개의 네임스페이스를 함께 연결할 수 있습니다. 흔히 파이프라고 부르지만, 저는 양쪽 끝에 2개의 인터페이스가 있는 가상 케이블이라고 부르겠습니다.

(> ip -n red addr add 192.168.15.1 dev veth-red)

(> ip -n blue addr add 192.168.15.2 dev veth-blue)

 

 

 케이블을 생성하려면 유형을 veth로 설정하고 ip link set 커맨드를 실행하고 두 끝 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 커맨드를 사용하여 인터페이스를 불러옵니다. 링크가 작동하고 이제 네임스페이스가 서로 연결할 수 있습니다.

 

 

그렇다면 2개가 아니라 더 많으면 어떻게 소통할까요? 호스트 내부에서 가상 네트워크를 생성해야 합니다. 네트워크를 만들려면 스위치가 필요한 것과 같이, 가상 네트워크를 만들려면 가상 스위치가 필요합니다. 호스트 내에 가상 스위치를 생성하고 네임 스페이스를 연결하는 것입니다. 다양한 솔루션이 존재하고 있고, 해당 예제에서는 LINUX BRIDGE를 사용하겠습니다. 

 

내부 Bridge 네트워크를 만들려면 호스트에 새로운 인터페이스를 추가합니다. ip link를 이용해 브리지 형식의 명령 추가로 가능하고, 이름은 v-net-0라고 명명하겠습니다. 호스트에 관한 또다른 인터페이스일 뿐이죠. 위에서 봤던 eth0와 같죠. 다른 인터페이스와 함께 ip link 명령의 결과물이 나옵니다. 네임 스페이스의 경우 해당 v-net-0는 연결할 수 있는 스위치 역할이라고 봐도 됩니다. 호스트의 인터페이스와 네임스페이스의 스위치로 생각하면 편합니다.

 

다음 단계는 네임스페이스를 이 새 가상 네트워크 스위치에 연결하는 것이죠. 앞서 veth-red, veth-blue 인터페이스를 연결하는 케이블을 만들었는데, 두 네임스페이스를 직접 연결하고 싶다면, 이제 모든 네임스페이스를 브리지 네트워크에 연결하면 됩니다. 그래서 새로운 케이블이 필요하게 됩니다. 이 케이블은 더이상 필요없으니 제거하고(ip -n red link del veth-red), 해당 명령을 통해 케이블을 삭제할 수 있습니다. 한쪽 끝의 링크를 삭제하면 다른 쪽 veth-blue도 자동을 삭제됩니다.

 

 

새 케이블을 만들죠, ip link add 명령을 실행하고, 이전처럼 한쪽 끝에 veth-red을 연결합니다. 이번에는 다른 쪽 끝에 이름을 붙이는데, 브리지 네트워크에 연결된 veth-red-br이죠. 마찬가지로 blue도 생성하고, 아래와 같은 명령을 통해 내부 브리지 네트워크에 연결된 4개의 네임스페이스가 모두 서로 통신이 가능합니다.

 

 

 각각의 인테페이스는 192.168.15.1, 2, 3, 4의 IP 주소를 가지고 있습니다. 그리고 기억하세요. 우리 호스트는 내 호스트의 IP 192.168.1.2를 할당했습니다. 이러한 네임스페이스에서 이러한 인터페이스 중 하나에 도달하려고 하면 어떻게 될까요? 작동할까요? 아니요. 내 호스트는 한 네트워크에 있고 네임스페이스는 다른 네트워크에 있습니다. 하지만 내 호스트와 이러한 네임스페이스 간에 연결을 설정하고 싶다면 어떻게 해야 할까요? 가상 스위치는 실제로 호스트의 네트워크 인터페이스라고 말한 것을 기억하세요. 따라서 호스트의 192.168.15 네트워크에 인터페이스가 있습니다. 이것은 단지 또 다른 인터페이스이기 때문에 우리가 해야 할 일은 IP 주소를 할당하여 이를 통해 네임스페이스에 도달할 수 있도록 하는 것입니다.

 

 

> ip addr add 192.168.15.5/24 dev v-net-0 명령 실행을 통해, 로컬 호스트에서 빨간색 네임스페이스로 ping이 가능해집니다. 이 전체 네트워크는 호스트 내에서 private이고, 제한되어 있다는 것을 기억해야 합니다. 네임스페이스 안에서는 외부와 연결될 수 없고, 외부인은 이 안에 호스팅된 서비스나 애플리케이션에 접근할 수 없습니다. 바깥으로 통하는 유일한 문은 호스트의 이더넷 포트입니다.

 

이더넷 포트를 통해 LAN 네트워크에 도달할 수 있는 bridge를 어떻게 구성할까요?  주소가 192.168.1.3인 lan 네트워크에 다른 호스트가 연결되어 있다고 가정합니다. 내 네임스페이스 내에서 이 호스트에 도달하려면 어떻게 해야 합니까? 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 주소가 있습니다. 하나는 192.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 게이트웨이를 추가합니다. 이제 이러한 네임스페이스 내에서 외부 세계에 도달할 수 있어야 합니다.

 

 

Docker Netoworking

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를 할당받습니다.

 

 

새 컨테이너가 생성될 때마다 동일한 절차가 수행됩니다. 도커는 네임스페이스를 만들고, 인터페이스 쌍을 만들고, 한쪽 끝을 컨테이너에 연결하고, 다른 쪽 끝을 브리지 네트워크에 연결합니다. 인터페이스 쌍은 번호를 사용하여 식별할 수 있습니다. 홀수와 짝수가 짝을 이룹니다. 9와 10, 7과 8,11과 12는 한 쌍입니다. 컨테이너는 이제 모두 네트워크의 일부입니다. 그들은 모두 서로 의사소통을 할 수 있습니다.

 

포트 80의 Docker 호스트 내에서 용기의 IP를 사용하여 curl을 사용하여 웹 페이지에 액세스하려고 하면 웹 페이지가 표시됩니다. 호스트 외부에서 동일한 작업을 수행하려고 하면 웹 페이지를 볼 수 없습니다. 외부 사용자가 컨테이너에 호스팅된 응용프로그램에 액세스할 수 있도록 도커는 포트 게시 또는 포트 매핑 옵션을 제공합니다. 컨테이너를 실행할 때 Docker에게 Docker 호스트의 포트 8080을 컨테이너의 포트 80에 매핑하도록 지시합니다. 이렇게 하면 도커 호스트의 IP와 포트 8080을 사용하여 웹 애플리케이션에 액세스할 수 있습니다. 도커 호스트의 포트 8080에 대한 트래픽은 컨테이너의 포트 80으로 전달됩니다. 이제 모든 외부 사용자와 다른 애플리케이션 또는 서버가 이 URL을 사용하여 호스트에 배포된 애플리케이션에 액세스할 수 있습니다.

 

 

하지만 도커는 어떻게 할까요? 어떻게 한 포트에서 다른 포트로 트래픽을 전달합니까? 도커와 다른 모든 것들은 잠시 잊어버립시다. 요구 사항은 한 포트에서 들어오는 트래픽을 서버의 다른 포트로 전달하는 것입니다. 우리는 그것에 대해 우리의 선행 강의 중 하나에서 이야기했습니다. NAT은 이를 위한 NAT 규칙을 만듭니다. IP 테이블을 사용하여 NAT 테이블에 항목을 생성하여 대상 포트를 8080에서 80으로 변경하는 규칙을 사전 라우팅 체인에 추가합니다. 도커도 같은 방식으로 합니다. Docker는 Docker 체인에 규칙을 추가하고 컨테이너의 IP도 포함하도록 대상을 설정합니다.

 

 

CNI

위에서는 네트워크 네임스페이스 작동 방식에 대해 알아보았습니다.

1. 시스템 내 격리된 네트워크 네임스페이스 환경을 생성하는 법

2. 브리지 네트워크를 통해 다수의 네임스페이스를 연결하는 법

3. 양쪽에서 가상 인터페이스를 통해 가상 케이블이나 파이프를 생성하는 법

4. 브리지와 엔드 네임스페이스에 연결하는 법

5. IP를 할당하는 법

6. 마지막으로 NAT, IP의 외부 통신하는 법

 

Rocket이나 Mesos Container와 같이 컨테이너와 함께 작동하고 Kubernetes와 같이 컨테이너 간의 네트워킹을 구성해야 하는 다른 솔루션들도 마찬가지입니다.

 

 

모두가 사소한 차이를 가지고 유사한 접근 방식을 연구하고 최종적으로 식별함으로써 동일한 네트워킹 문제를 해결하려고 한다면, 왜 동일한 솔루션을 여러 번 코딩하고 개발할까요? 모두가 따를 수 있는 단일 표준 접근 방식을 만들어 보는 것은 어떨까요? 그래서 우리는 이 모든 아이디어를 다른 솔루션에서 가져와 그것의 모든 네트워킹 부분을 하나의 프로그램이나 코드로 옮깁니다. 그리고 이것이 브리지 네트워크를 위한 것이기 때문에, 우리는 그것을 브리지라고 부릅니다.

 

그래서 우리는 컨테이너를 브리지 네트워크에 연결하기 위해 필요한 모든 작업을 수행하는 프로그램이나 스크립트를 만들었습니다. 예를 들어 Bridge라는 이름을 사용하여 이 프로그램을 실행하고 특정 네트워크 namespace에 이 컨테이너를 추가하도록 지정할 수 있습니다. Bridge 프로그램은 컨테이너 런타임 환경이 이러한 작업에서 벗어나도록 나머지 부분을 처리합니다. 예를 들어, Rocket 또는 Kubernetes가 새 컨테이너를 만들 때 Bridge Program을 호출하고 컨테이너 ID와 네임스페이스를 전달하여 해당 컨테이너에 대한 네트워킹을 구성합니다.

 

그렇다면 만약 여러분이 새로운 네트워킹 유형을 위해 그런 프로그램을 만들고 싶다면 어떨까요? 만약 당신이 그렇게 한다면, 그것은 어떤 arguments와 커맨드를 지원해야 합니까? 작성한 프로그램이 현재 실행 시간에 맞게 작동하는지 어떻게 확인합니까? Kubernetes나 Rocket과 같은 컨테이너 실행 시간이 당신의 프로그램을 정확하게 호출할 것이라는 것을 어떻게 압니까? 그것이 우리가 정의해야 할 몇 가지 기준이 필요한 부분입니다. 프로그램이 어떻게 보여야 하는지, 컨테이너 실행 시간이 어떻게 실행되는지 정의하는 표준으로, 모든 사용자가 단일 표준 세트를 준수하고 실행 시간에 걸쳐 작동하는 솔루션을 개발할 수 있습니다.

 

여기서 컨테이너 네트워크 인터페이스(CNI)가 등장합니다. 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와 유사하지만 약간의 차이가 있는 컨테이너 네트워킹 문제를 해결하는 것을 목표로 하는 또 다른 표준인 컨테이너 네트워크 모델을 의미합니다.

 

 

Cluster Networking

 

 

쿠버네티스 클러스터는 마스터와 작업 노드로 구성되어있습니다. 각 노드는 네트워크에 연결된 인터페이스가 최소한 하나는 있어야 합니다. 각 인터페이스는 반드시 구성된 주소가 있어야 하고, 호스트는 고유한 호스트 이름 세트와 고유한 mac 주소가 있어야 합니다. 기존 VM에서 replication하여 VM을 생성한 경우에는 이 점에 유의해야 합니다.

 

 

Ports

 

 

몇개의 포트도 열려있어야 하는데, 이들은 controlplane의 다양한 컴포넌트에 의해 사용됩니다. 마스터는 API 서버에 대해 6443의 연결을 허용해야 합니다. 워커 노드, Kube 제어 도구, 외부 사용자 및 기타 모든 제어부 config요소는 이 (6443)포트를 통해 Kube API 서버에 액세스합니다. 마스터 및 워커 노드의 kubelet은 포트 10250에서 수신합니다. 네, 이에 대해 논의하지 않은 경우 마스터 노드에도 쿠벨렛이 있을 수 있습니다. Kube 스케줄러를 사용하려면 포트 10259가 열려 있어야 합니다. Kube 컨트롤러 관리자를 사용하려면 포트 10257이 열려 있어야 합니다. 워커 노드는 포트 30000-32767에서 외부 액세스를 위한 서비스를 노출하므로 이 또한 열려 있어야 합니다. 마지막으로, etcd 서버는 포트 2379에서 수신합니다.

 

 

마스터 노드가 여러 개 있는 경우에는 이러한 모든 포트도 해당 포트에서 열어야 합니다. 그리고 당신은 etcd 클라이언트가 서로 통신할 수 있도록 추가 포트 2380이 열려 있어야 합니다.

 

 

Pos Networking

 

 

지금까지 우리는 여러 개의 Kubernetes 마스터 및 워커 노드를 설정하고, 이들 노드 간의 네트워킹을 구성하여 이들은 모두 서로 연결할 수 있는 네트워크에 있습니다. 또한 Kubernetes controlplane 컴포넌트가 서로 도달할 수 있도록 방화벽 및 네트워크 보안 그룹이 올바르게 구성되었는지 확인했습니다. 우리가 또한 kube-apiserver, etcd 서버, kubelet, 등과 같은 모든 Kubernetes 제어 평면 컴포넌트를 설정했고 마침내 애플리케이션을 배포할 준비가 되었다고 가정합니다. 하지만 그러기 전에, 우리가 해결해야 할 것이 있습니다. 우리는 노드를 함께 연결하는 네트워크에 대해 이야기했지만, 클러스터가 작동하는 데 중요한 또 다른 네트워킹 계층인 파드 계층의 네트워킹에 대해서도 이야기해야 합니다.

우리의 Kubernetes 클러스터는 곧 많은 수의 파드와 서비스를 실행할 것입니다. 파드는 어떻게 처리됩니까? 그들은 어떻게 서로 의사소통을 할까요? 클러스터 내에서뿐만 아니라 클러스터 외부에서도 이러한 파드에서 실행되는 서비스에 액세스하려면 어떻게 해야 합니까? 이것들은 쿠버네티스가 여러분이 해결하기를 기대하는 과제들입니다. 오늘날, 쿠버네티스는 이것에 대한 기본 제공 솔루션을 제공하지 않습니다. 그것은 당신이 이러한 과제를 해결하는 네트워킹 솔루션을 구현하기를 기대합니다. 그러나 Kubernetes는 파드 네트워킹에 대한 요구 사항을 명확하게 제시했습니다. 그것들이 무엇인지 살펴봅시다.

 

Kubernetes는 모든 파드가 고유한 IP 주소를 가질 것으로 예상하며, 모든 파드는 해당 IP 주소를 사용하여 동일한 노드 내의 다른 모든 파드에 도달할 수 있습니다. 또한 모든 Pod는 동일한 IP 주소를 사용하여 다른 노드의 모든 Pod에 연결할 수 있습니다. IP 주소가 어떤 IP 주소이고 어떤 범위 또는 서브넷에 속하는지는 중요하지 않습니다. IP 주소를 자동으로 할당하고 노드의 파드와 다른 노드의 부품 간 연결을 설정하는 솔루션을 구현할 수 있다면 네트워크 rule을 구성할 필요가 없습니다. 그렇다면 이러한 요구사항을 해결하는 모델을 어떻게 구현할 수 있을까요?

 

 

3개의 노드 클러스터가 있습니다. 어느 쪽이 주인이고 노동자인지는 중요하지 않습니다. 관리 또는 워크로드 목적으로 모두 파드를 실행합니다. 네트워킹에 관한 한, 우리는 그것들을 모두 동일하게 고려할 것이다. 그래서 먼저, 우리가 무엇을 할지 계획해 봅시다.

 

노드는 외부 네트워크의 일부이며 192.168.1. 시리즈의 IP 주소를 가집니다. 노드 1은 11, 노드 2는 12, 노드 3은 13이 할당됩니다. 다음 단계에서 컨테이너가 생성되면 Kubernetes는 컨테이너에 대한 네트워크 네임스페이스를 생성합니다. 이들 간의 통신을 가능하게 하기 위해, 우리는 이러한 네임스페이스를 네트워크에 연결한다. 하지만 어떤 네트워크일까요? 네임스페이스를 연결하기 위해 노드 내에 생성할 수 있는 브리지 네트워크에 대해 배웠습니다. 그래서 우리는 각 노드에 브리지 네트워크를 만들고 그들을 불러옵니다.

 

 

브리지 인터페이스 또는 네트워크에 IP 주소를 할당할 때입니다. 그런데 IP 주소가 뭐죠? 우리는 각 브리지 네트워크가 자체 서브넷에 있을 것이라고 결정한다. 개인 주소 범위(예: 10.244.1, 10.244.2 및 10.244.3)를 선택합니다. 다음으로 브리지 인터페이스의 IP 주소를 설정합니다.

 

 

나머지 단계는 새 컨테이너가 생성될 때마다 각 컨테이너에 대해 수행됩니다. 그래서 우리는 그것을 위한 스크립트를 작성합니다. 이제 복잡한 스크립팅을 알 필요가 없습니다. 이 파일은 앞으로 사용할 모든 커맨드가 포함된 파일이며, 앞으로 각 컨테이너에 대해 여러 번 실행할 수 있습니다.

 

 

컨테이너를 네트워크에 연결하려면 파이프 또는 가상 네트워크 케이블이 필요합니다. ip link add 커맨드를 사용하여 생성합니다. 옵션에 집중하지 마세요. 이전 강의에서 본 것과 비슷하니까요. 입력에 따라 다르다고 가정합니다. 그런 다음 ip link set 커맨드를 사용하여 한쪽 끝을 컨테이너에 부착하고 다른 쪽 끝을 브리지에 부착합니다. 그런 다음 ip addr 커맨드를 사용하여 IP 주소를 할당하고 default 게이트웨이에 route를 추가합니다. 하지만 어떤 IP를 추가해야 할까요? 우리는 그 정보를 스스로 관리하거나 일종의 데이터베이스에 저장합니다. 현재로서는 서브넷에서 사용 가능한 IP인 10.244.1.2라고 가정합니다. 우리는 다음 강의 중 하나에서 IP 주소 관리에 대해 자세히 논의합니다.

 

마지막으로, 우리는 인터페이스를 불러옵니다. 그런 다음 두 번째 컨테이너에 대해 동일한 스크립트를 실행하고 해당 컨테이너를 네트워크에 연결합니다. 이제 두 컨테이너가 서로 통신할 수 있습니다. 스크립트를 다른 노드에 복사하고 스크립트를 실행하여 IP 주소를 할당하고 해당 컨테이너를 자체 내부 네트워크에 연결합니다. 그래서 우리는 과제의 첫 부분을 해결했습니다. 파드들은 모두 고유한 IP 주소를 얻으며, 각자의 노드에서 서로 통신할 수 있다. 다음 부분은 다른 노드의 다른 파드에 도달할 수 있도록 하는 것입니다. 예를 들어 10.244.1.2에 있는 Pod(노드 1)가 Pod 10.244.2.2 또는 노드 2를 ping하려고 한다고 가정합니다.

 

 

정리해봅시다. 브리지 네트워크와 라우팅 테이블을 사용하여 환경을 준비하기 위해 여러 가지 수동 단계를 수행했습니다. 그런 다음 각 컨테이너를 네트워크에 연결하는 데 필요한 단계를 수행하는 각 컨테이너에 대해 실행할 수 있는 스크립트를 작성하고 스크립트를 수동으로 실행했습니다. 물론, 매분 수천 개의 파드가 생성되는 대규모 환경에서와 같이, 우리는 그렇게 하고 싶지 않습니다. 그렇다면 쿠버네티스에서 파드이 생성될 때 어떻게 자동으로 스크립트를 실행할 수 있을까요? 거기서 중간자 역할을 하는 CNI가 나옵니다.

 

CNI는 컨테이너를 생성하는 즉시 스크립트를 호출하는 방법을 Kubernetes에 알려줍니다. 그리고 CNI는 우리에게 당신의 스크립트가 이렇게 보여야 한다고 말합니다. 그래서 우리는 CNI 기준에 맞게 스크립트를 조금 수정해야 합니다. 네트워크에 컨테이너를 추가하는 추가 섹션과 네트워크에서 컨테이너 인터페이스를 삭제하고 IP 주소를 해제하는 삭제 섹션이 있어야 합니다.

 

이렇게 스크립트가 준비되었습니다. 각 노드의 Container Runtime은 컨테이너 생성을 담당합니다. 컨테이너가 생성될 때마다 Container Runtime은 CNI configuration을 보고 실행 시 커맨드라인 arguments로 전달되며 스크립트의 이름을 식별합니다. 그런 다음 CNI의 bin 디렉토리를 검색하여 스크립트를 찾은 다음 add 커맨드과 컨테이너의 이름 및 네임스페이스 ID로 스크립트를 실행합니다. 그리고 나머지는 우리 스크립트가 알아서 합니다.

 

 

CNI in kubernetes

이 강의에서는 이러한 네트워크 플러그인을 사용하도록 Kubernetes가 어떻게 구성되어 있는지 알아보겠습니다. prerequisite 강의에서 논의한 바와 같이, CNI는 Container Runtime 책임을 정의합니다. 이 경우, Kubernetes는 컨테이너 네트워크 네임스페이스를 생성하고, 확인 및 부착하는 일을 합니다. 올바른 네트워크 플러그인을 호출하여 해당 네임스페이스를 식별하죠. 

 

그렇다면 쿠버네티스가 사용할 CNI 플러그인을 어디에 지정해야 할까요? CNI 플러그인은 반드시 컨테이너를 만드는 구성 요소를 기반으로 작동해야 합니다. 왜냐하면 컨테이너를 생성한 후 해당 컴포넌트가 적절한 네트워크 플러그인을 호출해야 하므로 컨테이너 생성을 담당하는 Kubernetes 내의 컴포넌트에서 CNI 플러그인을 호출해야 합니다.

 

컨테이너 생성을 책임지는 컨테이너 구성 요소는 Container Runtime입니다. 예로 containerd, cri-o 등이 자주 사용되는 예고, Docker가 원래 Container Runtime은 아닌것이죠.

 

특정 플러그인을 사용하기 위해 Container Runtime을 어떻게 구성하나요? 우선 네트워크 플러그인은 /opt/cni/bin에 설치되어 있습니다. Container Runtime이 플러그인을 찾는 곳이죠. 어떤 플러그인을 어떻게 사용할지는 /etc/cni/net.d에 구성되어 있습니다.

 

 

CNI weave solution

 

 

이 강의에서 우리는 CNI, 특히 Weaveworks를 기반으로 한 하나의 솔루션에 대해 논의할 것입니다. Weaveworks는 CNI 플러그인과 함께 작동합니다. 이전 연습 테스트에서는 구성 방식을 확인했습니다. 이제 우리는 그것이 어떻게 작동하는지에 대해 더 자세히 볼 것입니다.

파드 네트워킹 개념 섹션에서 우리가 중단한 부분부터 시작하겠습니다. 우리는 자체적으로 CNI 스크립트를 구축하고 CNI를 통해 kubelet에 통합했습니다.

 

이제는 Weave 플러그인을 통합하는 방법을 보겠습니다. 이제 Weave 솔루션이 어떻게 작동하는지 알아보겠습니다. 하나 이상의 솔루션을 잘 이해하는 것이 중요하기 때문입니다. 그러면 이 문제를 다른 솔루션과도 연결할 수 있습니다. 따라서 수동으로 설정한 네트워킹 솔루션에는 어떤 네트워크가 어떤 호스트에 있는지 매핑하는 라우팅 테이블이 있었습니다. 패킷이 한 파드에서 다른 파드로 전송될 때, 패킷은 네트워크, 라우터로 전송되고 그 파드를 호스트하는 노드로 전송됩니다.

 

위 방법은 소규모 환경과 단순한 네트워크에서 작동하지만 클러스터에 수백 개의 노드가 있고 각 노드에 수백 개의 파드가 있는 대규모 환경에서는 실용적이지 않습니다. 라우팅 테이블은 너무 많은 항목을 지원하지 않을 수 있으므로 창의적으로 다른 솔루션을 찾아야 합니다.

 

 

Kubernetes 클러스터를 우리 회사로, 노드를 서로 다른 사무실 사이트로 생각해봅시다. 사이트마다 부서가 다르고 부서마다 사무실이 다릅니다. 1번 사무실에 있는 누군가가 3번 사무실로 소포를 보내서 사무실 직원에게 넘기길 원합니다. 그가 아는 것은 그것이 3번 사무실로 가야 한다는 것이고, 그는 그것이 누구에게 어떻게 운반되는지 신경 쓰지 않습니다.

 

사무실 직원은 소포를 들고, 차에 올라타서 GPS로 대상 사무실의 주소를 보고, 길을 안내받고, 목적지로 가는 길을 찾아서, 급여 부서에 소포를 전달하고, 그 다음에 3번 사무실로 소포를 전달합니다. 이것은 현재로서는 아주 잘 작동합니다. 이것을 다른 지역이나 국가로 확장하면 이 과정은 더 이상 작동하지 않습니다. 사무실 직원이 여러 나라에 걸쳐 이렇게 많은 사무실로 가는 많은 route를 추적하는 것은 어려운 일이며, 물론 그는 혼자서 이 사무실로 운전해서 갈 수도 없습니다. 그래서 우리는 모든 우편 및 배송 활동을 가장 잘 하는 회사에 아웃소싱하기로 결정했습니다.

 

일단 운송 회사가 계약되면, 그들이 가장 먼저 하는 일은 그들의 에이전트들을 우리 회사의 각 사이트에 배치하는 것입니다. 이러한 에이전트는 사이트 간의 모든 배송 작업을 관리합니다. 그들은 또한 서로 계속 이야기하고 잘 연결되어 있습니다. 그래서 그들은 서로의 사이트, 그 안에 있는 부서, 그리고 그 안에 있는 사무실에 대해 모두 알고 있습니다. 그래서 10번 사무실에서 3번 사무실로 소포를 보내면, 그 사이트의 운송업자가 소포를 가로채서 대상 사무실 이름을 봅니다. 그는 다른 사이트의 동료들과의 작은 내부 네트워크를 통해 그 사무실이 어느 사이트와 부서에 있는지 정확히 알고 나서, 대상 사이트의 위치에 목적지 주소가 설정된 자신의 새 패키지에 이 패키지를 넣은 다음 패키지를 통해 보냅니다. 패키지가 해당 사이트의 에이전트에 의해 다시 차단되는 대상에 도착하면, 그는 패킷을 열고 원래 패킷을 검색하여 올바른 부서로 전달합니다.

 

weave는 위와 비슷합니다. 각 노드에 에이전트를 배치하고, 서비스를 배포합니다. 서로 교류도 하며, 통신합니다. 각 에이전트는 다른 노드에서 파드와 자신의 IP를 알 수 있는 방식으로 전체 설정을 별도로 저장합니다. weave는 각각의 네트워크의 ip 주소를 가지고 있습니다. 

 

하나의 파드가 여러 브리지 네트워크에 연결될 수 있음을 기억하세요. 예를 들어, Docker에서 만든 Docker Bridge 뿐만 아니라 Weave Bridge에도 파드를 부착할 수 있습니다. 패킷이 대상에 도달하기 위해 사용하는 경로는 컨테이너에 config된 경로에 따라 다릅니다. 파드가 에이전트에 도달하도록 config된 올바른 경로를 확보하고 에이전트가 다른 파드를 처리하도록 했습니다. 이제 패킷이 한 파드에서 다른 노드의 다른 파드로 전송되면 weave는 패킷을 가로채고 별도의 네트워크에 있음을 식별합니다. 그런 다음 이 패킷을 새 소스 및 대상이 있는 새 패킷으로 캡슐화하고 네트워크를 통해 전송합니다. 반대쪽에 있는 다른 위브 에이전트는 패킷을 검색하여 캡슐을 해제하고 패킷을 파드로 라우팅합니다.

 

 

그렇다면 어떻게 Kubernetes 클러스터에 Weave를 배포할 수 있을까요? weave 와 weave peers는 수동으로 클러스터의 각 노드에 서비스 또는 데몬으로 배포할 수 있으며, 쿠버네티스가 이미 설정되어 있는 경우, 클러스터의 파드로 배포하는 것이 더 쉬운 방법입니다. 기본 Kubernetes 시스템이 노드로 준비되고, 노드와 컨트롤 플레인 컴포넌트 사이에 올바르게 구성된 네트워킹이 배포되면 kubectl apply 커맨드로 클러스터에서 weave에 필요한 모든 구성 요소를 배포할 수 있습니다.

 

이렇게 하면 Weave에 필요한 모든 컴포넌트가 클러스터에 배포됩니다. 가장 중요한 것은 위브 피어가 데몬 세트로 배포된다는 것입니다. 데몬 세트는 지정된 한 부분이 클러스터의 모든 노드에 배포되도록 합니다. 이것은 Weave peer들에게 완벽하게 작동합니다. kubeadm 도구와 Weave 플러그인을 사용하여 클러스터를 배포한 경우, Weave 피어를 각 노드에 배포된 부품으로 볼 수 있습니다. 문제 해결을 위해 kube control logs 커맨드를 사용하여 로그를 볼 수 있습니다.

 

 

IPAM(IP Adress Management)

 

 

가상 브리지 네트워크가 어떻게 IP 서브넷과 pod ip가 할당될까요? 그 정보는 어디에 있나요? 중복되는 IP는 어떻게 관리할까요? 기준을 정하는 것은 CNI입니다. CNI 플러그인의 임무는 컨에티어네 IP를 할당하는것이죠. 컨테이너 네트워크 네임스페이스에 IP를 할당한 적이 있는데, 이런 IP를 어떻게 관리할까요? 쉬운 방법은 파일에 IP 목록을 저장하고, 관리하기 위해 스크립트에 필요한 코드가 있는지 확인하는 것이죠. 

 

해당 파일은 각 호스트에 놓여져, 해당 노드의 IP를 관리할 수 있습니다. 우리의 스크립트에서 직접 코딩하는 대신, CNI에는 이 작업을 아웃소싱할 수 있는 두 개의 플러그인이 built in되어 있습니다. 이 경우 각 호스트의 IP 주소를 로컬로 관리하기 위해 수행한 방식을 구현하는 플러그인이 호스트 로컬 플러그인입니다. 그러나 스크립트에서 플러그인을 호출하는 것은 여전히 우리의 책임입니다. 그렇지 않으면 스크립트를 동적으로 만들어 다양한 종류의 플러그인을 지원할 수 있습니다.

 

 

CNI configuration 파일에는 사용할 플러그인 유형, 서브넷 및 경로를 지정할 수 있는 IPAM이라는 섹션이 있습니다. 이러한 세부 정보는 매번 호스트 로컬을 사용하도록 하드 코딩하는 대신 적절한 플러그인을 호출하기 위해 스크립트에서 읽을 수 있습니다. 네트워크 솔루션 공급자에 따라 이를 다르게 수행합니다.

 

 

예로 Weaveworks가 IP 주소를 어떻게 관리하는지 알아봅시다. 이전 연습 테스트에서 Weave가 할당한 IP 중 일부를 본 적이 있습니다. default로 Weave는 전체 네트워크에 대해 IP 범위 10.32.0.0/12를 할당합니다. 네트워크 IP 범위는 10.32.0.1 ~ 10.47.255.254입니다. 네트워크의 파드에 사용할 수 있는 IP는 약 백만 개입니다. 이 범위에서 peers는 IP 주소를 동일하게 분할하기로 결정하고, 각 노드에 한 부분을 할당합니다. 이 노드에서 생성된 파드는 이 범위의 IP를 가집니다. 물론 이러한 범위는 Weave 플러그인을 클러스터에 배포하는 동안 이전의 추가 옵션으로 구성할 수 있습니다.

 

 

Service Networking

앞선 강의에서는 파드 네트워킹에 대해 배웠습니다. 이번에는 서비스 네트워킹에 대해 얘기해보겠습니다. 각 노드 안에서 어떻게 네트워크가 생성되고, 어떻게 네임스페이스가 생성되며, 어떻게 인터페이스가 네임스페이스에 연결되며, 어떻게 노드에 할당된 서브넷에서 IP 주소를 얻는지 알아보겠습니다.

 

 파드가 서로 직접 통신하도록 구성하는 경우는 거의 없습니다. 다른 파드에서 호스팅되는 서비스에 액세스하려면 항상 서비스를 사용해야 합니다. 다양한 종류의 서비스에 대해 간단히 요약해 보겠습니다. blue 파드가 orange 파드에 접근할 수 있도록, 우리는 orange 서비스를 만듭니다. orange 서비스는 IP 주소와 할당된 이름을 가져옵니다. 이제 blue 파드는 orange 서비스 IP 또는 해당 이름을 통해 orange 파드에 액세스할 수 있습니다. 우리는 이번 강의에서 name resolution에 대해 이야기할 것입니다.

 

지금은 IP 주소에만 집중합시다. blue과 orange 보드가 같은 노드에 있습니다. 다른 파드나 다른 노드에서 액세스하는 것은 어떻습니까? 서비스가 생성되면 파드가 어떤 노드에 있는지에 관계없이 클러스터의 모든 파드에서 서비스에 액세스할 수 있습니다. 파드가 노드에서 호스팅되는 동안 서비스는 클러스터 전체에서 호스팅됩니다.  서비스는 특정 노드에 바인딩되지 않지만 클러스터 내에서만 액세스할 수 있습니다. 이러한 유형의 서비스를 클러스터 IP라고 합니다. orange 파드가 클러스터 내에서만 액세스할 수 있는 데이터베이스 애플리케이션을 호스팅하고 있었다면 이러한 유형의 서비스는 제대로 작동합니다.

 

purple 파드가 클러스터 외부에서 파드의 애플리케이션에 액세스할 수 있도록 웹 애플리케이션을 호스팅하고 있었다고 가정해 보겠습니다. 노드 포트 유형의 다른 서비스를 생성합니다. 또한 이 서비스는 할당된 IP 주소를 가져오고 클러스터 IP와 마찬가지로 작동합니다. 다른 모든 파드에서는 IP를 사용하여 서비스에 액세스할 수 있습니다. 또한 클러스터의 모든 노드에 있는 포트에 애플리케이션이 노출됩니다. 이렇게 하면 외부 사용자 또는 응용프로그램이 서비스에 액세스할 수 있습니다. 이것이 이번 강의의 주제입니다. 

 

우리는 파드보다는 서비스에 더 초점을 맞추고 있습니다. 서비스는 어떻게 이러한 IP 주소를 가져오고 클러스터의 모든 노드에서 이러한 IP 주소를 사용할 수 있을까요? 각 노드의 포트를 통해 외부 사용자가 서비스를 이용할 수 있는 방법은 무엇인가요? 누가, 어떻게, 그리고 어디에서 그것을 볼 수 있을까요? 그럼 시작해볼게요.

 

3개 노드 클러스터가 있고 파드나 서비스는 아직 없습니다. 우리는 모든 Kubernetes 노드가 파드를 만드는 kubelet 프로세스를 실행한다는 것을 알고 있습니다. 각 노드의 각 kubelet 서비스는 kube-apiserver를 통해 클러스터의 변경 사항을 모니터링하며, 새로운 파드가 생성될 때마다 노드에 파드를 생성합니다. 그런 다음 CNI 플러그인을 호출하여 해당 파드에 맞는 네트워킹을 구성합니다. 비슷하게, 각 노드는 kube-proxy로 알려진 또 다른 컴포넌트를 실행합니다. kube-proxy는 kube-apiserver를 통해 클러스터의 변화를 감시하고, 새로운 서비스가 생성될 때마다 kube-proxy가 실행됩니다.

 

파드와 달리 서비스는 각 노드에 생성되거나 각 노드에 할당되지 않습니다. 서비스는 클러스터 차원의 개념입니다. 클러스터의 모든 노드에 존재합니다. 사실, 그들은 전혀 존재하지 않습니다. 서비스의 IP를 실제로 수신하는 서버나 서비스가 없습니다. 파드에는 컨테이너가 있고 컨테이너에는 인터페이스와 Ip가 할당된 네임스페이스가 있습니다. 서비스에 대한 프로세스, 네임스페이스 또는 인터페이스가 없습니다. 그것은 단지 가상의 물체일 뿐입니다.

 

그렇다면 그들은 어떻게 IP 주소를 얻고 우리는 어떻게 서비스를 통해 파드의 애플리케이션에 액세스할 수 있을까요?

1. 쿠버네티스에서 서비스 객체를 생성하면 미리 정의된 범위에서 IP 주소를 할당합니다.

2. IP 주소를 할당하면 각 노드에서 실행중인 kube-proxy 구성 요소는 해당 IP 주소를 받아 클러스터 내 각 노드에 전달 규칙을 만듭니다.
3. 서비스의 IP인 이 IP로 오는 트래픽은 파드의 IP로 가야 합니다. 일단 서비스가 설치되면 파드가 서비스의 IP에 도달하려고 할 때마다 서비스는 클러스터의 모든 노드에서 액세스할 수 있는 파드의 IP 주소로 전달됩니다. IP뿐만 아니라 IP와 포트의 조합이라는 점을 기억하세요. 서비스가 생성되거나 삭제될 때마다 kube-proxy 컴포넌트는 이러한 rule을 생성하거나 삭제합니다.

 

그렇다면 이 규칙들은 어떻게 만들어졌을까요? kube-proxy는 userspace와 같이 다양한 방식을 지원하며, IPVS rule을 만들어 파드에 대한 연결을 수신합니다. 우리에게 익숙한 것은 iptables을 사용하는 것입니다. 프록시 모드는 kube-proxy 서비스를 구성하는 동안 프록시 모드 옵션을 사용하여 설정할 수 있습니다. 이 옵션을 설정하지 않으면 default로 iptables로 설정됩니다.

 

 

Cluster DNS

3개의 노드 쿠버네티스 클러스터가 있습니다. 일부 pod와 서비스가 배포된 상태죠. 각 노드에는 할당된 노드의 이름이 있고, IP 주소가 있습니다. 클러스터의 노드 이름과 IP 주소는 DNS 서버에 등록되어 있습니다. 그것을 어떻게 관리할까요?

 

파드와 서비스들 같은 클러스터 내에서, 다른 컴포넌트 사이들 내에 DNS resolution에 대해 얘기해보죠. 쿠버네티스는 클러스터를 설정할 때 기본 탑재된 DNS 서버를 배포합니다. 

 

두 개의 파드과 하나의 서비스로 시작해 보겠습니다. 왼쪽에는 IP가 10.244.1.5로 설정된 테스트 파드가 있고 오른쪽에는 IP가 10.2.44.2.5로 설정된 웹 파드가 있습니다. 그들의 IP를 보면 아마도 두 개의 다른 노드에서 호스팅되고 있다고 추측할 수 있지만 실제로는 중요하지 않습니다. DNS에 관한 한 모든 파드와 서비스는 IP 주소를 사용하여 서로 도달할 수 있다고 가정합니다. 테스트 파드에서 웹 서버에 액세스할 수 있도록 서비스를 작성합니다. 우리는 그것을 웹 서비스라고 불러보죠.

 

서비스는 IP 10.107.37.188을 받습니다. 서비스가 생성될 때마다 Kubernetes DNS 서비스는 서비스에 대한 레코드를 생성합니다. 서비스 이름을 IP 주소에 매핑하므로 클러스터 내에서 이제 모든 파드가 해당 서비스 이름을 사용하여 이 서비스에 도달할 수 있습니다. 이전에 네임스페이스에 대해 이야기한 것을 기억하세요. 네임스페이스 내의 모든 사람은 이름으로만 서로를 부르고 다른 네임스페이스에 있는 사람을 부르려면 전체 이름을 사용합니다. 이 경우 테스트 파드과 웹 파드 및 관련 서비스가 모두 default 네임스페이스인 동일한 네임스페이스에 있으므로 서비스 이름 web-service만 사용하여 테스트 파드에서 웹 서비스에 간단히 도달할 수 있었습니다.

 

웹 서비스가 Apps라는 별도의 네임스페이스에 있다고 가정해 보겠습니다. 그런 다음 default 네임스페이스에서 참조하려면 웹 서비스라고 말해야 합니다. 앱. 서비스의 성은 이제 네임스페이스의 이름입니다. 여기서 Web Service는 서비스의 이름이고 Apps는 네임스페이스의 이름입니다. 각 namespace에 대해 DNS 서버는 하위 도메인을 만듭니다. 모든 서비스는 SVC라는 또 다른 하위 도메인으로 함께 그룹화됩니다.

 

만약 같은 namespace에 있다면, > curl http://web-service

만약 다른 namespace에 있다면, > curl http://web-service.apps (Fullname)

 

자세히 살펴보겠습니다. 웹 서비스는 서비스의 이름이고 앱은 namespace의 이름입니다. 각 네임스페이스에 대해 DNS 서버는 해당 이름으로 하위 도메인을 만듭니다. 따라서 네임스페이스에 대한 모든 파드 및 서비스는 네임스페이스 이름의 하위 도메인 내에서 함께 그룹화됩니다. 모든 서비스는 SVC라는 또 다른 하위 도메인으로 그룹화됩니다. 따라서 webservice.apps.svc라는 이름으로 애플리케이션에 연결할 수 있습니다. 마지막으로 모든 서비스와 파드은 default로 cluster.local로 설정된 클러스터의 경로 도메인으로 함께 그룹화됩니다. 따라서 URL webservice.apps.svc.cluster.local을 사용하여 서비스에 액세스할 수 있으며 이는 서비스의 정규화된 도메인 이름입니다.

 

이것이 클러스터 내에서 서비스가 해결되는 방식입니다. 파드는 어떻습니까? 파드에 대한 레코드는 default로 생성되지 않지만 명시적으로 활성화할 수 있습니다. 다음 강의에서 보도록 하겠습니다. 활성화되면 파드에 대한 레코드도 생성됩니다. 하지만 파드 이름을 사용하지 않습니다. 각 파드에 대해 Kubernetes는 IP 주소의 점을 대시로 대체하여 이름을 생성합니다. namespace은 동일하게 유지되고 유형은 pod로 설정됩니다. 경로 도메인은 항상 cluster.local입니다.

 

마찬가지로 default 네임스페이스의 테스트 파드는 IP가 대시 호스트 이름인 10-244-1-5로 변환되고 네임스페이스가 default값으로 설정된 DNS 서버에서 레코드를 가져옵니다. 유형은 파드 이고 그 경로는 cluster.local입니다. 이것은 포드의 IP 주소로 귀결됩니다.

 

 

CoreDNS in k8s

2개의 IP 주소가 있는 2개의 파드가 주어졌다고 가정하면 어떻게 하시겠습니까? DNS에 대한 필수 강의에서 배운 내용을 기반으로 서로를 해결하는 쉬운 방법은 각각의 etc 호스트 파일에 항목을 추가하는 것입니다. 첫 번째 파드에서 두 번째 파드인 web은 10.244.2.5에 있고 두 번째 파드에서는 첫 번째 파드인 test가 10.244.1.5에 있다고 말할 수 있습니다. 물론 클러스터에 수천 개의 파드가 있고 매분 수백 개가 생성 및 삭제되는 경우 이는 적합한 솔루션이 아닙니다.

 

따라서 이러한 항목을 중앙 DNS 서버로 이동합니다. 그런 다음 etc/resolv.conf 파일에 항목을 추가하고 이름 서버가 DNS 서버의 IP 주소(이 경우 10.96.0.10)에 있음을 지정하여 이러한 파드를 DNS 서버로 지정합니다. 새 파드가 생성될 때마다 다른 파드가 새 파드에 액세스하고 파드의 etc/resolv.conf 파일이 DNS 서버를 가리키도록 구성할 수 있도록 해당 파드의 DNS 서버에 레코드를 추가합니다. 새 파드가 클러스터의 다른 파드를 확인할 수 있도록 합니다. 이것은 쿠버네티스가 수행하는 방식과 비슷하지만 이전 강의에서 본 것처럼 파드 이름을 IP 주소에 매핑하기 위해 파드에 대한 유사한 항목을 생성하지 않습니다. 서비스를 위해 그렇게합니다.

 

파드의 경우 파드의 IP 주소에서 점을 대시로 대체하여 호스트 이름을 구성합니다. Kubernetes는 동일한 방식으로 DNS를 구현합니다. 클러스터 내에 DNS 서버를 배포합니다. 버전 1.12 이전에는 Kubernetes에 의해 구현된 DNS 서버가 Kube DNS로 알려졌으며 Kubernetes 버전 1.12에서는 권장 DNS 서버가 CoreDNS입니다. 필수 강의 중 하나에서 CoreDNS를 간략하게 살펴보았습니다. 그렇다면 클러스터에서 CoreDNS는 어떻게 설정됩니까? CoreDNS 서버는 Kubernetes 클러스터의 kube-system namespace에 파드로 배포됩니다. replicas 세트의 일부로 중복성을 위해 두 개의 파드로 배포됩니다. 실제로 Delpolyment 내의 Replicaset이지만 실제로는 중요하지 않습니다. 하지만 이 강의에서는 CoreDNS를 파드로만 볼 것입니다.

 

이 파드는 CoreDNS 실행 파일을 실행합니다. CoreDNS를 직접 배포할 때 실행한 것과 동일한 실행 파일입니다. CoreDNS에는 configuration 파일이 필요합니다. 우리의 경우 Core file이라는 파일을 사용했고 Kubernetes도 마찬가지입니다. etc/coredns에 위치한 CoreFile이라는 파일을 사용합니다. 이 파일에는 여러 플러그인이 구성되어 있습니다.

 

플러그인은 오류 처리, 상태 보고, 메트릭 모니터링, 현금 등을 위해 구성됩니다. CoreDNS가 Kubernetes와 작동하도록 하는 플러그인은 Kubernetes 플러그인입니다. 그리고 클러스터의 최상위 도메인 이름이 설정되는 곳입니다. 이 경우 cluster.local입니다. 따라서 CoreDNS DNS 서버의 모든 레코드는 이 도메인에 속합니다.

 

Kubernetes 플러그인에는 여러 가지 옵션이 있습니다. 여기에서 볼 수 있는 파드 옵션은 클러스터의 파드에 대한 레코드 생성을 담당합니다. IP를 파선 형식으로 변환하여 각 파드에 대해 생성되는 레코드에 대해 이야기했음을 기억하세요. default로 비활성화되어 있지만 여기에서 이 항목을 사용하여 활성화할 수 있습니다.

 

예를 들어 파드가 www.google.com에 도달하려고 한다고 말하면 DNS 서버가 해결할 수 없는 모든 레코드는 CoreDNS 파드 등 resolv.conf 파일에 지정된 이름 서버로 전달됩니다. etc/resolv.conf 파일은 Kubernetes 노드에서 이름 서버를 사용한다고 합니다. 또한 이 코어 파일은 configmap 오브젝트로 파드에 전달됩니다. 이렇게 하면 이 configuration을 수정해야 하는 경우 configmap 오브젝트를 편집할 수 있습니다. 이제 적절한 Kubernetes 플러그인을 사용하여 CoreDNS 파드를 실행하고 있습니다. Kubernetes 클러스터에서 새로운 파드 또는 서비스를 감시하고 파드 또는 서비스가 생성될 때마다 데이터베이스에 레코드를 추가합니다.

 

다음 단계는 Pod가 CoreDNS 서버를 가리키는 것입니다. 파드는 DNS 서버에 도달하기 위해 어떤 주소를 사용할까요? CoreDNS 솔루션을 배포할 때 클러스터 내의 다른 컴포넌트에서 사용할 수 있도록 서비스도 생성합니다. 서비스 이름은 default로 kube-dns로 지정됩니다. 파드의 DNS config은 파드가 생성될 때 Kubernetes에 의해 자동으로 수행됩니다.

 

이를 담당하는 Kubernetes 구성요소를 추측하고 싶으신가요? kubelet입니다. kubelet의 config 파일을 보면 그 안에 DNS 서버와 도메인의 IP가 보입니다. 파드가 올바른 이름 서버로 config되면 이제 다른 파드 및 서비스를 확인할 수 있습니다. web service 또는 web service.default 또는 web service.default.svc 또는 webservice.default.svc.cluster.local를 사용하여 웹 서비스에 액세스할 수 있습니다.

 

NS lookup 또는 호스트 웹 서비스 명령을 사용하여 웹 서비스를 수동으로 조회하려고 하면 웹 서비스의 정규화된 도메인 이름(web-service.default.svc.cluster.local)이 반환됩니다. 하지만 당신은 그것을 요구하지 않았습니다. 당신은 방금 웹 서비스를 말했습니다다. 그렇다면 전체 이름은 어떻게 찾았을까요? resolv.conf 파일에도 default.service.cluster.local, svc.cluster.local 및 cluster.local로 설정된 검색 항목이 있습니다. 이렇게 하면 이름, 웹 서비스 또는 웹 service.default 또는 웹 service.default.svc를 사용하여 서비스를 찾을 수 있습니다. 그러나 서비스에 대한 검색 항목만 있으므로 동일한 방식으로 포드에 연결할 수 없습니다. 이를 위해서는 포드의 전체 FQDN을 지정해야 합니다.

 

 

Ingress

 

 

제품을 판매하는 온라인 매장이 있는 회사를 위해 Kubernetes에 애플리케이션을 배포하고 있습니다. 애플리케이션은 예를 들어 my-online-store.com에서 사용할 수 있습니다. 애플리케이션을 Docker 이미지로 빌드하고 Kubernetes 클러스터에 Deployment의 Pod로 배포합니다. 애플리케이션에는 데이터베이스가 필요하므로 MySQL 데이터베이스를 파드로 배포하고 mysql-service이라는 클러스터 IP 유형의 서비스를 생성하여 애플리케이션에 액세스할 수 있도록 합니다. 이제 애플리케이션이 작동합니다.

 

 

외부 세계에서 애플리케이션에 액세스할 수 있도록 하려면 이번에는 노드 포트 유형인 또 다른 서비스를 만들고 클러스터의 노드에 있는 high 포트에서 애플리케이션을 사용할 수 있도록 합니다. 이 예에서는 포트 38080이 서비스에 할당됩니다. 이제 사용자는 포트 38080 다음에 오는 노드의 URL HTTP://IP를 사용하여 애플리케이션에 액세스할 수 있습니다. 해당 설정이 작동하고 사용자가 애플리케이션에 액세스할 수 있습니다. 트래픽이 증가할 때마다 추가 트래픽을 처리하기 위해 파드의 replicas 수를 늘리고 파드 간에 트래픽을 분할하는 서비스를 처리합니다.

 

 

예를 들어 우리는 사용자가 매번 IP 주소를 입력해야 하는 것을 원하지 않습니다. 따라서 노드의 IP를 가리키도록 DNS 서버를 구성합니다. 이제 사용자는 URL myonlinestore.com 및 포트 38080을 사용하여 애플리케이션에 액세스할 수 있습니다. 이제 사용자가 포트 번호도 기억하지 않아도 되기를 바랍니다. 그러나 서비스 노드 포트는 30,000보다 큰 높은 번호의 포트만 할당할 수 있습니다. 따라서 DNS 서버와 클러스터 사이에 프록시 서버와 같은 추가 계층을 가져옵니다. 포트 80의 요청을 노드의 포트 38080으로 프록시합니다. 그런 다음 DNS를 이 서버로 지정하면 사용자는 이제 myonlinestore.com을 방문하기만 하면 애플리케이션에 액세스할 수 있습니다.

 

 

이제 애플리케이션이 데이터 센터에서 온프레미스로 호스팅되는 경우입니다. Google Cloud 플랫폼과 같은 퍼블릭 클라우드 환경에 있다면 무엇을 할 수 있는지 살펴보겠습니다. 이 경우 wear 애플리케이션에 대해 노드 포트 유형의 서비스를 생성하는 대신, 로드 밸런서 유형으로 설정할 수 있습니다. 이렇게 하면 Kubernetes는 서비스에 대해 high 포트를 프로비저닝하는 노드 포트에 대해 수행해야 하는 모든 작업을 계속 수행합니다.

 

그러나 그 외에도 Kubernetes는 이 서비스에 대한 네트워크 로드 밸런서를 프로비저닝하기 위해 Google Cloud 플랫폼에 요청을 보냅니다. 요청을 받으면 GCP는 트래픽을 모든 노드의 서비스 포트로 라우팅하도록 구성된 로드 밸런서를 자동으로 배포하고, 해당 정보를 Kubernetes에 반환합니다. 로드 밸런서에는 애플리케이션에 액세스하기 위해 사용자에게 제공할 수 있는 외부 IP가 있습니다. 이 경우에는 DNS가 이 IP를 가리키도록 설정하고 사용자는 URL myonlinestore.com을 사용하여 애플리케이션에 액세스합니다.

 

개발자는 기존의 것과 관련이 없기 때문에 완전히 다른 애플리케이션으로 새로운 비디오 스트리밍 애플리케이션을 개발했습니다. 그러나 동일한 클러스터 리소스를 공유하려면 동일한 클러스터 내에서 별도의 deployment로 새 애플리케이션을 배포합니다. 로드 밸런서 유형의 video-service라는 서비스를 생성합니다. Kubernetes는 이 서비스에 대해 포트 38282를 프로비저닝하고 클라우드에 네트워크 로드밸런서도 프로비저닝합니다.

 

 

새 로드 밸런서에는 새 IP가 있습니다. 이러한 로드 밸런서 각각에 대해 비용을 지불해야 하며 이러한 로드 밸런서가 많으면 클라우드 청구서에 영향을 미칠 수 있습니다. 그렇다면 사용자가 입력하는 URL을 기반으로 각 로드 밸런서 간에 어떻게 트래픽을 전달할까요? URL을 기반으로 트래픽을 다른 서비스로 리디렉션할 수 있는 또 다른 프록시 또는 로드 밸런서가 필요합니다. 새로운 서비스를 도입할 때마다 로드 밸런서를 재구성해야 합니다.

 

마지막으로 사용자가 HTTPS를 사용하여 애플리케이션에 액세스할 수 있도록 애플리케이션에 SSL을 활성화해야 합니다. 어디서 구성할까요? 이것은 애플리케이션 자체 레벨, 로드 밸런서 또는 프록시 서버 레벨 등 다양한 레벨에서 수행할 수 있습니다. 그런데 어떤 레벨인가요?
최소한의 유지 관리로 한 곳에서 구성하기를 원합니다. 이제는 다양한 configuration이 있으며 애플리케이션이 확장되면 이러한 모든 configuration을 관리하기가 어려워집니다. 각각의 새 서비스에 대해 방화벽 rule을 구성해야 하며 비용이 많이 들 뿐만 아니라 각 서비스에 대해 새 클라우드 native 로드 밸런서를 프로비저닝해야 합니다. Kubernetes 클러스터 내에서 모든 것을 관리하고 나머지 애플리케이션 deployment 파일과 함께 존재하는 또 다른 Kubernetes definition 파일로 모든 configuration을 가질 수 있다면 좋지 않을까요?

 

 

이것이 Ingress가 필요한 이유입니다. Ingress는 사용자가 URL 경로를 기반으로 클러스터 내의 다른 서비스로 라우팅하도록 구성할 수 있는 외부에서 액세스 가능한 단일 URL을 사용하여 애플리케이션에 액세스할 수 있도록 도와줍니다. 동시에 SSL 보안도 구현할 수 있습니다. 간단히 말해 Ingress를 Kubernetes의 다른 오브젝트와 마찬가지로 builtin Kubernetes 프리미티브를 사용하여 구성할 수 있는 Kubernetes 클러스터에 builtin된 레이어 7 로드 밸런서라고 생각하면 됩니다.

 

 

Ingress를 사용하더라도 클러스터 외부에서 액세스할 수 있도록 expose해야 합니다. 따라서 여전히 노드 포트로 게시하거나 클라우드 네이티브 로드 밸런서를 사용하여 publish 해야하지만 이는 일회성 configuration일 뿐입니다. 앞으로 Ingress 컨트롤러에서 모든 로드 밸런싱 authentication, SSL, URL 기반 라우팅 configuration을 수행하게 됩니다.

 

 

Ingress는 Kubernetes에서 같은 방식으로 구현됩니다. 먼저 여기에 나열된 솔루션 중 하나인 지원 솔루션을 배포한 다음 rule 집합을 지정하여 Ingress를 configuration합니다. 배포하는 솔루션을 Ingress 컨트롤러라고 하고 구성하는 rule 집합을 Ingress 리소스라고 합니다. ingress 리소스는 이 과정의 앞부분에서 파드, deployment 및 서비스를 생성하는 데 사용하는 것과 같은 definition 파일을 사용하여 생성됩니다.

 

Kubernetes 클러스터는 default로 Ingress 컨트롤러와 함께 제공되지 않는다는 점을 기억하세요. 이 과정의 데모에 따라 클러스터를 설정하면 Ingress 컨트롤러가 builtin되어 있지 않습니다. 따라서 단순히 Ingress 리소스를 생성하고 작동할 것으로 기대한다면 작동하지 않을 것입니다.

 

 

Ingress Controller

쿠버네티스에는 default로 Ingress Controller가 없기 때문에, 추가적인 설정이 필요합니다. 이번 예시는 Nginx로 하겠습니다. Ingress Controller는 단순한 로드 밸런서나 nginx 서버가 아닙니다. 그 일부분일 뿐이며, 새로운 definition 또는 Ingress Resources에 대해 k8s 클러스터를 모니터링하고, 상황에 맞게 Nginx 서버를 구성하기 위해 추가로 Builtin 되어 있습니다.

 

 

Nginx Controller는 k8s에서 또 다른 배포로 구성되는데, 하나의 replicas와 간단한 pod definition 템플릿이 있는 Nginx Ingress 컨트롤러라는 depolyment definition 파일로 시작합니다. Nginx Ingress 라는 레이블을 지정하고, 사용된 이미지는 올바른 버전의 Nginx Ingress 컨트롤러입니다. 이제 이것은 k8s에서 ingress 컨트롤러로 사용되도록 특별 제작된 Nginx의 특수한 빌드이고, 고유한 요구사항이 있습니다. 이미지내에서 Nginx 프로그램은 Nginx Ingress 컨트롤러 위치에 저장되므로, Nginx 컨트롤러 서비스를 시작하기 위한 명령으로 전달해야 합니다.

 

 

Nginx 컨트롤러 이미지에서 이러한 구성 파일의 데이터를 분리하려면, config map 오브젝트 생성을 통해 전달해야 합니다. config map 오브젝트는 이 시점에서 entry가 필요하지 않고, 비어있는 오브젝트가 있으면 되지만, 하나를 생성해서 나중에 구성 파일의 설정을 쉽게 수정이 가능합니다. 해당 config map에 추가하기만 하면 nginx configuration file 수정에 대해 걱정할 필요가 없습니다.

 

또한 pod 이름과 namespace를 포함하는 2개의 환경변수를 전달해야 합니다. nginx 서비스는 pod내에서 configuration 데이터를 읽고, 최종적으로 Ingress 컨트롤러가 사용하는 포트를(80 or 443)를 지정하기 위해 이들을 필요로 합니다.

 

 

이후에 Ingress 컨트롤러를 외부에 expose하는 서비스가 필요하므로, 우리는 서비스에 deployment를 연결하기 위해 Nginx Ingress 레이블 selector로 Node port 유형의 서비스를 만듭니다. 앞에서 언급했듯이 Ingress 컨트롤러는 k8s 클러스터에서 Ingress 리소스를 모니터링하고, 변경사항이 있을 때 underlying Nginx 서버를 구성하기 위한 추가 인텔리전스가 builtin 되어 있습니다. 그러나 Ingress 컨트롤러가 이를 수행하려면 올바른 권한 접근이 있는 서비스 계정이 필요합니다. 이를 위해 Roles, RoleBindings으로 서비스 계정을 만들 수 있습니다.

 

 

간단하게 Nginx Ingress 이미지 배포, 이를 expose 하는 서비스, Nginx Configuration 데이터를 제공하는 config map, 이러한 모든 오브젝트에 엑세스가 가능한 서비스 계정을 배포하면, Ingress Controller의 기초적인 준비가 끝인 것이죠.

 

 

Ingress Resources

Ingress Resources는 Ingress 컨트롤러에 적용되는 rule 및 configuration 집합입니다. 들어오는 모든 트래픽을 단일 애플리케이션으로 전달하거나, URL 기반으로 트래픽을 다른 애플리케이션으로 라우팅되도록 rule을 configuration할 수 있습니다. 따라서 사용자가 트래픽을 다른 애플리케이션으로 라우팅하도록 rule을 configuration할 수 있습니다. 따라서 사용자가 myonlinestore.com/wear 로 이동한다면, 애플리케이션 중 하나로 라우팅하거나 사용자가 watch URL을 방문면 비디오 앱으로 라우팅하는 등의 작업을 수행합니다. 또는 도메인 이름 자체를 기반으로 사용자를 라우팅할 수 있습니다. 예로 사용자가 wear.myonlinestore.com을 방문하면 사용자를 wear 애플리케이션으로 라우팅하거나 비디오 앱으로 라우팅합니다.

 

 

더 자세하게 configuration 하는 방법을 살펴보죠. Ingress Resources는 k8s definition 파일로 생성됩니다. 위의 경우 Ingress-wear.yaml. 다른 오브젝트와 마찬가지로 APIversion, kind, metadata, spec이 있습니다. 해당 구성은 아래와 같고, 트래픽은 물론 pod가 아닌 애플리케이션 서비스로 직접 라우팅 됩니다. backend 섹션은 트래픽이 라우팅되는 위치를 정의하고, 단일 backend인 경우 실제로 rule은 존재하지 않습니다. >kubectl create 명령어를 통해 Ingress Resources를 생성합니다. > kubectl get Ingress 명령을 실행하여 생성된 Ingress 리소스를 확인할 수 있습니다.

 

 

이제 새 Ingress가 생성되었고, 모든 수신 트래픡은 wear 서비스로 직접 라우팅됩니다. 다른 조건에 따라 트래픽을 라우팅하려면 rule을 사용하면 됩니다. 예를 들어 각 도메인 또는 호스트 이름에서 발생하는 트래픽에 대해 하나의 rule을 생성합니다. 즉, 사용자가 도메인 이름 myonlinestore.com을 사용하여 클러스터에 도달하면 rule 1을 사용하여 해당 트래픽을 처리할 수 있습니다. 사용자가 도메인 이름 wear.myonlinestore.com을 사용하여 클러스터에 도달하면 별도의 rule인 rule 2를 사용하여 해당 트래픽을 처리할 수 있습니다. rule 3을 사용하여 watch.myonline store.com의 트래픽을 처리하고 네 번째 rule을 사용하여 다른 모든 것을 처리합니다. 이제 각 rule 내에서 다른 경로를 처리할 수 있습니다.

 

 

예를 들어, rule 1 내에서 해당 트래픽을 cloth 애플리케이션으로 라우팅하는 wear 경로와 비디오 스트리밍 애플리케이션으로 트래픽을 라우팅하는 watch route, 및 처음 두 개를 제외한 모든 경로를 404 not found로 라우팅하는 세 번째 경로를 처리할 수 있습니다. 마찬가지로 두 번째 rule은 wear.myonlinestore.com의 모든 트래픽을 처리합니다. 이 rule 내에서 경로 정의를 사용하여 다른 경로를 기반으로 트래픽을 라우팅할 수 있습니다.

 

예를 들어 쇼핑, 반품 또는 지원을 위해 의류 섹션 내에 다양한 애플리케이션과 서비스가 있다고 가정합니다. 사용자가 wear.myonlinestore.com으로 이동하면 default로 쇼핑 페이지에 도달하지만 교환 또는 지원 URL로 이동하면 다른 백엔드 서비스에 도달합니다. watch.myonlinestore.com에 대한 트래픽을 비디오 스트리밍 애플리케이션으로 라우팅하지만 영화나 TV와 같은 추가 경로를 포함할 수 있는 rule 3도 마찬가지입니다. 그리고 마지막으로 여기에 나열된 것 이외의 모든 것은 네 번째 rule으로 이동합니다. 그것은 단순히 404 찾을 수 없음 오류 페이지를 표시합니다. 따라서 각 호스트 또는 도메인 이름에 대한 rule이 맨 위에 있고 각 rule 내에는 URL을 기반으로 트래픽을 라우팅하는 서로 다른 파드이 있음을 기억하세요.

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.