내가 docker 에 대해서 잘 모르는 상태에서 띄워놓았던 verdaccio 서버가 있다. 이 서버는 우리 팀의 프론트엔드 라이브러리 배포를 해주던 서버였다. 그런데, 회사 사무실 이전으로 인한 컴퓨터 전원 종료 이슈로 떠있던 컨테이너가 죽게 생겼다. 처음 띄울때, 일반 컴퓨터에 도커 이미지를 풀 받아서 docs 에 있는 가이드대로 실행을 했었다.그런데, 지금 와서 생각해보니 볼륨이 익명 볼륨으로 되어있고, 컨테이너가 죽으면 띄운 컨테이너를 삭제하도록 하는 옵션이 기본으로 되어있어 컨테이너가 죽으면 기존 라이브러리에 배포하던 버전들이 다 사라지게 되는 것이다. 회사 사무실이 이사가기 전에 이를 백업할 방안을 마련해야했고, 오늘 착수해 성공했다!
문제의 컨테이너를 띄웠던 명령어
docker run -it --rm -d --name verdaccio/verdaccio -p 4873:4873 verdaccio
여기서 —rm 은 컨테이너 stop 시 컨테이너를 삭제하는 옵션이다. 물론 이 옵션은 일반적으로는 주는게 더 합리적인 옵션이겠지만 (쿠베에 띄우는 경우), 나 같이 컴퓨터 전원 종료에 대한 대책 없이 그 호스트 컴퓨터에 직접 띄운 상황에서는… 여러모로 좋을게 없다. (예를 들어 갑자기 정전이 나서 컨테이너가 죽는다던가 하면 verdaccio 에 띄워 놓았던 버전들이 싹 다 날아가게 되어있다. 정말 바람 앞의 촛불 상태 였던 것)
여기서 몇가지 verdaccio 사용 시 알아두면 좋은 점을 보자
- verdaccio 의 volume 은 컨테이너 안에 /verdaccio/storage 폴더를 바라보는 것이 default 이다.
- 그 하위 폴더를 싹 다 복사 붙여넣기 하면 내용 복구가 가능하다!
해당 특징을 이용해서, verdaccio 띄워놓은 컨테이너에서 해당 폴더를 압축해 docker cp 를 이용해 호스트 컴퓨터로 가져온 뒤, 다른 컨테이너에 주입하는 방식으로 시도했는데, 잘 동작했다! 그 과정을 적고자 한다.
- 띄운 컨테이너 상태 확인하기
docker inspect verdaccio(컨테이너 이름)
해당 명령어는 docker 컨테이너의 상태를 확인 할 수 있는 명령어이다. 해당 결과를 잘 읽어보면 volume 이 어디에 있는지도 알 수 있다.
결과 보기
[ { "Id": "7e56108b7710c83df2b3cd20ca2cfdb8f3ed04f5c32b75d3362f99318eef2196", "Created": "2023-09-21T08:50:38.856033443Z", "Path": "uid_entrypoint", "Args": [ "/bin/sh", "-c", "verdaccio --config /verdaccio/conf/config.yaml --listen $VERDACCIO_PROTOCOL://0.0.0.0:$VERDACCIO_PORT" ], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 5381, "ExitCode": 0, "Error": "", "StartedAt": "2023-09-21T08:50:42.015452685Z", "FinishedAt": "0001-01-01T00:00:00Z" }, "Image": "sha256:baeb536e736ebbc19370e7ab363dbf7088cfbafe9ce8e4ae197efb8f9d35c55c", "ResolvConfPath": "/var/lib/docker/containers/7e56108b7710c83df2b3cd20ca2cfdb8f3ed04f5c32b75d3362f99318eef2196/resolv.conf", "HostnamePath": "/var/lib/docker/containers/7e56108b7710c83df2b3cd20ca2cfdb8f3ed04f5c32b75d3362f99318eef2196/hostname", "HostsPath": "/var/lib/docker/containers/7e56108b7710c83df2b3cd20ca2cfdb8f3ed04f5c32b75d3362f99318eef2196/hosts", "LogPath": "/var/lib/docker/containers/7e56108b7710c83df2b3cd20ca2cfdb8f3ed04f5c32b75d3362f99318eef2196/7e56108b7710c83df2b3cd20ca2cfdb8f3ed04f5c32b75d3362f99318eef2196-json.log", "Name": "/verdaccio", "RestartCount": 0, "Driver": "overlay2", "Platform": "linux", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "docker-default", "ExecIDs": null, "HostConfig": { "Binds": null, "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "default", "PortBindings": { "4873/tcp": [ { "HostIp": "", "HostPort": "4873" } ] }, "RestartPolicy": { "Name": "no", "MaximumRetryCount": 0 }, "AutoRemove": true, "VolumeDriver": "", "VolumesFrom": null, "CapAdd": null, "CapDrop": null, "CgroupnsMode": "host", "Dns": [], "DnsOptions": [], "DnsSearch": [], "ExtraHosts": null, "GroupAdd": null, "IpcMode": "private", "Cgroup": "", "Links": null, "OomScoreAdj": 0, "PidMode": "", "Privileged": false, "PublishAllPorts": false, "ReadonlyRootfs": false, "SecurityOpt": null, "UTSMode": "", "UsernsMode": "", "ShmSize": 67108864, "Runtime": "runc", "ConsoleSize": [ 0, 0 ], "Isolation": "", "CpuShares": 0, "Memory": 0, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": [], "BlkioDeviceReadBps": null, "BlkioDeviceWriteBps": null, "BlkioDeviceReadIOps": null, "BlkioDeviceWriteIOps": null, "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": [], "DeviceCgroupRules": null, "DeviceRequests": null, "KernelMemory": 0, "KernelMemoryTCP": 0, "MemoryReservation": 0, "MemorySwap": 0, "MemorySwappiness": null, "OomKillDisable": false, "PidsLimit": null, "Ulimits": null, "CpuCount": 0, "CpuPercent": 0, "IOMaximumIOps": 0, "IOMaximumBandwidth": 0, "MaskedPaths": [ "/proc/asound", "/proc/acpi", "/proc/kcore", "/proc/keys", "/proc/latency_stats", "/proc/timer_list", "/proc/timer_stats", "/proc/sched_debug", "/proc/scsi", "/sys/firmware" ], "ReadonlyPaths": [ "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger" ] }, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/a857daaac8ec5153410630c9fcffcc1f6c7e3e3884877466574e9377203b227e-init/diff:/var/lib/docker/overlay2/eeeae19810b5ed4c551cfb05adb3c59f5627357e6bc18260866124f3dffee08d/diff:/var/lib/docker/overlay2/c0c0d215bcad145ff97c2275a374cfe979aaa780d4ac0080315548a9f056c744/diff:/var/lib/docker/overlay2/9552f89eac38e58ec478e5c4aacdf516249a3025271a0a2a024467cbe4539e10/diff:/var/lib/docker/overlay2/7f4070a1fd2090acc3853867a3720aaab63f911bbec51b087073b386f09143bc/diff:/var/lib/docker/overlay2/bfb8a8f7d03920814f5c176bdce7a1570313c34ce5432ff9e264a0b5fa9fc707/diff:/var/lib/docker/overlay2/126674a88fc59430018a7106c29e7fe6cc10f08322021938bdc75e8b3f6d164f/diff:/var/lib/docker/overlay2/8fa0e78ee0916ac1337e339a3a125b9c11e403bfa5bfd5a251b232877aaaca57/diff:/var/lib/docker/overlay2/2462dc310e4b54e1b77b54dcf7ed2c213f26f24d553b497f3d0b91b0344bc5c4/diff:/var/lib/docker/overlay2/15c2e4f3f3b29c9f42ba396821d0552e3158dbff33916392851173fbb57dfc62/diff:/var/lib/docker/overlay2/f6218635ee6cab8693fc4bd26f452ba1dce1125bf8e046640c3b6da4a0c0763d/diff:/var/lib/docker/overlay2/9e9e479a751f9ae85f9fb34da34c4766b437711ca5eefb8a3d43eb34fa76d249/diff:/var/lib/docker/overlay2/42eb3328c58c880f71eecf460dc5872e62f740197607c67cf36e2dab3c83b43e/diff", "MergedDir": "/var/lib/docker/overlay2/a857daaac8ec5153410630c9fcffcc1f6c7e3e3884877466574e9377203b227e/merged", "UpperDir": "/var/lib/docker/overlay2/a857daaac8ec5153410630c9fcffcc1f6c7e3e3884877466574e9377203b227e/diff", "WorkDir": "/var/lib/docker/overlay2/a857daaac8ec5153410630c9fcffcc1f6c7e3e3884877466574e9377203b227e/work" }, "Name": "overlay2" }, "Mounts": [ { "Type": "volume", "Name": "8cdba174f86eb65afbba4140825ec034bda0d176a7ca486bc833637d3ace6bdc", "Source": "/var/lib/docker/volumes/8cdba174f86eb65afbba4140825ec034bda0d176a7ca486bc833637d3ace6bdc/_data", "Destination": "/verdaccio/storage", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], "Config": { "Hostname": "7e56108b7710", "Domainname": "", "User": "10001", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "4873/tcp": {} }, "Tty": true, "OpenStdin": true, "StdinOnce": false, "Env": [ "PATH=/opt/verdaccio/docker-bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "NODE_VERSION=18.16.0", "YARN_VERSION=1.22.19", "VERDACCIO_APPDIR=/opt/verdaccio", "VERDACCIO_USER_NAME=verdaccio", "VERDACCIO_USER_UID=10001", "VERDACCIO_PORT=4873", "VERDACCIO_PROTOCOL=http", "HOME=/opt/verdaccio" ], "Cmd": [ "/bin/sh", "-c", "verdaccio --config /verdaccio/conf/config.yaml --listen $VERDACCIO_PROTOCOL://0.0.0.0:$VERDACCIO_PORT" ], "Image": "verdaccio/verdaccio", "Volumes": { "/verdaccio/storage": {} }, "WorkingDir": "/opt/verdaccio", "Entrypoint": [ "uid_entrypoint" ], "OnBuild": null, "Labels": { "maintainer": "https://github.com/verdaccio/verdaccio", "org.opencontainers.image.created": "2023-06-03T06:50:28.907Z", "org.opencontainers.image.description": "📦🔐 A lightweight Node.js private proxy registry", "org.opencontainers.image.licenses": "MIT", "org.opencontainers.image.revision": "f3afd0401891ffbb1e626699a04d0fc72cc30e11", "org.opencontainers.image.source": "https://github.com/verdaccio/verdaccio", "org.opencontainers.image.title": "verdaccio", "org.opencontainers.image.url": "https://github.com/verdaccio/verdaccio", "org.opencontainers.image.version": "5.25.0" } }, "NetworkSettings": { "Bridge": "",
- 해당 볼륨 카피 하기
사실 카피하기 전에 사전작업이 필요하다. docker cp 를 통해서 host 로 파일을 카피하는 것은 되지만, 디렉터리는 recursive 하게 카피 되지 않으며, -r 같은 옵션도 없다고 한다. 그래서 컨테이너 안에 들어가 볼륨 폴더를 압축 후 압축한 파일을 docker cp 로 꺼내올 것이다.
docker exec -it verdaccio /bin/sh
로 컨테이너 접속 후 해당 볼륨으로 들어가 tar 를 통해 압축한다.
~: cd /verdaccio/storage /verdaccio/storage: tar cvf backup.tar *
이후 다시 나와 호스트 컴퓨터에서 카피해온다.
docker cp container_id:/container_path/backup.tar host_path docker cp verdaccio:/verdaccio/storage/backup.tar ./verdaccio_backup/
이후 호스트 컴퓨터에서 새로운 컨테이너에 압축 파일을 카피해 넣는다.
docker cp host_path/backup.tar container_id:container_path docker cp ./backup.tar verdaccio-copy:/verdaccio/storage/
이때, 띄워놓은 새로운 컨테이너는 —rm 옵션을 주지 않은 컨테이너여야한다!!
docker run -it -d --name verdaccio-copy -p 4874:4873 verdaccio/verdaccio
해당 옵션은 외부 호스트 포트를 4874 로 주었다. 왜냐하면 이미 떠있는 컨테이너가 4873 을 먹고있어서…
이후 docker 를 다시 start 하면 된다.
- 그런데 백업 해놓은 볼륨 파일을 그냥 호스트에 마운트 하면 되지 않을까?
된다!
docker run -it -d --name verdaccio-volume -p 4872:4873 -v ~/verdaccio_backup:/verdaccio/storage verdaccio/verdaccio