Kubernetes/Network Study

도커 없이 컨테이너 만들기

백곰곰 2024. 8. 28. 23:15
728x90
반응형

가시다님의 Kubernetes Advanced Networking Study에 참여하게 되어, 스터디 때 다룬 주제를 정리하려고 합니다.

1주차는 컨테이너 격리 & 네트워크 및 보안이 진행되었으며, 이번 글에서는 도커 없이 컨테이너를 만들면서 관련된 개념을 포함하고 있습니다.

 

실습의 주요 내용은 아래 영상을 참고했습니다.

https://www.youtube.com/watch?v=mSD88FuST80

 

 


컨테이너는 프로세스를 격리된 공간에서 실행한다는 특징이 있습니다.

격리를 할 때에는 새로운 기술을 활용하는 것이 아닌, 리눅스의 기능을 활용합니다.

컨테이너를 생성할 때 사용하는 주요 기능을 알아보겠습니다.

 

Namespace

Namespace는 컨테이너에 격리된 환경을 제공하는데 사용되는 주요 기능입니다.

  • 모든 프로세스는 namespace 타입별로 특정 네임스페이에 속함
  • 자식(Child) 프로세스는 부모(Parent) 프로세스의 namespace 상속 받음
  • namespace 공유할 수 있음
    • ex 1) 컨테이너의 일부 namespac만 격리하고, 일부 namespace는 호스트의 네임스페이스를 사용 가능
    • ex 2) 컨테이너 A와 컨테이너 B에 대해 동일한 Network namespace 사용하도록 설정

https://wizardzines.com/comics/https://wizardzines.com/comics/namespaces/

현재 아래와 같이 총 8개의 namespace가 있습니다.

Mount namespace

파일시스템의 마운트 포인트를 관리합니다. 다른 마운트 namespace와 격리된 경우, 특정 namespace 내에서 마운트된 파일시스템은 다른 namespace에서 보이지 않지만, namespace를 공유하면 동일한 마운트 포인트를 볼 수 있습니다.

PID namespace

프로세스 ID 번호를 격리합니다. 부모 네임스페이스는 자식 namespace의 프로세스를 볼 수 있지만, 자식 namespace는 부모의 프로세스를 볼 수 없습니다. 프로세스 격리를 위해서 일반적으로는 PID namespace는 다른 namespace와 공유하지 않습니다.

Network namespace

네트워크 인터페이스, IP 주소, 라우팅 테이블 등을 격리합니다. 네트워크 namespace를 공유하면 같은 네트워크 자원을 공유할 수 있습니다.

User namespace

사용자 및 그룹 ID(UID, GID)를 격리합니다. 서로 다른 유저 네임스페이스에서 동일한 UID를 가지더라도 서로 다른 실제 권한을 가질 수 있습니다. Remap을 통해서 namespace 안의 UID/GID를 namespace 밖의 UID/GID와 다르게 설정할 수 있으며, 이를 통해서 호스트(부모)에서의 권한과 특정 namespace 안의 권한을 다르게 설정할 수 있습니다. 예를 들어, 컨테이너에서 root 권한을 갖지만, 호스트에서는 root 권한이 아니게 설정할 수 있습니다.

참고로 도커에서는 기본적으로 user namespace를 사용하지 않고, kubernetes에서도 v1.30에서 beta feature로 제공되지만, 기본적으로 비활성화 되어있습니다.

Time namespace

프로세스가 볼 수 있는 시스템 시간을 격리하여, 특정 프로세스에 대해 다른 시간대를 설정할 수 있습니다.

IPC(Inter-Process Communication) namespace

프로세스 간 통신 리소스(공유 메모리, 세마포어, 메시지 큐)를 격리하여 각 네임스페이스 내의 프로세스가 독립적으로 통신할 수 있게 합니다.

UTS(Unix Time Sharing) namespace

호스트네임과 도메인네임을 격리하여 각 namespace 내에서 프로세스가 독립적인 호스트네임과 도메인네임을 가질 수 있게 합니다.

예전 UNIX에서 유래된 이름으로 당시 여러 사용자가 서버 자원을 동시에 공유하면서 각각의 시스템을 식별하기 위해 호스트 이름과 도메인 이름이 중요한 역할을 했다고 합니다.

참고)

https://windsock.io/uts-namespace/

cgroup namespace

cgroup namespace 내에 속한 프로세스는 자신이 속한 cgroup 및 하위의 cgroup에 대해서만 볼 수 있습니다. 실제 CPU, MEM 등의 자원 제어는 cgroup namespace가 아닌 cgroup을 통해 이루어집니다.

참고)

https://book.hacktricks.xyz/v/kr/linux-hardening/privilege-escalation/docker-security/namespaces/cgroup-namespace

 


pivot_root

pivot_root를 알아보기에 앞서 먼저 출시되었던 chroot를 알아보겠습니다.

chroot는 해당 프로세스의 root 디렉터리를 지정된 경로로 변경하지만, 실제로 시스템의 root 디렉터리 자체를 변경하지 않습니다. 지정된 경로를 root 디렉터리인 것처럼 사용하는 것이며, 프로세스가 의도적으로 root에 접근할 수 있습니다. 

pivot_root 는 namespace 내에서 root 파일시스템을 바꿔서, 전용 root 파일 시스템을 가지게 합니다.

