시작하기에 앞서
네트워크는 현대 사회에서 빼놓고 살아갈 수 없는 매우 중요한 인프라이자 시스템입니다. 통신이라는 이름으로 네트워크를 바라본다면 인터넷 통신 뿐만 아니라 음성 통신도 포함됩니다. 음성 통신이라는 단어가 나와서 당황하셨을 수도 있겠습니다만, 한 명의 개발자로서 혹은 관련된 직무에서 일을 하고 있는 프로로서 음성 통신을 처음 들어보셨다면 네트워크의 역사에 대해 알아보시는 것도 좋을것 같습니다.
우리가 전화기를 이용하여 상대방과 음성 통신을 하는 것을 떠올려 보면 다음과 같은 구조가 될것입니다.
이 때의 방식을 회선 교환(Circuit Switching) 방식이라 부르는데, 이미 지정된 경로를 통해 통신을 수행하게 됩니다.
송신자의 종단 즈음에서 아날로그 → 디지털로 전환된 “음성 데이터”가 기지국을 거쳐 수신자의 종단 즈음에서 디지털 → 아날로그로 전환되어 목소리를 들을 수 있게 되는거죠.
어릴 적 부모님께 전화를 걸 때, 부모님께서 이미 통화중이라면 “뚜.. 뚜.. 뚜..” 혹은 이미 통화중이라는 기계 음성을 들으신 적 있으실겁니다. (지금도 VoIP를 사용하지 않는 환경에서는 회선 교환 방식으로 통신하는 것으로 알고 있습니다.)
회선 교환 방식은 다음과 같은 특징을 가지고 있기 때문에 목표하는 회선이 이미 점유되어 있기 때문입니다.
- 통신을 시작하기 전 두 기기간 물리적 회선을 할당합니다.
- 한번 회선이 할당되면, 보낼 수 있는 최고 속도를 이용합니다.
- 물리적으로 할당된 회선을 이용하기 때문에 데이터 로스 등이 발생할 확률이 적습니다.
- 할당된 회선만을 이용하기 때문에 비교적 보안성이 높습니다.
현대 사회에는 회선 교환 방식은 패킷 교환 방식으로 대체되었습니다. 그 이유는 회선 교환 방식의 특징이자 한계점으로 인해서인데, 다음과 같습니다.
- 모든 회선이 사용중이라면 통신이 불가능합니다.
- 전체 회선의 성능을 나누어 사용합니다.
- 할당만 되어 있더라도 마찬가지입니다.
- 물리적 회선에 대한 비용이 비쌉니다.
- 데이터 전송에 필요한 연결 수립이 필요합니다.
패킷 교환 방식은 다음의 특징을 가지고 있습니다.
- 논리적 회선을 이용하기 때문에 망의 경로에 대해 생각할 필요 없습니다.
- 모든 회선이 사용중이어도 통신이 가능합니다.
- 데이터를 패킷(Packet)이라 불리는 작은 조각의 열로 전송합니다.
- 각 패킷은 목적지 까지 어떤 경로(somehow)를 따라 hop by hop으로 이동합니다.
- 패킷을 받은 중간 지점은 패킷이 모두 도착하기를 기다렸다가 전송하며, Fire and Forget 방식을 이용합니다.
이 외의 회선 교환, 패킷 교환 방식은 본 시리즈의 목적이 아니기 때문에 여기까지만 서술하겠습니다.
본 시리즈는 최종적으로 “쿠버네티스에서 네트워크 통신이 어떻게 이루어지는가에 대해 자세히 설명할 수 있다.” 목적을 가지고 있습니다. 이에 대해 다음의 주제로 나누어 글을 작성하려 합니다. 만약 아래 항목에 대해 이미 충분히 잘 알고 계시다면, 이 시리즈를 읽지 않으셔도 됩니다.
- 내가 데이터를 보낸다면 어떻게 수신자에게 전달될까?
- 네트워크 경로가 설정되고, 약속된 프로토콜을 통해 통신할 수 있다.
- 컨테이너 간 통신은 어떻게 이루어질까?
- Pod와 Localhost 통신으로 해결한다. 이는 Docker Network의 예시와 같다.
- Pod와 서비스 간 통신은 어떻게 이루어질까?
- Service Object를 이용하여 해결한다. 이는 kube-proxy를 통해 달성한다.
- 서비스와 클러스터 외부 간 통신은 어떻게 이루어질까?
- Service Object와 로드밸런서 등을 이용하여 해결한다.
- Pod 간 통신은 어떻게 이루어질까?
- Network Addons을 이용해 해결한다. 이는 우리가 흔히 알고 있는 Calico, Flannel, Cilium 등 CNI가 있다.
내가 데이터를 보낸다면
사전 준비물
두 대의 시스템간 통신을 바탕으로 데이터 송/수신을 해보겠습니다. 오늘 통신에 필요한 사전 준비물은 다음과 같습니다.
3 * Ubuntu 22.04 시스템
- 라우터 역할 시스템
- 종단 역할간 통신을 할 수 있도록 라우터 역할을 합니다.
- 라우터는 초기 네트워크가 구축되지 않았다는 가정으로, 네트워크를 할당하지 않습니다.
- 종단 역할 시스템 * 2
- 실제 통신을 수행하는 시스템을 가정합니다.
- 각 시스템은 서로 다른 네트워크 대역에 존재해야 하며, Hosted Only 네트워크를 할당받아야 합니다.
- 저의 경우 각 시스템에 vCPU 1개, 2GB Ram을 할당했으며, 각 시스템은 오직 Host OS와 통신이 가능한 상태입니다.
Router
router@router:~$ sudo ufw status
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)
router@router:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
router@router:~$ ping 192.168.100.2
ping: connect: Network is unreachable
router@router:~$ ping 192.168.150.2
ping: connect: Network is unreachable
Network 01
network@network01:~$ sudo ufw status
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)
network@network01:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 5a:e9:ac:ac:e1:ef brd ff:ff:ff:ff:ff:ff
inet 192.168.150.2/24 metric 100 brd 192.168.150.255 scope global dynamic enp0s1
valid_lft 3099sec preferred_lft 3099sec
inet6 fe80::58e9:acff:feac:e1ef/64 scope link
valid_lft forever preferred_lft forever
network@network01:~$ ping 192.168.100.2
ping: connect: Network is unreachable
Network 02
network@network02:~$ sudo ufw status
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)
network@network02:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 4e:4d:cb:7a:01:74 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.2/24 metric 100 brd 192.168.100.255 scope global dynamic enp0s1
valid_lft 3096sec preferred_lft 3096sec
inet6 fe80::4c4d:cbff:fe7a:174/64 scope link
valid_lft forever preferred_lft forever
network@network02:~$ ping 192.168.150.2
ping: connect: Network is unreachable
지금의 상태를 토폴로지로 나타내면 다음과 같습니다.
- 위 토폴로지의 세계상 아직 네트워크 구축이 되지 않았기 때문에, 라우터는 존재조차 하지 않는 가정으로 시작합니다.
- Network 01과 Network 02는 지역적으로 떨어져 있는 곳에 존재함을 가정합니다.
위 토폴로지를 바탕으로 한 오늘의 목표는 다음과 같습니다.
- Network 01 — 네트워크 — Network 02 상호간 ping 을 보낼 수 있다.
- Network 01 — 네트워크 — Network 02 상호간 임의의 포트를 통해 메시지를 주고 받을 수 있다.
- 클라우드 환경에서 VPC 내부의 서브넷간 통신 장애가 발생할 때 기본적인 네트워크 검사를 수행할 수 있다.
- 클라우드 환경에서 라우팅 기반의 서브넷 통신을 정의할 수 있다.
- 클라우드 환경에서 보안 그룹을 통해 허가된 통신만 수행할 수 있다.
왜 최초에는 Ping이 안될까?
최초 Router, Network 01, Network 02의 시스템 상에서 서로 Ping을 보내보면 Network not reachable 에러가 발생하는 것을 볼 수 있습니다. 이를 비유하기 위해 우리집 근처에 식당 A가 다음과 같이 위치한다고 가정합시다.
우리는 우리 집이 어디있는지 알고, 식당 A에 가기 위해서는 위로 도로를 건넌 뒤, 우측으로 도로를 두 번 건너면 된다는 것을 알고 있습니다.
이게 가능한 이유는 도로의 건널목을 “지표” 삼아서 식당 A로 가기 위해 건너야 하는 횡단 보도를 이미 알고 있기 때문입니다. 마찬가지로 다음과 같이 우측으로 한번 건넌 뒤, 위로 한 번 건너도 됩니다.
즉, 우리는 식당 A에 가기 위한 경로를 충분히 알고 있고, 도로를 건너는 행위를 기준으로 다음 목적지는 어디인지 알고 있는 상태입니다. 우리는 건널목 신호등의 상태 등을 감안하여 경로를 선택하면 되는겁니다. 감이 오셨을까요?
여기서 도로는 라우터이고, 다음 목적지는 어디로 가야하는지 알고 있는 행위가 바로 경로 설정입니다. 즉 라우터를 기준으로 라우팅 테이블은 작성되어 있어야 하며 이를 바탕으로 방향을 알고 길을 건널 수 있게 됩니다.
- 도로 건널목은 네트워크 경로 상에서 “hop”으로 표현되기도 하며, 목적지에 도달하기 위해 이러한 건널목을 지나는 행위는 hop by hop으로 표현되기도 합니다.
- 목적지 까지 여러 경로가 존재하기 때문에, 결국 어떤 방법을 통해 도달할 수 있게 됩니다. 영어로는 eventually, somehow, data will reach to the destination. 이라고도 표현합니다.
우리의 시스템으로 돌아오면, 아직 그 어느 경로도 설정되어 있지 않은것을 볼 수 있습니다.
도로는 Network 01 과 Network 02 사이에 바로 연결될 수도 있고, Network 01 — Router — Network 02 사이에 연결될 수 있습니다.
그러나 우리는 가정상, 그리고 실제 네트워크 상에서 종단간 시스템이 직접 연결되는 사례는 극히 드물기에, 이 경우는 제외하겠습니다.
경로 설정
이제 경로 설정을 수행해 보겠습니다. 우리는 현재 서로 분리되어 있는 두 시스템을 연결하는 도로를 설치해야 하는 상태입니다.
잠시 여기서 멈추시어 실생활에서 여러분은 이러한 도로의 역할로 어떤 매개체를 이용하고 있는지 한번 생각해 보시길 바랍니다.
보통 우리는 스마트폰, 노트북 등을 네트워크에 연결하기 위해 무선 매개체인 와이파이를 흔히 이용하고, 집 혹은 회사에 있는 데스크톱을 네트워크에 연결하기 위해 유선 매개체인 LAN 선을 이용하곤 합니다.
- 와이파이 등 무선 인프라의 경우에도 언젠가는 Access Point를 통해 유선 장비에 연결되어 데이터 통신을 수행합니다.
자, 드디어 경로 설정을 수행할 차례입니다. 우리는 Router와 Network 01을 연결하는 도로가 필요하며, Router에서 Network 02를 연결하는 도로가 필요합니다.
router@router:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 3a:9e:6f:dc:26:7b brd ff:ff:ff:ff:ff:ff
inet 192.168.150.3/24 metric 100 brd 192.168.150.255 scope global dynamic enp0s1
valid_lft 3587sec preferred_lft 3587sec
inet6 fe80::389e:6fff:fedc:267b/64 scope link
valid_lft forever preferred_lft forever
3: enp0s2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether ca:76:d5:f7:6a:85 brd ff:ff:ff:ff:ff:ff
inet 192.168.100.3/24 metric 100 brd 192.168.100.255 scope global dynamic enp0s2
valid_lft 3587sec preferred_lft 3587sec
inet6 fe80::c876:d5ff:fef7:6a85/64 scope link
valid_lft forever preferred_lft forever
도로가 정상적으로 연결되어 있는지 Router ←→ Network 01, 02를 수행해 보겠습니다.
Router ←→ Network 01
# Router -> Network 01 OK
router@router:~$ ping 192.168.150.2 -c 1
PING 192.168.150.2 (192.168.150.2) 56(84) bytes of data.
64 bytes from 192.168.150.2: icmp_seq=1 ttl=64 time=0.787 ms
--- 192.168.150.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.787/0.787/0.787/0.000 ms
# Network 01 -> Router OK
network@network01:~$ ping 192.168.150.3 -c 1
PING 192.168.150.3 (192.168.150.3) 56(84) bytes of data.
64 bytes from 192.168.150.3: icmp_seq=1 ttl=64 time=1.54 ms
--- 192.168.150.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.541/1.541/1.541/0.000 ms
Router ←→ Network 02
# Router -> Network 02 OK
router@router:~$ ping 192.168.100.2 -c 1
PING 192.168.100.2 (192.168.100.2) 56(84) bytes of data.
64 bytes from 192.168.100.2: icmp_seq=1 ttl=64 time=2.86 ms
--- 192.168.100.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 2.861/2.861/2.861/0.000 ms
# Network 02 -> Router OK
network@network02:~$ ping 192.168.100.3 -c 1
PING 192.168.100.3 (192.168.100.3) 56(84) bytes of data.
64 bytes from 192.168.100.3: icmp_seq=1 ttl=64 time=18.7 ms
--- 192.168.100.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 18.722/18.722/18.722/0.000 ms
생긴것만 보아하면, Network 01과 Network 02는 통신이 가능할 것 같습니다. 그러나 실질적으로 통신은 수행되지 않습니다.
# Network 01 -> Network 02 Fail
network@network01:~$ ping 192.168.100.2
ping: connect: Network is unreachable
# Network 02 -> Network 01 Fail
network@network02:~$ ping 192.168.150.2
ping: connect: Network is unreachable
그 이유는 Network 01은 Router 까지 가는 방법만 알고, Network 02 또한 Router 까지 가는 방법만 알고 있기 때문입니다. 예상하신바와 같이 Network 01 → Router → Network 02를 수행하고, 마찬가지로 Network 02 → Router → Network 01을 수행하면 됩니다.
하지만 상대는 컴퓨터기 때문에, 이러한 경로를 직접 알려줘야 합니다. 이러한 경로 설정은 ubuntu 22.04 기준 ip 패키지를 이용할 수 있는데, 명령어는 다음과 같습니다.
# route 확인
$ ip route
## Network 01의 기존 Route
network@network01:~$ ip route
192.168.150.0/24 dev enp0s1 proto kernel scope link src 192.168.150.2 metric 100
## Network 02의 기존 Route
network@network02:~$ ip route
192.168.100.0/24 dev enp0s1 proto kernel scope link src 192.168.100.2 metric 100
# route 추가
$ sudo ip route add DESTINATION via HOP
# route 제거
$ sudo ip route del DESTINATION
- Destination은 Subnet으로 설정하는 것이 좋습니다.
한번 Network 01에서 Network 02로 가기 위한 Hop을 Router로 설정해 보고 테스트 해보겠습니다. 그러나 예상과는 다르게 아직 Network 01에서 Network 02로 Ping을 보내는 것이 불가능한 상태입니다.
# sudo ip route add Network 02 대역 via Router
$ sudo ip route add 192.168.100.0/24 via 192.168.150.3
$ ping 192.168.100.2 -c 10
PING 192.168.100.2 (192.168.100.2) 56(84) bytes of data.
--- 192.168.100.2 ping statistics ---
10 packets transmitted, 0 received, 100% packet loss, time 9203m
흔히 네트워크를 공부할때 프로토콜(규약)은 사람의 인사로 비유 되곤 합니다. 사람간 대화를 시작하기 위해서, 혹은 인사를 할 때 누군가 말을 건네면 응답해 주는것이 일반적인 상황입니다. 그러나 우측과 같이 인사를 무시하는 경우도 발생할 수 있습니다. 영희가 바빠서 듣지 못했든, 이어폰을 끼고 있든, 의도적으로 무시했든, 철수는 상대방이 대화할 수 없는, 인사를 받을 수 없는 상황으로 인지할것입니다. 이 경우 철수는 다시 인사를 시도하거나, 영희에게 더 이상 말을 걸지 않을것입니다.
현재 우리 시스템에서 Network 01 → Network 02로 Ping을 보낼 때, 아래와 같이 영희가 응답하지 않는 상황입니다. 확인을 위해 Shell을 두 개 켠 뒤 tcpdump를 통해 확인해보면, 다음과 같이 모두 Network 02의 아이피로 request만 전달되고, reply가 오지 않는 것을 확인할 수 있습니다.
### Network 01 Shell 1
network@network01:~$ ping 192.168.100.2 -c 10
PING 192.168.100.2 (192.168.100.2) 56(84) bytes of data.
--- 192.168.100.2 ping statistics ---
10 packets transmitted, 0 received, 100% packet loss, time 9217ms
### Network 01 Shell 2
network@network01:~$ sudo tcpdump -e -i enp0s1 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp0s1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
02:14:07.734171 5a:e9:ac:ac:e1:ef (oui Unknown) > 3a:9e:6f:dc:26:7b (oui Unknown), ethertype IPv4 (0x0800), length 98: network01 > 192.168.100.2: ICMP echo request, id 3, seq 1, length 64
02:14:08.761944 5a:e9:ac:ac:e1:ef (oui Unknown) > 3a:9e:6f:dc:26:7b (oui Unknown), ethertype IPv4 (0x0800), length 98: network01 > 192.168.100.2: ICMP echo request, id 3, seq 2, length 64
02:14:09.786101 5a:e9:ac:ac:e1:ef (oui Unknown) > 3a:9e:6f:dc:26:7b (oui Unknown), ethertype IPv4 (0x0800), length 98: network01 > 192.168.100.2: ICMP echo request, id 3, seq 3, length 64
02:14:10.810160 5a:e9:ac:ac:e1:ef (oui Unknown) > 3a:9e:6f:dc:26:7b (oui Unknown), ethertype IPv4 (0x0800), length 98: network01 > 192.168.100.2: ICMP echo request, id 3, seq 4, length 64
02:14:11.833783 5a:e9:ac:ac:e1:ef (oui Unknown) > 3a:9e:6f:dc:26:7b (oui Unknown), ethertype IPv4 (0x0800), length 98: network01 > 192.168.100.2: ICMP echo request, id 3, seq 5, length 64
02:14:12.858743 5a:e9:ac:ac:e1:ef (oui Unknown) > 3a:9e:6f:dc:26:7b (oui Unknown), ethertype IPv4 (0x0800), length 98: network01 > 192.168.100.2: ICMP echo request, id 3, seq 6, length 64
02:14:13.882743 5a:e9:ac:ac:e1:ef (oui Unknown) > 3a:9e:6f:dc:26:7b (oui Unknown), ethertype IPv4 (0x0800), length 98: network01 > 192.168.100.2: ICMP echo request, id 3, seq 7, length 64
02:14:14.905286 5a:e9:ac:ac:e1:ef (oui Unknown) > 3a:9e:6f:dc:26:7b (oui Unknown), ethertype IPv4 (0x0800), length 98: network01 > 192.168.100.2: ICMP echo request, id 3, seq 8, length 64
02:14:15.931328 5a:e9:ac:ac:e1:ef (oui Unknown) > 3a:9e:6f:dc:26:7b (oui Unknown), ethertype IPv4 (0x0800), length 98: network01 > 192.168.100.2: ICMP echo request, id 3, seq 9, length 64
02:14:16.951320 5a:e9:ac:ac:e1:ef (oui Unknown) > 3a:9e:6f:dc:26:7b (oui Unknown), ethertype IPv4 (0x0800), length 98: network01 > 192.168.100.2: ICMP echo request, id 3, seq 10, length 64
이는 Network 02에서 확인해 볼 때도 마찬가지 입니다. 들어오는 request는 보이지만, reply는 보이지 않습니다.
network@network02:~$ sudo tcpdump -e -i enp0s1 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp0s1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
02:22:25.253982 ca:76:d5:f7:6a:85 (oui Unknown) > 4e:4d:cb:7a:01:74 (oui Unknown), ethertype IPv4 (0x0800), length 98: 192.168.150.2 > network02: ICMP echo request, id 11, seq 1, length 64
02:22:26.257601 ca:76:d5:f7:6a:85 (oui Unknown) > 4e:4d:cb:7a:01:74 (oui Unknown), ethertype IPv4 (0x0800), length 98: 192.168.150.2 > network02: ICMP echo request, id 11, seq 2, length 64
02:22:27.284460 ca:76:d5:f7:6a:85 (oui Unknown) > 4e:4d:cb:7a:01:74 (oui Unknown), ethertype IPv4 (0x0800), length 98: 192.168.150.2 > network02: ICMP echo request, id 11, seq 3, length 64
02:22:28.307913 ca:76:d5:f7:6a:85 (oui Unknown) > 4e:4d:cb:7a:01:74 (oui Unknown), ethertype IPv4 (0x0800), length 98: 192.168.150.2 > network02: ICMP echo request, id 11, seq 4, length 64
02:22:29.330388 ca:76:d5:f7:6a:85 (oui Unknown) > 4e:4d:cb:7a:01:74 (oui Unknown), ethertype IPv4 (0x0800), length 98: 192.168.150.2 > network02: ICMP echo request, id 11, seq 5, length 64
02:22:30.356599 ca:76:d5:f7:6a:85 (oui Unknown) > 4e:4d:cb:7a:01:74 (oui Unknown), ethertype IPv4 (0x0800), length 98: 192.168.150.2 > network02: ICMP echo request, id 11, seq 6, length 64
02:22:31.378002 ca:76:d5:f7:6a:85 (oui Unknown) > 4e:4d:cb:7a:01:74 (oui Unknown), ethertype IPv4 (0x0800), length 98: 192.168.150.2 > network02: ICMP echo request, id 11, seq 7, length 64
02:22:32.403816 ca:76:d5:f7:6a:85 (oui Unknown) > 4e:4d:cb:7a:01:74 (oui Unknown), ethertype IPv4 (0x0800), length 98: 192.168.150.2 > network02: ICMP echo request, id 11, seq 8, length 64
02:22:33.426113 ca:76:d5:f7:6a:85 (oui Unknown) > 4e:4d:cb:7a:01:74 (oui Unknown), ethertype IPv4 (0x0800), length 98: 192.168.150.2 > network02: ICMP echo request, id 11, seq 9, length 64
02:22:34.455507 ca:76:d5:f7:6a:85 (oui Unknown) > 4e:4d:cb:7a:01:74 (oui Unknown), ethertype IPv4 (0x0800), length 98: 192.168.150.2 > network02: ICMP echo request, id 11, seq 10, length 64
10 packets captured
10 packets received by filter
0 packets dropped by kernel
한번 직접 Router와 통신해 보시고 결과가 어떤지, 그리고 그 이유가 무엇인지 생각해 보시면 좋을것 같습니다.
Network간 통신이 불가능했던 이유는 우여곡절 끝에 192.168.100.0/24 의 이름을 가진 도로명을 알아냈지만, 다시 집으로 돌아가는 길을 잊었기 때문입니다.
- 혹은 192.168.100.0/24 도로를 알아낸 뒤, 식당에 도착했지만 알고보니 국경선을 무단으로 넘은 상태여서 집으로 돌아오지 못하는 상태일수도 있겠습니다.
즉 우리는 이를 위해 Network 01에서 한 바와 같이 Network 02 → Network 01의 경로를 설정해야 합니다. 이제 Network 01로 돌아가서 Network 02로 정상적으로 ping이 보내지는 것을 확인할 수 있습니다.
network@network02:~$ sudo ip route add 192.168.150.0/24 via 192.168.100.3
network@network02:~$ ip route
192.168.100.0/24 dev enp0s1 proto kernel scope link src 192.168.100.2 metric 100
192.168.150.0/24 via 192.168.100.3 dev enp0s1
# Network 01 -> Network 02 OK
network@network01:~$ ping 192.168.100.2 -c 4
PING 192.168.100.2 (192.168.100.2) 56(84) bytes of data.
64 bytes from 192.168.100.2: icmp_seq=1 ttl=63 time=10.0 ms
64 bytes from 192.168.100.2: icmp_seq=2 ttl=63 time=7.68 ms
64 bytes from 192.168.100.2: icmp_seq=3 ttl=63 time=2.61 ms
64 bytes from 192.168.100.2: icmp_seq=4 ttl=63 time=5.04 ms
--- 192.168.100.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3011ms
rtt min/avg/max/mdev = 2.612/6.344/10.047/2.788 ms
# Network 02 -> Network 01 OK
network@network02:~$ ping 192.168.150.2 -c 4
PING 192.168.150.2 (192.168.150.2) 56(84) bytes of data.
64 bytes from 192.168.150.2: icmp_seq=1 ttl=63 time=1.45 ms
64 bytes from 192.168.150.2: icmp_seq=2 ttl=63 time=5.22 ms
64 bytes from 192.168.150.2: icmp_seq=3 ttl=63 time=2.65 ms
64 bytes from 192.168.150.2: icmp_seq=4 ttl=63 time=3.90 ms
--- 192.168.150.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3014ms
rtt min/avg/max/mdev = 1.454/3.305/5.219/1.403 ms
경로 설정을 위해 만든 Router가 정상적으로 동작하는지 확인하고 싶으시다면 tcpdump를 이용하여 확인 가능합니다.
## enp0s1은 Router의 192.168.150.3/24를 가지는 NIC 입니다.
## enp0s2를 확인해 보아도 이와 비슷한 결과가 나옵니다.
router@router:~$ sudo tcpdump -i enp0s1 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp0s1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
# Network 01 -> Network 02
14:52:46.193749 IP 192.168.150.2 > 192.168.100.2: ICMP echo request, id 41, seq 1, length 64
14:52:46.194851 IP 192.168.100.2 > 192.168.150.2: ICMP echo reply, id 41, seq 1, length 64
14:52:47.195687 IP 192.168.150.2 > 192.168.100.2: ICMP echo request, id 41, seq 2, length 64
14:52:47.198908 IP 192.168.100.2 > 192.168.150.2: ICMP echo reply, id 41, seq 2, length 64
14:52:48.200837 IP 192.168.150.2 > 192.168.100.2: ICMP echo request, id 41, seq 3, length 64
14:52:48.202546 IP 192.168.100.2 > 192.168.150.2: ICMP echo reply, id 41, seq 3, length 64
14:52:49.203013 IP 192.168.150.2 > 192.168.100.2: ICMP echo request, id 41, seq 4, length 64
14:52:49.204313 IP 192.168.100.2 > 192.168.150.2: ICMP echo reply, id 41, seq 4, length 64
# Network 02 -> Network 01
14:53:03.654250 IP 192.168.100.2 > 192.168.150.2: ICMP echo request, id 5, seq 1, length 64
14:53:03.655086 IP 192.168.150.2 > 192.168.100.2: ICMP echo reply, id 5, seq 1, length 64
14:53:04.639904 IP 192.168.100.2 > 192.168.150.2: ICMP echo request, id 5, seq 2, length 64
14:53:04.641619 IP 192.168.150.2 > 192.168.100.2: ICMP echo reply, id 5, seq 2, length 64
14:53:05.644196 IP 192.168.100.2 > 192.168.150.2: ICMP echo request, id 5, seq 3, length 64
14:53:05.645515 IP 192.168.150.2 > 192.168.100.2: ICMP echo reply, id 5, seq 3, length 64
14:53:06.648683 IP 192.168.100.2 > 192.168.150.2: ICMP echo request, id 5, seq 4, length 64
14:53:06.652468 IP 192.168.150.2 > 192.168.100.2: ICMP echo reply, id 5, seq 4, length 64
허가된 통신
우리는 이제 VIP만 들어갈 수 있는 식당을 가보고자 합니다. VIP 식당은 보디가드를 통해서 선별된 인원만 접근이 가능하도록 하고 있습니다. 네트워크 통신에서는 방화벽을 통해 이 보디가드의 역할을 수행할 수 있습니다.
우리는 메시지 송수신을 위해 telnet(telecommunications network)과 nc(netcat) 를 이용할 예정입니다. nc를 이용하여 네트워크에 들어오는 메시지를 읽고, telnet을 이용하여 메시지를 보낼 예정입니다.
Router는 라우터 역할을 위해 Network 01 ←→ Network 02간 패킷을 모두 Forwarding 하는 것을 전제로 합니다.
## FORWARD 룰을 추가합니다.
## enp0s1으로 들어오는 192.168.150.0/24 대역의 송신지를 enp0s2의 192.168.100.0/24로 전달합니다.
router@router:~$ sudo iptables -A FORWARD -i enp0s1 -o enp0s2 -s 192.168.150.0/24 -d 192.168.100.0/24 -j ACCEPT
router@router:~$ sudo iptables -A FORWARD -i enp0s2 -o enp0s1 -s 192.168.100.0/24 -d 192.168.150.0/24 -j ACCEPT
- Network 01이 송신자를, Network 02가 수신자의 역할을 수행합니다.
- nc 명령어 → https://manpages.ubuntu.com/manpages/lunar/man1/nc_openbsd.1.html
- telnet 명령어 → https://manpages.ubuntu.com/manpages/xenial/man1/telnet-ssl.1.html
최초 특별한 설정 없이 nc와 telnet을 이용하여 연결을 시도해보면, 통신이 불가능한 것을 볼 수 있습니다.
## 수신자, Network 02
network@network02:~$ nc --listen 12345
# 메시지 대기중
## 송신자, Network 01
network@network01:~$ telnet 192.168.100.2 12345
Trying 192.168.100.2...
# 연결 대기중...
이는 Network 02의 방화벽은 12345 포트를 통한 데이터 통신이 허용되지 않았기 때문입니다. 방화벽에 추가하고 다시 한번 통신을 시도하면 정상적으로 메시지 송/수신이 가능한 것을 확인할 수 있습니다.
network@network02:~$ sudo ufw allow 12345/tcp
Rule added
Rule added (v6)
network@network02:~$ sudo ufw status
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
12345/tcp ALLOW Anywhere
22/tcp (v6) ALLOW Anywhere (v6)
12345/tcp (v6) ALLOW Anywhere (v6)
network@network02:~$ nc -l 12345
---
network@network01:~$ telnet 192.168.100.2 12345
Trying 192.168.100.2...
Connected to 192.168.100.2.
Escape character is '^]'.
마지막으로 메시지를 주고 받고, 오늘의 글을 마무리 하겠습니다.
마치며
오늘의 “내가 데이터를 보낸다면 어떻게 수신자에게 전달될까?” 글은 정말 기본적이면서도 필수로 알아야 하는 사항만을 다루었습니다. 시작할 때 짧게 서술한 음성 통신과 데이터 통신의 관계부터 하나의 라우터로 알아보는 시스템 통신에 필요한 경로설정, 그리고 방화벽을 통한 최소한의 보안 설정까지.
여기 까지 처음 보는 내용이나 몰랐던 부분이 있으셨다면, 해당 부분을 바탕으로 꼭 정리를 하셨으면 합니다. 오늘 본 부분은 기초이자 꼭 알아야 하는 부분이며, 앞으로 이어나갈 쿠버네티스의 네트워크에 있어서 굉장히 중요한 부분이기 때문입니다.
그렇다면 이것도…
- 클라우드 환경에서 네트워크 통신을 수행하기 위해 Virtual Private Cloud를 만들고, 필요한 만큼의 인스턴스를 할당할 수 있는 네트워크를 할당할 수 있으신가요?
- VPC와 External, VPC와 Internal, 그리고 External ←→ Internal 통신을 수행할 때 필요한 경로만을 설정했고, 보안 그룹은 어떻게 설정하셨나요?
- 보안 그룹은 어떻게 구성하는게 좋을까요?
- 오늘 한 시스템에서 Router가 여러개 존재한다면 어떻게 통신이 일어날까요?
- Router에서 어떻게 경로 설정을 수행하나요?
- Packet Loss는 어떤 환경에서 일어나는지 알고 계신가요?
- 네트워크 통신 중 장애가 발생했다면, 원인 분석을 할 수 있으신가요?
'DevOps > Kubernetes' 카테고리의 다른 글
네트워크로 시작하는 쿠버네티스 - iptables, ipvs, ipip, vxlan (1) | 2024.12.03 |
---|---|
네트워크로 시작하는 쿠버네티스 - 컨테이너 통신, 도커 네트워크 (0) | 2024.11.21 |
네트워크로 시작하는 쿠버네티스 - 컨테이너간 통신, Network Namespace (2) | 2024.11.14 |
쿠버네티스가 쉬워지는 컨테이너 이야기가 어렵다면 - cgroup, cpu 편 (0) | 2024.11.11 |