본 글은 https://qiita.com/zembutsu/items/24558f9d0d254e33088f 의 번역본 이며, 글 내용에 대한 권리는 원작자에게 있습니다.

3. hello-world 이미지를 상세하게 조사한다.
다운로드한 hello-world:latest 이미지를 확인합니다. 로컬에 다운로드완료한 이미지를 확인하려면 먼저 docker images를 실행합니다.
1 | $ docker images |
이러한 이미지의 정보가 표시 됩니다.
- repository... 리포지토리의 이름입니다. 여기서는 hello-world 입니다. (리포지토리이름이 사실상의 이미지명이라 생각해도 상관은 없습니다만, 정확히는 창고같은 보관장소로써의 리포지토리가 있어, 그 안에 [이미지명:태그] 이라는 인식표(라벨)의 정체성을 가진 씰이 붙여져 있는 단보루상자(역자 - 이사짐 등 큰거에 쓰이는 종이 골판지 상자) 있는것처럼 상상해 주세요.)
- tag... 이미지에 붙어 있는 태그 입니다. 여기서는 latest 입니다.
- imge id... 이미지가 갖고있는 고유이미지 아이디(64자릿수) 입니다. 여기서는 짧은 아이디(12자리수) 정보가 나오고 있습니다.
- created... 그 이미지가 언제 작성되었는지 입니다. 5months ago 라고 되어 있는걸 봐서 5개월 전입니다.
- size... 이 이미지의 실체로써 디스크위에 소비하고 있는 용량 입니다. 13.3kb를 사용하고 있습니다.
다음으로 docker inspect hello-wrold:latest을 실행하고, 이 이미지의 상세정보를 보겠습니다.
1 | $ docker inspect hello-world:latest |
여기서는 이하의 것들을 알 수 있습니다.
- id... 이 이미지의 id(64문자) 입니다.
- RepoTags... 이 이미지에 나눠 펼쳐진 태그가 hello-world:latest라고 알 수 있습니다.
- RepoDigests... 이 이미지내용에 대하여 해쉬식(해쉬코드) 입니다. 태그는 바뀌지 않습니다만, 이 식은 내용이 변경되지 않는 한 바뀌지 않습니다.
- Parent 부모 이미지의 정보 입니다. 빈 큰따옴표("") 의 기술은 의존관계를 가진 부모 이미지가 없습니다. 그 말은 이 hello-worle:latest 이미지는, 이 하나의 이미지 · 레이어에 의해 구성되어 있습니다.
화면을 좀 더 스크롤하면 "cmd"섹션이 보입니다. 이건 컨테이너 실행시 인수(매개변수)가 없으면 컨테이너 안에서 어떤 커맨드를 실행할지 지정합니다.
이 CMD["/hello"] 라고 적는 기술로써, 이 컨테이너를 실행하면 컨테이너 안의 path "/hello"를 실행하는걸 알 수 있습니다.
(덧붙여, "cmd"를 포함한 "ContainerConfig" 섹션은 컨테이너의 내용을 이미지로 commit할 때의 정보입니다. "cmd"섹션에 "/bin/sh"의 기술이있습니다만. 어디까지나 이미지의 커밋 (작성시)의 내부적인 기록일 뿐이며, CMD 명령으로 "/bin/sh"을 실행하는의도는 아닙니다.
참고1 :: https://github.com/moby/moby/blob/9842c7a741ee480c71bfd8e71e1f22893d010411/image/image.go#L32
참고2 :: https://stackoverrun.com/ja/q/9984570
화면을 거의 끝까지 스크롤하면, 다음과 같은 섹션이 보입니다.
1 | "Cmd": [ |
UpperDir 이라 적혀져 있는 path가, 이 도커를 실행하고 있는 호스트 상에, hello-wrold 이미지의 실체를 보존하고 있는 디렉토리 입니다. 이 화면상에는 94f... 로 시작하는 문자열 입니다만, 환경에 따라 랜덤한 문자열로 바꾸어 나타납니다.
그러면, 컨테이너 안을 ls -l <디렉토리명>의 콘테이너로 조사해 봅시다. 디렉토리명은 환경에 따라 서로 다르기 때문에 주의 부탁 드립니다. 하나 덧붙이자면 커맨드의 실행에는 root 권한이 필요합니다. 환경에 따라서는 sudo ls -l... 을 실행해 주세요.
1 | # ls -al /var/lib/docker/overlay2/94f82ed22188e11a7f2a75b015929aea7c3eaa5e170c9ca19c966bf978147f19/diff |
hello라는 이름의 파일이 보입니다. 이로부터 hello-world:latest 이미지의 파일시스템은, hello 라는 바이너리일 뿐이라는걸 알 수 있습니다.
(덧붙여서 이번 예제에선 하나의 파일만 있습니다만, 예를 들어 ubuntu 나 centos 등의 Linux 배포판(디스트리뷰션)의 이미지를 다운로드 하면 각 이미지용의 디렉토리 안에는 "./bin", "./sbin", "./var" 등의 각 배포판(디스트리뷰션)용의 "/" 이하 파일시스템이 전개 되어 있습니다. 그리고, 그걸로부터 도커 컨테이너를 실행하면, 호스트 상의 컨테이너 안에 서로 다른 리눅스 배포판(디스트리뷰션)이 동작 하고 있는 듯하게 "보이기"는 합니다만, 실제는 호스트 상의 리눅스 커널 상에서 도커는 지정한 도커 이미지의 배포판(디스트리뷰션), 예를 들면 centos 라고 하자면 centos의 파일시스템을 마운트하고 디폴트로 그 안에 포함 되어 있는 "bin/bash"을 PID 1개로 하는 이름공간(역자 - 네임스페이스)안에
실행하고 있습니다. 컨테이너 실행시, 하나의 리눅스 상에서 복수의 리눅스가 움직이고 있는 건 아닙니다)
<역자 설명>
OS별로 따로 마치 여러 컨테이너를 돌리고 있는 것처럼 보이지만. 여러 OS를 한번에 돌리는 것이 아닌, 하나의 OS에서 미리 세팅한 환경변수 등을 이용해 가상 으로 돌리고 있는 것 입니다.
이번에 실행한 hello-world는 레이어가 하나바께 없기 때문에 호스트상에서 하나의 디렉토리 안에서 hello-world 도커 이미지의 내용물을 전부 포함합니다. 그러기 위해 복수의 이미지레이어로 구성한 도커 이미지가 있다면 호스트 상에 복수의 디렉토리가 존재합니다.
더욱이, 이미지는 메타정보를 가지고 포함합니다. hello-world 로는 CMD 명령으로 /hello를 실행하는 명령이 있었습니다. 이 메타정보에도 이미지·레이어가 필요합니다. (하나 덧붙여, 메타정보는 개념으로써 이미지·레이어 이며 호스트상에서 실체로서 파일이나 디렉토리는 없습니다.)
이렇게 해서 도커 엔진은 도커의 이미지·레이어를 추상적인 도커 이미라는 단위로 취급하는 듯한 모습을 가지고 있습니다. 도커는 콘텐츠 실행시 모스트 상에선 여기저기 분산되어 있는 파일이나 디렉토리를 하나의 파일시스템으로 통합하여 조작가능 하게 해두고 있습니다.
상기 내용으로부터 도커 이미지는 호스트상에 하나의 실체로써 파일이 존재하지 않는다든걸 알 수 있습니다.

자, 이 hello를 컨테이너가 아니라 직접 실행 해보겠습니다. full path로 "/var/lib/docker/overlay2/<디렉토리명>/diff/hello" 를 실행합니다. ※이 path는 나중 단계에서 쓰이기때문에 에디터 등에 대기시켜 두겠습니다.
1 | # /var/lib/docker/overlay2/94f82ed22188e11a7f2a75b015929aea7c3eaa5e170c9ca19c966bf978147f19/diff/hello |
실행하면 "Hello from Docker!"에계속하여 문자열이 표시됩니다. 이건 소스코드 hello.c 에 적혀 있는 문자열 입니다.
상기 내용으로부터, hello-world:latest 이미지를 조사하면, 이 hello 라고 하는 바이너리를 실행하는 걸 알 수 있습니다. 그리고, 이 바이너리는 amd64/x86 지향 컴파일이 되어 있으므로 리눅스 상에서 그대로 실행할 수 있다는걸 확인 했습니다.
(덧붙여, CPU amd64/86 용 컴파일한 바이너리는 실행 할수 있습니다만. 다른 CPU 아키텍쳐 지향 바이너리는 amd64/86 상에서는 실행 할 수 없습니다. 예를 들어 Raspberry Pi는 ARM 이라고 하는 아키텍쳐라서 이 hello 바이너리는 Raspberry Pi 에서 그대로는 작동하지 않습니다. 바이너리로써 실행할수 없는 이상, 가짜로 도커 이미지에 넣었다 하더래도 이 다음 섹션에서 설명하는 도커 컨테이너로써 실행할 수 없습니다. 도커는 하드웨어의 애뮬레이션을 하지 않으며, 하드웨어를 가상화하는 기술 또한 아닙니다.)

덧글