Mount namespace와 함께 사용하여 호스트와 격리한 후에 root 파일시스템을 변경하여, 새로운 root 파일시스템을 사용할 수 있도록 합니다.

 

chroot 사용 시 탈옥 코드

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

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

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

 

참고)

https://tbhaxor.com/pivot-root-vs-chroot-for-containers/


Overlay 파일시스템

Overlay 파일시스템은 리눅스 커널에서 지원하는 가상 파일시스템으로, 두 개 이상의 파일시스템을 하나의 통합된 파일시스템으로 겹쳐서 사용할 수 있게 해줍니다(Union 파일시스템의 구현체 중 하나). 주로 컨테이너 환경에서 널리 사용되며, 여러 계층(layer)을 겹쳐서 파일을 관리하는 방식입니다. 이 방식은 파일시스템의 효율성을 높이고, 불필요한 데이터 복사를 줄이며, 스토리지 공간을 절약할 수 있게 해줍니다. (by ChatGPT)

https://tech.kakaoenterprise.com/171

lower dir

read-only 파일시스템 계층이며, upper dir 아래 모든 계층이 lower dir에 해당

upper dir

read-write 파일시스템 계층이며 가장 상위에 위치

lower dir에 변경이 필요한 경우에, upper dir에 파일을 복사한 후에 변경(Copy-On-Write)

merge dir

overlay 파일시스템이 마운트되는 디렉터리이며, upper + lower 레이어를 통합하여 제공

work dir

overlay 파일시스템에서 원자성(atomic)을 보장하기 위한 계층이며, 파일을 상위 계층에 복사하거나 수정할 때 해당 작업을 위한 임시 공간을 제공

 

 

참고)

https://blog.naver.com/alice_k106/221530340759

https://tech.kakaoenterprise.com/171

 

 


컨테이너를 구성하는데 필요한 여러가지 개념을 알아보았고, 이제 직접 컨테이너와 유사한 환경을 만들어보겠습니다.

그 전에 docker로 생성한 컨테이너와 호스트 서버의 정보를 비교해보겠습니다.

 

호스트 서버의 namespace 정보

ubuntu@MyServer:~$ lsns -p $$
        NS TYPE   NPROCS   PID USER   COMMAND
4026531834 time        3   899 ubuntu /lib/systemd/systemd --user
4026531835 cgroup      3   899 ubuntu /lib/systemd/systemd --user
4026531836 pid         3   899 ubuntu /lib/systemd/systemd --user
4026531837 user        3   899 ubuntu /lib/systemd/systemd --user
4026531838 uts         3   899 ubuntu /lib/systemd/systemd --user
4026531839 ipc         3   899 ubuntu /lib/systemd/systemd --user
4026531840 net         3   899 ubuntu /lib/systemd/systemd --user
4026531841 mnt         3   899 ubuntu /lib/systemd/systemd --user

 

컨테이너의 namespace 정보

ubuntu@MyServer:~$ docker run --rm -it ubuntu:16.04 bash
root@34c5df6779ba:/# ls -al /proc/$$/ns
total 0
dr-x--x--x 2 root root 0 Aug 26 07:51 .
dr-xr-xr-x 9 root root 0 Aug 26 07:48 ..
lrwxrwxrwx 1 root root 0 Aug 26 07:51 cgroup -> cgroup:[4026532269]
lrwxrwxrwx 1 root root 0 Aug 26 07:51 ipc -> ipc:[4026532208]
lrwxrwxrwx 1 root root 0 Aug 26 07:51 mnt -> mnt:[4026532206]
lrwxrwxrwx 1 root root 0 Aug 26 07:51 net -> net:[4026532210]
lrwxrwxrwx 1 root root 0 Aug 26 07:51 pid -> pid:[4026532209]
lrwxrwxrwx 1 root root 0 Aug 26 07:51 pid_for_children -> pid:[4026532209]
lrwxrwxrwx 1 root root 0 Aug 26 07:51 time -> time:[4026531834]
lrwxrwxrwx 1 root root 0 Aug 26 07:51 time_for_children -> time:[4026531834]
lrwxrwxrwx 1 root root 0 Aug 26 07:51 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Aug 26 07:51 uts -> uts:[4026532207]

 

Namespace 명 호스트 컨테이너
time 4026531834 4026531834
cgroup 4026531835 4026532269
pid 4026531836 4026532209
user 4026531837 4026531837
uts 4026531838 4026532207
ipc 4026531839 4026532208
net 4026531840 4026532210
mnt 4026531841 4026532206

time, user namespace를 제외하고 namespace id가 다른 것을 확인할 수 있습니다.

 

 


도커 없이 컨테이너 만들기

목표

RED, BLUE 컨테이너를 생성하고, 두 컨테이너가 통신 가능하게 설정하는 실습이 포함되어 있습니다.

 

0) 실습 환경

cloudformation을 통해서 VPC + EC2(ubuntu, t3.small)를 생성하고, 해당 EC2에 접속하여 실습을 진행합니다. 

# YAML 파일 다운로드 - aws 크리덴셜 필요
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/kans/kans-1w.yaml

