Docker Lab #6

반영환·2023년 6월 28일
0

Docker

목록 보기
15/18
post-thumbnail

Docker Week 4

커널 네임 스페이스

컨테이너의 격리 공간에는 Sand Box 가 있지만 여전히 Host OS의 커널을 공유한다.

그렇기에 Host System에서 컨테이너 프로세스들을 볼 수 있는 것이고 컨테이너들 또한 각자 OS를 가지고 있지 않아도 되는 것이다.

CGroup ( Control Group ) 에 의해서 컨테이너는 실행에 필요한 하드웨어 자원을 공유받는다.

하드웨어 자원의 종류에는 cpu, memory, hdd, network 등이 있다.

네트워크 네임스페이스

커널 네임 스페이스는 기본적으로 컨테이너를 위해 세부 조정이 가능한 네트워크 네임스페이스를 생성한다.

컨테이너와 리눅스 브릿지는 veth : virtual ethernet 링크를 통해 연결한다.

컨테이너의 eth0 포트에서 보낸 트래픽은 veth 인터페이스를 통해 브릿지에 전달한 후 스위칭을 거친다.

컨테이너 네트워크 실습

nginx 컨테이너 두 개를 외부 포트를 개방한 채로 올려보자

docker run --name web -p 8080:80 -d nginx

docker run --name web2 -p 8081:80 -d nginx

docker0 가 어떤 veth에 연결돼있는지는 아래 커맨드로 확인 가능하다.

apt install bridge-utils

brctl show

Docker0 는 해당 컨테이너들의 매핑 관계를 iptables의 docker chain에서 관리한다.

iptables -t nat -L -v -n

도커 체인에 우리가 설정한 destination port ( 외부 포트 ) 에서 컨테이너 내부 포트로 맵핑 관계가 설정된 것을 확인할 수 있다.

도커 컨테이너는 기본적으로 외부와 통신이 불가능한 상태이므로 -p 옵션으로 포트를 개방해주어야 통신이 가능하다.

docker-proxy

만약 정책상의 이유로 docker host의 iptables나 ip_forward를 enable하지 못하는 경우에 docker-proxy 프로세스가 패킷을 포워딩하는 역할을 대신하게 된다.

docker host의 iptables의 DNAT을 disable한 후 port forwarding하는지 확인하자.

# vi /etc/docker/daemon.json
{
  "iptables": false
}

DNAT 룰이 없음에도 컨테이너가 호출된다. 이것이 docker-proxy가 해결해주는 것이다.

docker-proxy 는 포트를 노출하는 만큼 프로세스를 생성한다.

  • 도커를 사용하며 docker-proxy 는 따로 건들지 말자.

왜냐면 도커 프록시는 iptables를 사용하지 못하는 경우에 애플리케이션 레벨에서 NAT를 사용하기 위해서인데 결국 애플리케이션 레벨이기에 성능이 아쉽게된다.

따라서 docker 내부 네트워크는 모두 iptables에서 처리한다.

컨테이너 간 통신 제한

도커는 기존 도커 필터 체인에 설정된 규칙을 삭제하거나 수정하지 않는다.

사용자가 규칙을 생성해 컨테이너에 대한 접근을 제한할 수 있다.

도커는 한 호스트에 있는 모든 컨테이너 사이의 패킷 플로우를 docker0 브릿지로 처리한다.

컨테이너 사이의 패킷 흐름에 대한 규칙을 iptables의 FORWARD 체인에 추가한다.

--icc=false 옵션으로 dockerd가 실행되면 iptables의 FORWARD 체인에 DROP이 추가돼 컨테이너간 통신이 불가해진다. 
# vi /etc/docker/daemon.json
{
 "iptables": true,
 "icc": false
}
iptables -L -FORWARD

DOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
  • 원래의 forward chain
docker run -d --name webb1 nginx
docker run -it --name cc1 ubuntu

# apt-get update
# apt-get install curl
# curl 172.17.0.2
# --- 응답없음 ---
# exit

--link 옵션을 통해 통신을 허용할 수도 있고, iptable에 룰을 추가할 수도 있다.

docker run -d --name web -p 8080:80 nginx
iptables -L DOCKER -v -n

Chain DOCKER (3 references)
 pkts bytes target     prot opt in     out     source
   0     0 ACCEPT     tcp  --  !docker0 docker0  0.0.0.0/0
tcp dpt:80

# 웹 클라이언트 실행 후 iptables rule 확인

docker run -it --name client1 --rm centos 
# curl 172.17.0.2
# 실행되나? -> 안됨
# exit

docker run -it --name client2 --link web:web centos:7
# curl 172.17.0.2
# hello ( 실행 됨 )

# 추가된 룰 확인
iptables -L DOCKER -v -n

# iptables 룰 삭제
iptables -D DOCKER 1 # 숫자는 표의 행 숫자와 동일

# command line에서 rule을 추가하여 통신 가능하도록 설정
iptables -A DOCKER -p tcp --dport 80 -s 172.17.0.3 -d 172.17.0.2 -j ACCEPT 

iptables -A DOCKER -p tcp --dport 80 -s 172.17.0.2 -d 172.17.0.3 -j ACCEPT T2# iptables -L DOCKER

추가된 룰 확인!!
client # curl 172.17.0.2
hello

net.ipv4.tcp_tw_reuse

tcp_tw_reuse

사용할 수 있는 가용 포트가 모두 소진됐을 때 time wait 상태의 소켓을 재사용하게 된다.
로컬 포트가 고갈되는 현상이 있을 경우 ip_local_port_range 값을 튜닝하기 보다 tw_reuse를 사용하는 것이 좋다.

SO_REUSEADDR 과 무슨 차이?
SO_REUSEADDR 은 bind와 listen하는 과정에서 커널이 선점하고 있는 포트를 다시 사용할 수 있게 하는 것이고 tcp_tw_reuse 는 outgoing 트래픽에 대해 TW상태의 로컬 포트를 재사용할 수 있게 해주는 것

profile
최고의 오늘을 꿈꾸는 개발자

0개의 댓글