<컨테이너 가상화의 이해> chroot를 사용해 프로세스의 루트 바꾸기
안녕하세요. 프로그래머 @mishana입니다.
오늘 소개할 리눅스 명령어는 프로세스가 인식하는 루트 디렉터리를 바꿔주는 chroot입니다.
chroot를 직접 사용할 일은 별로 없습니다. 하지만 chroot를 사용해보면 리눅스 위에서 프로세스를 격리 시키는 기본적인 방법을 직접 경험해 볼 수 있습니다. 요즘 도커Docker와 컨테이너 가상화가 인기를 끌고 있는데, chroot를 사용해보면 이런 컨테이너 가상화 도구를 이해하는 데 큰 도움이 됩니다.
도커(Docker)와 프로세스 격리
도커를 처음 사용하는 사람들이 많이 하는 질문 중 하나가 "도커는 가상 머신인가요?"입니다. 오늘의 주제는 도커가 아니니 결론만 짚고 넘어가도록 하겠습니다.
도커는 가상 머신이 아닙니다.
가상 머신은 하드웨어를 소프트웨어로 구현합니다. 버추얼 박스VirtualBox나 VMWare 같은 도구를 사용해보셨다면 아시겠지만, 가상 머신을 생성할 때 CPU나 램도 설정해야하고, 설정을 잘 살펴보면 ODD, 사운드 카드, 랜카드 같은 것도 설정을 할 수 있습니다. 가상 머신은 정말로 컴퓨터 안에 만들어진 컴퓨터입니다.
하지만 도커는 가상 머신을 만들지 않습니다. 단지 프로세스를 격리된 환경에 실행하는 걸 도와주고, 이렇게 만들어진 프로세스를 컨테이너라고 합니다. 그래서 컨테이너는 단지 프로세스일 뿐입니다.
컨테이너에는 다양한 프로세스 격리 기술이 사용됩니다. 프로세스 네임스페이스와, 권한과 네트워크도 모두 격리됩니다. 그리고 컨테이너가 인식하는 루트 디렉터리도 호스트의 루트가 아닌 다른 "위치"가 됩니다. chroot는 정확히 이 루트 디렉터리를 바꿔주는 역할을 합니다.
chroot 입문
chroot는 이름에서 유추해볼 수 있듯이 "change root (directory)"라는 의미를 가지고 있습니다. 여기서 루트는 사용자는 아니고 /
, 즉 시스템의 최상위 디렉터리를 의미합니다. 일반적인 프로세스는 이 루트 디렉터리를 기준으로 그 아래에 있는 디렉터리나 파일에 접근하는 게 가능합니다.
chroot를 사용하면 프로세스가 인식하는 루트 디렉터리를 변경해버립니다. 예를 들어 chroot에서 /tmp/chroot
를 루트 디렉터리로 지정하여 어떤 프로세스를 실행하면, 이 프로세스는 /tmp/chroot
를 /
(루트 디렉터리)로 인식합니다. 이 프로세스는 호스트의 /tmp/chroot
보다 디렉터리 구조 상에서 상위에 있는 디렉터리에 접근할 수 없습니다. 이 프로세스에게는 /tmp/chroot
가 루트이고 오직 이 아래의 파일들만 접근 가능합니다.
루트 디렉터리 격리가 어떤 의미인지 대충 감이 오시죠?
chroot를 사용하는 건 의외로 어렵습니다. 루트 디렉터리가 바뀌기 때문에 어떤 프로세스를 실행할 때 참조하는 파일들도 모두 이 디렉터리 아래에 준비해야하기 때문입니다. 실제로 사용하는 방법과 사용하는 과정에 생기는 문제는 튜토리얼을 진행하면서 살펴보도록 하겠습니다.
실습 환경 준비와 chroot 설치
우선 chroot를 사용하기 위한 실습 환경을 준비해야합니다.
실습 환경은 우분투 16.04입니다. 저는 디지털 오션Digital Ocean에서 드롭릿Droplet을 하나 만들어서 사용했습니다. 우분투가 설치된 가상 머신이나 혹은 실제 우분투가 설치된 서버나 데스크톱 모두 사용할 수 있습니다. (편의상 아래 튜토리얼에서는 root 사용자로 진행합니다.)
$ lsb_release -d
Description: Ubuntu 16.04.3 LTS
chroot는 coreutils 패키지에 포함되어있고 일반적으로는 설치되어 있습니다. chroot가 설치되어있는지 확인해봅니다.
$ chroot --version
chroot (GNU coreutils) 8.25
Copyright (C) 2016 Free Software Foundation, Inc.
...
chroot
명령어가 설치 되어있지 않으면 다음과 같이 에러가 납니다.
$ chroot
chroot: command not found
chroot가 설치되어있지 않은 경우 apt-get
으로 설치할 수 있습니다. coreutils 패키지를 설치합니다.
$ apt-get update
$ apt-get install coreutils
설치가 끝나면 다시 chroot --version
명령어로 설치가 되어있는지 확인해봅니다.
이제 실제로 chroot를 사용해서 프로세스의 루트 디렉터리를 변경해보겠습니다.
chroot 입문
chroot를 사용하는 기본적인 방법은 아주 간단합니다.
$ chroot <루트 디렉터리> <명령어>
그럼 디렉터리를 만들고, 그 아래에 셸을 복사하고 바로 사용해 보겠습니다. /tmp/root
를 만들고 이 디렉터리를 루트로 bash
를 실행해보고자 합니다. 이 디렉터리 아래에 bash
도 필요하므로 호스트의 bash
명령어도 복사합니다.
$ mkdir /tmp/root
$ mkdir /tmp/root/bin
$ cp -v /bin/bash /tmp/root/bin/
'/bin/bash' -> '/tmp/root/bin/bash'
ls
로 복사가 잘 되었는지 확인해봅니다.
$ cd /tmp/root
$ ls -R
.:
bin
./bin:
bash
그럼 바로 chroot
를 실행해봅니다. 첫 번째 인자는 루트 디렉터리로 사용할 디렉터리를 지정합니다. 두 번째 인자는 루트 디렉터리를 기준으로 실행할 명령어를 지정합니다. bash
는 /tmp/root/bin/bash
에 있으므로 /tmp/root
아래의 /bin/bash
에 있으므로 /bin/bash
를 지정해줍니다.
$ chroot /tmp/root/ /bin/bash
- [ ] chroot: failed to run command '/bin/bash': No such file or directory
에러가 발생합니다. No such file or directory
, 파일은 분명히 있는데?
bash가 의존하고 있는 라이브러리 파일들을 복사하고 실행하기
앞서 분명히 ls
로 /bin/bash
파일을 확인했지만, 파일이 없다는 에러가 발생을 합니다. 이 메시지는 조금 불분명하니, 게의치 않고 문제를 해결해보겠습니다. 분명히 파일이 없어서 발생하는 문제는 아닙니다. 이 문제가 발생하는 이유는 bash
를 실행하기 위한 라이브러리 파일이 /tmp/root
아래에 없기 때문입니다. 루트 디렉터리 아래에 어떤 프로세스를 실행시키기 위한 모든 파일이 준비되어 있어야합니다. 앞에서 이야기했지만, 바로 이러한 이유로 chroot
는 간단하지만 실제로 사용하기는 상당히 까다롭습니다.
ldd
를 사용해 bash
를 실행할 때 필요한 파일들을 찾아보겠습니다.
$ ldd /bin/bash
linux-vdso.so.1 => (0x00007fff86bf1000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f88b36b2000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f88b34ae000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f88b30e4000)
/lib64/ld-linux-x86-64.so.2 (0x00007f88b38db000)
이 파일들을 /tmp/root
아래에 같은 구조로 복사해줍니다.
$ mkdir /tmp/root/{lib,lib64}
$ cp /lib/x86_64-linux-gnu/libtinfo.so.5 \
/lib/x86_64-linux-gnu/libdl.so.2 \
/lib/x86_64-linux-gnu/libc.so.6 \
/tmp/root/lib
$ cp /lib64/ld-linux-x86-64.so.2 /tmp/root/lib64
그럼 다시 chroot
를 실행해봅니다.
$ chroot /tmp/root/ /bin/bash
bash-4.3#
프롬프트가 바뀌었습니다! bash
가 새로 실행된 것을 알 수 있습니다.
그럼 정말 루트가 바뀌었을까요? ls
를 한 번 실행해보겠습니다.
bash-4.3# ls
bash: ls: command not found
아... ls
가 없네요.
ls로 루트 디렉터리가 변경된 것을 확인하기
ls
도 같은 방식으로 실행 파일과 의존하고 있는 파일들을 복사를 해야합니다. exit
를 실행해 일단 chroot
로 실행한 bash
를 종료합니다. ls
를 복사합니다.
$ cp -v /bin/ls /tmp/root/bin/
$ ldd /bin/ls
linux-vdso.so.1 => (0x00007ffcc2cfe000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f3111a97000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f31116cd000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f311145d000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f3111259000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3111cb9000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f311103c000)
$ cp /lib/x86_64-linux-gnu/libselinux.so.1 \
/lib/x86_64-linux-gnu/libc.so.6 \
/lib/x86_64-linux-gnu/libpcre.so.3 \
/lib/x86_64-linux-gnu/libdl.so.2 \
/lib/x86_64-linux-gnu/libpthread.so.0 \
/tmp/root/lib
$ cp /lib64/ld-linux-x86-64.so.2 /tmp/root/lib64
이제 다시 chroot
로 bash
를 실행하고 ls
를 실행해봅니다.
$ chroot /tmp/root/ /bin/bash
$ ls -l /
total 12
drwxr-xr-x 2 0 0 4096 Jan 18 13:45 bin
drwxr-xr-x 2 0 0 4096 Jan 18 13:44 lib
drwxr-xr-x 2 0 0 4096 Jan 18 13:27 lib64
이제 ls
가 잘 실행 됩니다. 루트 디렉터리가 /tmp/root
인 것을 알 수 있습니다. 루트에서 cd ..
로 호스트의 디렉터리에 접근을 시도해봅니다.
bash-4.3# cd /
bash-4.3# pwd
/
bash-4.3# cd ..
bash-4.3# pwd
/
bash-4.3# ls
bin lib lib64
최상위 디렉터리(호스트 기준/tmp/root
)에서 더 이상 위로 올라갈 수 없는 것을 알 수 있습니다.
여기까지 프로세스의 루트(실행 위치)가 성공적으로 격리되었습니다!
호스트에서는?
호스트에서는 이 bash
프로세스가 어떻게 보일까요? 먼저 chroot
의 bash
에서 현재 프로세스의 프로세스ID를 확인해보겠습니다.
bash-4.3# echo $$
13251
$$
는 bash
의 프로세스ID를 담은 특수한 환경변수입니다. 호스트에서 이 프로세스를 찾아보겠습니다.
터미널을 하나 더 띄워 호스트에 접속합니다. ps
명령어로 이 프로세스를 찾아보겠습니다.
$ ps aux | grep 13251
root 13251 0.0 0.2 9680 2960 pts/1 S+ 13:45 0:00 /bin/bash
호스트에서는 다른 프로세스들과 마찬가지로 호스트의 프로세스로 보이는 것을 알 수 있습니다.
여기까지 chroot
기본적인 사용법을 알아보았습니다.
마치며
chroot를 실제로 사용할 일은 별로 없긴 합니다. 하지만 처음에 이야기했듯이 컨테이너 가상화에서 사용하는 기본적인 프로세스 격리 방법 중 하나이므로 익혀두시면 도움이 많이 될 것입니다. chroot를 써보고 도커 컨테이너를 사용한다면 기술적으로 거의 차이가 없다는 것을 바로 이해할 수 있습니다.
오늘 이야기는 여기서 마치고, 또 다른 컨테이너 이야기로 다시 돌아오겠습니다 ;)
최근에 공개한 글 목록입니다.
- <나의 글쓰기> 노트 애플리케이션 베어(Bear): 1편 수려한 디자인과 독보적인 마크다운 에디터
- <스팀잇 생존기> 보팅봇은 정말 생활에 보탬이 될까?
- <투자가의 공구상자> 월 스트리트 저널 쿼츠(WSJ Quotes)에서 주가수익비율(PER) 시계열 차트로 보기
- <소식> 리디북스, 투자/재태크 서적 무료 대여 이벤트 2탄
- <투자가의 공구상자> 코스피와 코스닥의 시장 주가수익비율(PER)
글쓰고, 프로그래밍하고, 투자하는 @mishana입니다.
웹사이트 | 트위터 | RSS | Feedly에서 구독
- 이 글이 도움이 되셨다면 리스팀, 팔로우 부탁드려요 :)
Cheer Up!
스스로 홍보하는 프로젝트에서 나왔습니다.
오늘도 좋은글 잘 읽었습니다.
오늘도 화이팅입니다.!
짱짱맨도 외칩니다! 가즈아!!!
날씨가 다시 추워진거같아요
따뜻하게!! 봄날씨로 가즈아!!!
오늘도 감사합니다 ;)
아..
하도 Docker docker 하길래 어떤건지 궁금했는데..
Linux에서 이런식으로 격리가능할거란 생각은 안해봤는데. 신기하네요.🤗
좋은글 감사합니다!😀
컨테이너 흥미로운 주제죠 ㅎㅎ. 이 기세로 조만간 도커까지 다뤄보겠습니다 :)