Linux 네트워크 이름 공간 및 가상 스위치를 사용하여 서버를 격리하는 컨테이너 네트워크 이해
24263 단어 devopslinuxdockernamespaces
Linux 이름 공간이란 무엇입니까?
Linux 이름 공간은 운영체제의 자원에 대한 추상적인 것입니다.우리는 명칭 공간을 하나의 상자로 볼 수 있다.이 상자에는 시스템 자원이 있습니다. 이것은 상자의 (명칭 공간) 유형에 완전히 달려 있습니다.현재 7가지 명칭 공간 Cgroup, IPC, 네트워크, Mount, PID, User, UTS가 있다.
네트워크 이름 공간이란 무엇입니까?
네트워크 이름 공간, man 7 네트워크 이름 공간에 따라:
네트워크 이름 공간은 네트워크와 관련된 시스템 자원을 분리했다. 네트워크 장치, IPv4와 IPv6 프로토콜 창고, IP 루트 테이블, 방화벽 규칙,/proc/net 디렉터리,/sys/class/net 디렉터리,/proc/sys/net 아래의 각종 파일, 포트 번호(플러그인) 등이다.
가상 인터페이스 및 브리지:
가상 인터페이스는 우리에게 물리적 네트워크 인터페이스의 가상화 표시를 제공했다.다리는 우리에게 가상의 스위치를 주었다.
저희가 뭘 보도해야 돼요?
우리 시작합시다...
0단계:
호스트/루트 네임스페이스의 기본 네트워크 상태를 확인합니다.현재 상태를 추적해서 더 잘 이해할 수 있도록만 하면 된다.[나는 AWS에서ec2 실례(ubuntu)를 시작해서 이 실제 조작을 모의했다. VM은 심지어 일반적인 linux 기계도 가능하다.]
# list all the interfaces
sudo ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 0a:1b:b1:bc:70:d0 brd ff:ff:ff:ff:ff:ff
# find the routing table
sudo route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.31.0.1 0.0.0.0 UG 100 0 0 eth0
172.31.0.0 0.0.0.0 255.255.240.0 U 0 0 0 eth0
172.31.0.1 0.0.0.0 255.255.255.255 UH 100 0 0 eth0
단계 1.1:
두 개의 네트워크 이름 공간 만들기
# add two two network namespaces using "ip netns" command
sudo ip netns add ns1
sudo ip netns add ns2
# list the created network namespaces
sudo ip netns list
ns1
ns2
# By convention, network namespace handles created by
# iproute2 live under `/var/run/netns`
sudo ls /var/run/netns/
ns1 ns2
단계 1.2:
기본적으로 이미 만들어진 네트워크의 네트워크 인터페이스가 닫히고 순환 인터페이스도 닫힙니다.지어내다.
sudo ip netns exec ns1 ip link set lo up
sudo ip netns exec ns1 ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
sudo ip netns exec ns2 ip link set lo up
sudo ip netns exec ns2 ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2.1단계:
호스트에 브리지 네트워크 생성
sudo ip link add br0 type bridge
# up the created bridge and check whether it is created and in UP/UNKNOWN state
sudo ip link set br0 up
sudo ip link
3: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/ether 12:38:75:40:c0:17 brd ff:ff:ff:ff:ff:ff
2.2단계:
브리지 네트워크에 IP 구성
sudo ip addr add 192.168.1.1/24 dev br0
# check whether the ip is configured and also ping to ensure
sudo ip addr
3: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether 12:38:75:40:c0:17 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.1/24 scope global br0
valid_lft forever preferred_lft forever
inet6 fe80::1038:75ff:fe40:c017/64 scope link
valid_lft forever preferred_lft forever
ping -c 2 192.168.1.1
--- 192.168.1.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1026ms
rtt min/avg/max/mdev = 0.020/0.029/0.039/0.009 ms
단계 3.1:
두 네트워크를 위해 두 개의veth 인터페이스를 만들고 브리지와 네트워크에 연결합니다
# For ns1
# creating a veth pair which have two ends identical veth0 and ceth0
sudo ip link add veth0 type veth peer name ceth0
# connect veth0 end to the bridge br0
sudo ip link set veth0 master br0
# up the veth0
sudo ip link set veth0 up
# connect ceth0 end to the netns ns1
sudo ip link set ceth0 netns ns1
# up the ceth0 using 'exec' to run command inside netns
sudo ip netns exec ns1 ip link set ceth0 up
# check the link status
sudo ip link
3: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 9a:af:0d:89:8b:81 brd ff:ff:ff:ff:ff:ff
5: veth0@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP mode DEFAULT group default qlen 1000
link/ether 9a:af:0d:89:8b:81 brd ff:ff:ff:ff:ff:ff link-netns ns1
# check the link status inside ns1
sudo ip netns exec ns1 ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: ceth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 3e:66:e5:b6:07:9a brd ff:ff:ff:ff:ff:ff link-netnsid 0
# For ns2; do the same as ns1
sudo ip link add veth1 type veth peer name ceth1
sudo ip link set veth1 master br0
sudo ip link set veth1 up
sudo ip link set ceth1 netns ns2
sudo ip netns exec ns2 ip link set ceth1 up
sudo ip link
3: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 1a:f5:b2:8e:ca:a5 brd ff:ff:ff:ff:ff:ff
5: veth0@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP mode DEFAULT group default qlen 1000
link/ether 9a:af:0d:89:8b:81 brd ff:ff:ff:ff:ff:ff link-netns ns1
7: veth1@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP mode DEFAULT group default qlen 1000
link/ether 1a:f5:b2:8e:ca:a5 brd ff:ff:ff:ff:ff:ff link-netns ns2
sudo ip netns exec ns2 ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: ceth1@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 3e:1e:48:de:47:07 brd ff:ff:ff:ff:ff:ff link-netnsid 0
단계 3.2:
현재, 우리는 넷nsveth 인터페이스에 IP 주소를 추가하고, 루트표를 업데이트하여 브리지 네트워크와의 통신을 구축할 것이며, 두 넷ns 간에 브리지를 통해 통신을 할 수 있도록 할 것이다.
# For ns1
sudo ip netns exec ns1 ip addr add 192.168.1.10/24 dev ceth0
sudo ip netns exec ns1 ping -c 2 192.168.1.10
sudo ip netns exec ns1 ip route
192.168.1.0/24 dev ceth0 proto kernel scope link src 192.168.1.10
# check if you can reach bridge interface
sudo ip netns exec ns1 ping -c 2 192.168.1.1
--- 192.168.1.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1020ms
rtt min/avg/max/mdev = 0.046/0.050/0.054/0.004 ms
# For ns2
sudo ip netns exec ns2 ip addr add 192.168.1.11/24 dev ceth1
sudo ip netns exec ns2 ping -c 2 192.168.1.11
sudo ip netns exec ns2 ip route
192.168.1.0/24 dev ceth1 proto kernel scope link src 192.168.1.11
# check if you can reach bridge interface
sudo ip netns exec ns2 ping -c 2 192.168.1.1
-------- 192.168.1.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1020ms
rtt min/avg/max/mdev = 0.046/0.050/0.054/0.004 ms
4단계:
두 네트워크 사이의 연결을 검증하면 작동할 수 있을 거야!
# For ns1:
# we can log in to netns environment using below;
# it will be totally isolated from any other network
sudo nsenter --net=/var/run/netns/ns1
# ping to the ns2 netns to verify the connectivity
ping -c 2 192.168.1.11
-------- 192.168.1.11 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1019ms
rtt min/avg/max/mdev = 0.033/0.042/0.051/0.009 ms
# exit from the ns1
exit
# For ns2
sudo nsenter --net=/var/run/netns/ns2
# ping to the ns1 netns to verify the connectivity
ping -c 2 192.168.1.10
-------- 192.168.1.10 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1022ms
rtt min/avg/max/mdev = 0.041/0.044/0.048/0.003 ms
# exit from the ns2
exit
두 네트워크 이름 공간 사이의 브리지 연결이 완료되었습니다.
the diagrom is taken from ops.tips blog
5.1단계:
지금은 인터넷에 접속할 때이다.보시다시피
ns1
의 루트 테이블은 기본 게이트웨이가 없기 때문에 192.168.1.0/24
범위 밖의 다른 기기에서 접근할 수 없습니다.sudo ip netns exec ns1 ping -c 2 8.8.8.8
ping: connect: Network is unreachable
# check the route inside ns1
sudo ip netns exec ns1 route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 ceth0
# As we can see, no route is defined to carry other traffic than 192.168.1.0/24
# we can fix this by using adding default route
sudo ip netns exec ns1 ip route add default via 192.168.1.1
sudo ip netns exec ns1 route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 ceth0
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 ceth0
# Do the same for ns2
sudo ip netns exec ns2 ip route add default via 192.168.1.1
sudo ip netns exec ns2 route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 ceth1
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 ceth1
# now first ping the host machine eth0
ip addr | grep eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP group default qlen 1000
inet 172.31.13.55/20 brd 172.31.15.255 scope global dynamic eth0
# ping from ns1 to host ip
sudo ip netns exec ns1 ping 172.31.13.55
64 bytes from 172.31.13.55: icmp_seq=1 ttl=64 time=0.037 ms
64 bytes from 172.31.13.55: icmp_seq=2 ttl=64 time=0.036 ms
# we get the response from host machine eth0
5.2단계:
이제 ns1이 인터넷과 통신할 수 있는지 살펴보자. 우리는 tcpdump를 사용하여 데이터 패키지가 어떻게 전송되는지 분석할 수 있다.다른 터미널을 열고 tcpdump로 데이터를 포획합니다.
# terminal-1
# now trying to ping 8.8.8.8 again
sudo ip netns exec ns1 ping 8.8.8.8
# still unreachable
# terminal 2
# open tcpdump in eth0 to see the packet
sudo tcpdump -i eth0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
# no packet captured, let's capture traffic for br0
sudo tcpdump -i br0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br0, link-type EN10MB (Ethernet), capture size 262144 bytes
02:17:30.807072 IP ip-192-168-1-10.ap-south-1.compute.internal > dns.google: ICMP echo request, id 17506, seq 1, length 64
02:17:31.829317 IP ip-192-168-1-10.ap-south-1.compute.internal > dns.google: ICMP echo request, id 17506, seq 2, length 64
# we can see the traffic at br0 but we don't get response from eth0.
# it's because of IP forwarding issue
sudo cat /proc/sys/net/ipv4/ip_forward
0
# enabling ip forwarding by change value 0 to 1
sudo sysctl -w net.ipv4.ip_forward=1
sudo cat /proc/sys/net/ipv4/ip_forward
1
# terminal-2
sudo tcpdump -i eth0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
02:30:12.603895 IP ip-192-168-1-10.ap-south-1.compute.internal > dns.google: ICMP echo request, id 18103, seq 1, length 64
02:30:13.621367 IP ip-192-168-1-10.ap-south-1.compute.internal > dns.google: ICMP echo request, id 18103, seq 2, length 64
# as we can see now we are getting response eth0
# but ping 8.8.8.8 still not working
# Although the network is now reachable, there’s no way that
# we can have responses back - cause packets from external networks
# can’t be sent directly to our `192.168.1.0/24` network.
5.3단계:
이러한 상황을 피하기 위해서 우리는
iptables
표의 POSTROUTING
체인에 nat
규칙을 놓아서 NAT(네트워크 주소 변환)를 사용할 수 있다.sudo iptables \
-t nat \
-A POSTROUTING \
-s 192.168.1.0/24 ! -o br0 \
-j MASQUERADE
# -t specifies the table to which the commands
# should be directed to. By default it's `filter`.
# -A specifies that we're appending a rule to the
# chain then we tell the name after it;
# -s specifies a source address (with a mask in this case).
# -j specifies the target to jump to (what action to take).
# now we're getting response from google dns
sudo ip netns exec ns1 ping -c 2 8.8.8.8
-------- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 1.625/1.662/1.700/0.037 ms
단계: 6
이제 이름 공간에서 서비스를 열고 외부로부터 응답을 받도록 하겠습니다.
sudo nsenter --net=/var/run/netns/netns1
python3 -m http.server --bind 192.168.1.10 3000
AWS에서 온ec2 실례가 있기 때문에 공공 IP가 추가되어 있습니다.특정 포트를 통해 외부에서 IP 에 액세스하려고 합니다.telnet 65.2.35.192 5000
Trying 65.2.35.192...
telnet: Unable to connect to remote host: Connection refused
우리가 본 바와 같이 우리는 목적지에 도달할 수 없다.호스트에 전송된 데이터를 어디에 두는지 알려주지 않았기 때문이다.우리는 다시 NAT를 해야 한다. 이번에 우리는 목적지를 정의할 것이다.
sudo iptables \
-t nat \
-A PREROUTING \
-d 172.31.13.55 \
-p tcp -m tcp --dport 5000 \
-j DNAT --to-destination 192.168.1.10:5000
# -p specifies a port type and --dport specifies the destination port
# -j specifies the target DNAT to jump to destination IP with port.
# from my laptop
# now I can connect the destination with port.
# We successfully recieved traffic from internet inside container network
telnet 65.2.35.192 5000
Trying 65.2.35.192...
Connected to 65.2.35.192.
Escape character is '^]'.
이제 시작이다.우리가 이룩한 성과:
Only commands will be found here
Find the github repo here
리소스
Reference
이 문제에 관하여(Linux 네트워크 이름 공간 및 가상 스위치를 사용하여 서버를 격리하는 컨테이너 네트워크 이해), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/faayam/understanding-container-networking-using-linux-network-namespaces-and-a-virtual-switch-to-isolate-servers-2k0c텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)