새소식

Kubernetes

[KANS Study 1주차] 컨테이너 네트워크 알아보기

  • -

CloudNet@ 팀의 가시다님께서 리딩하시는 KANS Study (Kubernetes Advanced Networking Study) 1주차 스터디 내용 정리

 

1주차에서는 쿠버네티스의 기반이 되는 컨테이너에 대해 알아보고, 컨테이너가 등장하기까지의 리눅스 기술 변천사에 대해서 공부했습니다.

 

 

1. 도커 소개

 

도커(Docker) 는 가상실행 환경을 제공해주는 오픈소스 플랫폼, 이 가상실행 환경을 '컨테이너(Container)' 라고 지칭

 

좀 더 정확하게는 '컨테이너화된 프로세스'를 의미하며,

도커 플랫폼이 설치된 곳이면 컨테이너 애플리케이션을 어디서든 실행할 수 있는 장점을 지닙니다.

 

도커나 컨테이너를 공부하다보면 격리된 프로세스라는 단어를 굉장히 많이 접하게 되기 때문에, 프로세스의 정의를 알고 있는 것이 중요합니다.

 

프로세스(Process) 란 CPU 와 메모리 자원을 할당받아 실행 중인 프로그램을 의미

 

프로세스는 각각의 고유한 ID 가 할당되는 데, 이를 PID (Process ID) 라고 지칭합니다.



1.1. 도커 아키텍처

 

출처: https://docs.docker.com/get-started/docker-overview/#docker-architecture

 

도커는 크게 'Client''Host(Server)' 로 구성되어 있습니다.

 

  • Docker Client

사용자가 docker run 과 같은 도커 명령어를 사용할 때, 도커 서버로 명령어를 전송해주는 역할을 합니다.

 

  • Docker Host

도커 호스트는 도커 데몬을 실행시키고 있는 서버를 의미하며, 도커 데몬을 통해 모든 작업을 수행합니다.

도커 클라이언트와 호스트는 상호간에 유닉스 소켓 통신을 하며, 관련 정보는 아래 명령어로 확인할 수 있습니다.

 

docker info
docker version

 

 

1.2. Unix Domain Socket

 

유닉스 도메인은 쉽게 말해 동일한 시스템 내에서 실행되는 프로세스 간의 통신을 의미

 

출처 : https://www.verycosy.net/posts/2023/09/unix-domain-socket

 

사진에서 보듯이 유닉스 도메인 소켓 통신을 할 경우, TCP/IP 통신보다 훨씬 빠른 속도를 얻을 수 있는 장점이 있습니다.

 

도커는 설치 시에 root 권한으로만 실행이 가능하며 일반 사용자는 접근이 불가합니다.

 

이는, 일반 사용자가 docker socket 에 대한 접근 권한이 없기 때문입니다.

 

docker 설치 시에 docker 라는 그룹이 자동으로 생성되며,

이 docker 그룹은 docker socket 에 대한 접근 권한이 있기 때문에 일반 사용자들을 해당 그룹에 넣어주면 docker 에 대한 접근 권한이 부여됩니다.

 

# 일반 사용자를 docker 그룹에 추가
echo $USER
sudo usermod -aG docker $USER

 

2. 컨테이너 격리

 

지금부터는 도커가 나오기 전의 기술 개발 역사를 한 번 살펴보겠습니다.

 

출처: https://speakerdeck.com/kakao/ige-dwaeyo-dokeo-eobsi-keonteineo-mandeulgi?slide=200

 

 

2.1. chroot 와 chroot 문제점 (탈옥)

 

chroot 는 특정 프로세스에게 특정 디렉토리를 root 디렉토리라고 속이는 것을 의미

 

테스트를 하기 위해 /tmp/myroot 라는 디렉토리를 만들고, 해당 디렉토리를 chroot 로 설정하겠습니다.

 

# root 전환
sudo su -

# chroot 실습 디렉토리 생성
cd /tmp
mkdir myroot

# chroot 사용
chroot myroot /bin/sh

 

 

해당 명령어를 사용했을 때 오류가 발생하는 데, 이는 myroot 안에 /bin/sh 명령어를 수행할 수 있는 파일이 없기 때문입니다.
'/bin/sh' 명령어를 수행하기 위한 종속적인 라이브러리를 모두 복사해서 붙여 넣고, chroot 탈옥 실습에 필요한 명령어 패키지도 붙여넣어 줍니다.

 

# /bin/sh 명령어 와 라이브러리 복사
mkdir -p myroot/bin
cp /usr/bin/sh myroot/bin/
mkdir -p myroot/{lib64,lib/x86_64-linux-gnu}
cp /lib/x86_64-linux-gnu/libc.so.6 myroot/lib/x86_64-linux-gnu/
cp /lib64/ld-linux-x86-64.so.2 myroot/lib64

