Logo

Docker 컨테이너에 데이터 저장 (볼륨/바인드 마운트)

Docker 컨테이너(container)에 쓰여진 데이터는 기본적으로 컨테이너가 삭제될 때 함께 사라지게 됩니다. Docker에서 돌아가는 많은 애플리케이션이 컨테이너의 생명 주기와 관계없이 데이터를 영속적으로 저장을 해야하는데요. 뿐만 아니라 많은 경우 여러 개의 Docker 컨테이너가 하나의 저장 공간을 공유해서 데이터를 읽거나 써야합니다.

이렇게 Docker 컨테이너의 생명 주기와 관계없이 데이터를 영속적으로 저장할 수 있도록 Docker는 두가지 옵션을 제공하는데요. 첫번째는 Docker 볼륨(volume), 두번째는 바인드 마운트(bind mount)입니다. 이번 포스팅에서는 Docker 컨테이너에 데이터를 저장하는데 사용되는 이 두가지 방법에 대해서 알아보도록 하겠습니다.

types of mounts and where they live on the Docker host

볼륨 생성 및 조회

먼저, Docker에서 권장하는 방법인 볼륨(volume)에 대해서 먼저 살펴보겠습니다.

docker volume create 커맨드를 이용해서 볼륨을 하나 생성해보도록 하겠습니다.

$ docker volume create our-vol
our-vol

그 다음, docker volume ls 커맨드를 실행하면 다음과 같이 막 생성한 볼륨을 확인할 수 있습니다.

$ docker volume ls
DRIVER              VOLUME NAME
local               our-vol

docker volume inspect 커맨드를 통해 해당 볼륨을 좀 더 상세한 정보를 확인해볼 수 있습니다.

$ docker volume inspect our-vol
[
    {
        "CreatedAt": "2020-05-09T17:03:46Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/our-vol/_data",
        "Name": "our-vol",
        "Options": {},
        "Scope": "local"
    }
]

Mountpoint 항목을 보면 해당 볼륨이 컴퓨터의 어느 경로에 생성되었는지를 알 수 있습니다.

볼륨을 컨테이너에 마운트하기

컨테이너가 볼륨을 사용하기 위해서는 볼륨을 컨테이너에 마운트(mount)해줘야 합니다. docker run 커맨드로 컨테이너를 실행할 때 -v 옵션을 사용하면 되는데요. 콜론(:)을 구분자로 해서 앞에는 마운트할 볼륨명 뒤에는 컨테이너 내의 경로를 명시해주면 됩니다.

예를 들어, our-vol 볼륨을 one 컨테이너의 /app 경로에 마운트를 해보겠습니다.

$ docker run -v our-vol:/app --name one busybox touch /app/test.txt

touch /app/test.txt 커맨드를 실행하였기 때문에, test.txt 파일이 our-vol 볼륨의 경로에도 남아있을 것입니다.

$ ls /var/lib/docker/volumes/our-vol/_data
test.txt

docker inspect 커맨드로 컨테이너의 상세 정보를 확인해보면 our-vol 볼륨이 volume 타입으로 마운트되어 있는 것을 확인할 수 있습니다.

$ docker inspect one
(...생략...)
    "Mounts": [
        {
            "Type": "volume",
            "Name": "our-vol",
            "Source": "/var/lib/docker/volumes/our-vol/_data",
            "Destination": "/app",
            "Driver": "local",
            "Mode": "z",
            "RW": true,
            "Propagation": ""
        }
    ],
(...생략...)

볼륨을 다른 컨테이너에도 마운트하기

이 번에는 같은 our-vol 볼륨을 two 컨테이너의 /app 경로에 마운트를 해보겠습니다. ls /app 커맨드를 실행해보니, one 컨테이너가 볼륨에 생성해놓은 파일이 그대로 보이는 것을 알 수 있습니다.

$ docker run -v our-vol:/app --name two busybox ls /app
test.txt

이렇게 여러 개의 컨테이너가 하나의 볼륨에 접근할 수 있기 때문에 컨테이너 간 데이터 공유가 가능한 것입니다. 다시 말해, 어떤 볼륨에 데이터를 저장해두고, 여러 컨테이너에 마운트만 해주면 해당 데이터를 모든 컨테이너에서 접근할 수 있게 됩니다.

볼륨 삭제

마지막으로 docker volume rm 커맨드를 사용해서 our-vol 볼륨을 제거해보겠습니다.

