Chapter 3. Docker의 심해 속으로.

안녕하세요, 지난 챕터에서 컨테이너의 정의와 Docker에 대해서 간략하게 다뤄보았는데
요번에는 Docker에 대해 조금 더 Detail 하게 들여다 보려고 합니다.
01. Container 격리 기술
Docker container를 띄워놓고 안의 구조를 들여다 보았습니다.
- 여기서 'bash' 명령어는 linux 안으로 들어간다는 의미입니다. (보통 linux의 Shell을 bash shell 이라고 하죠?!)
- 즉, 컨테이너를 실행 시킨 후 바로 접근한다는 의미.
docker run -it --rm --name=ssunghwan ubuntu:14.04 /bin/bash
container 내부에 들어온 후에 'ls' 명령어를 쳤을 때 아래와 같이 출력이 된다.

우리가 흔히 아는 linux system의 디렉토리 구조와 굉장히 유사하다.
또한 자세히 보시면 루트 경로로 바로 접근이 된 것을 확인할 수 있다.
최상위 경로에 linux system과 유사한 디렉토리 구조 → LXC 기술중 하나인 chroot (change root directory).
이 의미는 독립적인 파일 시스템 즉, 독립성을 보장받는다는 의미이다!
추가적으로 hostname에서의 '6ab18376a90f'의 의미는 눈치 채셨다 싶이
우리가 cli로 container를 생성할때 container ID가 생기는데, 그 container ID가 hostname이 된다.
이번에는 'ps -ef' 명령을 통해서 프로세스를 한번 출력해보자.

PID 1은 시스템 부팅 시 가장 먼저 실행되는 프로세스이며, 컨테이너 내부에서는 PID 1이 메인 프로세스 역할!
- 즉, Container는 하나의 프로세스를 중심으로 동작하는 경량 가상환경
- PID 1이 /bin/bash인 이유는, docker run으로 container 생성 시 bash로 실행하였기 때문이다.
추가적으로 네트워크를 담당하는 'if config' 명령을 통해서 라우팅 정보를 출력해보자.

Docker는 Container마다 독립된 네트워크 스택을 제공하며, eth0 interface와 host의 docker0 브리지와 연결.
- container eth0 (172.17.0.2) → host의 docker0 bridge (172.17.0.1) → NAT를 통해 외부와 통신.
- 즉, 컨테이너는 독립된 IP를 가지지만 실제로는 호스트와 커널을 공유한다!!
실제로 터미널을 하나 띄워서 Host의 라우팅 정보를 확인해보면 docker0의 대역과 일치한다.

📌 요약을 해보자.
위 내용처럼 Docker는 Container를 독립적으로 격리하기 위해 여러 Linux Namespace를 사용한다.
- 프로세스의 루트 디렉토리를 격리 (가상의 루트 디렉토리 생성) : chroot
- container ID가 hostname으로 부여 : UTS Namespace (hostname과 domain 격리)
- container는 독립된 프로세스 (PID 1로 시작) : PID Namespace
- container마다 독립된 네트워크 : Network Namespace
02. Docker Container Lifecycle
1. docker container는 'docker create' 명령을 통해 image의 snapshot으로 /var/lib/docker 영역에 생성된다.
docker create -it --name ssunghwan ubuntu:14.04 /bin/bash
아직 ubuntu:14.04 image를 통해 container를 생성만 했을뿐, 실행되지는 않는다.
/var/lib/docker 영역 어디에 저장이 되는지 확인해보자.

현재 UpperDir에서 확인한 경로에 컨테이너의 writable layer 스냅샷이 생성된 것이며,
이 쓰기가 가능한 동적 컨테이너를 실행시키기 위해 아래와 같이 'docker start' 명령을 실행하자!
2. docker start 명령은 읽고 쓰기가 가능한 Process 영역인 container layer를 생성하여 동적 컨테이너를 구성한다.
반대로, 'docker stop' 명령은 생성된 container를 중지시킨다.


생성된 컨테이너를 중지 시킨다고 해도, writable layer의 스냅샷 등 모든 layer의 스냅샷은 유지된다.
(컨테이너를 다시 재실행할 수 있어야 되기 때문에)
3. 'docker rm' 명령은 생성된 snapshot를 삭제하며, 이를 통해 docker lifecycle을 알 수 있다.
(컨테이너 메타데이터 + 컨테이너 writable lyaer이 삭제된다)

- 아까 존재하던 /containers 디렉토리에 container ID를 가지고 있던 메타데이터가 없어짐
- /overlay2 디렉토리에 존재하던 writable layer 스냅샷이 삭제됨.
📌 요약을 해보자.
Container 메타데이터는 '/containers' 에 위치한다.
- Docker는 컨테이너의 상태,설정,로그,네트워크 정보를 별도로 관리해야 한다.
- 그래서 '/var/lib/docker/containers/<container-id> 아래에 여러 파일로 관리된다.
- config.json , hostconfig.json , log파일 , hosts, resolv.conf 등등.
Image 레이어와 container writable layer는 '/overlay2'에 위치한다.
- OverlayFS는 파일시스템 레이어를 합성하는 커널 기능이다.
- 이미지 레이어는 불변이고, 컨테이너 writable layer는 변경 가능하다 (읽고, 쓰기 가능한 동적 레이어)
- 이 둘은 OverlayFS 규칙에 따라 'diff/', 'lower', 'work/' 구조를 가지게 된다.
- diff/ : 해당 레이어의 실제 파일
- lower : 하위 레이어 목록 (텍스트 형태로 저장된다)
- work/ : 커널 작업 디렉터리
즉, Docker는 위 구조를 그대로 사용하며 모든 Layer(image + writable)는 /overlay2에 저장된다.