안녕하세요. 바른호랑이입니다.
이번 게시글에서는 Docker 볼륨에 대해서 알아볼 예정입니다.
게시글은 '시작하세요! 도커/쿠버네티스 친절한 설명으로 쉽게 이해하는 컨테이너 관리'를 기반으로 작성하였으니 참고 바랍니다.
Docker 이미지로 컨테이너를 생성하면 이미지는 읽기 전용이 되며 컨테이너 변경 사항만 별도로 저장하여 각 컨테이너의 정보를 보존합니다.
# create db server container
sudo docker run -d \
--name wordpressdb \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=wordpress \
mysql:5.7
예를 들어 위의 코드로 생성된 컨테이너의 경우 mysql:5.7이라는 이미지로 생성되었지만, DB 등의 정보는 컨테이너 자체가 가지고 있습니다. 이미 생성된 이미지의 경우 변경되지 않으며, 원래 이미지에서 파일시스템과 같이 변경된 사항이 있다면 컨테이너 계층에 저장합니다. 즉, mysql을 실행하는 데 필요한 애플리케이션 파일은 이미지 파일에 들어가 변경되지 않고, 로그인 정보나 게시글 정보 등과 같이 DB를 운용하면서 적재되는 데이터들은 컨테이너 계층에 들어가게 됩니다.
하지만 이와 같은 구조는 mysql 컨테이너를 삭제할 경우, 컨테이너 계층에 저장되어 있던 DB의 정보들도 삭제된다는 치명적인 단점을 가지고 있고, Docker의 컨테이너의 경우 생성과 삭제가 매우 쉬우므로 실수로 컨테이너를 삭제하면 데이터를 복구할 수 없기에 이를 방지하는 것이 중요합니다. 바로 이 경우에 볼륨을 활용할 수 있습니다.
볼륨을 활용하는 첫 번째 방법은 Docker 엔진이 설치된 호스트의 볼륨을 공유하는 것으로 아래의 코드를 통해 따라 해볼 수 있습니다.
# create container
sudo docker run -d \
--name wordpressdb_hostvolume \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=wordpress \
-v /home/wordpress_db:/var/lib/mysql \
mysql:5.7
sudo docker run -d \
-e WORDPRESS_DB_PASSWORD=password \
--name wordpress_hostvolume \
--link wordpressdb_hostvolume:mysql \
-p 80 \
wordpress
워드프레스 컨테이너에 -p 옵션으로 컨테이너의 80번 포트를 외부에 노출했으므로 wordpress_hostvolume 컨테이너의 호스트 포트로 워드프레스 컨테이너에 접속할 수 있습니다. 위에서 사용한 -v 옵션은 호스트의 /home/wordpress_db 디렉터리와 컨테이너의 /var/lib/mysql 디렉터리(MySQL이 DB의 데이터를 저장하는 기본 디렉터리)를 공유한다는 의미로 사용되었으며, [호스트의 공유 디렉터리]:[컨테이너의 공유 디렉터리]의 형태로 사용할 수 있습니다.
미리 /home/wordpress_db 디렉터리를 호스트에 생성하지 않아도 Docker가 자동으로 생성해 주며, 실제로 해당 경로로 이동해 보면 아래와 같이 DB 관련 파일들이 위치한 것을 알 수 있습니다.
정상적으로 해당 디렉터리에 파일들이 존재하는 것을 확인했으면 아래의 코드들로 생성했던 컨테이너들을 삭제하고 다시 해당 위치의 파일들이 존재하는지 확인해 보면, 컨테이너 삭제 유무와 관계없이 데이터가 남아 있는 것을 확인할 수 있습니다.
# Delete Container
sudo docker rm -f wordpress_hostvolume wordpressdb_hostvolume
# check files
ls /home/wordpress_db
-v 옵션을 사용하여 컨테이너의 디렉터리를 호스트와 공유하는 것은 컨테이너의 '/var/lib/mysql' 디렉터리와 호스트의 '/home/wordpress_db' 디렉터리가 동기화되는 것이 아니라 완전히 동일한 디렉터리이며, 아래 코드와 같이 단일 파일 단위의 공유와 동시에 -v 옵션을 여러 개 사용하는 것도 가능합니다.
sudo docker run -i -t \
--name file_volume \
-v /home/hello:/hello \
-v /home/hello2:/hello2 \
ubuntu:24.04
만약 호스트에 이미 디렉터리가 존재하고 컨테이너에도 존재할 경우 두 디렉터리를 공유하면 호스트의 디렉터리 내용을 기준으로 컨테이너의 디렉터리 자체가 덮어씌워지게 되니 해당 부분은 유의가 필요합니다. 즉, -v 옵션을 통한 호스트 볼륨 공유는 호스트의 디렉터리를 컨테이너의 디렉터리에 마운트 한다라고 할 수 있습니다.
볼륨을 사용하는 두 번째 방법은 -v 옵션으로 볼륨을 사용하는 컨테이너를 다른 컨테이너와 공유하는 것으로 --volume-from 옵션과 -v 또는 --volume 옵션을 활용하여 적용할 수 있습니다. 하지만 이는 -v 옵션을 적용한 컨테이너를 통해 공유하는 것이라는 것을 유의해야 합니다. 아래의 코드를 통해 호스트와 볼륨을 공유하는 컨테이너를 만들고 해당 컨테이너를 활용해 다른 컨테이너에서 볼륨을 공유받는 형태를 만들어볼 수 있습니다.
# 호스토와 볼륨을 공유하는 컨테이너 생성
sudo docker run -i -t --name volume_overide \
-v /home/wordpress_db:/home/testdir_2 \
alicek106/volume_test
# volume_overide 컨테이너를 통해 볼륨을 공유받는 컨테이너 생성
sudo docker run -i -t --name volumes_from_container \
--volumes-from volume_overide \
ubuntu:24.04
위의 예제는 호스트와 볼륨을 공유하는 volume_overide 컨테이너를 만들고 volume_overide라는 컨테이너를 통해 볼륨을 공유받는 volumes_from_container를 만드는 것으로 전체적인 구조도는 아래와 같습니다.
예제에서는 하나의 컨테이너가 볼륨 컨테이너를 사용하게끔 하였지만 여러 개의 컨테이너가 볼륨 컨테이너를 사용하게끔 할 수도 있으며, 이와 같은 구조를 활용하면 호스트에서 볼륨만 공유하고 별도의 역할을 담당하지 않는 볼륨 컨테이너로서 활용하는 것이 가능합니다. 즉, 볼륨을 사용하려는 컨테이너에 -v 옵션 대신 --volume-from 옵션을 사용함으로써 볼륨 컨테이너에 연결해 데이터를 간접적으로 공유받는 형식이라고 할 수 있습니다.
볼륨을 사용하는 세 번째 방법은 docker volume 명령어를 사용하는 것으로 이는 도커 자체에서 제공하는 볼륨 기능입니다. 아래의 코드를 활용하면 간단하게 볼륨을 만들고 현재 작성된 볼륨 리스트를 확인할 수 있습니다.
# create docker volume
sudo docker volume create --name myvolume
# check volume list
sudo docker volume ls
정상적으로 볼륨이 만들어졌다면 컨테이너를 생성할 때 -v 옵션을 사용하여 해당 볼륨을 사용할 수 있으며, 아래의 코드를 통해 실제로 파일이 공유되는지를 확인해 볼 수 있습니다.
# create container
sudo docker run -i -t --name myvolume_1 \
-v myvolume:/root/ \
ubuntu:24.04
# create file in container
echo hello, volume! >> /root/volume
# create container
sudo docker run -i -t --name myvolume_2 \
-v myvolume:/root/ \
ubuntu:24.04
# check file
cat /root/volume
볼륨은 디렉터리 하나에 상응하는 단위로 도커 엔진에서 관리하며, 호스트 볼륨과 마찬가지로 호스트에 데이터를 저장하지만 실제로 파일이 어디에 저장되는지를 사용자가 알 필요 없이 자동으로 관리해 주는 것이 특징입니다. 자동 관리되는 데이터가 어디에 저장되는지 알기 위해서는 docker inspect 명령어를 사용하면 되며, 해당 명령어는 볼륨뿐만 아니라 컨테이너, 이미지 등의 도커의 모든 구성단위의 정보를 확인할 때 사용되고, 확인할 정보의 종류를 --type 옵션에 지정해 주어 사용할 수 있습니다. 아래의 코드를 사용하면 myvolume의 구성 정보를 확인할 수 있습니다.
sudo docker inspect --type volume myvolume
Driver는 볼륨이 쓰는 드라이버를 Label은 볼륨을 구분하는 라벨정보를 그리고 Mountpoint는 해당 볼륨이 실제로 호스트 엔진에 저장된 위치를 의미합니다. 아래의 코드를 통해 파일을 살펴보면 컨테이너에서 사용한 파일이 존재함을 확인할 수 있습니다.
sudo ls /var/lib/docker/volumes/myvolume/_data
sudo cat /var/lib/docker/volumes/myvolume/_data/volume
docker volume create 명령을 별도로 입력하지 않아도 -v 옵션을 입력할 시 자동으로 볼륨을 생성할 수도 있지만 이 경우 이름이 무작위의 16진수 형태로 작성되기에 실제로 사용하기에는 어려움이 있을 수 있습니다.
# create container
sudo docker run -i -t --name volume_auto \
-v /root \
ubuntu:24.04
# check volume list
sudo docker volume ls
# check container details
sudo docker container inspect volume_auto
추가로 이와 같이 자동으로 볼륨을 생성하게 되면 불필요한 볼륨들이 남아있을 수 있는데, 이는 도커 볼륨을 사용 중인 컨테이너를 삭제한다고 해서 자동으로 볼륨을 삭제해주지는 않기 때문입니다. 이 경우 사용하지 않는 도커 볼륨을 삭제하기 위해서 docker volume prune 명령어를 사용할 수 있습니다.
# delete volume
sudo docker volume prune
# check volume list
sudo docker volume ls
이와 같이 컨테이너가 아닌 외부에 데이터를 저장하고 컨테이너는 그 데이터로 동작하도록 설계하는 것을 stateless 하다고 이야기하며, 컨테이너 자체는 상태가 없고 상태를 결정하는 데이터는 외부로부터 제공받는 것이 특징입니다. 이와 같은 형태는 컨테이너가 삭제되어도 데이터는 보존되기에 도커를 사용할 때 바람직한 설계라고 할 수 있습니다.
이와 반대로 컨테이너가 데이터를 가지고 있는 경우 stateful 하다고 이야기하는데 이는 데이터 손실의 위험이 있으므로 지양하는 것이 좋습니다.
-v 옵션 대신 --mount 옵션을 사용할 수도 있으며, 두 옵션의 기능은 동일하지만 볼륨의 정보를 나타내는 방법이 다르기 때문에 사용하기 편한 옵션을 사용하면 됩니다. 만약 호스트의 디렉터리를 컨테이너 내부에 마운트 하는 경우 type을 bind로 지정하고, source는 호스트 디렉터리의 경로를 지정하여 사용할 수 있습니다.
# 도커 볼륨과 mount 옵션 사용 예시
sudo docker run -i -t --name mount_option_1 \
--mount type=volume,source=myvolume,target=/root \
ubuntu:24.04
# 호스트 볼륨 mount 옵션 사용 예시
sudo docker run -i -t --name mount_option_2 \
--mount type=bind,source=/home/wordpress_db,target=/home/testdir \
ubuntu:24.04
'IT & 데이터 사이언스 > Data Engineering' 카테고리의 다른 글
[Docker] 컨테이너 로깅 (0) | 2024.08.26 |
---|---|
[Docker] Docker 네트워크 (1) | 2024.08.08 |
[Docker] 컨테이너 외부 네트워크에 오픈하기 (0) | 2024.07.29 |
[Docker] Docker 엔진의 기본 단위와 컨테이너 생성, 삭제 (0) | 2024.07.25 |
[Docker] Docker란? (0) | 2024.07.18 |
댓글