# CloudFormation 스택 배포
# aws cloudformation deploy --template-file kans-1w.yaml --stack-name mylab --parameter-overrides KeyName=<My SSH Keyname> SgIngressSshCidr=<My Home Public IP Address>/32 --region ap-northeast-2
예시) aws cloudformation deploy --template-file kans-1w.yaml --stack-name mylab --parameter-overrides KeyName=kp-gasida SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2

## Tip. 인스턴스 타입 변경 : MyInstanceType=t2.micro
예시) aws cloudformation deploy --template-file kans-1w.yaml --stack-name mylab --parameter-overrides MyInstanceType=t2.micro KeyName=kp-gasida SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2

# CloudFormation 스택 배포 완료 후 작업용 EC2 IP 출력
aws cloudformation describe-stacks --stack-name mylab --query 'Stacks[*].Outputs[0].OutputValue' --output text --region ap-northeast-2

# [모니터링] CloudFormation 스택 상태 : 생성 완료 확인
while true; do 
  date
  AWS_PAGER="" aws cloudformation list-stacks \
    --stack-status-filter CREATE_IN_PROGRESS CREATE_COMPLETE CREATE_FAILED DELETE_IN_PROGRESS DELETE_FAILED \
    --query "StackSummaries[*].{StackName:StackName, StackStatus:StackStatus}" \
    --output table
  sleep 1
done

# Ansible Server EC2 SSH 접속
ssh -i ~/.ssh/<My SSH Keyname>.pem ubuntu@$(aws cloudformation describe-stacks --stack-name mylab --query 'Stacks[*].Outputs[0].OutputValue' --output text --region ap-northeast-2)

# OS 정보 확인
root@MyServer:~# lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 22.04.4 LTS
Release:	22.04
Codename:	jammy

# 도커 설치
root@MyServer:~# curl -fsSL https://get.docker.com | sh
root@MyServer:~# usermod -aG docker ubuntu

 

 

1) 이미지 준비

myroot, tools 디렉터리를 lower dir로 사용하여 컨테이너를 만들 예정입니다. 각각 다른 명령어와 의존성 패키지를 복사합니다.

myroot : sh, ls, mkdir, mount, ps 

- sh 복사

root@MyServer:~# mkdir /tmp/myroot
# sh 및 의존성 라이브러리 복사
root@MyServer:~# which sh
/usr/bin/sh
root@MyServer:~# ldd /usr/bin/sh
	linux-vdso.so.1 (0x00007ffca3af0000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007022ce000000)
	/lib64/ld-linux-x86-64.so.2 (0x00007022ce313000)
root@MyServer:~# cd /tmp
root@MyServer:/tmp# mkdir -p /tmp/myroot/usr/bin
root@MyServer:/tmp# cp /usr/bin/sh /tmp/myroot/usr/bin/.

root@MyServer:/tmp# mkdir -p /tmp/myroot/{lib64,lib/x86_64-linux-gnu}
root@MyServer:/tmp# cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/myroot/lib/x86_64-linux-gnu/.
root@MyServer:~# cp /lib64/ld-linux-x86-64.so.2 /tmp/myroot/lib64/.

root@MyServer:/tmp# tree myroot
myroot
├── lib
│   └── x86_64-linux-gnu
│       └── libc.so.6
├── lib64
│   └── ld-linux-x86-64.so.2
└── usr
    └── bin
        └── sh

# sh 정상 동작 확인
root@MyServer:/tmp# chroot myroot /bin/sh
#
# exit

- ls 복사

root@MyServer:/tmp# which ls
/usr/bin/ls
root@MyServer:/tmp# ldd /usr/bin/ls
	linux-vdso.so.1 (0x00007ffe4ed4c000)
	libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x000073c977d8b000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x000073c977a00000)
	libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x000073c977cf4000)
	/lib64/ld-linux-x86-64.so.2 (0x000073c977de3000)
    
root@MyServer:/tmp# cp /usr/bin/ls /tmp/myroot/usr/bin/.
root@MyServer:/tmp# cp /lib/x86_64-linux-gnu/libselinux.so.1 /tmp/myroot/lib/x86_64-linux-gnu/.
root@MyServer:/tmp# cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/myroot/lib/x86_64-linux-gnu/.
root@MyServer:/tmp# cp /lib/x86_64-linux-gnu/libpcre2-8.so.0 /tmp/myroot/lib/x86_64-linux-gnu/.
root@MyServer:/tmp# cp /tmp/myroot/lib64/ld-linux-x86-64.so.2 /tmp/myroot/lib64/.

root@MyServer:/tmp# chroot myroot /usr/bin/sh
# ls
lib  lib64  usr

 

- 나머지 명령어 복사

cp /usr/bin/ps /tmp/myroot/usr/bin/.
cp /lib/x86_64-linux-gnu/libprocps.so.8 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libsystemd.so.0 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/liblzma.so.5 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libzstd.so.1 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/liblz4.so.1 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libcap.so.2 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libgcrypt.so.20 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libgpg-error.so.0 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib64/ld-linux-x86-64.so.2 /tmp/myroot/lib64/.

cp /usr/bin/mkdir /tmp/myroot/usr/bin/.
cp /lib/x86_64-linux-gnu/libselinux.so.1 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libpcre2-8.so.0 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib64/ld-linux-x86-64.so.2 /tmp/myroot/lib64/.

