오늘은 평소와 달리 비교적 짧고 간단한 주제, 바로 도커(Docker) 컨테이너 자동화 프레임워크의 데이터 볼륨에 대해 다뤄보겠습니다. 컨테이너 내부에 데이터를 마운트하는 방법, 여러 컨테이너 간에 데이터를 공유하는 방법 등 인스턴스를 실질적으로 유용한 시스템으로 만들기 위해 꼭 알아야 할 핵심 내용들을 정리했습니다.
지금까지 상세한 입문 가이드부터 서비스 구성, 네트워킹, 그리고 까다로운 오류 해결 과정까지 함께 살펴봤습니다. 이번 튜토리얼 역시 지금까지의 전통을 이어받아, 한 단계씩 차근차근 진행하므로 누구나 쉽고 명확하게 따라올 수 있습니다. 그럼 시작해 보겠습니다.
데이터 볼륨 마운트의 기본
호스트의 데이터를 컨테이너 내부로 노출하는 과정은 생각보다 간단하며, 리눅스의 mount 명령과 매우 유사합니다. 소스가 될 디렉터리(또는 파일)와 대상이 될 디렉터리(또는 파일)를 지정하기만 하면 됩니다. 호스트 쪽과 컨테이너 쪽으로 구성된다는 점에서 포트 매핑 방식과도 닮았습니다.
docker run -it -v /root/testing:/dedoimedo centos:latest /bin/bash
위 명령은 Bash 셸로 새 컨테이너를 실행하면서, 호스트의 /root/testing 디렉터리를 컨테이너 내부의 /dedoimedo 경로에 마운트합니다. 호스트 쪽 소스는 어떤 경로든 지정할 수 있고, NFS 마운트도 포함되므로 원격 데이터 공유 환경처럼 활용할 수도 있습니다.
컨테이너에 들어간 뒤 /dedoimedo 디렉터리의 내용을 확인해 보면 됩니다. 그런데 표준 기본 설정의 CentOS(이번 테스트 환경)에서는 다음과 같은 오류를 만나게 될 가능성이 높습니다.
ls
ls: cannot open directory .: Permission denied
원인은 바로 보안 기능, 즉 SELinux입니다. 다행히 이 문제는 해결할 수 있습니다. 강제(enforcing) 정책 자체를 변경하거나, 컨테이너가 마운트된 볼륨에 접근할 수 있도록 새로운 규칙을 추가하면 됩니다.
setenforce 0
규칙을 직접 추가하고 싶다면 아래와 같이 실행합니다.
chcon -Rt svirt_sandbox_file_t /<volume>
이제 디렉터리 내용이 정상적으로 보이며, 파일 생성과 수정 등 본격적인 작업을 시작할 수 있습니다. 호스트에서 마운트된 디렉터리에 새 파일을 만들어 보면 컨테이너 쪽에서도 즉시 확인할 수 있어, 양방향 데이터 연동이 제대로 동작한다는 것을 알 수 있습니다.
컨테이너 간 데이터 공유
네트워킹에서 했던 것처럼, 하나의 컨테이너에 있는 데이터를 다른 컨테이너들에 노출하고 싶을 때가 있습니다. 이런 용도로 사용되는 컨테이너를 데이터 볼륨 컨테이너(Data Volume Container)라고 부릅니다. 컨테이너를 기능별로 묶어 관리할 때 매우 유용하며, 저장 공간도 크게 절약할 수 있습니다.
또한 컨테이너 간에 볼륨을 체인(chain) 형태로 연결할 수도 있습니다. 이렇게 하면 동시에 호스트 데이터에 접근하는 컨테이너의 수를 조절할 수 있는데, 유닉스 계열 시스템에서 흔히 그렇듯 호스트에 견고한 쓰기 잠금(write locking) 메커니즘이 없는 경우 특히 유용합니다.
간단한 예제를 살펴보겠습니다. 먼저 data-source라는 이름의 컨테이너를 실행하고 /data 마운트 포인트를 지정합니다. 원한다면 /data를 호스트의 특정 디렉터리에 매핑할 수도 있지만, 일단은 생략하겠습니다. 그다음 두 번째 컨테이너를 생성하면서 --volumes-from 옵션으로 data-source 컨테이너의 볼륨을 사용하도록 합니다.
docker run -ti --name data-source -v /data centos:latest /bin/bash
docker run -ti --volumes-from data-source centos:latest /bin/bash
이제 두 컨테이너를 확인해 보면 둘 다 /data 디렉터리를 가지고 있습니다. 다만 data-source 컨테이너가 --volumes-from 옵션으로 실행된 모든 컨테이너의 데이터 진입점(entry point) 역할을 합니다. 이 방식을 활용하면 저장 공간을 크게 아끼고, 컨테이너들이 원본 데이터에 접근하는 방식을 통제할 수 있으며, 여러 소프트웨어 구성을 더욱 손쉽게 테스트할 수 있습니다.
[root@68d3ed5e243a data]# pwd
/data
[root@68d3ed5e243a data]# touch STUFF
[root@68d3ed5e243a data]#
그리고 볼륨을 공유받은 두 번째 컨테이너의 결과입니다.
[root@7aed935cc156 /]# ls -la /data
total 4
drwxr-xr-x. 2 root root 18 May 1 11:46 .
drwxr-xr-x. 18 root root 4096 May 1 11:45 ..
-rw-r--r--. 1 root root 0 May 1 11:46 STUFF
[root@7aed935cc156 /]#
첫 번째 컨테이너에서 생성한 STUFF 파일이 두 번째 컨테이너에서 그대로 보이는 것을 확인할 수 있습니다. 별도의 복사 작업 없이 실시간으로 데이터가 공유되는 것입니다.
다음 단계는?
믿기 어려울 수도 있지만, 여기서 잠시 마무리하겠습니다. 백업, 데이터 삭제 같은 추가 작업도 있지만, 이는 별도의 주제로 나누어 다룰 예정입니다. 지금까지 배운 내용만으로도 데이터 볼륨을 다루고 컨테이너 안에 마운트 포인트로 노출하는 작업을 충분히 시작할 수 있습니다.
참고로 경험 법칙에 따르면, 환경 도구와 설정 파일에는 읽기 전용(read-only) 데이터를 사용하고, 대용량 데이터 처리에는 볼륨 컨테이너를, 그리고 간단한 테스트용으로는 작은 디렉터리와 마운트 포인트를 활용하는 것이 좋습니다.
마치며
도커의 볼륨 처리 방식은 비교적 단순하지만, 컨테이너 기술의 이 부분은 프레임워크의 다른 요소들만큼 성숙해지기 위해서는 아직 발전이 필요합니다. 기능 면에서 풍부하지 않은 편이며, 스냅샷, 데이터 분산 및 병렬화에 대한 기본 지원 등 데이터를 제어할 수 있는 추가적인 방법들이 마련되어야 합니다.
그래도 이번 튜토리얼을 통해 몇 가지 새로운 것들을 배웠을 것입니다. 마운트 포인트 생성과 데이터 볼륨 마운트 방법, 볼륨 체인 연결 방법, 그리고 과정에서 마주치는 사소한 문제들의 해결법까지 말입니다. 늘 방대하고 긴 글만 필요한 것은 아니며, 때로는 짧고 핵심적인 가이드가 더 유용하기 마련입니다. 이번 글이 그런 경우였기를 바랍니다.
감사합니다.