리그캣의 개발놀이터

docker image directory 분석해보기 본문

인프라/Docker

docker image directory 분석해보기

리그캣 2021. 7. 30. 00:16

부끄럽지만 회사 이직 후 사내 적응기간을 핑계로 제대로 된 공부를 하지 못하였다.(1년이 다되가지만..;)
하나씩 공부해보고 기록해보고자 한다.

오늘은 docker image directory를 분석해보자


os : centos7 

Docker Engine - Community
 Engine:
  Version:          20.10.5

 

먼저 docker home 의 위치는 하기와 같다.

/var/lib/docker

 

해당 위치는 하기의 명령어로 확인이 가능하다. (docker home path 확인하기)

$ docker info | grep "Docker Root Dir"
> Docker Root Dir: /var/lib/docker

systemctl 등의 systemd를 관리하는 툴을 이용하면 loaded되는 service 설정에 대한 path를 가져올 수 있는데 

여기서 home path 변경이 가능하다. (추 후에 systemctl 과 systemd에 대해서도 공부해 보면 좋을것같다.)
하기에서는 /usr/lib/systemd/system/docker.service로 확인이 가능하다.

# systemctl status docker.service
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2021-04-27 16:16:36 KST; 3 months 1 days ago
     Docs: https://docs.docker.com
 Main PID: 1258 (dockerd)
    Tasks: 15
   Memory: 496.6M
   CGroup: /system.slice/docker.service
           └─1258 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/cont...

docker home path를 변경할 것이 아니기에 일단 해당 path로 들어가 어떤 구조인지 확인해보자

# ls
buildkit    image    overlay2  runtimes  tmp    volumes
containers  network  plugins   swarm     trust

container 운용을 위한 파일들이 있는것을 확인할 수 있다. 이때 log파일은 containers 폴더 안에 있다.

오늘 파악해볼 것은 image directory이기에 해당 directory를 확인해보자.
overlay2라는 directory가 있는것을 확인할 수 있었다.

# ls image/
overlay2

docker info라는 명령어를 사용해서 현재 환경에서 사용하는 docker에 대한 정보를 확인이 가능한데 Storage와 일치하는 것을 볼 수 있다. (Storage Driver : overlay2)

# docker info
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  app: Docker App (Docker Inc., v0.9.1-beta3)
....

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 37
 Server Version: 20.10.5
 Storage Driver: overlay2
....

그렇다면 이 overlay2란 무엇일까? overlay2는 레이어 파일 시스템이라고 한다.

docker docs를 보면 overlay2는 Linux 배포판에 대해서 선호되는 스토리지 드라이버라고 한다. 

Container의 Storage를 제한하기 위해서는 Docker Engine 자체의 기능을 이용하지 않고 Storage Driver의 도움이 필요한다고 한다.

이는 Container가 Storage Driver의 파일 시스템을 기반으로 동작해서 그런다는데. 이때 사용하는 파일 시스템이 Overlay2로 보인다.

 

예를 들어 AUFS를 이용하는 Container와 Devicemapper를 이용하는 Container가 있다고 해보면,
AUFS의 경우엔 Container가 /var/lib/docker/aufs에 존재하고 Devicemapper의 경우엔 Container가 /var/lib/docker/devicemapper에 존재하게 된다.