cp /usr/bin/mount /tmp/myroot/usr/bin/.
cp /lib/x86_64-linux-gnu/libmount.so.1 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libselinux.so.1 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libblkid.so.1 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libpcre2-8.so.0 /tmp/myroot/lib/x86_64-linux-gnu/.
cp /lib64/ld-linux-x86-64.so.2 /tmp/myroot/lib64/.
root@MyServer:/tmp# tree myroot
myroot
├── lib
│   └── x86_64-linux-gnu
│       ├── libblkid.so.1
│       ├── libc.so.6
│       ├── libcap.so.2
│       ├── libgcrypt.so.20
│       ├── libgpg-error.so.0
│       ├── liblz4.so.1
│       ├── liblzma.so.5
│       ├── libmount.so.1
│       ├── libpcre2-8.so.0
│       ├── libprocps.so.8
│       ├── libselinux.so.1
│       ├── libsystemd.so.0
│       └── libzstd.so.1
├── lib64
│   └── ld-linux-x86-64.so.2
└── usr
    └── bin
        ├── ls
        ├── mkdir
        ├── mount
        ├── ps
        └── sh

 

tools : ping, stress, umount, hostname, which, rm

mkdir /tmp/tools
mkdir -p /tmp/tools/usr/bin
mkdir -p /tmp/tools/{lib64,lib/x86_64-linux-gnu,usr/lib/x86_64-linux-gnu}

apt-get install stress

cp /usr/bin/ping /tmp/tools/usr/bin/.
cp /lib/x86_64-linux-gnu/libcap.so.2 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libidn2.so.0 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libunistring.so.2 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib64/ld-linux-x86-64.so.2 /tmp/tools/lib64/.

cp /usr/bin/stress /tmp/tools/usr/bin/.
cp /lib/x86_64-linux-gnu/libm.so.6 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib64/ld-linux-x86-64.so.2 /tmp/tools/lib64/.

cp /usr/bin/umount /tmp/tools/usr/bin/.
cp /lib/x86_64-linux-gnu/libmount.so.1 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libblkid.so.1 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libselinux.so.1 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libpcre2-8.so.0 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib64/ld-linux-x86-64.so.2 /tmp/tools/lib64/.

cp /usr/bin/hostname /tmp/tools/usr/bin/.
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib64/ld-linux-x86-64.so.2 /tmp/tools/lib64/.


cp /usr/bin/rm /tmp/tools/usr/bin/.
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/tools/lib/.
cp /lib64/ld-linux-x86-64.so.2 /tmp/tools/lib64/.

cp /usr/bin/which /tmp/tools/usr/bin/.
root@MyServer:/tmp# tree tools
tools
├── lib
│   ├── libc.so.6
│   └── x86_64-linux-gnu
│       ├── libblkid.so.1
│       ├── libc.so.6
│       ├── libcap.so.2
│       ├── libidn2.so.0
│       ├── libm.so.6
│       ├── libmount.so.1
│       ├── libpcre2-8.so.0
│       ├── libselinux.so.1
│       └── libunistring.so.2
├── lib64
│   └── ld-linux-x86-64.so.2
└── usr
    ├── bin
    │   ├── hostname
    │   ├── ping
    │   ├── rm
    │   ├── stress
    │   ├── umount
    │   └── which
    └── lib
        └── x86_64-linux-gnu

 

2) Network namespace 및 IP 설정

root@MyServer:/tmp# ip netns add RED
root@MyServer:/tmp# ip netns add BLUE
root@MyServer:/tmp# ip netns ls
BLUE
RED

root@MyServer:/tmp# ip link add veth0 type veth peer name veth1
root@MyServer:/tmp# ip -c link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 02:46:2c:55:80:6d brd ff:ff:ff:ff:ff:ff
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
    link/ether 02:42:a7:c2:79:a0 brd ff:ff:ff:ff:ff:ff
6: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether fe:ee:17:a6:9c:ed brd ff:ff:ff:ff:ff:ff
7: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 4e:6a:29:13:83:94 brd ff:ff:ff:ff:ff:ff
root@MyServer:/tmp# ip -c addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 02:46:2c:55:80:6d brd ff:ff:ff:ff:ff:ff
    inet 192.168.50.10/24 metric 100 brd 192.168.50.255 scope global dynamic ens5
       valid_lft 1935sec preferred_lft 1935sec
    inet6 fe80::46:2cff:fe55:806d/64 scope link
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:a7:c2:79:a0 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:a7ff:fec2:79a0/64 scope link
       valid_lft forever preferred_lft forever