# /bin/ls 명령어와 라이브러리 복사
cp /usr/bin/ls myroot/bin/
mkdir -p myroot/bin
cp /lib/x86_64-linux-gnu/{libselinux.so.1,libc.so.6,libpcre2-8.so.0} myroot/lib/x86_64-linux-gnu/
cp /lib64/ld-linux-x86-64.so.2 myroot/lib64

 

 

이후 다시 chroot 명령어로 접근하고 ls 명령어로 루트 디렉토리를 살펴봅니다.

chroot myroot /bin/sh
ls /

 

 

chroot 환경에서는 지정된 루트 디렉토리에 갇힌 것처럼 보입니다.
하지만, chroot 에는 탈옥(breakout) 이 가능하다는 치명적인 단점이 있습니다.
탈옥을 위한 코드를 다음과 같이 작성한 후 컴파일 해줍니다.

 

#include <sys/stat.h>
#include <unistd.h>

int main(void)
{
  mkdir(".out", 0755);
  chroot(".out");
  chdir("../../../../../");
  chroot(".");

  return execl("/bin/sh", "-i", NULL);
}

 

# 컴파일
gcc -o myroot/escape_chroot escape_chroot.c

# 컴파일 확인
file myroot/escape_chroot

 

 

다시 chroot 환경에 접근하여 탈옥 코드를 실행합니다.

 

chroot myroot /bin/sh

# 탈옥 코드 실행
./escape_chroot

# 탈옥 확인
ls /

 

 

사진에서 보듯이 리눅스 루트 경로로 빠져나온 것을 알 수 있습니다.
이러한 단점 때문에 컨테이너에서는 chroot 를 사용하지 않으며, 대신에 pivot_root 를 사용합니다.

 

 

2.2. pivot-root

 

pivot_root 란 root 파일 시스템의 마운트 포인트를 변경함으로써 특정 디렉토리를 새로운 루트 디렉토리로 만드는 명령어

 

chroot 는 실제로는 root 파일시스템이 동일하였기 때문에 탈옥이 가능했던 반면에, pivot_root 는 root 파일 시스템의 마운트 포인트 자체가 변경되기 때문에 탈옥이 불가능하다는 장점이 있습니다.

 

pivot_root 를 위해 unshare 명령어를 수행합니다.

 

# Namespace 격리
unshare --mount /bin/sh

 

이후, 격리된 pivot_root 와 바깥 루트계정에서 동일한 pivot_root 디렉토리를 바라보게 되면 다른 파일시스템을 바라보고 있다는 것을 알 수 있습니다.

 

 

2.3. Namespace

 

Namespace 는 리눅스 커널 기능으로, 프로세스에 격리된 환경을 제공

 

리눅스 Namespace 를 보는 명령어는 아래와 같습니다.

 

lsns -p $$

 

 

lsns 명령어 구성 항목
NS 네임스페이스 ID 
TYPE 네임스페이스 유형
NPROCS 해당 네임스페이스에 속한 프로세스 개수
PID 네임스페이스를 소유하는 프로세스의 PID
USER 프로세스를 실행하는 사용자
COMMAND 프로세스 명령어

 

네임스페이스 유형
time 시스템의 시간 설정 관리
cgroup 컨테이너나 프로세스가 사용하는 CPU, 메모리, I/O 관리
pid 프로세스 ID 관리
user 사용자와 그룹 ID 관리
uts 호스트 이름 및 도메인 이름 관리
ipc 프로세스 간 통신 자원 관리
net 네트워크 인터페이스 및 설정 관리 
mnt 파일 시스템의 마운트 포인트 관리

 

 

2.4. cgroups

 

cgroups 이란 CPU, Disk I/O, Memory, Network 등의 자원 사용을 제한 / 격리 (Control) 시키는 커널 기능

 

리눅스에서는 자원할당과 제어를 모두 파일시스템으로 제공하고 있습니다.

 

# cgroup 정보 확인
tree /proc/$(pgrep sleep) -L 2
tree /sys/fs/cgroup/user.slice/user-1000.slice -L 1

 

 

  • cgroup 테스트

CPU 자원을 제한하는 실습을 진행해보겠습니다.

 

# 디렉터리 이동
cd /sys/fs/cgroup

# 서브 디렉터리 생성 후 확인 확인
mkdir test_cgroup_parent && cd test_cgroup_parent

# cpu를 subtree이 추가하여 컨트롤 할 수 있도록 설정 : +/-(추가/삭제) 
cat cgroup.subtree_control
echo "+cpu" >> /sys/fs/cgroup/test_cgroup_parent/cgroup.subtree_control

# cpu.max 제한 설정 : 첫 번쨰 값은 허용된 시간(마이크로초) 두 번째 값은 총 기간 길이 > 1/10 실행 설정
echo 100000 1000000 > /sys/fs/cgroup/test_cgroup_parent/cpu.max

# 이후 Stress 테스트 진행 - A
stress -c 1

# cpu.max 값 수정
echo 1000000 1000000 > /sys/fs/cgroup/test_cgroup_parent/cpu.max

