[KANS Study 1주차] 컨테이너 네트워크 알아보기
- -
CloudNet@ 팀의 가시다님께서 리딩하시는 KANS Study (Kubernetes Advanced Networking Study) 1주차 스터디 내용 정리
1주차에서는 쿠버네티스의 기반이 되는 컨테이너에 대해 알아보고, 컨테이너가 등장하기까지의 리눅스 기술 변천사에 대해서 공부했습니다.
1. 도커 소개
도커(Docker) 는 가상실행 환경을 제공해주는 오픈소스 플랫폼, 이 가상실행 환경을 '컨테이너(Container)' 라고 지칭
좀 더 정확하게는 '컨테이너화된 프로세스'를 의미하며,
도커 플랫폼이 설치된 곳이면 컨테이너 애플리케이션을 어디서든 실행할 수 있는 장점을 지닙니다.
도커나 컨테이너를 공부하다보면 격리된 프로세스라는 단어를 굉장히 많이 접하게 되기 때문에, 프로세스의 정의를 알고 있는 것이 중요합니다.
프로세스(Process) 란 CPU 와 메모리 자원을 할당받아 실행 중인 프로그램을 의미
프로세스는 각각의 고유한 ID 가 할당되는 데, 이를 PID (Process ID) 라고 지칭합니다.
1.1. 도커 아키텍처
도커는 크게 'Client' 와 'Host(Server)' 로 구성되어 있습니다.
- Docker Client
사용자가 docker run 과 같은 도커 명령어를 사용할 때, 도커 서버로 명령어를 전송해주는 역할을 합니다.
- Docker Host
도커 호스트는 도커 데몬을 실행시키고 있는 서버를 의미하며, 도커 데몬을 통해 모든 작업을 수행합니다.
도커 클라이언트와 호스트는 상호간에 유닉스 소켓 통신을 하며, 관련 정보는 아래 명령어로 확인할 수 있습니다.
docker info
docker version
1.2. Unix Domain Socket
유닉스 도메인은 쉽게 말해 동일한 시스템 내에서 실행되는 프로세스 간의 통신을 의미
사진에서 보듯이 유닉스 도메인 소켓 통신을 할 경우, TCP/IP 통신보다 훨씬 빠른 속도를 얻을 수 있는 장점이 있습니다.
도커는 설치 시에 root 권한으로만 실행이 가능하며 일반 사용자는 접근이 불가합니다.
이는, 일반 사용자가 docker socket 에 대한 접근 권한이 없기 때문입니다.
docker 설치 시에 docker 라는 그룹이 자동으로 생성되며,
이 docker 그룹은 docker socket 에 대한 접근 권한이 있기 때문에 일반 사용자들을 해당 그룹에 넣어주면 docker 에 대한 접근 권한이 부여됩니다.
# 일반 사용자를 docker 그룹에 추가
echo $USER
sudo usermod -aG docker $USER
2. 컨테이너 격리
지금부터는 도커가 나오기 전의 기술 개발 역사를 한 번 살펴보겠습니다.
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
3. 컨테이너 네트워크
3.1. 네트워크 네임스페이스 간 통신
컨테이너 네트워크를 알아보기 앞서, 격리된 네임스페이스 간 통신이 어떻게 이루어 지는 지 파악하는 것이 필요합니다.
예시처럼 'RED' 네임스페이스와 'BLUE' 네임스페이스가 분리되어 있을 경우, 상호 통신이 어떻게 이루어지는 지 실습했습니다.
- 가상 이더넷 디바이스 생성
ip link add veth0 type veth peer name veth1
- 각 네트워크 네임스페이스 생성
# RED , BLUE 네트워크 네임스페이스 생성
ip netns add RED
ip netns add BLUE
# 생성된 네트워크 네임스페이스 확인
ip netns list
- 생성한 이더넷 디바이스를 각 네트워크 네임스페이스로 이관
# veth0 을 RED 네임스페이스로 이동
ip link set veth0 netns RED
# veth1 을 BLUE 네임스페이스로 이동
ip link set veth1 netns BLUE
- 이더넷 디바이스 활성화 및 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가지가 존재하며, 각각의 특징과 장단점에 대해서 알아보겠습니다.
도커 네트워크 모드
- Bridge
- Host
- None
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주차에는 컨테이너 기술에 대한 전반적인 지식과 네트워크 등에 대해서 공부했습니다.
이전에도 스터디를 많이 진행해봤지만, 이번만큼 어려운 스터디도 없었던 것 같습니다.
다음 주차부터는 쿠버네티스 네트워크에 대한 심화과정으로 진입하게 되는 데, 여러번 반복하여 습득할 수 있도록 노력하겠습니다.
'Kubernetes' 카테고리의 다른 글
[Study 2주차] 쿠버네티스 Flannel CNI (1) | 2024.09.07 |
---|---|
[Study 2주차] 쿠버네티스 Pause 컨테이너 (0) | 2024.09.07 |
[Study 2주차] Kind 로 로컬 PC 에 쿠버네티스 설치 (0) | 2024.09.06 |
ArgoCD 란 무엇인가 ?? (핵심 용어, 구성 요소 등) (0) | 2024.06.15 |
GitOps 개념과 Kubernetes (1) | 2024.05.03 |