6: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether fe:ee:17:a6:9c:ed brd ff:ff:ff:ff:ff:ff
7: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 4e:6a:29:13:83:94 brd ff:ff:ff:ff:ff:ff
root@MyServer:/tmp# ifconfig -a
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:a7ff:fec2:79a0  prefixlen 64  scopeid 0x20<link>
        ether 02:42:a7:c2:79:a0  txqueuelen 0  (Ethernet)
        RX packets 2254  bytes 121431 (121.4 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2699  bytes 17581348 (17.5 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9001
        inet 192.168.50.10  netmask 255.255.255.0  broadcast 192.168.50.255
        inet6 fe80::46:2cff:fe55:806d  prefixlen 64  scopeid 0x20<link>
        ether 02:46:2c:55:80:6d  txqueuelen 1000  (Ethernet)
        RX packets 58879  bytes 71244858 (71.2 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 22069  bytes 2879306 (2.8 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 242  bytes 26920 (26.9 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 242  bytes 26920 (26.9 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

veth0: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether 4e:6a:29:13:83:94  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

veth1: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether fe:ee:17:a6:9c:ed  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

root@MyServer:/tmp# ip link set veth0 netns RED
root@MyServer:/tmp# ip netns ls
BLUE
RED (id: 0)
root@MyServer:/tmp# ip -c link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 02:46:2c:55:80:6d brd ff:ff:ff:ff:ff:ff
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
    link/ether 02:42:a7:c2:79:a0 brd ff:ff:ff:ff:ff:ff
6: veth1@if7: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether fe:ee:17:a6:9c:ed brd ff:ff:ff:ff:ff:ff link-netns RED
root@MyServer:/tmp# ip netns exec RED ip -c a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
7: veth0@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 4e:6a:29:13:83:94 brd ff:ff:ff:ff:ff:ff link-netnsid 0
root@MyServer:/tmp# ip link set veth1 netns BLUE
root@MyServer:/tmp# ip netns exec RED ip -c a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
7: veth0@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 4e:6a:29:13:83:94 brd ff:ff:ff:ff:ff:ff link-netns BLUE

## 참고) 위 작업은 아래 명령어 실행과 동일
## ip link add veth0 netns RED type veth peer name veth1 netns BLUE

root@MyServer:/tmp# ip netns exec RED ip -c a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
7: veth0@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 4e:6a:29:13:83:94 brd ff:ff:ff:ff:ff:ff link-netns BLUE
root@MyServer:/tmp# ip netns exec BLUE ip -c a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: veth1@if7: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether fe:ee:17:a6:9c:ed brd ff:ff:ff:ff:ff:ff link-netns RED
root@MyServer:/tmp# ip -c a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 02:46:2c:55:80:6d brd ff:ff:ff:ff:ff:ff
    inet 192.168.50.10/24 metric 100 brd 192.168.50.255 scope global dynamic ens5
       valid_lft 3582sec preferred_lft 3582sec
    inet6 fe80::46:2cff:fe55:806d/64 scope link
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:a7:c2:79:a0 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:a7ff:fec2:79a0/64 scope link
       valid_lft forever preferred_lft forever
       

root@MyServer:/tmp# ip netns exec RED ip link set veth0 up
root@MyServer:/tmp# ip netns exec RED ip -c a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
7: veth0@if6: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN group default qlen 1000
    link/ether 4e:6a:29:13:83:94 brd ff:ff:ff:ff:ff:ff link-netns BLUE
    
    
root@MyServer:/tmp# ip netns exec BLUE ip link set veth1 up
root@MyServer:/tmp# ip netns exec BLUE ip -c a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: veth1@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether fe:ee:17:a6:9c:ed brd ff:ff:ff:ff:ff:ff link-netns RED
    inet6 fe80::fcee:17ff:fea6:9ced/64 scope link
       valid_lft forever preferred_lft forever
       
## ip 설정 추가
root@MyServer:/tmp# ip netns exec RED ip addr add 11.11.11.2/24 dev veth0
root@MyServer:/tmp# ip netns exec BLUE ip addr add 11.11.11.3/24 dev veth1
root@MyServer:/tmp# ip netns exec RED ip -c a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
7: veth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 4e:6a:29:13:83:94 brd ff:ff:ff:ff:ff:ff link-netns BLUE
    inet 11.11.11.2/24 scope global veth0
       valid_lft forever preferred_lft forever
    inet6 fe80::4c6a:29ff:fe13:8394/64 scope link
       valid_lft forever preferred_lft forever

 

3) RED 컨테이너 구성

3-1) cgroup 생성 및 cpu, mem, swap 설정

실습 환경 EC2에서 cgroup v2를 사용하므로 그에 맞게 변경했습니다.

mkdir /sys/fs/cgroup/red

## cpu.cfs_quota_us, cpu.cfs_period_us(기본 100ms)를 차례로 입력
echo "40000 100000" > /sys/fs/cgroup/red/cpu.max

## memory.limit_in_bytes 대체
echo "209715200" > /sys/fs/cgroup/red/memory.max

## swap 비활성화
echo "0" > /sys/fs/cgroup/red/memory.swap.max

 

3-2) RED 컨테이너 분리

mnt, uts, ipc, pid, net namespace 분리

root@MyServer:/tmp/myroot# unshare -m -u -i -fp nsenter --net=/var/run/netns/RED /usr/bin/sh
#
# echo $$
1

## cgroup 할당
# echo "1" > /sys/fs/cgroup/red/cgroup.procs

## overlay 파일시스템 설정
# mkdir /redfs
# mkdir /redfs/container
# mkdir /redfs/work
# mkdir /redfs/merge
# tree /redfs
/redfs
├── container
├── merge
└── work

# mount -t overlay overlay -o lowerdir=/tmp/tools:/tmp/myroot,upperdir=/redfs/container,workdir=/redfs/work /redfs/merge

## myroot와 tools 디렉터리가 합쳐져서 보이는 것을 확인
# tree /redfs/merge
/redfs/merge
├── lib
│   ├── libc.so.6
│   └── x86_64-linux-gnu
│       ├── libblkid.so.1
│       ├── libc.so.6
│       ├── libcap.so.2
│       ├── libgcrypt.so.20
│       ├── libgpg-error.so.0
│       ├── libidn2.so.0
│       ├── liblz4.so.1
│       ├── liblzma.so.5
│       ├── libm.so.6
│       ├── libmount.so.1
│       ├── libpcre2-8.so.0
│       ├── libprocps.so.8
│       ├── libselinux.so.1
│       ├── libsystemd.so.0
│       ├── libunistring.so.2
│       └── libzstd.so.1
├── lib64
│   └── ld-linux-x86-64.so.2
├── proc
├── put_old
└── usr
    ├── bin
    │   ├── hostname
    │   ├── ls
    │   ├── mkdir
    │   ├── mount
    │   ├── ping
    │   ├── ps
    │   ├── rm
    │   ├── sh
    │   ├── stress
    │   ├── umount
    │   └── which
    └── lib
        └── x86_64-linux-gnu
        
        
## pivot_root 실행
# mkdir -p /redfs/merge/put_old
# cd /redfs/merge
# pivot_root . put_old
# cd /

## put_old 디렉터리에 호스트 root 파일시스템이 연결되어 있으므로, 보안을 위해 삭제
# ls put_old
bin  boot  dev	etc  home  lib	lib32  lib64  libx32  lost+found  media  mnt  opt  proc  redfs	root  run  sbin  snap  srv  sys  tmp  usr  var

# mkdir /proc
# mount -t proc proc /proc
# umount -l put_old
# rm -rf put_old
# ls
lib  lib64  proc  usr

## hostname 변경
# hostname
MyServer
# hostname RED
# hostname
RED

 

RED 컨테이너 namespace id 확인

# ls -al /proc/$$/ns
total 0
dr-x--x--x 2 0 0 0 Aug 27 09:15 .
dr-xr-xr-x 9 0 0 0 Aug 27 09:13 ..
lrwxrwxrwx 1 0 0 0 Aug 27 09:15 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 0 0 0 Aug 27 09:15 ipc -> 'ipc:[4026532327]'
lrwxrwxrwx 1 0 0 0 Aug 27 09:15 mnt -> 'mnt:[4026532324]'
lrwxrwxrwx 1 0 0 0 Aug 27 09:15 net -> 'net:[4026532204]'
lrwxrwxrwx 1 0 0 0 Aug 27 09:15 pid -> 'pid:[4026532328]'
lrwxrwxrwx 1 0 0 0 Aug 27 09:15 pid_for_children -> 'pid:[4026532328]'
lrwxrwxrwx 1 0 0 0 Aug 27 09:15 time -> 'time:[4026531834]'
lrwxrwxrwx 1 0 0 0 Aug 27 09:15 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 0 0 0 Aug 27 09:15 user -> 'user:[4026531837]'
lrwxrwxrwx 1 0 0 0 Aug 27 09:15 uts -> 'uts:[4026532326]'

 

Namespace 명 호스트 RED 컨테이너
time 4026531834 4026531834
cgroup 4026531835 4026531835
pid 4026531836 4026532328
user 4026531837 4026531837
uts 4026531838 4026532326
ipc 4026531839 4026532327
net 4026531840 4026532204
mnt 4026531841 4026532324

time, cgroup, user namespace를 제외하고 모두 호스트와 다른 namespace에 속한 것을 확인할 수 있습니다.

 

4) BLUE 컨테이너 구성

BLUE 컨테이너 구성은 RED 컨테이너 구성과 유사하지만, time, cgroup namespace도 분리 해보겠습니다.

 

4-1) 명령어 추가

테스트를 위해 추가로 필요한 명령어를 복사합니다.

cp /usr/bin/date /tmp/tools/usr/bin/.
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib64/ld-linux-x86-64.so.2 /tmp/tools/lib64/.

cp /usr/bin/uptime /tmp/tools/usr/bin/.
cp /lib/x86_64-linux-gnu/libprocps.so.8 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libsystemd.so.0 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib64/ld-linux-x86-64.so.2 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/liblzma.so.5 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libzstd.so.1 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/liblz4.so.1 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libcap.so.2 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libgcrypt.so.20 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib/x86_64-linux-gnu/libgpg-error.so.0 /tmp/tools/lib/x86_64-linux-gnu/.

cp /usr/bin/cat /tmp/tools/usr/bin/.
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/tools/lib/x86_64-linux-gnu/.
cp /lib64/ld-linux-x86-64.so.2 /tmp/tools/lib64/.

 

4-1) cgroup 생성 및 cpu, mem, swap 설정

