티스토리 뷰

728x90
반응형

서론

앞선 포스팅에서 docker save와 docker load 그리고 docker export와 docker import 명령어를 사용하는 방법에 대해 살펴보았습니다.

 

[Docker Command] docker 명령어 뽀개기

 

간단히 명령어에 대해 리마인드를 진행해 보자면 다음과 같습니다.

1) docker save / load (docker image를 tar 파일로 추출)

[root@CIServer sysconfig]# docker save https:v1.1 -o save.tar 
[root@CIServer sysconfig]# ls -la save.tar 
-rw-------. 1 root root 167019008 Dec  2 01:08 save.tar 
[root@CIServer sysconfig]# docker load -i save.tar 
Loaded image: https:v1.1 
[root@CIServer sysconfig]#

docker save와 load를 사용하여 docker 이미지를 추출하고 로드할 수 있습니다.

2) docker export / import (docker image와 container를 tar 파일로 추출)

[root@CIServer sysconfig]# docker export myapache >> apache.tar 
[root@CIServer sysconfig]# ls -la apache.tar 
-rw-r--r--. 1 root root 167010816 Dec  2 00:43 apache.tar 
[root@CIServer sysconfig]# docker import apache.tar https:v1.1 
sha256:35b0914eb5716b6ad7bffbe7ae5601ee65d5468bb65473c0568c4624dd507748 [root@CIServer sysconfig]# docker export a7fce4baf6a6 | docker import - httpd:v1.1 
sha256:83db3564935410c73aa5c5721dc93ec87ad58b4ee690873914298ba6d624e24c 
[root@CIServer sysconfig]# docker images 
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE 
httpd               v1.1                83db35649354        7 seconds ago       162 MB 
httpd               v1.0                0fe8bdfe6399        58 minutes ago      165 MB 
docker.io/httpd     latest              2ae34abc2ed0        2 days ago          165 MB 
docker.io/jenkins   latest              cd14cecfdb3a        16 months ago       696 MB 
[root@CIServer sysconfig]#

docker export와 import 명령어를 통해 docker image 뿐 아니라 기동 중인 docker container를 tar 파일로 추출하고 로드할 수 있습니다.

 

위와 같이 명령어를 활용하여 docker images와 docker container를 저장하고 또 다른 환경으로 이관할 수 있습니다.

본 포스팅에서는 두가지 명령어의 차이점에 대해 살펴보고 활용방안에 대해 알아보겠습니다.

본론

먼저 docker save와 docker load에 대해 살펴보겠습니다.

1) docker save/load & docker export/import 비교

docker save와 load 명령어는 현재 docker local repository에 있는 docker image를 tar 파일로 추출하고 다시 로드하는 명령어입니다.

docker image를 조작하지 않고 단순히 또 다른 환경으로 이관하기 위한 용도로 사용할 수 있습니다. 즉 docker save로 추출된 이미지는 original 도커 이미지와 동일한 이미지라고 할 수 있습니다.

 

2) docker layer 비교

docker export 명령어를 수행하여 tar 파일을 추출할 경우, docker save와 같이 tar 파일로 추출하게 되지만, docker의 layer에 대한 정보는 포함하지 않습니다.

다음은 jupyterhub를 구성하기 위한 tljh-systemd 이미지에 대한 비교 내용입니다.

[tljh jupyterhub original image inspect info]