A라는 Storage Driver를 기반으로 생성한 Container가 있을때, B라는 Storage Driver로 바꾸게 되면 
각 Container는 서로 다른 파일 시스템을 기반으로 하므로 각 Container들이 사용하는 파일 시스템과 다른 환경이라면 동작하지 않는다고 한다.(https://bigpel66.oopy.io/library/docker/docker/4)

 

나의 환경의 경우 overlay2 파일 시스템을 사용하기 때문에 /var/lib/docker/overlay2가 존재하는 것 같다.

이 부분은 확인해봐야하는데 그렇기에 image에 대한 정보 또한 /var/lib/docker/image/overlay2에 존재하나? 조심스럽게 유추해본다.

 

기회가 된다면, 각각의 Storage Driver의 특성등을 공부해봐야겠다.

 

overlay2 directory 안에는 다음과 같은 directory가 존재한다.

# ls -al
total 8
drwx------ 5 root root   81 Jul 11 22:22 .
drwx------ 3 root root   22 Mar 25 09:37 ..
drwx------ 4 root root   58 Mar 25 10:00 distribution
drwx------ 4 root root   37 Mar 25 09:37 imagedb
drwx------ 5 root root   45 Mar 25 10:00 layerdb
-rw------- 1 root root 4438 Jul 11 22:22 repositories.json

docker image 관리 기본 체계는 Layer 방식으로 이미지를 관리한다.

이부분에 대해서는 자세히 소개한 글이 있다.(https://eqfwcev123.github.io/2020/01/30/%EB%8F%84%EC%BB%A4/docker-image-layer/) 해당 내용은 추후에 학습해봐야겠다.
위의 정보를 보면 

distribution - layer 해시 값과 diff id간의 대응정보를 저장한다.
imagedb - 다운로드 한 이미지 정보를 저장

layerdb - 여러개의 레이어로 구성된 실질적인 이미지 정보는 레이어가 가지고 있다. 이미지의 정확한 정보를 위해서는 layerdb를 확인하면 된다.

repositories.json - image id 에 해당 하는 해시값의 정보를 저장한다. 

 

repositories.json을 출력하니 다운받은 image에 대한 정보를 확인할 수 있었다.
이전에 grafana에 대한 image를 다운받은적이 있어서 해당 image에 대한 해시값을 가지고 있는것으로 보인다.

# jq . repositories.json
{
  "Repositories": {
    "grafana/grafana": {
      "grafana/grafana:6.5.0": "sha256:15186a7d4aeda54a4e3c6b1cafbd619a0e1e7a0ec259c063b819ccd6ddad2708",
      "grafana/grafana@sha256:d73accd1f60661e7143c387a138ae5e25e854c57ea7063d2a1c5e5e5ec1d34c4": "sha256:15186a7d4aeda54a4e3c6b1cafbd619a0e1e7a0ec259c063b819ccd6ddad2708"
    }
....
}

tree 명령어를 통해서 2단계까지의 구조를 가져와 보았다.

# tree -L 2 -N
.
├── distribution
│   ├── diffid-by-digest
│   └── v2metadata-by-diffid
├── imagedb
│   ├── content
│   └── metadata
├── layerdb
│   ├── mounts
│   ├── sha256
│   └── tmp
└── repositories.json

 

layerdb에 대해서 살펴보자면 docker pull 명령어를 다음과 같이 실행시 

# docker pull nginx:latest
latest: Pulling from library/nginx
33847f680f63: Pull complete
dbb907d5159d: Pull complete
8a268f30c42a: Pull complete
b10cf527a02d: Pull complete
c90b090c213b: Pull complete
1f41b2f2bf94: Pull complete
Digest: sha256:8f335768880da6baf72b70c701002b45f4932acae8d574dedfddaf967fc3ac90
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

위와 같은 33847f680f63 , dbb907d5159d 등의 값을 확인할 수 있다.

 

하기와 같은 명령어를 확인하면 해시 값을 출력하게 되는데 (해시 함수는 같은 입력에 대해서는 항상 같은 출력을 나오게 한다.),  위의 33847f680f63, dbb907d5159d ... 등과 하나도 일치 하지 않는것을 확인할 수 있다. grep을 통해서 잡아보아도 잡히지 않았다. 
이미지 ID가 한가지가 아니기 때문에 발생하는 문제라고한다. 이미지를 풀할 때 출력되는 해시 값은 원격 도커 레지스트리(ex. Docker Hub)에서 관리하는 고유아이디로. image를 pull하고 다운로드된 layer에 id는 내 서버에서는 변경되어서 저장되는것 같다.

# ls /var/lib/docker/image/overlay2/layerdb/sha256
0132aeca1bc9ac49d397635d34675915693a8727b103639ddee3cc5438e0f60a
038ca5b801cea48e9f40f6ffb4cda61a2fe0b6b0f378a7434a0d39d2575a4082
0681459bc7b0170312570c1dc4deb2cacc793e2851d704692e0ba9bac5a82812
...

docker image inspect 명령어로 방금 다운받은 nginx:latest의  layer list를 확인해보자.
위에서 pull받을때 6줄의 해시값이 출력된것을 볼 수 있는데 하기도 6줄의 해시값으로 된 layer를 확인할 수 있다.

# docker image inspect nginx:latest | jq '.[].RootFS'
{
  "Type": "layers",
  "Layers": [
    "sha256:814bff7343242acfd20a2c841e041dd57c50f0cf844d4abd2329f78b992197f4",
    "sha256:7c0b223167b96d7deaacf1e1d2d35892166645b09b17bcc8675a4d882ef84893",
    "sha256:59b01b87c9e7f668b740d23eb872c5964636c33aef795f1186f08b172197bc35",
    "sha256:988d9a3509bbb7ea8037d4eba3a5e0ada5dc165144c8ff0df89c0048d1ac6132",
    "sha256:b857347059916922b353147882544f17bb96e64c639081c0677bf386c446be4f",
    "sha256:e3135447ca3e69c6975aee1621c406e3865e0e143c807bbdcf05abefa56054a2"
  ]
}

위의 값들은 layerdb/sha256 directory에 존재하는것을 확인할 수 있다.

# ls /var/lib/docker/image/overlay2/layerdb/sha256 | grep 814bff
814bff7343242acfd20a2c841e041dd57c50f0cf844d4abd2329f78b992197f4

 

distribution내부를 보니.

 

다이제스트(해시) 값들을 저장된 것을 볼 수 있다. 이는 diffid와 layer 해시값에 대한 대응정보를 저장하고 있다고 한다.

# tree -L 2 -N
.
├── diffid-by-digest
│   └── sha256
└── v2metadata-by-diffid
    └── sha256

하나의 해시값에 대한 정보를 가져와 보니 해시값 : 해시값 대응하는것을 볼 수 있었다. 
어 그러면 ? docker hub에서 가져온 hash 값과 내 컴퓨터 에서 다루는 image layer에 대한 hash값이 다르므로 서로 대응해주는것일까?
라고 생각을 해보았다.

$cat diffid-by-digest/sha256/7babd9b3a647cc86f9f700ea95d7792811a4f6d141bcb260b66d748811024614
sha256:ba4c83fe893a2e5de9de55941f0df9bb5b5724629dfbe59383565e197433de52

헉. 그러면 위에서 pull받은 보이지 않던 nginx:latest에 대한 layer 해시값 하나를 여기서 가져올 수 있지 않을까 하여 시도해보았다.
위에서 33847f680f63, dbb907d5159d 등에 대한 정보를 볼 수 없었는데 그렇다면 여기에 저장되지 않았을까?
시도해보았다.

$ ls diffid-by-digest/sha256/ | grep 33847
33847f680f63fb1b343a9fc782e267b5abdbdb50d65d4b9bd2a136291d67cf75

위와 같이 grep 을 해보니 해당 해시값(docker hub에서 사용하는)이 보였다.
내 생각이 맞다면 cat을 했을 때 해당 해시값과 대응하는 내 서버에서 사용하는 layer에 대한 해시값이 보여야한다.

# cat diffid-by-digest/sha256/33847f680f63fb1b343a9fc782e267b5abdbdb50d65d4b9bd2a136291d67cf75
sha256:814bff7343242acfd20a2c841e041dd57c50f0cf844d4abd2329f78b992197f4

814bff7343242acfd20a2c841e041dd57c50f0cf844d4abd2329f78b992197f4 라는 해시값이 layerdb/sha256 에서 검출되어야한다.

하기 명령어를 통하여 grep해서 보니 이미지 pull받은 시간과 일치하는것을 확인할 수 있었다. 

# ls -al layerdb/sha256 | grep 814bff7343242acfd20a2c841e041dd57c50f0cf844d4abd2329f78b992197f4
drwx------   2 root root    71 Jul 29 23:31 814bff7343242acfd20a2c841e041dd57c50f0cf844d4abd2329f78b992197f4

다음에 기회가 된다면 layer에 대한 구조를 더 파봐야겠다.

 

...하루하루 배우지만 너무 모자른게 많은것같다. 

 

ref

- https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=cache798&logNo=221060912824 

- https://fliedcat.tistory.com/113

- https://www.44bits.io/ko/post/how-docker-image-work

- https://bigpel66.oopy.io/library/docker/docker/4

- https://subin-0320.tistory.com/28

- https://www.programmersought.com/article/95266566494/

Comments