mkdir /sys/fs/cgroup/blue

## cpu.cfs_quota_us, cpu.cfs_period_us(기본 100ms)를 차례로 입력
echo "40000 100000" > /sys/fs/cgroup/blue/cpu.max

## memory.limit_in_bytes 대체
echo "209715200" > /sys/fs/cgroup/blue/memory.max

## swap 비활성화
echo "0" > /sys/fs/cgroup/blue/memory.swap.max

4-2) BLUE 컨테이너 분리

root@MyServer:/tmp/myroot# unshare -m -u -i -T -C --boottime 1000000000 -fp nsenter --net=/var/run/netns/BLUE /usr/bin/sh
#
# uptime
 22:57:42 up 11574 days, 16:40,  5 users,  load average: 0.02, 0.03, 0.00
## 호스트 uptime과 비교
root@MyServer:~# uptime
 22:57:45 up 14:54,  5 users,  load average: 0.02, 0.03, 0.00 
 
## cgroup 할당
# echo "1" > /sys/fs/cgroup/blue/cgroup.procs
/usr/bin/sh: 2: echo: echo: I/O error
# cat /sys/fs/cgroup/blue/memory.max
209715200
# cat /sys/fs/cgroup/blue/cpu.max
40000 100000

RED 컨테이너와 다르게 /sys/fs/cgroup/blue/cgroup.procs 파일 수정이 불가합니다.