[
    {
        "Id": "sha256:000b57f055093807652dfe4a5a48b159f3283c724929336aaed21dae83601290",
        "RepoTags": [
            "192.168.2.151:13000/jupyterpackage/jupyterhub/tljh:latest",
            "tljh-systemd:latest"
        ],
        "RepoDigests": [
            "192.168.2.151:13000/jupyterpackage/jupyterhub/tljh@sha256:1996857e56912ddd3c22f1c18a59d486d8a3db2d6bf6759e21d7a5d8048af392"
        ],
        "Parent": "sha256:793b2fec2967b335e80d19c3e1638b448e7d388a16c7eab40f725985e1e33eae",
        "Comment": "",
        "Created": "2020-02-05T00:45:22.847616558Z",
        "Container": "0bd70d1bed16a90b5543078d95f91411dca3975ac9189771d070b76f933eb155",
        "ContainerConfig": {
            "Hostname": "kubemaster",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/opt/tljh/hub/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "TLJH_BOOTSTRAP_DEV=yes",
                "TLJH_BOOTSTRAP_PIP_SPEC=/srv/src"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"/bin/bash\" \"-c\" \"exec /sbin/init --log-target=journal 3>&1\"]"
            ],
            "Image": "sha256:793b2fec2967b335e80d19c3e1638b448e7d388a16c7eab40f725985e1e33eae",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {},
            "StopSignal": "SIGRTMIN+3"
        },
        "DockerVersion": "19.03.5",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/opt/tljh/hub/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "TLJH_BOOTSTRAP_DEV=yes",
                "TLJH_BOOTSTRAP_PIP_SPEC=/srv/src"
            ],
            "Cmd": [
                "/bin/bash",
                "-c",
                "exec /sbin/init --log-target=journal 3>&1"
            ],
            "Image": "sha256:793b2fec2967b335e80d19c3e1638b448e7d388a16c7eab40f725985e1e33eae",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null,
            "StopSignal": "SIGRTMIN+3"
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 274298992,
        "VirtualSize": 274298992,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/a35df2529261b6734e9c9b28be0ec8f2da19d3ba1dabe5f1898b7f0959a6bee2/diff:/var/lib/docker/overlay2/9b93fe435a173b56a5e66125c9e8107203994b818d305f276985c91eb25d0f74/diff:/var/lib/docker/overlay2/2ff9bc616de54f909f06537873d2e769b5e186a7053d0ac9c3e79490b594d6b8/diff:/var/lib/docker/overlay2/4f58322c86837c3abb0113e5eb8587332aa8043d505d8b4cf96cf74b9ae97b76/diff:/var/lib/docker/overlay2/b1c9694245f004c3e0ac72644a0265fc6295f1b42489cddb936554d1d7cf23fc/diff:/var/lib/docker/overlay2/df0b89fd1b8bdd64272491aa7ecf6f5fc987a8dd67264c314315fa69a9e59d96/diff:/var/lib/docker/overlay2/03e4a35a62cce7887ce6bd238450b50425e2a2898b939bea16934227e64db8e0/diff",
                "MergedDir": "/var/lib/docker/overlay2/a04c8bc2ffb37d5470c7df121ea09ef252fa0fa83cfb367f34cc09d98c547471/merged",
                "UpperDir": "/var/lib/docker/overlay2/a04c8bc2ffb37d5470c7df121ea09ef252fa0fa83cfb367f34cc09d98c547471/diff",
                "WorkDir": "/var/lib/docker/overlay2/a04c8bc2ffb37d5470c7df121ea09ef252fa0fa83cfb367f34cc09d98c547471/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:43c67172d1d182ca5460fc962f8f053f33028e0a3a1d423e05d91b532429e73d",
                "sha256:21ec61b65b20ec53a1b7f069fd04df5acb0e75434bd3603c88467c8bfc80d9c6",
                "sha256:1d0dfb259f6a31f95efcba61f0a3afa318448890610c7d9a64dc4e95f9add843",
                "sha256:f55aa0bd26b801374773c103bed4479865d0e37435b848cb39d164ccb2c3ba51",
                "sha256:50395ecc5afcc0ab36db7b7e50e9084a613b4d2c138aa27713a5118d2c63849f",
                "sha256:a8fda65e8b5f4c0d74dd8837c4307bed27f4cd3d17624f03769cb824616379a5",
                "sha256:3c6d8ec6e3141e5fc66c96cbb171ffc2c5aa2509709f6faefdf042f9d2ada3ee",
                "sha256:755886c83cb21a430d651f2e7240ef94d6ec5d722cb2aa7f6e5aaaf474fcbb1c"
            ]
        },
        "Metadata": {
            "LastTagTime": "2020-02-05T09:46:09.767647815+09:00"
        }
    }
]

