PID namespace 외에 Network namespace 를 알아보겠습니다.

처음 글을 시작한 의도는 docker 를 잘 활용하자는 의미였는데 하다보니 아직 그 내용은 들어가 보지도 못했네요.


개발자나 운영자들은 잘 인식하지 못하지만 linux 의 Network 는 모두 namespace 구조하에 움직이고 있습니다.


기본적으로 host 기반으로 사용하는 network 의 namespace 는 1 입니다. 그리고 docker 가 실행되면 docker process 에 대해서 내부적인 network 를 사용합니다.


network namespace 와 network namespace 간의 연결은 virtual ethernet (veth) 를 사용하여 연결합니다. 즉, veth pair 를 만들어서 하나는 docker 내부에 다른 하나는 host 로 하여 서로 네트워크로 연결하고 host 에 있는 veth 는 host 의 bridge 로 연결하면 docker 내부에서 host 의 bridge 로 연결이 됩니다.

 

docker 컨테이너 (eth0)  <-> host veth  <->  host bridge (docker0)  <->  host network (ens2f0)

 


먼저, host veth 의 리스트를 보겠습니다.


$ sudo ip addr show


15479: vethf5fa5c1@if15478: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP

    link/ether 32:83:61:96:55:4a brd ff:ff:ff:ff:ff:ff link-netnsid 1

15481: veth4667f7d@if15480: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP

    link/ether 56:39:6e:41:3d:50 brd ff:ff:ff:ff:ff:ff link-netnsid 0

15483: vethd61c546@if15482: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP

    link/ether b2:4a:88:71:d0:03 brd ff:ff:ff:ff:ff:ff link-netnsid 2

15489: vethbe5dd5b@if15488: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker_gwbridge state UP

    link/ether fe:85:37:ac:ea:76 brd ff:ff:ff:ff:ff:ff link-netnsid 4

15493: veth66998b7@if15492: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP

    link/ether 42:5f:03:92:45:9d brd ff:ff:ff:ff:ff:ff link-netnsid 5

 


총 5개가 보이는데 이중 하나는 docker gateway bridge 로 연결되고 나머지 4개는 1:1 로 각각 docker 내부의 eth0 와 연결되어 있습니다.


이를 좀 쉽게 찾기 위해서 veth.sh 파일을 만들었습니다.


#!/bin/bash


VETHS=`ifconfig -a | grep veth | sed 's/ .*//g'`

DOCKERS=$(docker ps -a | grep Up | awk '{print $1}')


for VETH in $VETHS

do

  PEER_IFINDEX=`ethtool -S $VETH 2>/dev/null | grep peer_ifindex | sed 's/ *peer_ifindex: *//g'`

  for DOCKER in $DOCKERS

  do

    PEER_IF=`docker exec $DOCKER ip link list 2>/dev/null | grep "^$PEER_IFINDEX:" | awk '{print $2}' | sed 's/:.*//g'`

    if [ -z "$PEER_IF" ]; then

      continue

    else

      printf "%-10s is paired with %-10s on %-20s\n" $VETH $PEER_IF $DOCKER

      break

    fi

  done

done



위 파일을 실행하면 아래와 같이 나옵니다.


veth4667f7d: is paired with eth0@if15481 on b75a945f84fa        

veth66998b7: is paired with eth0@if15493 on 67246d3e1c68        

vethd61c546: is paired with eth0@if15483 on 87faa6bacbba        

vethf5fa5c1: is paired with eth0@if15479 on 0b4bc5ba78f9

 

마지막에 보이는 것은 docker id 입니다.

 

host 의 docker0 bridge 가 어떻게 연결되어 있는 지는 brctl 로 알 수 있습니다. 


$ sudo yum install -y bridge-utils


$ sudo brctl show




docker0 bridge 가 어떻게 host 의 외부 네트워크로 나가는 지는 iptables 와 routing 을 보면 알 수 있습니다.


$ sudo iptables -t nat -S


-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

 


source 가 docker 내부 ip 대역이고 host 입장에서 패킷이 나가는 인터페이스가  docker0 가 아니면 jump 를 하고 host의 ip 로 변경해서 (masquerade) 나가라고 되어 있습니다. 

 


$ netstat -rn


Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface

0.0.0.0            192.168.30.1    0.0.0.0           UG        0 0          0 ens2f0

172.17.0.0        0.0.0.0            255.255.0.0     U         0 0          0 docker0

172.18.0.0        0.0.0.0            255.255.0.0     U         0 0          0 docker_gwbridge

 

그리고 위와 같이 외부로 나갈 때는 default gateway 로 외부로 나가게 됩니다.

 

 

Posted by Kubernetes Korea co-leader seungkyua@gmail.com

컨테이너가 linux 의 cgroup 과 namespace 를 활용하여 동작하는 것은 이제 보편적으로 알려진 내용입니다. cgroup 은 자원의 활용에 사용하고 namespace 는 자원의 isolation 에 사용합니다.


이 중에서 namespace 의 종류는 다음과 같습니다.


