컨테이너 파일 시스템 관리

Beginner

This tutorial is from open-source community. Access the source code

소개

기본적으로 컨테이너 내에서 생성된 모든 파일은 쓰기 가능한 컨테이너 레이어에 저장됩니다. 이는 다음을 의미합니다.

  • 컨테이너가 더 이상 존재하지 않으면 데이터가 손실됩니다.
  • 컨테이너의 쓰기 가능한 레이어는 호스트 머신에 긴밀하게 연결되어 있습니다.
  • 파일 시스템을 관리하려면 Linux 커널을 사용하여 유니온 파일 시스템을 제공하는 스토리지 드라이버가 필요합니다. 이 추가적인 추상화는 파일 시스템에 직접 쓰는 data volumes에 비해 성능을 저하시킵니다.

Docker 는 호스트 머신에 파일을 저장하기 위한 두 가지 옵션, volumesbind mounts를 제공합니다. Linux 에서 Docker 를 실행하는 경우 tmpfs mount를 사용할 수도 있으며, Windows 에서 Docker 를 실행하는 경우 named pipe를 사용할 수도 있습니다.

Types of Mounts
  • Volumes는 Docker 가 관리하는 호스트 파일 시스템에 저장됩니다.
  • Bind mounts는 호스트 시스템의 어느 곳에나 저장됩니다.
  • tmpfs mounts는 호스트 메모리에만 저장됩니다.

원래, --mount 플래그는 Docker Swarm 서비스에 사용되었고, --volume 플래그는 독립 실행형 컨테이너에 사용되었습니다. Docker 17.06 이상부터는 독립 실행형 컨테이너에도 --mount를 사용할 수 있으며, 일반적으로 --volume보다 더 명시적이고 자세합니다.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 초급 레벨의 실험이며 완료율은 100%입니다.학습자들로부터 100%의 긍정적인 리뷰율을 받았습니다.

볼륨 (Volumes)

data volume 또는 volume은 Docker 의 Union File System을 우회하는 디렉토리입니다.

볼륨에는 세 가지 유형이 있습니다.

  • 익명 볼륨 (anonymous volume),
  • 명명된 볼륨 (named volume), 그리고
  • 호스트 볼륨 (host volume).

익명 볼륨 (Anonymous Volume)

인기 있는 오픈 소스 NoSQL 데이터베이스인 CouchDB 의 인스턴스를 생성하고 익명 볼륨을 사용하여 데이터베이스의 데이터 파일을 저장해 보겠습니다.

CouchDB 의 인스턴스를 실행하려면 https://hub.docker.com/_/couchdb에서 Docker Hub 의 CouchDB 이미지를 사용하십시오. 문서에 따르면 CouchDB 의 기본값은 자체 내부 볼륨 관리를 사용하여 호스트 시스템의 디스크에 데이터베이스 파일을 쓰는 것입니다.

다음 명령을 실행합니다.

docker run -d -p 5984:5984 --name my-couchdb -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=passw0rd1 couchdb:3.1

CouchDB 는 익명 볼륨을 생성하고 해시된 이름을 생성합니다. 호스트 시스템에서 볼륨을 확인합니다.

labex:~/ $ docker volume ls
DRIVER VOLUME NAME
local 1d292aca855adb9de9be7acea88f6d3f8e6a08eef5bfd986a81f073f1906b82f

생성된 이름의 값을 사용하여 환경 변수 VOLUME을 설정합니다.

export VOLUME=<VOLUME NAME>

생성된 볼륨을 검사하려면 볼륨에 대해 생성된 해시 이름을 사용합니다.

$ docker volume inspect $VOLUME
[
{
  "CreatedAt": "2020-09-24T14:10:07Z",
  "Driver": "local",
  "Labels": null,
  "Mountpoint": "/var/lib/docker/volumes/f543c5319ebd96b7701dc1f2d915f21b095dfb35adbb8dc851630e098d526a50/_data",
  "Name": "f543c5319ebd96b7701dc1f2d915f21b095dfb35adbb8dc851630e098d526a50",
  "Options": null,
  "Scope": "local"
}
]

