[Docker] 도커의 데이터 외부 저장 매커니즘 볼륨과 바인드 마운트
컨테이너 데이터 저장의 한계와 볼륨
이미지와 컨테이너에는 로컬 폴더를 기반으로하는 자체 파일 시스템이 존재한다.
빌드된 이후에는 로컬 폴더와 이미지/컨테이너 내부 파일 시스템 사이에 연결은 없다.
⚠️ 컨테이너는 격리되어야 하기 때문에
즉, 이미지/컨테이너 내부 파일 시스템은 로컬 폴더의 스냅샷과 같다.
이미지 기반으로 컨테이너를 실행하면 이미지 위에 컨테이너 레이어(read-write)가 추가된다.
이미지는 읽기전용이기 때문에 데이터를 저장할 수 없고, 임시 데이터는 컨테이너(read-write)의 내부 파일 시스템에 저장될 수 있다.
임시 데이터밖에 저장을 못하는 이유는, 컨테이너를 삭제하면 당연히 내부 파일 시스템이 삭제되고 모든 데이터가 지워지기 때문이다.
⚠️ 컨테이너를 중지한다고 해서 내부 파일 시스템이 삭제되는 것은 아니다.
즉, 컨테이너가 삭제되어도 유지되어야 하는 영구 데이터는 컨테이너에 저장하지만 볼륨에도 저장해야 한다.
볼륨은 도커의 내장 기능으로 컨테이너가 실행되는 호스트 머신의 폴더를 말하는데, 이는 컨테이너나 이미지에 있는 것이 아니다.
즉, 도커 컨테이너 내부의 폴더와 호스트 머신의 특정 폴더를 매핑하여, 연결시키면 컨테이너는 해당 폴더에 데이터를 읽고 쓸 수 있다.
이후, 컨테이너가 종료/삭제된 경우에도 호스트 머신의 매핑된 특정 폴더(볼륨)에 계속 존재한다.
도커의 데이터 외부 저장 매커니즘
볼륨과 바인드 마운트의 가장 큰 차이는
볼륨은 도커가 관리하는 볼륨의 위치를 알 수 없지만, 바인드 마운트는 볼륨의 위치를 알고 있다.
바인드 마운트는 호스트 머신 상에 매핑될 컨테이너의 경로를 설정하기 때문이다.
- 볼륨
- 특정 데이터를 호스트 머신 파일 시스템에 아웃소싱할 수 있다. ⚠️도커 컨테이너에 의해 관리되지 x
- 익명볼륨
anonymous volume
- 컨테이너가 존재하는 동안에만 존재하며, 호스트 머신 내의 도커가 관리하는 어딘가에 숨겨져 있다.
- 🎯 컨테이너에 이미 존재하는 특정 데이터를 (다른 모듈에 의해 덮어쓰이지 않게) 잠그는데 유용하다.
- 🎯 성능 향상을 위해
temp
폴더를 익명볼륨에 매핑하면 유용하다.- 방법1 :
VOLUME ["/app/test"]
in🐋 Dockerfile
- 방법2 :
docker run -v /app/test
- 🎯 컨테이너에 이미 존재하는 특정 데이터를 (다른 모듈에 의해 덮어쓰이지 않게) 잠그는데 유용하다.
- 익명볼륨
- 명명된볼륨
named volume
- 컨테이너가 종료/제거된 후에도 볼륨이 유지되고, 특정 컨테이너에 국한되지 않는다.
docker run -v test:/app/test
컨테이너를 실행할 때 명명된 볼륨을 만들 수 있다.- 영구적인 데이터 유지에 도움은 되지만, 편집은 불가능하다. 어디에 저장되있는지 모르니까
- 명명된볼륨
- 바인드 마운트
bind mount
- 컨테이너가 종료/제거된 후에도 볼륨이 유지되고, 특정 컨테이너에 국한되지 않는다.
- 매핑된 호스트 머신 상 특정 폴더의 절대 경로를 알고 있기 때문에 영구적이고 편집가능한 데이터를 저장하는데 적합하다.
- 🎯 소스코드를 바인드 마운트에 넣고, 컨테이너가 소스코드를 바인드 마운트에서 복사하면 실행 중인 컨테이너에서 변경된 코드를 적용시킬 수 있다.
단, 바인드 마운트의 데이터를 지우려면 호스트 머신에서 삭제해야 한다. ⚠️ 도커 명령어로 지울 수 없다.docker run -v "HOST_MACHINE_ABSOLUTE_PATH:/app"
바인드 마운트에 저장된 데이터(소스코드)를 덮어쓰는 것이다. - 매핑된 호스트 머신 상 특정 폴더의 절대 경로를 알고 있기 때문에 영구적이고 편집가능한 데이터를 저장하는데 적합하다.
- 바인드 마운트
바인드 마운트의 소스코드를 덮어쓸 시 유의점
🐋 Dockerfile
1
2
3
4
5
# ... (생략)
COPY package.json .
RUN npm install
COPY . .
# ... (생략)
종속성 설치 후 그 결과인 node_modules
폴더는 🐋 docker build
시 생성되고,
생성된 node_modules
폴더까지 이미지에 복사한다.
즉, 로컬 머신의 매핑될 폴더(소스코드가 있는)에는 아직 node_modules
가 존재하지 않는다.
하지만 이것을 docker run -v "HOST_MACHINE_ABSOLUTE_PATH:/app"
해당 명령을 통해 로컬 머신에 있던 소스코드로 덮어써 버리면
node_modules
폴더가 사라지기 때문에 실행에 오류가 생긴다.
때문에, 도커에게 외부에서 덮어쓰지 말하야할 폴더가 있음을 알려줘야 한다. 이는 익명볼륨을 추가해 해결할 수 있다.
도커는 항상 컨테이너에 설정하는 모든 볼륨을 평가하며
충돌이 있는 경우에는 더 구체적인 내부 경로를 우선한다.
즉, docker run -v "HOST_MACHINE_ABSOLUTE_PATH:/app" -v /app/node_modules
이런 식으로 명령을 작성하면
/app/node_modules
가 /app
보다 더 구체적인 경로이기 때문에 (충돌이 생겼을 때) 해당 익명볼륨을 우선하게 된다.
때문에, 바인드 마운트의 데이터(소스코드)로 덮어쓰여지더라도 node_modules
폴더는 살아남을 수 있다.
소스코드와 같이 실행 중에 변경해서는 안되는 컨테이너 내부 파일을 읽기 전용으로 국한하는 것이 좋다.
볼륨은 기본적으로 read-write 권한을 가지고 있는데, 이는 컨테이너가 볼륨에서 데이터를 읽고 쓸 수 있음을 의미한다.
docker run -v "HOST_MACHINE_ABSOLUTE_PATH:/app:ro"
로컬 호스트 머신의 소스코드 전체 폴더를 바인드 마운트로 바인딩하여
코드 변경사항이 실행중인 컨테이너에 자동으로 반영되게 하는데 여전히 Dockerfile에서 모든 항목을 COPY하는 이유
바인드 마운트로 바인딩은 docker run 명령시에 옵션으로 설정한다.
그리고 docker run 명령은 개발 중에 사용하는 명령이다.
즉, 바인드 마운트는 개발의 편리성을 위해 사용하는 것이지, 배포 환경에서 바인드 마운트를 사용하지 않는다.
때문에 production 환경에서는 항상 소스코드의 (변경되지않는, 일종의)스냅샷을 써야한다.
그래서 🐋 Dockerfile의 COPY 명령을 유지해 놓아야 한다.
도커 볼륨 관리
볼륨은 도커에 의해 관리되고, 도커 컨테이너에 마운트된다.
도커에 의해 관리된다는 것은 컨테이너를 실행 할 때 볼륨이 존재하지 않으면 (자동)생성한다는 의미이다.
🐋 docker volume ls
- 현재 활성화된 볼륨을 모두 리스팅
- ⚠️ 바인드 마운트는 도커에 의해 관리되는 볼륨이 아니기 때문에 리스팅 되지 않는다.
🐋 docker volume create VOLUME_NAME
- 수동으로 볼륨을 생성
🐋 docker volume inspect VOLUME_NAME
- 볼륨 상세 정보 조회
- “Mountpoint”: “/var/lib/docker/volumes/VOLUME_NAME/data” ⚠️ 도커가 실행되는 가상 머신 내의 경로
- 호스트 머신 파일 시스템에 있는 실제 경로가 아니다.
- “Mountpoint”: “/var/lib/docker/volumes/VOLUME_NAME/data” ⚠️ 도커가 실행되는 가상 머신 내의 경로
🐋 docker volume rm VOLUME_NAME
- 볼륨 제거