## overlay 파일시스템 설정
# mkdir /bluefs
# mkdir /bluefs/container
# mkdir /bluefs/work
# mkdir /bluefs/merge
# tree /bluefs
/bluefs
├── container
├── merge
└── work

# mount -t overlay overlay -o lowerdir=/tmp/tools:/tmp/myroot,upperdir=/bluefs/container,workdir=/bluefs/work /bluefs/merge

## pivot_root 실행
# mkdir -p /bluefs/merge/put_old
# cd /bluefs/merge
# pivot_root . put_old
# cd /

## put_old 디렉터리 삭제
# mkdir /proc
# mount -t proc proc /proc
# umount -l put_old
# rm -rf put_old
# ls
lib  lib64  proc  usr

## hostname 변경
# hostname
MyServer
# hostname BLUE
# hostname
BLUE

## timezone 변경
# export TZ="America/New_York"
# date
Tue Aug 27 14:01:16 America 2024

## 1년 후로 변경
# date -s "$(date -d '+1 year' '+%Y-%m-%d %H:%M:%S')"
# date
Wed Aug 27 14:03:22 America 2025

## 호스트 date와 비교
root@MyServer:~# date
Wed Aug 27 23:04:02 KST 2025

호스트와 관계 없이 서버 시간과 boottime이 변경된 것을 확인할 수 있습니다.

 

4-2) cgroup namespace 관련 확인

# mkdir -p /sys/fs/cgroup
# mount -t cgroup2 none /sys/fs/cgroup -o rw,nosuid,nodev,noexec,relatime
# mount
overlay on / type overlay (rw,relatime,lowerdir=/tmp/tools:/tmp/myroot,upperdir=/bluefs/container,workdir=/bluefs/work,nouserxattr)
proc on /proc type proc (rw,relatime)
none on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)

# cd /sys/fs/cgroup
# cd /sys/fs/cgroup
# ls
cgroup.controllers	cgroup.pressure		cpu.pressure	     memory.high       memory.peak	    memory.swap.high	  pids.events
cgroup.events		cgroup.procs		cpu.stat	     memory.low        memory.pressure	    memory.swap.max	  pids.max
cgroup.freeze		cgroup.stat		io.pressure	     memory.max        memory.reclaim	    memory.swap.peak	  pids.peak
cgroup.kill		cgroup.subtree_control	memory.current	     memory.min        memory.stat	    memory.zswap.current
cgroup.max.depth	cgroup.threads		memory.events	     memory.numa_stat  memory.swap.current  memory.zswap.max
cgroup.max.descendants	cgroup.type		memory.events.local  memory.oom.group  memory.swap.events   pids.current
# cat cgroup.controllers
memory pids
# cat cgroup.subtree_control

# mkdir bluesub
# ls bluesub
cgroup.controllers  cgroup.freeze  cgroup.max.depth	   cgroup.pressure  cgroup.stat		    cgroup.threads  cpu.pressure  io.pressure
cgroup.events	    cgroup.kill    cgroup.max.descendants  cgroup.procs     cgroup.subtree_control  cgroup.type     cpu.stat	  memory.pressure

## 호스트와 비교
root@MyServer:/sys/fs/cgroup/blue# cat cgroup.controllers
cpuset cpu io memory pids
root@MyServer:/sys/fs/cgroup/blue# cat cgroup.subtree_control
root@MyServer:/sys/fs/cgroup/blue# ls
root@MyServer:/sys/fs/cgroup/blue# ls
cgroup.controllers      cgroup.threads  cpu.weight.nice        io.weight            memory.peak           memory.zswap.max
cgroup.events           cgroup.type     cpuset.cpus            memory.current       memory.pressure       pids.current
cgroup.freeze           cpu.idle        cpuset.cpus.effective  memory.events        memory.reclaim        pids.events
cgroup.kill             cpu.max         cpuset.cpus.partition  memory.events.local  memory.stat           pids.max
cgroup.max.depth        cpu.max.burst   cpuset.mems            memory.high          memory.swap.current   pids.peak
cgroup.max.descendants  cpu.pressure    cpuset.mems.effective  memory.low           memory.swap.events
cgroup.pressure         cpu.stat        io.max                 memory.max           memory.swap.high
cgroup.procs            cpu.uclamp.max  io.pressure            memory.min           memory.swap.max
cgroup.stat             cpu.uclamp.min  io.prio.class          memory.numa_stat     memory.swap.peak
cgroup.subtree_control  cpu.weight      io.stat                memory.oom.group     memory.zswap.current