위와 같이 해당 docker file의 Layers는

"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:43c67172d1d182ca5460fc962f8f053f33028e0a3a1d423e05d91b532429e73d",
                "sha256:21ec61b65b20ec53a1b7f069fd04df5acb0e75434bd3603c88467c8bfc80d9c6",
                "sha256:1d0dfb259f6a31f95efcba61f0a3afa318448890610c7d9a64dc4e95f9add843",
                "sha256:f55aa0bd26b801374773c103bed4479865d0e37435b848cb39d164ccb2c3ba51",
                "sha256:50395ecc5afcc0ab36db7b7e50e9084a613b4d2c138aa27713a5118d2c63849f",
                "sha256:a8fda65e8b5f4c0d74dd8837c4307bed27f4cd3d17624f03769cb824616379a5",
                "sha256:3c6d8ec6e3141e5fc66c96cbb171ffc2c5aa2509709f6faefdf042f9d2ada3ee",
                "sha256:755886c83cb21a430d651f2e7240ef94d6ec5d722cb2aa7f6e5aaaf474fcbb1c"
            ]
        },

총 8단계로 나뉘어 구성되어 있습니다.

이를 docker export로 추출한 이미지를 import한 docker image와 비교해 보도록 하겠습니다.

[tljh jupyterhub import image inspect info]

[
    {
        "Id": "sha256:416397accdf22e543315dbd9a8fdeb3f6f54ab4f009e57695495c823eb5bda62",
        "RepoTags": [
            "192.168.2.151:13000/jupyterhub/tljh_add_bootstrap:v1.0"
        ],
        "RepoDigests": [],
        "Parent": "",
        "Comment": "Imported from -",
        "Created": "2020-02-05T02:21:19.149160748Z",
        "Container": "",
        "ContainerConfig": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": null,
            "Cmd": null,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "DockerVersion": "18.09.7",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": null,
            "Cmd": null,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 2120217745,
        "VirtualSize": 2120217745,
        "GraphDriver": {
            "Data": {
                "MergedDir": "/var/lib/docker/overlay2/ef7582ee39c4246459fe63f924cb5c32230b71eae36437244947c1df11b77d86/merged",
                "UpperDir": "/var/lib/docker/overlay2/ef7582ee39c4246459fe63f924cb5c32230b71eae36437244947c1df11b77d86/diff",
                "WorkDir": "/var/lib/docker/overlay2/ef7582ee39c4246459fe63f924cb5c32230b71eae36437244947c1df11b77d86/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:e5fc2009202763467fc51b8976c72cc178954d265ec7d9d55caa71324818157a"
            ]
        },
        "Metadata": {
            "LastTagTime": "2020-02-05T11:21:19.166191386+09:00"
        }
    }
]

import로 로드한 이미지의 Layers 정보는

"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:e5fc2009202763467fc51b8976c72cc178954d265ec7d9d55caa71324818157a"
            ]
        },

동일한 이미지 임에도 불구하고 위와 같이 하나로 통합된 것을 확인할 수 있습니다.

이를 통해 docker export 명령어는 현재 docker container 내부의 디렉토리 전체를 압축하여 새로운 이미지로 생성해 준다고 볼 수 있습니다.

 

3) docker export/import 한 이미지 기동

그럼 docker import로 로드한 이미지를 기동해 보도록 하겠습니다.

기존 오리지날 jupyterhub 기동에 사용했던 명령어를 그대로 입력해 보도록 하겠습니다.

[root@CIServer the-littlest-jupyterhub]# docker run --privileged --detach --name=tljh-dev --publish 12000:80 --mount type=bind,source=$(pwd),target=/srv/src 192.168.2.151:13000/jupyterhub/tljh_add_bootstrap:v1.0
docker: Error response from daemon: No command specified.
See 'docker run --help'.
[root@CIServer the-littlest-jupyterhub]#