Docker 가 /var/lib/docker/volumes/$VOLUME_NAME/_data 아래의 Docker 호스트 파일 시스템에 볼륨을 생성하고 관리하는 것을 볼 수 있습니다. 이는 호스트 머신의 경로가 아니라 Docker 가 관리하는 파일 시스템의 일부입니다.

새 데이터베이스 mydb를 생성하고 hello world 메시지가 있는 새 문서를 삽입합니다.

curl -X PUT -u admin:passw0rd1 http://127.0.0.1:5984/mydb
curl -X PUT -u admin:passw0rd1 http://127.0.0.1:5984/mydb/1 -d '{"msg": "hello world"}'

컨테이너를 중지하고 다시 시작합니다.

docker stop my-couchdb
docker start my-couchdb

데이터가 지속되었는지 테스트하기 위해 데이터베이스에서 문서를 검색합니다.

curl -X GET -u admin:passw0rd1 http://127.0.0.1:5984/mydb/_all_docs
curl -X GET -u admin:passw0rd1 http://127.0.0.1:5984/mydb/1

출력:

## $ curl -X GET -u admin:passw0rd1 http://127.0.0.1:5984/mydb/_all_docs
{"total_rows":1,"offset":0,"rows":[
{"id":"1","key":"1","value":{"rev":"1-c09289617e06b96bc747fb1201fea7f1"}}
]}

## $ curl -X GET -u admin:passw0rd1 http://127.0.0.1:5984/mydb/1
{"_id":"1","_rev":"1-c09289617e06b96bc747fb1201fea7f1","msg":"hello world"}

볼륨 공유 (Sharing Volumes)

--volumes-from 옵션을 사용하여 익명 볼륨을 다른 컨테이너와 공유할 수 있습니다.

익명 볼륨이 컨테이너의 /data 디렉토리에 마운트된 busybox 컨테이너를 생성하고 셸 명령을 사용하여 로그 파일에 메시지를 씁니다.

$ docker run -it --name busybox1 -v /data busybox sh
/ ## echo "hello from busybox1" > /data/hi.log
/ ## ls /data
hi.log
/ ## exit

busybox1 컨테이너가 중지되었지만 제거되지 않았는지 확인합니다.

labex:~/ $ docker ps -a | grep busybox1
f4dbf9ee7513   busybox                               "sh"                     2 minutes ago   Exited (0) About a minute ago                                                                                                                                          busybox1

그런 다음 --volumes-from 옵션을 사용하여 busybox1에서 생성된 볼륨을 공유하는 busybox2라는 두 번째 busybox 컨테이너를 생성합니다.

$ docker run --rm -it --name busybox2 --volumes-from busybox1 busybox sh
/ ## ls -al /data
total 12
drwxr-xr-x 2 root root 4096 Jan 23 07:20 .
drwxr-xr-x 1 root root 4096 Jan 23 07:24 ..
-rw-r--r-- 1 root root 20 Jan 23 07:20 hi.log
/ ## cat /data/hi.log
hello from busybox1
/ ## exit

Docker 는 --volumes-from 옵션을 사용하여 공유할 수 있었던 익명 볼륨을 생성하고 새 익명 볼륨을 생성했습니다.

labex:~/ $ docker volume ls
DRIVER VOLUME NAME
local 0f971b2477d5fc0d0c2b31fc908ee59d6b577b4887e381964650ce6853890dc9
local 1d292aca855adb9de9be7acea88f6d3f8e6a08eef5bfd986a81f073f1906b82f

기존 볼륨과 컨테이너를 정리합니다.

docker stop my-couchdb
docker rm my-couchdb
docker rm busybox1
docker volume rm $(docker volume ls -q)
docker system prune -a
clear

명명된 볼륨 (Named Volume)

명명된 볼륨익명 볼륨은 Docker 가 위치를 관리한다는 점에서 유사합니다. 그러나 명명된 볼륨은 컨테이너 디렉토리에 마운트할 때 이름으로 참조할 수 있습니다. 이는 여러 컨테이너에서 볼륨을 공유하려는 경우에 유용합니다.

먼저 명명된 볼륨을 생성합니다.

docker volume create my-couchdb-data-volume

볼륨이 생성되었는지 확인합니다.

$ docker volume ls
DRIVER VOLUME NAME
local my-couchdb-data-volume