호스트와 비교 시 cgroup.controllers, cgroup.subtree_control 값이 다르고 각각 cgroup 아래에 폴더를 생성했을 때 자동으로 생성되는 파일이 다른 것을 확인할 수 있습니다.

cgroup namespace 분리 시에 자원 limit 설정 방법은 추후 다시 다뤄보겠습니다.

 

BLUE 컨테이너 namespace id 확인

# ls -al /proc/$$/ns
total 0
dr-x--x--x 2 0 0 0 Aug 27  2024 .
dr-xr-xr-x 9 0 0 0 Aug 27  2024 ..
lrwxrwxrwx 1 0 0 0 Aug 27  2024 cgroup -> 'cgroup:[4026532332]'
lrwxrwxrwx 1 0 0 0 Aug 27  2024 ipc -> 'ipc:[4026532326]'
lrwxrwxrwx 1 0 0 0 Aug 27  2024 mnt -> 'mnt:[4026532319]'
lrwxrwxrwx 1 0 0 0 Aug 27  2024 net -> 'net:[4026532263]'
lrwxrwxrwx 1 0 0 0 Aug 27  2024 pid -> 'pid:[4026532327]'
lrwxrwxrwx 1 0 0 0 Aug 27  2024 pid_for_children -> 'pid:[4026532327]'
lrwxrwxrwx 1 0 0 0 Aug 27  2024 time -> 'time:[4026532329]'
lrwxrwxrwx 1 0 0 0 Aug 27  2024 time_for_children -> 'time:[4026532329]'
lrwxrwxrwx 1 0 0 0 Aug 27  2024 user -> 'user:[4026531837]'
lrwxrwxrwx 1 0 0 0 Aug 27  2024 uts -> 'uts:[4026532324]'
Namespace 명 호스트 RED 컨테이너
time 4026531834 4026532329
cgroup 4026531835 4026532332
pid 4026531836 4026532327
user 4026531837 4026531837
uts 4026531838 4026532324
ipc 4026531839 4026532326
net 4026531840 4026532204
mnt 4026531841 4026532319

 

5) RED - BLUE 통신 테스트

# hostname
BLUE
# ping 11.11.11.2
PING 11.11.11.2 (11.11.11.2) 56(84) bytes of data.
64 bytes from 11.11.11.2: icmp_seq=1 ttl=64 time=0.028 ms
64 bytes from 11.11.11.2: icmp_seq=2 ttl=64 time=0.033 ms
64 bytes from 11.11.11.2: icmp_seq=3 ttl=64 time=0.035 ms
^C
--- 11.11.11.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2056ms
rtt min/avg/max/mdev = 0.028/0.032/0.035/0.003 ms
# hostname
RED
# ping 11.11.11.3
PING 11.11.11.3 (11.11.11.3) 56(84) bytes of data.
64 bytes from 11.11.11.3: icmp_seq=1 ttl=64 time=0.024 ms
64 bytes from 11.11.11.3: icmp_seq=2 ttl=64 time=0.033 ms
64 bytes from 11.11.11.3: icmp_seq=3 ttl=64 time=0.036 ms
^C
--- 11.11.11.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2039ms
rtt min/avg/max/mdev = 0.024/0.031/0.036/0.005 ms

RED <-> BLUE 사이 통신이 잘 되는 것을 확인할 수 있습니다.

 

6) RED 컨테이너 cgroup 제한 테스트

# stress --vm 1 --vm-bytes 200M
stress: info: [11] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: FAIL: [11] (416) <-- worker 12 got signal 9
stress: WARN: [11] (418) now reaping child worker processes
stress: FAIL: [11] (452) failed run completed in 0s

root@MyServer:~# dmesg
[ 1153.994720] Tasks state (memory values in pages):
[ 1153.994721] [  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
[ 1153.994722] [   2493]     0  2493      723      416    49152        0             0 sh
[ 1153.994726] [   2515]     0  2515      927      480    49152        0             0 stress
[ 1153.994729] [   2516]     0  2516    52128    51072   458752        0             0 stress
[ 1153.994731] oom-kill:constraint=CONSTRAINT_MEMCG,nodemask=(null),cpuset=red,mems_allowed=0,oom_memcg=/red,task_memcg=/red,task=stress,pid=2516,uid=0
[ 1153.994741] Memory cgroup out of memory: Killed process 2516 (stress) total-vm:208512kB, anon-rss:204032kB, file-rss:256kB, shmem-rss:0kB, UID:0 pgtables:448kB oom_score_adj:0

memory limit에 따른 OOM kill 현상을 확인할 수 있습니다.

 

지금까지 linux 명령어를 사용해서 컨테이너와 유사한 수준의 격리 환경을 만드는 실습을 진행했습니다.

이를 통해 컨테이너를 구성하는 방식에 대해 이해도를 높일 수 있었습니다.

728x90

'Kubernetes > Network Study' 카테고리의 다른 글

Kubernetes Service 분석 - ClusterIP, NodePort  (3) 2024.09.28
Calico 개념 및 실습  (3) 2024.09.21
Flannel CNI 실습  (3) 2024.09.07
Pause Container 이해하기  (11) 2024.09.02
iptables 이해하기  (0) 2024.08.31