docker run을 수행하였지만, 위와 같은 에러 메시지를 받게됩니다.

docker: Error response from daemon: No command specified.

여기서 살펴볼 점은 바로 도커 export로 추출하여 로드한 docker image의 경우 docker container를 단순히 아카이빙 한 이미지 라는 것입니다. 즉 압축한 파일 자체를 이미지로 로드해 둔 것이라고 볼 수 있습니다.

이를 정상적으로 기동하기 위해서는 import 이미지를 기반으로 새롭게 Dockerfile을 작성하거나, import 시점에 명령어를 주입시켜 주어야 합니다.

[root@CIServer ~]# docker import --change 'CMD ["/bin/bash","-c","exec /sbin/init --log-target=journal 3>&1"]' tljh.tar 192.168.2.151:13000/jupyterhub/tljh_add_bootstrap:v1.0
sha256:045273611b2cb6febc9778c9a06b8f57c97e988a6757ab950fc0023592bcfd35
[root@CIServer ~]#

위와 같이 docker import --change 옵션을 사용하여 필요한 정보들을 기입합니다.

--change 옵션은 Dockerfile에 기입할 내용을 import 시점에 옵션으로 등록할 수 있습니다.

기존 Original Docker file의 CMD에 정의 된 아래 내용을 기반으로

"Cmd": [
                "/bin/bash",
                "-c",
                "exec /sbin/init --log-target=journal 3>&1"
            ],

--change CMD ["/bin/bash","-c","exec /sbin/init --log-target=journal 3>&1"] 옵션을 추가하면 import 시점에 Dockerfile의 CMD를 추가한 것과 같이 동작하게 됩니다.

[root@CIServer the-littlest-jupyterhub]# docker import --change 'CMD ["/bin/bash","-c","exec /sbin/init --log-target=journal 3>&1"]' tljh.tar 192.168.2.151:13000/jupyterhub/tljh_add_bootstrap:v1.0
sha256:045273611b2cb6febc9778c9a06b8f57c97e988a6757ab950fc0023592bcfd35
[root@CIServer the-littlest-jupyterhub]# docker run --privileged --detach --name=tljh-dev --publish 12000:80 --mount type=bind,source=$(pwd),target=/srv/src 192.168.2.151:13000/jupyterhub/tljh_add_bootstrap:v1.0
716291ec798118d7a1793d5da41a4c20fe8792d924929ae35ad2e357cee635f7
[root@CIServer the-littlest-jupyterhub]# docker ps -l
CONTAINER ID        IMAGE                                                    COMMAND                  CREATED             STATUS              PORTS                   NAMES
716291ec7981        192.168.2.151:13000/jupyterhub/tljh_add_bootstrap:v1.0   "/bin/bash -c 'exec …"   5 seconds ago       Up 3 seconds        0.0.0.0:12000->80/tcp   tljh-dev
[root@CIServer the-littlest-jupyterhub]#

위와 같이 Docker Container가 정상 기동 된 것을 확인할 수 있습니다.

결론

지금까지 살펴본 내용을 정리하자면 다음과 같습니다.

1) docker save & docker load : docker image를 tar 파일로 추출하고 로드하는 역할로 이미지에 변경이 있지 않은 오리지널 이미지와 동일하다.

2) docker export & docker import : docker container를 tar 파일로 추출하고 로드하는 역할로 오리지널 이미지를 아카이빙하여 하나의 layer로 저장된 이미지를 생성한다.

3) docker export & docker import로 로드한 이미지를 기동하기 위해서는 Dockerfile을 작성하거나, import --change 옵션을 사용하여 필요한 구문을 추가해야 한다.

 

위와 같은 결론을 기반으로 명령어를 활용하자면, Docker Image를 단순히 옮기고 싶을 경우에는 docker save를 Container에 커스터마이징 된 정보를 기반으로 Container를 이미지로 생성하고 싶을 경우에는 docker export를 활용할 수 있을 것입니다.

728x90
반응형