이제 명명된 볼륨을 사용하여 my-couchdb-name-vol이라는 CouchDB 컨테이너를 생성합니다.

docker run -d -p 59840:5984 --name my-couchdb-name-vol -v my-couchdb-data-volume:/opt/couchdb/data -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=passw0rd1 couchdb:3.1

CouchDB 컨테이너가 실행되고 인스턴스를 사용할 수 있을 때까지 기다립니다.

새 데이터베이스 mydb를 생성하고 hello world 메시지가 있는 새 문서를 삽입합니다.

curl -X PUT -u admin:passw0rd1 http://127.0.0.1:59840/mydb
curl -X PUT -u admin:passw0rd1 http://127.0.0.1:59840/mydb/1 -d '{"msg": "hello world"}'

이제 다른 컨테이너와 볼륨을 쉽게 공유할 수 있습니다. 예를 들어 busybox 이미지를 사용하여 볼륨의 내용을 읽고 my-couchdb-data-volume 볼륨을 busybox 컨테이너의 디렉토리에 마운트하여 공유합니다.

labex:~/ $ docker run --rm -it --name busybox -v my-couchdb-data-volume:/myvolume busybox sh
/ #
/ ## ls -al /myvolume
total 40
drwxr-xr-x 4 5984 5984 4096 Jan 23 07:30 .
drwxr-xr-x 1 root root 4096 Jan 23 07:31 ..
drwxr-xr-x 2 5984 5984 4096 Jan 23 07:29 .delete
-rw-r--r-- 1 5984 5984 8388 Jan 23 07:30 _dbs.couch
-rw-r--r-- 1 5984 5984 8385 Jan 23 07:29 _nodes.couch
drwxr-xr-x 4 5984 5984 4096 Jan 23 07:30 shards
/ ## exit

특권 권한으로 busybox 컨테이너를 실행하고 프로세스 ID 를 host로 설정하여 호스트 시스템을 검사하고 Docker 관리 디렉토리를 탐색하여 볼륨에 대한 Docker 관리 파일 시스템을 확인할 수 있습니다.

docker run -it --privileged --pid=host busybox nsenter -t 1 -m -u -n -i sh
/ ## ls -l /var/lib/docker/volumes
total 28
-rw------- 1 root root 32768 Nov 10 15:54 metadata.db
drwxr-xr-x 3 root root 4096 Nov 10 15:54 my-couchdb-data-volume
/ ## exit

정리,

docker stop my-couchdb
docker rm my-couchdb
docker volume rm my-couchdb-data-volume
docker system prune -a
docker volume prune
clear

호스트 볼륨 (Host Volume)

Docker 관리 디렉토리를 사용하는 대신 호스트 머신에서 볼륨 디렉토리에 직접 쉽게 액세스하려는 경우 호스트 볼륨을 생성할 수 있습니다.

현재 작업 디렉토리 (명령 pwd로 표시됨) 의 data라는 디렉토리를 사용하거나 호스트 머신에서 자체 데이터 디렉토리 (예: /home/couchdb/data) 를 선택합니다. docker 가 아직 존재하지 않는 경우 $(pwd)/data 디렉토리를 생성하도록 합니다. CouchDB 의 기본 데이터 디렉토리인 CouchDB 컨테이너 내의 호스트 볼륨을 컨테이너 디렉토리 /opt/couchdb/data에 마운트합니다.

다음 명령을 실행합니다.

cd /home/labex/project
docker run -d -p 5984:5984 --name my-couchdb -v $(pwd)/data:/opt/couchdb/data -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=passw0rd1 couchdb:3.1

data 디렉토리가 생성되었는지 확인합니다.

$ ls -al
total 20
drwxrwxr-x 3 labex labex 4096 Aug 29 14:14 .
drwxr-x--- 25 labex labex 4096 Aug 29 14:14 ..
drwxr-xr-x 3 5984 5984 4096 Aug 29 14:14 data

그리고 CouchDB 가 여기에 데이터 파일을 생성했는지 확인합니다.