ipc : 프로세스간 양방향 통신

mnt : 파일 시스템

net : 네트워크

pid : 프로세스 id

user : 사용자 계정

uts : Unix time sharing

 

위의 namespace를 기본으로 docker 의 프로세스 구조를 보면 다음과 같습니다.

먼저, pstree 명령어를 설치합니다.  어떤 패키지인지 모르면 아래 명령어로 패키지명을 찾을 수 있습니다.


$ sudo yum whatprovides pstree

psmisc-22.20-15.el7.x86_64 : Utilities for managing processes on your system

Repo        : base

Matched from:

Filename    : /usr/bin/pstree

 

$ sudo yum install -y psmisc

 

이제 pstree 로 docker 의 패키지를 봅니다.


$ pstree -lSps $(pidof dockerd)




() 안에 들어간 번호는 프로세스 id 입니다.  dockerd 프로세스는 15472 이고 이후의 프로세스 명이 잘려서 보이니 ps 로 프로세스 명을 보면 다음과 같습니다.


$ ps -ef | grep 15489


15489 는 docker-containerd 입니다.

 

$ ps -ef | grep 15675



15675 는 docker-container-shim 입니다.


$ ps -ef | grep 15711


그리고 실제 컨테이너로 띄고 있는 minio 프로세스는 15711 입니다.



위의 내용을 보면 docker 프로세스는 다음과 같은 구조로 되어 있습니다.


dockerd (15472, docker 데몬)   ->   docker-containerd (15489, docker cotainerd) -> docker-container-shim (15675) -> minio (15711, 실행중인 docker 컨테이너)


docker-containerd 는 docker runtime 과 관련 있습니다. 컨테이너 실행은 runc 와 containerd 를 따릅니다. runc 는 Open Container Initiative(OCI) 에 의해 정의된 컨테이너를 실행시키는 부분으로 namespace 와 보안에 관한 표준입니다. containerd 는 runc 를 기반으로 컨테이너 이미지 관리, 스토리지, 실행 등의 기능을 확장한 것으로 CNCF 에 기부된 프로젝트 입니다.

 

docker-container-shim 은 docker 에서 자체적으로 추가한 것으로, 실행되는 컨테이너와 containerd 사이에서 컨테이너를 연결하여 containerd  가 문제가 생기더라도 실행되는 컨테이너에는 여향을 주지 않기 위해서 만들었습니다. 그런데 사실 이게 왜 더 필요한지는 모르겠습니다. 괜히 관리 레이어만 하나 더 추가된 부분으로 보이긴 합니다.

 

PID namespace 를 docker 에서 어떻게 적용되는지 보겠습니다.


앞에서 minio 컨테이너는 host 에서 보면 프로세스 id 가 15711 이고 그 부모 프로세스는 15675 인 docker-container-shim 인 것을 확인했습니다.


이제 minio 컨테이너를 아래와 같이 확인 합니다.


$ sudo docker (container) ls | grep minio

0b4bc5ba78f9        minio/minio                 "minio server /export"   18 months ago       Up 4 hours          0.0.0.0:9000->9000/tcp   minio

 

그리고, minio 컨테이너 안으로 들어가 보겠습니다.

sudo docker (container) exec -it 0b4bc5ba78f9 sh

 

프로세스를 조회해보면 다음과 같이 1번 프로세스로 minio 서버를 띄운 것이 보이고 (컨테이너 밖의 host 에서는 15711) 그 위의 부모 프로세스는 보이지 않습니다.




 

Posted by Kubernetes Korea co-leader seungkyua@gmail.com

ip link 로 device 를 namespace 로 보내면 Host 에서 해당 device 는 볼 수 가 없다.

이를 다시 Host 로 원복하는 방법



## Host 서버의 eno2 를 qrouter namespace 에 넣고 ip 세팅
$ sudo ip netns
qrouter-68cfc511-7e75-4b85-a1ca-d8a09c489ccc
qdhcp-03a6de58-9693-4c41-9577-9307c8750141

## eno2 를 네임스페이스로 보내기
$ sudo ip link set eno2 netns qrouter-68cfc511-7e75-4b85-a1ca-d8a09c489ccc
$ sudo ip netns exec qrouter-68cfc511-7e75-4b85-a1ca-d8a09c489ccc ip a
4: eno2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 3c:a8:2a:20:ed:d1 brd ff:ff:ff:ff:ff:ff

$ sudo ip netns exec qrouter-68cfc511-7e75-4b85-a1ca-d8a09c489ccc ip addr add 192.168.130.100/24 dev eno2
$ sudo ip netns exec qrouter-68cfc511-7e75-4b85-a1ca-d8a09c489ccc ifconfig eno2 up



## qrouter namespace 에 있는 eno2 를 Host 로 다시 돌려 보내기

$ ip netns exec qrouter-68cfc511-7e75-4b85-a1ca-d8a09c489ccc ip link set eno2 netns 1










Posted by Kubernetes Korea co-leader seungkyua@gmail.com