본문 바로가기
IT/Linux

[Linux] 도커 없이 컨테이너 만들기 강의 정리(1)

by 저당단 2025. 7. 20.

https://youtu.be/lVtgqmjv4BQ?si=HkWN11XM1uECmBEg

위의 카카오엔터프라이즈 강의 내용 정리

강의가 생각보다 길어서 절반정도의 내용까지 정리했습니다.

 

- 컨테이너를 쓰려면 리눅스와 런타임(컨테이너 관리 도구)이 있어야 함.

- 대규모 서비스를 돌려야 해서 서버를 여러대 사용하고 있다면 한번에 관리하기 위해 쿠버네티스를 사용한다.

 

docker run 명령어를 통해 컨테이너 만든 뒤

- ls로 보면 컨테이너의 루트 디렉토리의 FileSystem은 overlay, 호스트서버는 /dev/mapper/... 로 표시된다.

- hostname은 컨테이너의 uid, 호스트서버는 pc 이름이 표시된다.

- id 명령어를 쳐보면 uid(유저id), gid(그룹id)는 같다

- 사실 루트권한으로 프로그램을 실행하지는 않는 게 좋다. (해당 프로그램으로 루트 쉘 탈취 가능성 등 보안상의 이유 때문)

 

컨테이너가 만들어진 이유

- 해커를 막기 위해 /chroot 안에 격리된 환경을 만듦. 해커는 그 안에 갇혀 거기가 실제 서버 내부인줄 알게 됨. 해당 격리 환경의 루트를 Fake root라고 함.

 

chroot 명령어 사용하여 격리 환경 만들기

- 사용법: chroot [옵션] [새로운 루트의 경로] [실행할 커맨드]

- chroot myroot /bin/sh

- 커맨드를 비워두면 $SHELL 이 기본값

- 바로 명령어를 실행하면 /bin/sh가 myroot 밑에 없다고 에러가 뜸.

- which sh 명령어로 실행파일을 복사하고, ldd /bin/sh로 바이너리 파일 목록도 확인해서 복사해야 함.

- 바이너리 파일 목록 중 커널 레이어에 있는 vdso를 제외한 나머지 libc, ld-linux만 복사함

- myroot 아래에 bin, lib, lib64 이하 3개의 디렉토리가 존재하게 됨

- 이제 다시 맨 처음 명령어를 입력하면 분리된 환경이 만들어짐

- 근데 ls 명령어가 없으므로, sh 명령어를 복사했을 때와 같은 방법으로 복사해줌

- 여기서 했던 작업은 특정 경로에 모으고(패키징), 경로에 가둬서(격리) 실행하는 것이 컨테이너와 굉장히 유사함

 

격리 환경에서 ps 명령어 실행하기

- 의존성이 있는 mkdir, mount 명령어도 같이 복사해야 가능함. wget으로 스크립트 가져오는게 편함

- ps 명령어 복사 후 실행하려고 하면 mount 관련 에러가 표시됨 (mount -t proc proc /proc)

- mount는 USB를 부착하는 것과 같은 의미

- mount -t proc proc /proc 명령어는 /proc 이라는 폴더(이걸 마운트 포인트라고 함)에 USB를 꽂으라는 의미

- /proc 폴더를 만들고 위의 명령어를 치면 ps 명령어가 동작한다.

 

이렇게 한땀한땀 복사하기 힘들어서 남이 구성해놓은 환경, '이미지'를 이용

- 도커 이미지를 docker run 없이 chroot 격리환경에 구성해보기

- docker export $(docker create nginx) | tar -C [폴더명] -xvf -     << 도커를 통해 nginx 이미지 압축 푼것

- chroot [폴더명] /bin/sh      << 격리 환경 만들기

- 해당 환경에서 nginx -g "daemon off;" 으로 웹서버 구동

- 밖에서 curl localhost:80 으로 접근 가능.

 

하지만 chroot로 만든 fake root에서 탈옥할 수 있음

- escape.c 를 작성함

#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 [컴파일 결과물 저장할 경로] escape.c

- 이래서 chroot를 실제 컨테이너로 쓸 수가 없다.

 

pivot_root를 통해 탈옥을 막을 수 있음

- 루트파일시스템이란 루트 디렉토리를 포함한 최상위 파일 시스템임.

- /bin/, /dev/, /etc/ 등 하위의 모든 파일시스템들이 USB처럼 마운트(하위 디렉토리로 부착하는 것)되어있음.

- pivot_root는 이 루트파일시스템을 피봇하는 것. 즉 chroot와 달리 진짜로 호스트 루트가 다른 디렉토리로 바뀐다.

- 그래서 마운트 네임스페이스를 이용한다. 그럼 호스트에 영향이 없다.

- 마운트 네임스페이스란, 자기들만의 파일시스템 마운트 상태를 갖게 해주는 것이다.

- 즉 마운트 포인트들을 포함한 구조만 unshare 명령어로 복사해서 자식 마운트 네임스페이스를 만든다.

- unshare --mount /bin/sh

- 위와 같이 하면 부모 구조를 그대로 갖고오기 때문에 똑같은 구조의 격리 환경이 만들어진다.

- 격리 환경 안에서 new_root 를 만들고 mount -t tmpfs none new_root 를 한다. (tmpfs 타입은 임시 파일시스템이다.)

- 그럼 tree new_root 시 격리 환경에서만 마운트되고 호스트에서는 빈 디렉토리만 보이는 걸 알 수 있다.

- pivot_root new_root put_old

- 위 명령어를 입력하고 루트 디렉토리로 이동해보면 루트가 new_root에 있던 파일시스템으로 바뀌어 있다.

- put_old에는 호스트에 있던 루트파일시스템들이 들어가있다.

- 이 상태에서 escape.c를 실행해 보려고 해도 탈옥 못한다.