Docker가 데이터를 저장하는 위치와 방법, 그리고 컨테이너의 파일 시스템을 관리하는 방법을 살펴보겠습니다. Docker가 로컬 파일 시스템에 데이터를 저장하는 방법부터 살펴봅시다. 시스템에 Docker를 설치하면 /var/lib/docker/에 이 폴더 구조가 생성됩니다.
cd /var/lib/docker/
그 아래에는 aufs, 컨테이너, 이미지, 볼륨 등 여러 폴더가 있습니다. 도커가 default로 모든 데이터를 저장하는 곳입니다. 데이터라고 하면 Docker 호스트에서 실행되는 이미지 및 컨테이너와 관련된 파일을 의미합니다. 예를 들어 컨테이너와 관련된 모든 파일은 컨테이너 폴더 아래에 저장되고 이미지와 관련된 파일은 이미지 폴더 아래에 저장됩니다. 도커 컨테이너에 의해 생성된 모든 볼륨은 볼륨 폴더 아래에 생성됩니다. 이것에 대해서는 조금 후에 다시 이야기 하고, 지금은 Docker가 파일을 저장하는 위치와 형식을 이해하겠습니다.
그렇다면 Dockers는 이미지와 컨테이너의 파일을 정확히 어떻게 저장할까요? 이를 이해하려면 Docker의 계층화된 아키텍처를 이해해야 합니다. 전에 배운 내용을 빠르게 요약해 보겠습니다. Docker가 이미지를 빌드할 때 계층화된 아키텍처에서 이미지를 빌드합니다. Docker 파일의 각 지침 라인은 이전 레이어의 변경 사항만으로 Docker 이미지에 새 레이어를 생성합니다.
예를 들어, Layer 1은 base Ubuntu 운영 체제이고, 두 번째 커맨드는 모든 APT 패키지를 설치하는 Layer 2를 생성한 다음 세 번째 커맨드는 Python 패키지로 Layer 3를 생성합니다. 소스 코드를 복사하는 Layer 4와 마지막으로 이미지의 entry point을 업데이트하는 Layer 5가 이어집니다. 각 레이어는 이전 레이어의 변경 사항만 저장하므로 크기에도 반영됩니다. base Ubuntu 이미지를 보면 크기가 약 120MB입니다. 설치하는 APT 패키지는 약 300MB이고 나머지 레이어는 작습니다.
이 계층화된 아키텍처의 이점을 이해하기 위해 두 번째 애플리케이션을 고려해 보겠습니다.
이 애플리케이션은 다른 도커 파일이 있습니다. Ubuntu와 동일한 base 이미지를 사용하고 동일한 Python 및 플라스크 종속성을 사용한다는 점에서 첫 번째 애플리케이션과 매우 유사합니다. 그러나 다른 소스 코드를 사용하여 다른 애플리케이션을 생성하고, 다른 entry point가 있습니다. 이 애플리케이션의 새 이미지를 빌드하기 위해 Docker build 커맨드를 실행할 때 두 애플리케이션의 처음 세 계층이 동일하기 때문에 Docker는 처음 세 계층을 빌드하지 않습니다. 대신 캐시에서 첫 번째 애플리케이션용으로 구축한 것과 동일한 3개 계층을 재사용합니다. 그리고 새 소스와 새 entry point으로 마지막 두 레이어만 생성합니다. 이러한 방식으로 Docker는 이미지를 더 빠르게 빌드하고 디스크 공간을 효율적으로 절약합니다. 이는 애플리케이션 코드를 업데이트하는 경우에도 적용됩니다. 이 경우 app.py와 같은 애플리케이션 코드를 업데이트할 때마다 Docker는 캐시에서 이전 레이어를 모두 재사용하고 최신 소스 코드를 업데이트하여 애플리케이션 이미지를 신속하게 다시 빌드합니다. 따라서 재구축 및 업데이트 중에 많은 시간을 절약할 수 있습니다. 더 잘 이해할 수 있도록 레이어를 아래에서 위로 재정렬해 봅시다.
맨 아래에는 base 우분투 레이어가 있고, 그 위에 패키지, 종속성, 애플리케이션의 소스 코드, entry point이 있습니다. 이러한 모든 레이어는 최종 도커 이미지를 형성하기 위해 docker build 커맨드를 실행할 때 생성됩니다. 이것들은 모두 도커 이미지 레이어입니다. 빌드가 완료되면 이러한 레이어의 내용을 수정할 수 없습니다. 따라서 읽기 전용이며 새 빌드를 시작해야만 수정할 수 있습니다.
docker run 커맨드를 사용하여 이 이미지를 기반으로 컨테이너를 실행하면 Docker는 이러한 레이어를 기반으로 컨테이너를 만들고 이미지 레이어 위에 쓰기 가능한 새 레이어를 만듭니다.
이 writeable layer는 애플리케이션이 작성한 로그 파일, 컨테이너가 생성한 임시 파일 또는 해당 컨테이너에서 사용자가 수정한 파일과 같이 컨테이너가 생성한 데이터를 저장하는 데 사용됩니다. 하지만 이 레이어의 수명은 컨테이너가 살아있는 동안만 지속됩니다. 컨테이너가 소멸되면 이 레이어와 여기에 저장된 모든 변경 사항도 함께 소멸됩니다. 이 이미지를 사용하여 생성된 모든 컨테이너는 동일한 이미지 레이어를 공유합니다. 새로 생성된 컨테이너에 로그인하고 temp.txt라는 새 파일을 생성한다고 말하면 컨테이너 레이어에 읽기 및 쓰기가 가능한 해당 파일이 생성됩니다.
이미지 레이어의 파일은 읽기 전용이므로 해당 레이어의 어떤 것도 편집할 수 없습니다. 애플리케이션 코드의 예를 들어 보겠습니다. 코드를 이미지에 bake하기 때문에 코드는 이미지 레이어의 일부이며 컨테이너를 실행하고 나서는 읽기 전용입니다. 변경 사항을 테스트하기 위해 소스 코드를 수정하려면 어떻게 해야 할까요? 이 이미지에서 생성된 여러 컨테이너 간에 동일한 이미지 레이어를 공유할 수 있습니다. 그렇다면 컨테이너 내에서 이 파일을 수정할 수 없다는 의미일까요? 아니요, 여전히 이 파일을 수정할 수 있지만, 수정된 파일을 저장하기 전에 Docker가 자동으로 읽기 쓰기 레이어에 파일 복사본을 생성하고 읽기 쓰기 레이어에서 파일의 다른 버전을 수정하게 됩니다. 이후의 모든 수정은 읽기 쓰기 레이어에 있는 파일의 이 복사본에서 수행됩니다. 이것을 copy on write mechanism이라고 합니다. 이미지 레이어가 읽기 전용이라는 것은 이러한 레이어의 파일이 이미지 자체에서 수정되지 않음을 의미합니다. 따라서 이미지는 docker build 커맨드를 사용하여 이미지를 다시 빌드할 때까지 항상 동일하게 유지됩니다.
컨테이너를 제거하면 어떻게 될까요? 컨테이너 레이어에 저장된 모든 데이터도 삭제됩니다. 우리가 앱에 적용한 변경 사항과 우리가 만든 새 임시 파일도 제거됩니다. 이 데이터를 유지하려면 어떻게 해야 할까요? 예를 들어 데이터베이스로 작업 중이고 컨테이너에서 생성된 데이터를 보존하려는 경우 persistent volume을 컨테이너에 추가할 수 있습니다.
$ docker volume create data_volume
$ ls -l /var/lib/docker/volumes/
drwxr-xr-x 3 root root 4096 Aug 01 17:53 data_volume
$ docker volume ls
DRIVER VOLUME NAME
local data_volume
이렇게 하려면 먼저 docker volume create 커맨드를 사용하여 볼륨을 만듭니다. docker volume create data_volume 커맨드를 실행하면 var/lib/docker/volumes 디렉토리 아래에 data_volume이라는 폴더가 생성됩니다.
docker run -v data_volume:/var/lib/mysql mysql
그런 다음 docker run 커맨드를 사용하여 docker 컨테이너를 실행할 때 이와 같이 -v 옵션을 사용하여 docker containers rewrite 레이어 내부에 이 볼륨을 마운트할 수 있습니다. docker run -v를 실행한 다음 새로 생성된 볼륨 이름 뒤에 콜론과 mysql이 데이터를 저장하는 default 위치인 내 컨테이너 내부의 위치를 지정하고 (/var/lib/mysql/)과 이미지 이름(mysql)을 지정합니다. 이렇게 하면 새 컨테이너가 생성되고 컨테이너 내부의 /var/lib/mysql/ 폴더에 생성한 데이터 볼륨이 마운트됩니다. 따라서 데이터베이스에서 작성한 모든 데이터는 실제로 Docker 호스트에서 생성된 볼륨에 저장됩니다. 컨테이너가 파괴되더라도 데이터는 여전히 활성 상태입니다.
예를 들어 Docker run 커맨드를 실행하여 아직 생성하지 않은 data_volume2 볼륨으로 mysql 컨테이너의 새 인스턴스를 생성하면 Docker는 자동으로 데이터 data_volume2라는 볼륨을 생성하고 컨테이너에 마운트합니다. /var/lib/docker볼륨 폴더의 내용을 조회하면 이러한 모든 볼륨을 볼 수 있어야 합니다. /var/lib/docker 볼륨 폴더 아래에 Docker가 생성한 볼륨을 마운트하므로 이를 volume mounting이라고 합니다.
하지만 데이터가 이미 다른 위치에 있다면 어떻게 될까요? 예를 들어 /data의 Docker 호스트에 일부 외부 저장소가 있고 default /var/lib/docker 볼륨 폴더가 아닌 /data 볼륨에 데이터베이스 데이터를 저장하려고 한다고 가정해 보겠습니다. 이 경우 Docker run -v 커맨드를 사용하여 컨테이너를 실행하지만 이 경우 마운트하려는 폴더의 전체 경로를 제공합니다. 그것은 /data/mysql:/data이므로 컨테이너를 만들고 폴더를 컨테이너에 마운트합니다. 이것을 바인드 마운팅이라고 합니다.
따라서 마운트에는 두 가지 유형이 있습니다. 볼륨 마운팅과 바인드 마운트입니다. 볼륨 마운트는 볼륨 디렉토리에서 볼륨을 마운트하고 바인드 마운트는 Docker 호스트의 모든 위치에서 디렉토리를 마운트합니다.
마지막으로 포인트 하나를 짚고 가겠습니다. -v를 사용하는 것은 오래된 스타일입니다. 새로운 방법은 --mount 옵션을 사용하는 것입니다. --mount는 각 파라미터를 키와 값 형식으로 지정할 수 있으므로 선호되는 방법입니다. 예를 들어 이전 커맨드는 type source 및 target 옵션을 사용하여 이와 같이 --mount 옵션으로 작성할 수 있습니다.
$ docker run --mount type=bind,source=/data/mysql,target=/var/lib/mysql mysql
docker run -v data_volume2:/var/lib/mysql mysql
$ docker volume ls
DRIVER VOLUME NAME
local data_volume
local data_volume2
예를 들어 Docker run 커맨드를 실행하여 아직 생성하지 않은 data_volume2 볼륨으로 mysql 컨테이너의 새 인스턴스를 생성하면 Docker는 자동으로 데이터 data_volume2라는 볼륨을 생성하고 컨테이너에 마운트합니다. /var/lib/docker볼륨 폴더의 내용을 조회하면 이러한 모든 볼륨을 볼 수 있어야 합니다. /var/lib/docker 볼륨 폴더 아래에 Docker가 생성한 볼륨을 마운트하므로 이를 volume mounting이라고 합니다.
하지만 데이터가 이미 다른 위치에 있다면 어떻게 될까요? 예를 들어 /data의 Docker 호스트에 일부 외부 저장소가 있고 default /var/lib/docker 볼륨 폴더가 아닌 /data 볼륨에 데이터베이스 데이터를 저장하려고 한다고 가정해 보겠습니다. 이 경우 Docker run -v 커맨드를 사용하여 컨테이너를 실행하지만 이 경우 마운트하려는 폴더의 전체 경로를 제공합니다. 그것은 /data/mysql:/data이므로 컨테이너를 만들고 폴더를 컨테이너에 마운트합니다. 이것을 바인드 마운팅이라고 합니다.
따라서 마운트에는 두 가지 유형이 있습니다. 볼륨 마운팅과 바인드 마운트입니다. 볼륨 마운트는 볼륨 디렉토리에서 볼륨을 마운트하고 바인드 마운트는 Docker 호스트의 모든 위치에서 디렉토리를 마운트합니다.
마지막으로 포인트 하나를 짚고 가겠습니다. -v를 사용하는 것은 오래된 스타일입니다. 새로운 방법은 --mount 옵션을 사용하는 것입니다. --mount는 각 파라미터를 키와 값 형식으로 지정할 수 있으므로 선호되는 방법입니다. 예를 들어 이전 커맨드는 type source 및 target 옵션을 사용하여 이와 같이 --mount 옵션으로 작성할 수 있습니다.
$ mkdir -p /data/mysql
$ docker run --mount type=bind,source=/data/mysql,target=/var/lib/mysql mysql
이 경우 유형은 바인드입니다. 소스는 내 호스트의 위치이고 대상은 내 컨테이너의 위치입니다. 그렇다면 이러한 모든 작업을 담당하는 것은 누구인가요? 계층화된 아키텍처 유지, 쓰기 가능한 계층 생성, 계층 간 파일 이동을 통해 복사 및 쓰기 등도 가능하게 하는 것은 바로 스토리지 드라이버입니다. 따라서 Docker는 스토리지 드라이버를 사용하여 계층화된 아키텍처를 활성화합니다.
일반적인 스토리지 드라이버 중 일부는 아래와 같습니다.
스토리지 드라이버의 선택은 사용 중인 underlying OS에 따라 다릅니다. 예를 들어 Ubuntu의 경우 default 스토리지 드라이버는 AUFS인 반면 이 스토어의 드라이버는 Fedora 또는 Cent OS와 같은 다른 운영 체제에서 사용할 수 없습니다. 이 경우 Device Mapper
가 더 나은 옵션일 수 있습니다. Docker는 OS를 기반으로 자동으로 사용 가능한 최상의 스토리지 드라이버를 선택합니다. 다른 스토리지 드라이버는 또한 다른 성능 및 안정성 특성을 제공합니다.따라서 애플리케이션과 조직의 요구 사항에 맞는 것을 선택하는 것이 좋습니다. 이러한 스토리 드라이버에 대해 자세히 알아보려면 첨부된 설명서의 링크를 참조하십시오. 지금은 이것이 모두 Docker 아키텍처 개념에서 나온 것입니다.
이전 강의에서 스토리지 드라이버에 대해 논의했습니다. 스토리지 드라이버는 이미지 및 컨테이너의 저장소를 관리하는 데 도움이 됩니다. 우리는 또한 이전 강의에서 볼륨에 대해 간략하게 다루었습니다. 스토리지를 유지하려면 볼륨을 생성해야 한다는 것을 배웠습니다. 볼륨은 스토리지 드라이버에 의해 처리되지 않는다는 점을 기억하세요.
볼륨은 볼륨 드라이버 플러그인에 의해 처리됩니다. default 볼륨 드라이버 플러그인은 로컬입니다. 로컬 볼륨 플러그인은 Docker 호스트에서 볼륨을 생성하고 해당 데이터를 var/lib/docker volumes 디렉토리 아래에 저장하는 데 도움이 됩니다.
타사 솔루션에 볼륨을 생성할 수 있는 여러 볼륨 드라이버 플러그인이 있습니다. Azure file storage, Convoy, DigitalOcean, Block Storage, Flocker, Google Compute Persistent Disks, Cluster FS, NetApp, REX-Ray, Portworx, 및 VMware vSphere 스토리지 등입니다. 이들은 많은 것 중 일부에 불과합니다.
이러한 볼륨 드라이버 중 일부는 다른 스토리지 공급자를 지원합니다. 예를 들어 REX-Ray 스토리지 드라이버를 사용하여 AWS EBS, S3, Isilon 및 ScaleIO와 같은 EMC 스토리지 어레이, Google Persistent Disk 또는 OpenStack Cinder에 스토리지를 프로비저닝할 수 있습니다.
Docker 컨테이너를 실행할 때 REX-Ray EBS와 같은 특정 볼륨 드라이버를 사용하여 Amazon EBS에서 볼륨을 프로비저닝하도록 선택할 수 있습니다. 이렇게 하면 컨테이너가 생성되고 AWS 클라우드에서 볼륨이 연결됩니다. 컨테이너가 종료되면 데이터는 클라우드에 안전하게 보관됩니다.