참고
1. 목차
NOTE
BOX_IMAGE = "bento/ubuntu-18.04"
HOST_NAME = "ubuntu1804"
$pre_install = <<-SCRIPT
echo ">>>> pre-install <<<<<<"
sudo apt-get update &&
sudo apt-get -y install gcc &&
sudo apt-get -y install make &&
sudo apt-get -y install pkg-config &&
sudo apt-get -y install libseccomp-dev &&
sudo apt-get -y install tree &&
sudo apt-get -y install jq &&
sudo apt-get -y install bridge-utils
echo ">>>>> install docker <<<<<<"
sudo apt-get -y install apt-transport-https ca-certificates curl gnupg lsb-release > /dev/null 2>&1 &&
sudo mkdir -p /etc/apt/keyrings &&
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg &&
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 2>&1 &&
sudo apt-get update &&
sudo apt-get -y install docker-ce docker-ce-cli docker-compose-plugin > /dev/null 2>&1
SCRIPT
Vagrant.configure("2") do |config|
config.vm.define HOST_NAME do |subconfig|
subconfig.vm.box = BOX_IMAGE
subconfig.vm.hostname = HOST_NAME
subconfig.vm.network :private_network, ip: "192.168.104.2"
subconfig.vm.provider "virtualbox" do |v|
v.memory = 1536
v.cpus = 2
end
subconfig.vm.provision "shell", inline: $pre_install
end
end
Bash
복사
도커 vs VM호스트 비교
NOTE
docker run -it busybox
Bash
복사
•
굉장히 많음
도커와 호스트의 루트 디렉토리는 다르다.
•
루트 디렉토리가 다르다 ⇒ 시스템이 다르다.
◦
도커의 경우 루트 디렉토리가 오버레이다.
◦
호스트의 경우 루트 디렉토리가 dev다.
컨테이너의 루트와 호스트의 루트는 동일한가.
chroot
NOTE
# chrppt [옵션] NEWROOT 커맨드
mkdir myroot
chroot myroot /bin/sh
## sh 복사
which sh
ldd /bin/sh
mkdir -p myroot/bin
cp /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
# ls 복사
which ls
ldd /bin/ls
cp /bin/ls myroot/bin/
cp /lib/x86_64-linux-gnu/{libselinux.so.1,libc.so.6,libpcre.so.3,libdl.so.2,libpthread.so.0} myroot/lib/x86_64-linux-gnu/
cp /lib64/ld-linux-x86-64.so.2 myroot/lib64/
## cd로 chroot에서 벗어날 수 없음
## ps 복사
wget https://raw.githubusercontent.com/sam0kim/container-internal/main/scripts/chroot_ps.sh
mount -t proc proc /proc
# mount: /proc: mount point does not exists
mkdir /proc
,mount -t proc proc /proc
ps
unmount /tmp/myroot/proc
Bash
복사
nginx 이미지 chroot 해보기
NOTE
mkdir nginx-root
docker export $(docker create nginx) | tar -C nginx-root -xvf -
tree -L 1 nginx-root/
#nginx-root/
#├── bin -> usr/bin
#├── boot
#├── dev
#├── docker-entrypoint.d
#├── docker-entrypoint.sh
#├── etc
#├── home
#├── lib -> usr/lib
#├── lib64 -> usr/lib64
#├── media
#├── mnt
#├── opt
#├── proc
#├── root
#├── run
#├── sbin -> usr/sbin
#├── srv
#├── sys
#├── tmp
#├── usr
#└── var
chroot nginx-root /bin/sh
nginx -g "daemon off;" # chroot
curl localhost:80 # root(통신이 됨!)
Bash
복사
chroot만 있어도 도커 이미지를 만들 수 있을까?
chroot는 사용자를 fake root로 가둠으로써 사용하게 되는건데 만약 fake root를 탈출하면 어떻게 되는가?
#include <sys/stat.h>
#include <unistd.h>
int main(void)
{
mkdir(".out", 0755);
chroot(".out");
chdir("../../../../../");
chroot(".");
return execl("/bin/sh", "-i", NULL);
}
Bash
복사
# gcc -o myroot/escape_chroot
escape_chroot.c
ls
Bash
복사
탈옥이 됨!
pivot_root
NOTE
unshare --mount /bin/sh
mkdir new_root
mount -t tmpfs none new_root
Bash
복사
•
중복을 해결하자(오버레이 파일시스템)
NOTE
01 07
mkdir -p tools/usr/bin
cp /usr/bin/which tools/usr/bin/
mkdir -p tools/{bin,lib64,lib/x86_64-linux-gnu}
cp /bin/rm tools/bin/
cp /lib/x86_64-linux-gnu/libc.so.6 tools/lib/x86_64-linux-gnu/;
cp /lib64/ld-linux-x86-64.so.2 tools/lib64
mkdir -p rootfs/{container,work,merge}
mount -t overlay overlay -o lowerdir=tools:myroot2,upperdir=rootfs/container,workdir=rootfs/work rootfs/merge
tree -L 2 myroot/{bin,usr};
tree -L 2 rootfs/merge/{bin,usr};
umount /tmp/rootfs/merge
Bash
복사
# OverlayFS 파일 시스템을 마운트하는 명령어
# mount 명령어를 사용하여 파일 시스템을 마운트합니다
mount -t overlay overlay \
# 파일 시스템 유형을 overlay로 지정합니다
-o lowerdir=tools:myroot2,upperdir=rootfs/container,workdir=rootfs/work \
# OverlayFS 마운트 옵션:
# lowerdir=tools:myroot2
# - 읽기 전용으로 결합할 하위 디렉토리들입니다. 여러 디렉토리를 :로 구분합니다.
# - 여기서는 tools와 myroot2 디렉토리의 내용을 읽기 전용으로 결합합니다.
#
# upperdir=rootfs/container
# - 읽기 및 쓰기 가능한 상위 디렉토리입니다.
# - 여기서 파일 시스템의 변경 사항이 저장됩니다.
#
# workdir=rootfs/work
# - OverlayFS의 내부 작업을 처리하기 위해 필요한 작업 디렉토리입니다.
rootfs/merge
# 결합된 파일 시스템을 마운트할 대상 디렉토리입니다
# - 결합된 파일 시스템은 rootfs/merge 디렉토리에 마운트됩니다
rootfs/merge
├── tools (읽기 전용)
├── myroot2 (읽기 전용)
└── rootfs/container (읽기 및 쓰기 가능)
Bash
복사
컨테이너 격리와 자원(네임스페이스)
NOTE
•
모든 프로세스는 타입별로 네임스페이스에 속한다.
•
자식 프로세스는 부모의 네임스페이스를 상속한다.
•
UTS, Unix Time Sharing (서버 나눠쓰기)
◦
호스트명, 도메인명 격리
•
IPC, Inter-Process Communication 격리
◦
Shared Memory, Pipe, Message Queue 등
•
PID (Process ID) 넘버스페이스를 격리
◦
부모-자식 네임스페이스 중첩 구조
◦
부모 네임스페이스 - (see) -> 자식네임스페이스
◦
pid = 1, (init 프로세스 - 커널이 생성, 시그널 처리, 좀비 고아 프로세스 처리, 죽으면 패닉)
◦
컨테이너 PID 1
▪
unshare 할 때 fork하며 자식 PID 네임스페이스의 pid 1로 실행
▪
시그널 처리
▪
좀비, 고아 프로세스 처리
▪
죽으면 컨테이너 종료
◦
unshare -fp --mount-proc /bin/sh (PID 네임스페이스 만들기)
▪
-p : pid namespace
▪
-f : fork
▪
—mount-proc : proc 파일시스템
◦
-proc
▪
메모리 기반의 가상파일 시스템
▪
커널이 관리하는 시스템 정보
▪
시스템 모니터링 및 분석에 활용
# unshare [옵션] [프로그램 [arguments ... ]]
# -m --mount
# -u --uts
# -i --ipc
# -p --pid
# -n --net
# -U --user
ls -al /proc/$$/ns
readlink /proc/$$/ns/mnt
lsns -p 1
lsns -t mnet -p 1
# -t: 네임스페이스 타입 pid, mnt, uts
# -p: 조회할 프로세스 아이디
unshare -m
lsns -p $$
Bash
복사
격리 안됨
NOTE
•
•
격리 안됨
NOTE
•
•