icon

메티의 블로그

잘못 띄워놓은 verdaccio 서버 volume 찾아서 백업하기
잘못 띄워놓은 verdaccio 서버 volume 찾아서 백업하기

잘못 띄워놓은 verdaccio 서버 volume 찾아서 백업하기

Tags
Docker
날짜
Nov 22, 2023
상태
공개
내가 docker 에 대해서 잘 모르는 상태에서 띄워놓았던 verdaccio 서버가 있다. 이 서버는 우리 팀의 프론트엔드 라이브러리 배포를 해주던 서버였다. 그런데, 회사 사무실 이전으로 인한 컴퓨터 전원 종료 이슈로 떠있던 컨테이너가 죽게 생겼다. 처음 띄울때, 일반 컴퓨터에 도커 이미지를 풀 받아서 docs 에 있는 가이드대로 실행을 했었다.그런데, 지금 와서 생각해보니 볼륨이 익명 볼륨으로 되어있고, 컨테이너가 죽으면 띄운 컨테이너를 삭제하도록 하는 옵션이 기본으로 되어있어 컨테이너가 죽으면 기존 라이브러리에 배포하던 버전들이 다 사라지게 되는 것이다. 회사 사무실이 이사가기 전에 이를 백업할 방안을 마련해야했고, 오늘 착수해 성공했다!
 
문제의 컨테이너를 띄웠던 명령어
docker run -it --rm -d --name verdaccio/verdaccio -p 4873:4873 verdaccio
여기서 —rm 은 컨테이너 stop 시 컨테이너를 삭제하는 옵션이다. 물론 이 옵션은 일반적으로는 주는게 더 합리적인 옵션이겠지만 (쿠베에 띄우는 경우), 나 같이 컴퓨터 전원 종료에 대한 대책 없이 그 호스트 컴퓨터에 직접 띄운 상황에서는… 여러모로 좋을게 없다. (예를 들어 갑자기 정전이 나서 컨테이너가 죽는다던가 하면 verdaccio 에 띄워 놓았던 버전들이 싹 다 날아가게 되어있다. 정말 바람 앞의 촛불 상태 였던 것)
 
여기서 몇가지 verdaccio 사용 시 알아두면 좋은 점을 보자
  1. verdaccio 의 volume 은 컨테이너 안에 /verdaccio/storage 폴더를 바라보는 것이 default 이다.
  1. 그 하위 폴더를 싹 다 복사 붙여넣기 하면 내용 복구가 가능하다!
 
해당 특징을 이용해서, verdaccio 띄워놓은 컨테이너에서 해당 폴더를 압축해 docker cp 를 이용해 호스트 컴퓨터로 가져온 뒤, 다른 컨테이너에 주입하는 방식으로 시도했는데, 잘 동작했다! 그 과정을 적고자 한다.
 
  1. 띄운 컨테이너 상태 확인하기
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": "",
 
  1. 해당 볼륨 카피 하기
사실 카피하기 전에 사전작업이 필요하다. 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 하면 된다.
 
  1. 그런데 백업 해놓은 볼륨 파일을 그냥 호스트에 마운트 하면 되지 않을까?
된다!
docker run -it -d --name verdaccio-volume -p 4872:4873 -v ~/verdaccio_backup:/verdaccio/storage verdaccio/verdaccio

연관 포스트