# 이후 Stress 테스트 진행 - B
stress -c 1

 

cpu.max 값 100,000
cpu.max 값 1,000,000

 

3. 컨테이너 네트워크

 

3.1. 네트워크 네임스페이스 간 통신

 

컨테이너 네트워크를 알아보기 앞서, 격리된 네임스페이스 간 통신이 어떻게 이루어 지는 지 파악하는 것이 필요합니다.

 

출처 : https://malwareanalysis.tistory.com/249

 

예시처럼 'RED' 네임스페이스와 'BLUE' 네임스페이스가 분리되어 있을 경우, 상호 통신이 어떻게 이루어지는 지 실습했습니다.

 

  1. 가상 이더넷 디바이스 생성
ip link add veth0 type veth peer name veth1

 

  1. 각 네트워크 네임스페이스 생성
# RED , BLUE 네트워크 네임스페이스 생성
ip netns add RED
ip netns add BLUE

# 생성된 네트워크 네임스페이스 확인
ip netns list

 

  1. 생성한 이더넷 디바이스를 각 네트워크 네임스페이스로 이관
# veth0 을 RED 네임스페이스로 이동
ip link set veth0 netns RED

# veth1 을 BLUE 네임스페이스로 이동
ip link set veth1 netns BLUE

 

  1. 이더넷 디바이스 활성화 및 IP 설정
ip netns exec RED ip link set veth0 up
ip netns exec RED ip addr add 11.11.11.2/24 dev veth0
ip netns exec BLUE ip link set veth1 up
ip netns exec BLUE ip addr add 11.11.11.3/24 dev veth1

 

 

이후 ping 을 통해 'RED' -> 'BLUE' 테스트를 진행하면, 통신이 잘 되는 것을 확인할 수 있습니다.
이것이 바로 도커 컨테이너의 기본 네트워크 통신 원리입니다.

 

이러한 네트워크 작업은 수동으로 하면 무척 번거롭기 때문에, 도커는 설치 시 이런 네트워크 작업을 대신 실행시켜 주는 편리함이 있습니다.

 

3.2. 도커 네트워크 모드

 

도커 네트워크는 다음과 같이 3가지가  존재하며, 각각의 특징과 장단점에 대해서 알아보겠습니다.

 

도커 네트워크 모드

  1. Bridge
  2. Host
  3. None

출처 : http://www.abusedbits.com/2016/09/docker-host-networking-modes.html

 

 

3.3. 도커 네트워크 Bridge 모드

 

Bridge 모드는 도커에서 기본으로 사용하는 네트워크 모드로, 컨테이너 기본 생성 시 자동으로 docker0 브릿지를 사용

 

# Docker Network 모드 확인
docker network ls

# 브릿지 확인
brctl show

 

 

Bridge Network Mode
특징 도커 컨테이너들이 상호 통신은 물론, 컨테이너와 호스트 간 통신 가능
컨테이너 기본 IP 대역은 172.16.0.0/16
장점 호스트 네트워크와 별도의 컨테이너 네트워크 격리 가능
호스트 포트와 컨테이너 포트 간 충돌 가능성 없음
단점 네트워크 성능 이슈

 

3.4. 도커 네트워크 Host 모드

 

Host 모드는 호스트 네트워크 환경을 컨테이너에서도 그대로 사용

 

  • 도커 Host 네트워크 테스트해보기
# Host 네트워크로 Nginx 실행
docker run --rm -d --network host --name my_nginx nginx

# Docker Inspect 로 정보 확인
docker inspect my_nginx | grep NetworkMode

 

 

Host Network Mode
특징 호스트와 동일한 IP 주소와 포트 사용
장점 우월한 네트워크 성능
단점 호스트 네트워크와 컨테이너 네트워크 간 격리 불가
호스트와 컨테이너 간 포트 충돌 가능성

 

 

3.5. 도커 네트워크 None 모드

 

None 모드는 컨테이너에 네트워크 설정을 부여하지 않는 모드

 

# Host 네트워크로 Nginx 실행
docker run --rm -d --network none --name my_nginx nginx

# Docker Inspect 로 정보 확인
docker inspect my_nginx | grep NetworkMode

 

 

None Network Mode
특징 네트워크 연결이 없음
네트워크 연결이 필요없는 백그라운드 작업에 용이
장점 완전히 격리된 환경으로 인한 높은 보안성
단점 네트워크 관련 작업 불가
다른 호스트 및 컨테이너와의 통신 불가

 

 

 


 

 

1주차에는 컨테이너 기술에 대한 전반적인 지식과 네트워크 등에 대해서 공부했습니다.
이전에도 스터디를 많이 진행해봤지만, 이번만큼 어려운 스터디도 없었던 것 같습니다.
다음 주차부터는 쿠버네티스 네트워크에 대한 심화과정으로 진입하게 되는 데, 여러번 반복하여 습득할 수 있도록 노력하겠습니다.

Contents

포스팅 주소를 복사했습니다