$ ls -al data
total 32
drwxr-xr-x 3 5984 5984 4096 Aug 29 14:14 .
drwxrwxr-x 3 labex labex 4096 Aug 29 14:14 ..
-rw-r--r-- 1 5984 5984 4257 Aug 29 14:14 _dbs.couch
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:14 .delete
-rw-r--r-- 1 5984 5984 8385 Aug 29 14:14 _nodes.couch

또한 이제 호스트 볼륨을 사용하고 있으므로 docker 에서 관리하는 볼륨이 생성되지 않았는지 확인합니다.

docker volume ls

그리고

docker run -it --privileged --pid=host busybox nsenter -t 1 -m -u -n -i sh
sh-5.1## ls -l /var/lib/docker/volumes
total 28
brw------- 1 root root 252, 3 Jan 23 15:15 backingFsBlockDev
-rw------- 1 root root 32768 Jan 23 15:33 metadata.db
drwx-----x 3 root root 4096 Jan 23 15:26 my-couchdb-data-volume
sh-5.1## exit

새 데이터베이스 mydb를 생성하고 hello world 메시지가 있는 새 문서를 삽입합니다.

curl -X PUT -u admin:passw0rd1 http://127.0.0.1:5984/mydb
curl -X PUT -u admin:passw0rd1 http://127.0.0.1:5984/mydb/1 -d '{"msg": "hello world"}'

CouchDB 가 shards 폴더를 생성했음을 참고하십시오.

$ ls -al data
total 40
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15 .
drwxrwxr-x 3 labex labex 4096 Aug 29 14:14 ..
-rw-r--r-- 1 5984 5984 8388 Aug 29 14:15 _dbs.couch
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:14 .delete
-rw-r--r-- 1 5984 5984 8385 Aug 29 14:14 _nodes.couch
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15 shards

shards 디렉토리의 내용을 나열합니다.

$ ls -al data/shards
total 16
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15 .
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15 ..
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:15 00000000-7fffffff
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:15 80000000-ffffffff

그리고 첫 번째 샤드 (shard) 를 나열합니다.

$ ls -al data/shards/00000000-7fffffff/
total 20
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:15 .
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15 ..
-rw-r--r-- 1 5984 5984 8346 Aug 29 14:15 mydb.1693289721.couch

샤드 (shard)는 데이터베이스의 데이터 수평 분할입니다. 데이터를 샤드로 분할하고 각 샤드의 복사본을 클러스터의 서로 다른 노드에 배포하면 노드 손실에 대한 데이터 내구성이 향상됩니다. CouchDB 는 자동으로 데이터베이스를 샤딩하고 문서의 하위 집합을 노드 간에 배포합니다.

정리,

docker stop my-couchdb
docker rm my-couchdb
sudo rm -rf $(pwd)/data
docker system prune -a

바인드 마운트 (Bind Mounts)

mount 구문은 volume 구문보다 Docker 에서 권장됩니다. 바인드 마운트는 볼륨에 비해 기능이 제한적입니다. 파일 또는 디렉토리는 컨테이너에 마운트될 때 호스트 머신에서 전체 경로로 참조됩니다. 바인드 마운트는 호스트 머신의 파일 시스템에 특정 디렉토리 구조가 있어야 하며 Docker CLI 를 사용하여 바인드 마운트를 관리할 수 없습니다. 바인드 마운트는 컨테이너에서 실행되는 프로세스를 통해 호스트 파일 시스템을 변경할 수 있습니다.

콜론 구분자 (:) 로 구분된 세 개의 필드를 사용하는 -v 구문 대신, mount 구문은 더 자세하며 여러 key-value 쌍을 사용합니다.

  • type: bind, volume 또는 tmpfs,
  • source: 호스트 머신의 파일 또는 디렉토리 경로,
  • destination: 컨테이너 내 경로,
  • readonly,
  • bind-propagation: rprivate, private, rshared, shared, rslave, slave,
  • consistency: consistent, delegated, cached,
  • mount.
cd /home/labex/project
mkdir data
docker run -it --name busybox --mount type=bind,source="$(pwd)"/data,target=/data busybox sh

컨테이너에서 명령을 입력합니다.

echo "hello busybox" > /data/hi.txt
exit

파일이 호스트 머신에 생성되었는지 확인합니다.

cat data/hi.txt

