※ 도커의 컨테이너안에 데이터를 저장할 수 있지만, 여기에는 몇 가지 문제점이 존재한다.
- 컨테이너가 삭제되면 데이터도 삭제된다.
- 다른 프로세스에서 특정 컨테이너에 저장된 데이터를 사용하기 어렵다.
- 컨테이너에 데이터를 저장하기 위해서는 파일시스템을 관리하는 스토리지 드라이버가 필요하다. 그러나 이 기능은 호스트 파일시스템에 직접 쓰는것보다 성능이 떨어진다.
따라서 이러한 문제를 해결하기 위해 여러가지 방법이 있는데, 그 중 2가지 방법에 대해서 알아본다.
첫번째는 호스트 서버의 경로와 컨테이너의 경로를 연결하는 방식
두번째는 docker volume을 생성해서 연결하는 방식
* 호스트 서버의 경로와 컨테이너의 경로를 연결
▣ docker container run -v 옵션을 사용해서 호스트의 디렉토리와 마운트될 컨테이너의 디렉토리를 명시할 수 있다.
1. 호스트 디스크를 명시하지 않고 생성
- 컨테이너에서 -v 명령에서 명시될 디렉토리들은 없으면 알아서 만들어진다. (따라서 미리 만들 필요가 없다)
- 아래 예시는 한 컨테이너 안에 2개의 마운트 포인트를 만드는 것이다.
- 이 마운트 포인트는 호스트 서버의 /var/lib/docker/volumes에 저장된다. 컨테이너가 삭제되어도 해당 데이터는 남아있다.
- 호스트 디스크는 도커 디렉토리 (/var/lib/docker/volumes) 에 저장되므로, 해당 디렉토리 파티션의 용량이 한도가 된다.
Command
#docker run -it --name data_share -v /data_dir -v /admin_dir ubuntu /bin/bash
호스트에서 해당 컨테이너의 마운트 정보를 보려면 다음과 같이 입력한다.
#docker inspect --format="{{ .HostConfing.Binds }}" data_share
2. 호스트 디스크를 명시하고 생성
- 호스트 디스크를 따로 명시하므로, 해당 디스크가 외장 스토리지가 될 수도 있고, 다른 내부 저장공간이 될 수도 있다.
- -v 옵션이후 호스트와 컨테이너 디렉토리는 없으면 알아서 만들어진다.
- 따라서 둘 다 일부러 따로 만들 필요가 없다.
- 이렇게 하면 호스트에 /test1 /test2를 만들어서 각각 컨테이너의 /data_dir, /test_dir 에 마운트된다.
- 호스트의 /test1, /test2는 외장 스토리지나 NFS 등 여러방식으로 외장 스토리지가 될 수 있다.
Command
#docker run -it --name data_share -v /test1:/data_dir -v /test2:/test_dir ubuntu /bin/bash
* docker volume을 구성해서 컨테이너에 연결
- docker volume은 따로 docker에서 관리하는 형태로 호스트에 volume을 생성하며, 해당 볼륨은 #docker volume ls 등으로 리스트를 확인할 수 있다.
- 따라서 관리하는 측면에서 훨씬 유용하다.
- 또한 volume이 저장되는 공간만 외장 스토리지로 마운트하여 대용량으로 사용할수도 있다.
- 도커 volume은 /var/lib/docker/volumes 경로에 저장된다.
- 또한 각 데이터는 /var/lib/docker/volumes/볼륨명/_data 밑에 저장된다.
- 이러한 volume 들은 컨테이너가 삭제되어도 그대로 유지된다.
- 또한 다른 컨테이너에서 다시 마운트하면 해당 데이터를 볼 수 있다.
- 상세 명령은 아래 명령에서 확인
1. Docker volume 관련 명령어들
#docker volume create 볼륨명
- docker에서 사용할 volume을 생성한다. 볼륨명을 명시하지 않으면, random한 이름으로 생성된다.
#docker volume ls
- 현재 생성되어 있는 모든 볼륨을 보여준다.
- 긴 이름으로 된 볼륨들은 위에서 수행한 "호스트 디스클를 명시하지 않고 생성하거나, 볼륨 생성시 따로 이름을 주지 않은 것들이다.
#docker volume rm 볼륨명
- 현재 존재하는 볼륨을 삭제한다.
#docker volume prune
- 사용하지 않는 모든 볼륨을 지울 수 있다.
#docker volume inspect 볼륨명
- volume의 상세 정보를 확인할 수 있다.
#docker inspect data_share | grep -i volumes
- 컨테이너가 가지고 있는 볼륨을 확인하기
2. docker volume을 이용하여 컨테이너 생성하기
Command
#docker run -it --name disk-test -v test-volume:/test ubuntu /bin/bash
* 동일 디스크 정보를 그대로 공유받기
- 생성된 볼륨이나 파일시스템들은 동시에 볼륨을 여러 컨테이너에 마운트할 수 있다.
- 아래와 같이 --volumes-from 옵션을 사용할 수 있다.
- 아래 명령은 맨 처음에 만든 data_share 라는 이름의 컨테이너가 가진 볼륨 정보를 그대로 공유받아서 마운트한다.
Command
#docker run -d -it --name disk-test-share --volumes-from data_share ubuntu /bin/bash
또 새롭게 컨테이너를 만들어서, 예를들어 이름을 disk-test-share2 하고 똑같은 data_share의 볼륨을 "공유" 받을 수 있다. 이렇게 하면 아래와 같은 형식이 될 것이다.
* 오버레이 파일시스템 드라이버
overlay는 도커에서 사용하는 파일시스템 드라이버이다. 자세한 설명은 생략.
컨테이너를 만들고 호스트에서 df -h를 쳤을 때 overlay 라고 마운트되어있는 것은 각 컨테이너의 루트디렉토리이다.
즉 /var/lib/docker/overlay2 에는 각 컨테이너의 루트 디렉토리, /var/lib/docker/volumes 에는 생성한 볼륨이 들어간다.
해당 데이터는 마운트 포인트인 /var/lib/docker/overlay2/이름/merged 디렉토리에 저장된다.
들어가보면 루트 파일시스템 같은 모양을 확인할 수 있을 것이다.
컨테이너가 삭제되면, 이 오버레이 마운트 경로의 데이터는 모두 삭제된다.
ㆍ참고 : 컨테이너 내에서 lsblk, blkid 명령은 제대로 나오지 않는다.
* -v 대신 사용하는 --mount 옵션
- 위에서 언급한대로 독립형 컨테이너에서는 -v / --volume이 사용되며, 도커 스웜 모드에서는 --mount가 사용된다.
- 이후 도커 17.06 부터 --mount를 독립형 컨테이너에서 사용할 수 있게 되었다.
- 따라서 -v 옵션 외에 --mount 옵션도 쓸 수 있다.
- 특히 특정 볼륨 드라이버를 명시해서 사용할 때는 --mount를 사용해야 한다.
- --mount 옵션은 쉼표(,)로 구분되고 각각 여러 key-value 쌍으로 구성된다.
- --mount 구문은 -v 또는 --volume보다 길지만, key의 순서는 중요치 않으며 Flag의 값을 이해하기 쉽게 되어있다.
Ex)
# docker run -d -it --name=nginxtest --mount source=nginx-vol,destination=/usr/share/nginx/html,readonly nginx:latest
- type : mount의 유형을 지정한다. (bind, volume,tmpfs)
- source(src) : volume의 이름. 익명 볼륨을 사용한다면 생략해도 된다.
- destination(dst,target) : 컨테이너에 마운트 될 경로
- readonly : 컨테이너에 읽기 전용으로 마운트됨 opt 등 여러 추가 옵션이 있으나 더 이상 자세한 설명은 생략한다.
* 추가 예시 : dd로 디스크 img 파일을 만들어 할당하기
1. disk 파일 생성
#dd if=/dev/zero of=파일명 count=512 bs=1M
2. 해당 이미지 파일로 파일시스템 생성
#mkfs.ext4 harddrivce.img
3. 호스트 서버에서 테스트 디렉토리 생성 후 마운트
#mkdir /test
#mount /harddrivce.img /test
4. 도커 컨테이너를 만들고 해당 파일시스템을 참조시킨다.
#docker run -it -v /test:/container_dr ubuntu /bin/bash