도커(Docker) 없이 컨테이너(Container) 네트워크 환경 구성하기
- 도커 없이 네트워크 네임스페이스 환경에서 통신 구성
도커가 Namespace를 사용하여 네트워크 환경을 구성하기 때문에 Network Namespace를 사용하여 도커 없이
도커와 동일한 환경 구성이 가능함
- 컨테이너는 생각보다 오래된 리눅스 기능임
그런 컨테이너가 왜 최근에 각광받기 시작 했는가? 생각해보면 간단한 문제이다.
도커가 등장함으로서 컨테이너를 사용하기 위해 설정해야 했던 그 모든 불편한 설정을 도커가 대신 해주기 때문임
- 그렇기 때문에 도커의 환경구성 이해를 위해 도커 없이 Network Namespace만을 사용하여 컨테이너(container)
환경을 구성해 봄으로서 도커가 대신해주는 네트워크 환경에 대해 이해를 높일 수 있음
Network Namespace를 사용하여 컨테이너(Container) 간 통신
- 그림과 같이 컨테이너는 하나 이상의 Network Namespace로 격리된 Network interface를 가지며 해당
Interface들은 통신하기 위해서 리눅스의 브릿지 기능을 이용함
- 여기서 리눅스의 브릿지는 리눅스에서 제공하는 가상의 L2스위치 이며 VM웨어의 vSwitch와 다르지 않다
- 컨테이너가 존재하는 host의 모든 Network 정책은 iptables에 의해 구현된다.
iptables
- iptables의 특징
- iptables는 커널스페이스에서 동작하는 netfilter와 유저스페이스에서 동작하는 iptables로 나뉜다.
- iptables는 netfilter를 쉽게 동작시켜주는 UI같은 개념이며 실제 동작은 Netfilter로 이루어 진다
- iptables의 table은 실제로 netfilter에서 hook(PREROUTING, FORWARD 등)에 매칭되며 table은
각각 특정한 목적을 가지고 만들어 젔다
iptables 요소
- hook 에 정의된 체인은 테이블 순서대로 등록된 룰을 체크하고 조건을 만족하면 action(-j target)을 트리거합니다.
- table : 목적/용도별 rules 모음 → 예) filter, nat, mangle ...
- chain : 패킷이 지나가는 hook 별로 존재 → 예) PREROUTING, FORWARD, INPUT ... (넷필터의 hook 에 매핑됩니다)
- rule : table 과 chain matrix 에 대해서 정의 → 예) protocol type, dest/src.address, headers ...
- action(target) : 패킷이 룰에 매칭되면 트리거됨 → 예) ACCEPT, DROP, REJECT ... * -j : jump <대상>
iptables table
- iptables raw는 hook(tables)을 등록하거나 로드 할때 그어떤 table 보다 가장 먼저 로드 되는 table이며
Connection tracking과 같은 memory를 많이 사용하는 서비스를 사전에 차단하기 위해 사용하기도 한다
- iptables mangle은 iptables raw를 거친 패킷들을 조작하기 위해 사용되는 table이며 mangle에서 패킷을 수정
하여도 여전히 다른 table 보다는 앞이기 때문에 이후 동작하는 NAT, forward 테이블에 따라 추가적인 수정이 가능
- iptables nat은 두개의 hook을 가집니다 DNAT(Destination NAT)가 가먼저 적용되고 이후에 SNAT(Source NAT)가
동작합니다 해당 table은 NAT를 하기위한 설정 데이터베이스 일뿐이며 NAT외에는 그 어떤 동작도 관여하지 않는다
- iptalbes filter는 일반적으로 filtering(firewall)을 목적으로 사용된다
- security filter는 Mandatoty Access Control(강제 접근 통제:MAC)를 제공하며 SECMARK 와 CONNSECMARK같은
기능을 제공한다 Mandatory Access Control은 SElinux같은 linux 보안모듈에 의해 동작한다 Security table은
filter table 전에 동작하고 Mandatory Access Control 의 룰이 적용되기 전에 Descretionary Access Control
(임의 접근 통제:DAC) 동작한다 Security filter table은 input(유저스페이스로 올라가기 전 패킷),
output(유저스페이스에서 나온 후 패킷), forward(해당 호스트를 지나가는 패킷) chain을 가진다
- tables의 구조 간략도
- iptables는 table 마다 적용되는 Hook이 상이하며 순서 또한 다르다
- 패킷의 목적지가 Local이냐? 아니냐?에 따라 적용받는 iptables의 table이 다르다
- 컨테이너(Network namespace 포함)는 Local network가 아닌것으로 판단해 FORWARD 정책을 적용 받음
Namespace를 사용하여 위의 그림과 비슷한 환경을 구성해 보자
- Network Namespace로 격리된 네트워크 환경에는 Host와 별도로 ARP tabe, Mac address, ip tables 등을 가진다
- Network Namespace를 사용한 격리는 모든 설정이 Namespace에 종속되기 때문에 Namespace 삭제시 모든 설정이
삭제된다
- 위 그림은 컨테이너 환경을 위해 도커가 대신 설정해주는 환경의 극히 일부분을 컨테이너 없이 구현한것 뿐이다
실제로는 더 많은 설정을 도커가 컨테이너를 위해 대신 해주고 있다
실습 - Network Namespace를 활용하여 네트워크 환경을 만들기
Network namespace 생성 및 연결
- ip netns add RED
- RED namespace 생성
- ip link add reth0 type veth peer name reth1
- reth0 가상인터페이스 생성 및 reth1번과 peering
- ip link set reth0 netns RED
- 가상인테페이스 reth0을 RED namespace속으로 격리
- ip netns add BLUE
- BLUE namespace 생성
- ip link add beth0 type veth peer name beth1
- beth0 가상인터페이스 생성 및 beth1과 peering
- ip link set beth0 netns BLUE
- 가상인터페이스 beth0를 BLUE namespace 속으로 격리
linux bridge 확인
- brctl show
- docker0 bridge는 docker 설치시 자동으로 생성되는 bridge로 실습에는 사용하지 않음
- ip link add br0 type bridge
- br0라는 브릿지를 생성한다
- 생성된 브릿지의 추가 정보 확인
br0 브릿지와 가상의 인터페이스 연결
- ip link set reth1 master br0
- 가상인터페이스 reth1인터페이스를 br0에 연결
- ip link set beth1 master br0
- 가상인터페이스 reth1인터페이스를 br0에 연결
- br0라는 브릿지에 가상인터페이스를 연결시키는 것은 일종의 L2 스위치에 랜선을 연결하는 것으로 비유할수 있다
네임스페이스에 속한 가상인터페이스에 IP를 할당
- ip netns exec RED ip addr add 11.11.11.2/24 dev reth0
- RED네임스페이스에 ip addr add 11.11.11.2/24 device reth0를 전송하여 RED 네임스페이스 안에 있는
인터페이스에 IP를 할당 한다
- ip netns exec BLUE ip addr add 11.11.11.3/24 dev beth0
- BLUE네임스페이스에 ip addr add 11.11.11.3/24 device reth0를 전송하여 BLUE 네임스페이스 안에 있는
인터페이스에 IP를 할당 한다
- ip netns exec RED ip link set reth0 up; ip link set reth1 up
- RED네임스페이스에 ip link set reth0을 전송하여 reth0을 up한 이후 호스트에 ip link set reth1을 입력하여
reth1인터페이스를 up 상태로 만든다
- ip netns exec BLUE ip link set beth0 up; ip link set beth1 up
- BLUE네임스페이스에 ip link set beth0을 전송하여 beth0을 up한 이후 호스트에 ip link set beth1을 입력하여
beth1인터페이스를 up 상태로 만든다
- ip -br -c addr
Network Namespace로 접속하여 상태를 확인
- nsenter --net=/var/run/netns/RED
- nsenter와 -n 또는 --net 옵션을 사용하여 Namesapce로 진입
Network namespace만을 격리 하였기 때문에 프롬프트가 바뀌지 않음
- ip -c a; echo; ip -c route; echo; ip -c neigh
- Network namespace안에서 해당 명령어를 사용 함으로서 ip -c a 와 ip -c route 와 ip -c neigh 명령어를
한번에 출력한다
- BLUE Namespace에서도 위와 동일한 방식으로 Network namespace에 접속하여 확인해 볼수있다
- 이로서 RED와 BLUE의 통신을 위한 준비는 모두 되었다 그럼 Host에서 몇가지 정보를 더 확인해 보자
Host 필요정보 확인
- ip_forward 기능과 iptables룰을 확인한다
Network namespace간 ping test
- namespace BLUE와 host의 br0 인터페이스에서 tcpdunp를 걸고 namespace RED에서 BLUE로 ping을 쏴본다
- BLUE namespace에서의 tcpdump
- host의 br0 블릿지에서의 tcpdump
- namespace RED에서 BLUE 로 ping을 시도해 보았지만 정상적으로 통신이 되지 않음을 확인 하였다
- Host에서 tcpdump를 사용한 결과 이다
- ARP는 정상통신을 하는 것이 확인이 되지만 ICMP는 Request만 있고 Reply가 없음을 확인 하였다
- host에서 tcpdump 결과가 의미하는 것은 무엇인가?
- 아래의 그림과 같이 ARP는 정상적으로 RED와 BLUE간 통신을 하였지만 ICMP는 그러지 못 했음
- Namespace RED에서 ARP 테이블 확인 결과 정상적으로 학습하였음을 알수있음
- host까지만 통신이 가능하니 host의 iptales를 확인이 필요해 보임
- iptables -v --numeric --table filter --list FORWARD;echo;iptables -v --numeric --table filter --list DOCKER-USER;echo;iptables -v --numeric --table filter --list DOCKER-ISOLATION-STAGE-1
- iptables를 보니 1~5를 거처 최종적으로 묵시적 Deny에 의해 Drop됨을 알수있다.
패킷 허용 정책 삽입
- 일반적으로 Docker를 사용할때 권고사항이 DOCKER-USER Chain을 사용하도록 권고 하고 있기 때문에
FORWARD table이 아닌 DOCKER-USER Chain에 허용 정책을 넣어준다
- iptables 룰을 입력 후 정상적으로 통신 됨을 확인 할수 있다
- Namespace가 동일 host에 존재함에도 불구하고 FORWARD table rule을 적용 받음을 확인 할수있다
- 이는 Host가지는 root namespace와 실습시 만든 Namespace가 서로 격리되어 있기 때문으로 알수있다
- lsns -t net을 보면 만든 Namespace는 두개이지만 호스트에 존재하는 Namespace까지 총 3개가 있음을 확인
서로 다른 Namespace를 사용하기 때문에 별개의 머신처럼 인식을 하기 때문에 FORWARD table에 적용을 받음
- Accept rule에 정상적으로 적용 되었음을 확인 할수있다
host의 bridge와 namespace같의 통신
- host에서 namespace RED로 통신을 시도하였지만 통신이 정상적으로 되지 않음을 확인
- 라우팅 테이블 확인시 11.11.11.0/24네트워크가 라우팅 테이블에 존재하지 않음을 확인
- br0 인터페이스에 ip가 존재하지 않음을 확인
- br0 인터페이스에 namespace가 가지는 11.11.11.0/24네트워크의 ip를 할당
- br0인터페이스에 ip입력후 host와 namespace간의 정상통신이 됨을 확인
Namespace와 host interface와 통신
- namespace RED에서 host의 bridge인터페이스와는 정상 통신이 가능하나 host의 network 인터페이스와는
정상통신 되지 않음을 확인
- routing table 확인결과 routing table에 namespace 네트워크 대역 외에 존재하는게 아무것도 없음을 확인
- default route 입력 후 정상적으로 host 의 네트워크 인터페이스와 통신 됨을 확인
- default route 입력 후 host와는 정상적으로 통신이 되지만 외부(공인망)으로는 통신되지 않음을 확인
- iptables의 nat table 확인결과 Source nat를 관리하는 POSTROUTING에서 172.17.0.0/16네트워크만 MASQUERADE
되고 있음을 확인
- nat table에 11.11.11.0/24 네트워크를 MAQUERADE rule 적용하여 Source nat 정책 설정
- 정상적으로 nat table에 11.11.11.0/24네트워크에 대한 rule이 수립되었음을 확인
- namespace에서 정상적으로 외부(공인망)과 ping통신이 이루어 짐을 확인
- netfilter에서 제공하는 conntrak 기능을 이용하여 Source nat에 대한 connection에 대한 정보를 확인 할 수 있음
Docker engine에 대한 도움을 받지 않고 컨테이너 통신에 대한 실습을 완료함
일련의 모든 실습은 Docker engine사용시 docker가 모두 자동으로 설정해 주지만 그럴경우 Docker network type bridge에 대한 이해가 어렵기 때문에 한번쯤은 실습 해보는 것이 좋음
Docker network type
- 지원되는 도커의 네트워크 타입을 확인한다
- 기본적으로 bridge, host, none 이며 추가 plug-in으로 ipvlan, macvlan, overay모드를 지원한다
- docker network type none
- 말 그래도 아무런 네트워크를 쓰지 않는 것. 외부와의 연결이 단절됨. 컨테이너 내부에 lo 인터페이스만 존재.
- docker network type Bridged
- 위에서 진행한 일련의 실습과 동일한 네트워크 환경 제공
- 위에서 실습한것과 달리 iptables, namespace등의 모든 설정을 docker가 자동으로 지원해 줌
- docker network type host
- 컨테이너를 위한 iptables 설정도 자동으로 지원되지 않음
- Host 는 호스트의 환경을 그대로 사용. 애플리케이션 별도 포트 포워딩 없이 바로 서비스 가능.
- 컨테이너의 호스트 이름도 호스트 머신의 이름과 동일.
- host는 자원을 share해주는 것외에 일체의 동작을 하지 않음
- 모든 컨테이너가 동일 자원을 사용하기 때문에 정교한 네트워크 컨트롤을 전재로 함
- docker network type MacVLAN
- macvlan은 하나의 인터페이스를 가상의 인터페이스로 분리하여 사용할수 있게 해줌
- 물리 인터페이스는 부모(parent) 가상인터페이스는 자녀(child)인터페이스로 구분된다
- macvlan은 여러가지 각 각 별개의 Mac address 와 모드를 지니며 모드에 따라 패킷 전송정책이 변경되지만
child interface와 parent interface간의 직접 통신은 허용되지 않는다
- 물리 인터페이스 뿐만 아니라 Vlan interface나 bridge interface같은 가상의 인터페이스도 parent interface로
사용이 가능하다
- Macvlan은 Private Mode, VEPA Mode, Bridge Mode, Passthru Mode 4가지 Mode가 존재한다.
- Macvlan mode private
- child와 child가 통신할때 모드가 private면 child는 무조건 parent로 패킷을 전송함
- 패킷이 parent에서 child로 전송되는 경우 macvlan에서 패킷의 source mac address를
mac addres hash table(일종의 mac-table)에서 검사 후 자신에게 있으면 drop 자신에게
없으면 child로 전송함
- 동일한 macvlan내에 있는 child끼리 통신을 하면 안될경우 사용됨
- Macvlan mode vepa(Virtual Ethernet Port Aggregator)
- child와 child가 통신할때 모드가 vepa면 child는 무조건 parent로 패킷을 전송함
- 패킷이 parent에서 child로 전송되는 경우 아무런 조건없이 child로 전송됨
- cild와 child가 통신을 함에 있어 별다른 제약사항이 없지만 반드시 parent를 거처야 하는 특징을 가짐
- child의 패킷이 반드시 외부를 거처야 할경우 주로 사용됨
- Macvlan mode bridge
- child가 외부와 통신할때 macvlan에서 destination mac address가 mac hash table(일종의 mac-table)에
존재할경우 child로 바로 전송한다
- parent에서 child로 패킷을 전송 할 경우 아무런 제약없이 child로 패킷을 전송한다
- 동작이 리눅스의 bridge와 완전히 동일하기 때문에 리눅스의 bridge 대용으로 사용된다
- Macvlan mode passthru
- parent와 child를 1:1로 매칭시킨다
- macvlan이 mac hash table을 사용하지 않는다
- 일반적은 환경에서는 사용되지 않으며 mactap을 통해 가상머신에게 nic를 제공하기위해 사용된다
- docker network type ipvlan
- ipvlan은 하나의 인터페이스를 가상의 인터페이스로 분리하여 사용할수 있게 해줌
- 물리 인터페이스는 부모(parent) 가상인터페이스는 자녀(child)인터페이스로 구분된다
- 올드버전의 커널(kernel)에서는 지원이 제한된다
- ipvlan mode l2
- 네트워크 라우터(host 외부 라우터)와 컨테이너 그리고 host가 동일 서브넷을 사용
- ipvlan의 기본모드
- 사용자의 목적에 따라 internal 과 external 네트워크를 완전히 격리시킬수도 있음
- ipvlan mode trunk
- 802.1q를 사용하여 하위 컨테이너 네트워크 인터페이스를 vlan으로 연결함
- 기본적으로 라우터의 라우팅 없이 vlan간 통신은 할수없음
- 외부의 특정 서비스와 컨테이너를 연결하기 위해 주로 사용됨
- ipvlan mode L3
- host와 각각의 컨테이너가 서로 다른 ip 대역을 사용하기 위해 사용됨
- 컨테이너는 서로 다른 ip 대역을 가지고 있지만 parent interface를 공유한다면 별도의 라우팅 없이
컨테이너끼리 통신이 가능함
- 모든 broadcast 와 multicast를 삭제하고 오로지 unicast를 사용하여서만 동작함
- 모든 broadcast 와 multicast를 삭제하기 때문에 Gateway는 host의 parent interface 가 된다
'Linux > 쿠버네티스 네트워크' 카테고리의 다른 글
도커(docker) (0) | 2021.12.04 |
---|