가시다님의 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 사용하도록 설정
현재 아래와 같이 총 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을 통해 이루어집니다.
참고)
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)
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 명령어를 사용해서 컨테이너와 유사한 수준의 격리 환경을 만드는 실습을 진행했습니다.
이를 통해 컨테이너를 구성하는 방식에 대해 이해도를 높일 수 있었습니다.
'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 |