출처 : https://tech.kakaoenterprise.com/154 [카카오엔터프라이즈 기술블로그 Tech&(테크앤):티스토리]
[컨테이너 인터널 #1] 컨테이너 톺아보기
시작하며 안녕하세요. 카카오엔터프라이즈에서 검색 서비스를 개발하고 있는 검색클라우드기술파트의 Sam(김삼영)입니다. 지난 글 서비스 개발자를 위한 컨테이너 뽀개기 (a.k.a 컨테이너 인터널
tech.kakaoenterprise.com
(전체적인 글 및 실습은 위 주소를 많이 참고 하였으며 더 자세한 글은 위 주소에서 직접 읽어보시길 강력히 추천합니다!)
chroot

위 사진은 컨테이너가 발전해온 기록들입니다. 그 중 제일 맨 처음으로 거슬러 올라가면 chroot가 있는 걸 보실 수 있습니다.
chroot(Change Root directory)는 프로세스의 루트 디렉토리를 변경하는 리눅스 시스템 콜/ 명령어 입니다.
특정 디렉토리를 루트 디렉토리로 지정이 가능하다? -> 루트 디렉토리 위로는 못 나가기 때문에 해당 경로에 프로세스를 가둘 수 있다?
chroot에 갇힌 프로세스는 현재 디렉터리를 루트로 인지하여 작동하기에 프로세스를 실행할 때 필요한 커맨드 프로그램, 라이브러리, 설정 등을 chroot로 지정할 경로에 함께 넣어 주어야 합니다.
그럼 이 chroot를 사용해 리눅스에서 프로세스를 격리하는 기본적인 방법을 직접 경험해보아서 체득해보겠습니다!
chroot로 bash 실행하기
# 실습 경로로 이동해 주세요
root@kakao-techbootcamp-eddy:/# mkdir template
root@kakao-techbootcamp-eddy:/# cd template
# 루트로 사용할 디렉터리를 만듭니다.
root@kakao-techbootcamp-eddy:/template# mkdir new-root
# chroot로 new-root를 루트 디렉터리로 지정하여 /bin/bash를 실행합니다.
root@kakao-techbootcamp-eddy:/template# chroot new-root /bin/bash
chroot: failed to run command ‘/bin/bash’: No such file or directory
실행 시 에러 메시지가 출력됩니다. chroot에서 지정한 루트 디렉터리를 기준으로 "커맨드"(/bin/bash)를 찾기 때문에 (인자로 넘기는) "커맨드"가 new-root 밑에 있어야 합니다. 또한 /bin/bash에서 사용하는 의존성 라이브러리들을 확인해서 해당 경로에 복사해주어야 합니다!
# bash 커맨드의 위치를 확인한 후
root@kakao-techbootcamp-eddy:/template# which bash
/usr/bin/bash
# 동일한 경로를 만들고 복사해 줍니다.
root@kakao-techbootcamp-eddy:/template# mkdir -p new-root/usr/bin
root@kakao-techbootcamp-eddy:/template# cp /bin/bash new-root/usr/bin
# chroot를 실행해 보세요
root@kakao-techbootcamp-eddy:/template# chroot new-root /bin/bash
chroot: failed to run command ‘/bin/bash’: No such file or directory
# /bin/bash 의존성 라이브러리를 확인합니다.
root@kakao-techbootcamp-eddy:/template# ldd /bin/bash
linux-vdso.so.1 (0x0000e5e8a6e1b000)
libtinfo.so.6 => /lib/aarch64-linux-gnu/libtinfo.so.6 (0x0000e5e8a6bf0000)
libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000e5e8a6a30000)
/lib/ld-linux-aarch64.so.1 (0x0000e5e8a6dde000)
# 의존성 라이브러리들을 복사할 디렉터리를 만듭니다
root@kakao-techbootcamp-eddy:/template# mkdir -p new-root/{lib/aarch64-linux-gnu,lib}
root@kakao-techbootcamp-eddy:/template# tree new-root
new-root
├── lib
│ └── aarch64-linux-gnu
└── usr
└── bin
└── bash
# 의존성 라이브러리들을 new-root 디렉터리로 복사합니다. (vdso 파일은 제외)
root@kakao-techbootcamp-eddy:/template# cp /lib/aarch64-linux-gnu/{libtinfo.so.6,libc.so.6} new-root/lib/aarch64-linux-gnu
root@kakao-techbootcamp-eddy:/template# cp /lib/ld-linux-aarch64.so.1 new-root/lib
# 의존성 라이브러리들이 잘 복사됐는지 확인해보세요
root@kakao-techbootcamp-eddy:/template# tree new-root
new-root
├── lib
│ ├── aarch64-linux-gnu
│ │ ├── libc.so.6
│ │ └── libtinfo.so.6
│ └── ld-linux-aarch64.so.1
└── usr
└── bin
└── bash
# chroot를 실행합니다.
root@kakao-techbootcamp-eddy:/template# chroot new-root /usr/bin/bash
bash-5.2#
이렇게하면 chroot로 new-root를 지정하여 /bin/bash를 실행시키게 된 것입니다!
bash-5.2# ls
bash: ls: command not found
하지만 아직 ls 커맨드 관련 작업을 해주지 않아서 ls 커맨드가 작동하지 않습니다. 그렇다면 앞에서 /bin/bash 프로그램을 복사해온 것 처럼 ls 관련 라이브러리들을 복사해오면 되지 않을까요?
chroot한 Bash 셸에서 ls 해보기
그러면 이번에도 ls 커맨드의 의존성 라이브러리들을 확인해보겠습니다.
root@kakao-techbootcamp-eddy:/template# which ls
/usr/bin/ls
root@kakao-techbootcamp-eddy:/template# ldd /usr/bin/ls
linux-vdso.so.1 (0x0000e1aeae59a000)
libselinux.so.1 => /lib/aarch64-linux-gnu/libselinux.so.1 (0x0000e1aeae4d0000)
libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000e1aeae310000)
/lib/ld-linux-aarch64.so.1 (0x0000e1aeae55d000)
libpcre2-8.so.0 => /lib/aarch64-linux-gnu/libpcre2-8.so.0 (0x0000e1aeae260000)
위에서 진행했던것처럼 ls 복사도 진행하고 chroot를 실행시킵니다.
# /bin/ls를 복사합니다.
root@kakao-techbootcamp-eddy:/template# cp /usr/bin/ls new-root/bin
# ls 의존성 라이브러리를 복사합니다.
root@kakao-techbootcamp-eddy:/template# cp /lib/aarch64-linux-gnu/{libselinux.so.1,libc.so.6,libpcre2-8.so.0} new-root/lib/aarch64-linux-gnu
root@kakao-techbootcamp-eddy:/template# cp /lib/ld-linux-aarch64.so.1 new-root/lib
# chroot를 실행합니다.
root@kakao-techbootcamp-eddy:/template# chroot new-root /usr/bin/bash
bash-5.2# ls
bin lib usr
# 실제 환경의 ls /
root@kakao-techbootcamp-eddy:/template# ls /
bin cdrom etc lib media proc sbin srv template var
bin.usr-is-merged data home lib.usr-is-merged mnt root sbin.usr-is-merged swap.img tmp
boot dev host lost+found opt run snap sys usr
이로써 실제 환경의 ls, chroot를 통해 실행한 컨테이너 환경의 ls의 결과가 확연히 다르단 것을 알 수 있습니다.
그럼 chroot한 컨테이너 환경에서 루트 디렉토리 밖으로 벗어날 수 있는지 체크해보겠습니다.
# 루트 조회
bash-5.2# cd /
bash-5.2# ls
bin lib usr
# 루트 탈출 시도 및 확인
bash-5.2# cd ../../../../
bash-5.2# ls
bin lib usr
이처럼 사용자에게 제공하고 싶은 프로그램을 한 곳에 모으고, 사용자 프로세스가 활동할 수 있는 경로를 제한해서 실행한 것이 컨테이너의 초창기 모습입니다.
그런데 지금과 같이 일일히 필요한 라이브러리들을 직접 복사해오는 이 행동 자체가 컨테이너가 필요할 때마다 매번 이래야 한다면 매우 불편하고 손이 많이 갑니다. 그러면 우리가 컨테이너하면 자동으로 따라오는 그 친구, 바로 이미지(Image)가 떠오를겁니다. 비유를 하자면 지금 집(컨테이너)을 만들었는데 안이 텅 비어있는 집인 겁니다. 그러면 이삿짐(이미지)을 가져와서 집 안을 채워야 겠죠?
이미지를 통해 chroot 하기
Bash, Is로 chroot 사용하기에서는 사용할 프로그램들(bash, ls)을 복사하여 chroot로 실행해 보았다면, 이미지로 chroot 사용하기에서는 누군가 만들어 놓은 이미지(nginx)를 가져다가 실행해 보도록 하겠습니다.
# nginx-root 디렉터리를 만듭니다.
root@kakao-techbootcamp-eddy:/template# mkdir nginx-root
# 도커를 이용하여 nginx 이미지를 nginx-root에 압축을 풀어줍니다.
root@kakao-techbootcamp-eddy:/template# docker export $(docker create nginx:latest) | tar -C nginx-root -xvf -
## (출력 생략)
# nginx-root 경로를 한번 살펴보세요
root@kakao-techbootcamp-eddy:/template# tree -L 1 nginx-root
nginx-root
├── bin -> usr/bin
├── boot
├── dev
├── docker-entrypoint.d
├── docker-entrypoint.sh
├── etc
├── home
├── lib -> usr/lib
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin -> usr/sbin
├── srv
├── sys
├── tmp
├── usr
└── var
# chroot로 셸을 실행해 보세요
root@kakao-techbootcamp-eddy:/template# chroot nginx-root /bin/sh
# ls /
bin dev docker-entrypoint.sh home media opt root sbin sys usr
boot docker-entrypoint.d etc lib mnt proc run srv tmp var
#
이제 nginx를 chroot로 만든 컨테이너에서 실행시켜 봅니다!
# nginx를 실행합니다.
# nginx -g "daemon off;"
root@kakao-techbootcamp-eddy:/home/eddy# curl http://localhost:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
root@kakao-techbootcamp-eddy:/home/eddy#
다음 글에서는 컨테이너 구현 시 chroot의 한계 부터 네임스페이스들에 관하여 정리해보겠습니다 감사합니다!
'DevOps > Docker' 카테고리의 다른 글
| Container 파일시스템 (1) | 2024.09.18 |
|---|---|
| Docker Image 상세 구조 (2) | 2024.09.15 |
| Docker Compose (4) | 2024.02.06 |
| 컨테이너 교차 통신, Docker로 다중 어플리케이션 구성하기 (1) | 2024.02.06 |
| Docker 이미지와 컨테이너 내부의 데이터 관리 방법 (2) | 2024.02.06 |