$ docker volume rm our-vol
Error response from daemon: remove our-vol: volume is in use - [f73130c9dad14644ac46b89fe4018e561a7bcbfa4118d637949642d0d5d742e4, 666dda54f6be8ca852f3150b9741a9cab5a4659fa2e83fe6ca339550072c861ex]

위와 같이 제거하려는 볼륨이 마운트되어 있는 컨테이너가 있을 때는 해당 볼륨이 제거가 되지가 않습니다.

그럴 때는 해당 볼륨이 마운트되어 있는 모든 컨테이너를 먼저 삭제하고, 볼륨을 삭제해야 합니다.

$ docker rm -f one two
one
two
$ docker volume rm our-vol
our-vol

볼륨 청소

docker volume prune 커맨드를 이용해서 마운트되어 있지 않은 모든 볼륨을 한번에 제거할 수 있습니다.

$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y

바인드 마운트

Docker 컨테이너에 데이터를 저장하기 위한 다른 방법으로 바인드 마운트(bind mount)라는 것도 있습니다. 바인드 마운트를 사용하면 호스트 파일 시스템의 특정 경로를 컨테이너로 바로 마운트할 수 있습니다.

바인드 마운트를 사용하는 방법은 docker run 커맨드를 실행할 때, -v 옵션의 콜론(:) 앞 부분에 마운트명 대신에 호스트의 경로를 지정해주는 것입니다.

예를 들어, 현재 경로에 test.txt 파일을 생성하고, 해당 호스트 경로를 컨테이너의 /app 경로에 마운트해보겠습니다. 컨테이너에 터미널을 붙여서 ls /app 커맨드를 실행해보면 test.txt 파일이 컨테이너의 /app 경로에도 존재하는 것을 확인할 수 있습니다.

$ touch test.txt
$ docker run -v `pwd`:/app -it --name one busybox /bin/sh
/ # ls /app
test.txt

반대로 컨테이너의 /app 경로 상에서 test2.txt 파일을 실행해보면 호스트의 현재 경로에도 해당 파일이 보이는 것을 알 수 있습니다.

/ # touch /app/test2.txt
/ # exit
[node1] (local) root@192.168.0.18 ~
$ ls
test.txt   test2.txt

docker inspect 커맨드로 해당 컨테이너의 상세 정보를 확인해보면 현재 경로(/root)가 bind 타입으로 마운트되어 있는 것을 확인할 수 있습니다.

$ docker inspect one
(...생략...)
    "Mounts": [
        {
            "Type": "bind",
            "Source": "/root",
            "Destination": "/app",
            "Mode": "",
            "RW": true,
            "Propagation": "rprivate"
        }
    ],
(...생략...)

볼륨 vs 바인드 마운트

볼륨(volume)과 바인드 마운트(bind mount)의 가장 큰 차이점은 Docker가 해당 마운트 포인트를 관리해주느냐 안 해주느냐 입니다. 볼륨을 사용할 때는 우리가 스스로 볼륨을 생성하거나 삭제해야하는 불편함이 있지만, 해당 볼륨은 Docker 상에서 이미지(image)나 컨테이너(container), 네트워크(network)와 비슷한 방식으로 관리가 되는 이점이 있습니다. 그래서 대부분의 상황에서는 볼륨을 사용하는 것이 권장되지만 컨테이너화된 로컬 개발 환경을 구성할 때는 바인드 마운트가 더 유리할 수 있습니다.

로컬에서 개발을 할 때는 일반적으로 현재 작업 디렉터리에 프로젝트 저장소를 git clone 받아놓고 코드를 변경합니다. 따라서 바인드 마운트를 이용해서 해당 디렉터리를 컨테이너의 특정 경로에 마운트해주면 코드를 변경할 때 마다 변경 사항을 실시간으로 컨테이너를 통해 확인할 수 있습니다. 반대로 컨테이너를 통해 변경된 부분도 현재 작업 디렉터리에도 반영이 되기 때문에 편리할 것입니다.

바인드 마운트를 실제 프로젝트에서 활용하는 예제는 관련 포스팅를 참고 바라겠습니다.

마치면서

이상으로 Docker 볼륨과 바인트 마운트를 사용하는 방법에 대해서 살펴보았습니다. 본 포스팅에서 사용했던 각 커맨드에 대한 좀 더 자세한 내용은 아래 Docekr CLI 레퍼런스를 참고바라겠습니다.