[선택 사항] OverlayFS

OverlayFS 는 Linux 용 union mount filesystem 구현입니다. Docker 볼륨이 무엇인지 이해하려면 Docker 에서 레이어와 파일 시스템이 어떻게 작동하는지 이해하는 것이 도움이 됩니다.

컨테이너를 시작하기 위해 Docker 는 읽기 전용 이미지를 가져와 그 위에 새로운 읽기 - 쓰기 레이어를 생성합니다. 레이어를 하나로 보려면 Docker 는 Union File System 또는 OverlayFS(Overlay File System), 특히 overlay2 스토리지 드라이버를 사용합니다.

Docker 호스트 관리 파일을 보려면 Docker 프로세스 파일 시스템에 액세스해야 합니다. --privileged--pid=host 플래그를 사용하면 busybox와 같은 컨테이너 내부에서 호스트의 프로세스 ID 네임스페이스에 액세스할 수 있습니다. 그런 다음 Docker 의 /var/lib/docker/overlay2 디렉토리로 이동하여 Docker 에서 관리하는 다운로드된 레이어를 볼 수 있습니다.

Docker 에서 현재 레이어 목록을 보려면,

$ docker run -it --privileged --pid=host busybox nsenter -t 1 -m -u -n -i sh

/ ## ls -l /var/lib/docker/overlay2
total 16
drwx------ 3 root root 4096 Sep 25 19:44 0e55ecaa4d17c353191e68022d9a17fde64fb5e9217b07b5c56eb4c74dad5b32
drwx------ 5 root root 4096 Sep 25 19:44 187854d05ccd18980642e820b0d2be6a127ba85d8ed96315bb5ae37eb1add36d
drwx------ 4 root root 4096 Sep 25 19:44 187854d05ccd18980642e820b0d2be6a127ba85d8ed96315bb5ae37eb1add36d-init
drwx------ 2 root root 4096 Sep 25 19:44 l

/ ## exit

ubuntu 이미지를 다운로드하고 다시 확인합니다.

docker pull ubuntu
docker run -it --privileged --pid=host busybox nsenter -t 1 -m -u -n -i sh

레이어 목록을 다시 보려면 명령을 입력합니다.

ls -l /var/lib/docker/overlay2/ & exit

ubuntu 이미지를 다운로드하면 암묵적으로 4 개의 새로운 레이어가 다운로드된 것을 볼 수 있습니다.

  • a611792b4cac502995fa88a888261dfba0b5d852e72f9db9e075050991423779
  • d181f1a41fc35a45c16e8bfcb8eee6f768f3b98f82210a43ea65f284a45fcd65
  • dac2f37f6280a076836d39b87b0ae5ebf5c0d386b6d8b991b103aadbcebaa7c6
  • f3e921b440c37c86d06cd9c9fb70df50edad553c36cc87f84d5eeba734aae709

본질적으로 overlay2 스토리지 드라이버는 호스트의 서로 다른 디렉토리를 계층화하고 단일 디렉토리로 표시합니다.

  • base layer 또는 lowerdir,
  • diff layer 또는 upperdir,
  • overlay layer (사용자 보기), 그리고
  • work dir.

OverlayFS 는 하위 디렉토리를 기본 이미지와 다운로드된 읽기 전용 (R/O) 레이어가 포함된 lowerdir로 참조합니다.

상위 디렉토리는 upperdir이라고 하며 읽기 - 쓰기 (R/W) 컨테이너 레이어입니다.

통합 보기 또는 overlay 레이어는 merged라고 합니다.

마지막으로, workdir은 오버레이에서 내부적으로 사용되는 빈 디렉토리입니다.

overlay2 드라이버는 최대 128 개의 하위 OverlayFS 레이어를 지원합니다. l 디렉토리에는 단축된 레이어 식별자가 심볼릭 링크로 포함되어 있습니다.

Overlay2 Storage Driver

정리,

docker system prune -a
clear

요약

이 랩에서는 volumesbind mounts를 사용하여 컨테이너에서 데이터를 관리하는 방법을 배웠습니다. 또한 overlay2 스토리지 드라이버와 union file system을 사용하여 레이어를 관리하는 방법에 대해서도 배웠습니다.