이번에 학습하게된 Volume과 Bind Mounts는 뭘랄까...
쉬운것 같으면서도? 기억할 옵션들이 많은 느낌이랄까?... 정리를 좀 해놔야 겠다...
Docker 컨테이너(container)에 쓰여진 데이터는 기본적으로 컨테이너가 삭제될 때 함께 사라지게 됩니다.
Docker에서 돌아가는 많은 애플리케이션이 컨테이너의 생명 주기와 관계없이 데이터를 영속적으로 저장을 해야하는 경우들이 빈번합니다.
또한, 컨테이너가 host의 file system이 상호작용을 해야하는 경우도 있습니다.
이렇게 Docker 컨테이너의 생명 주기와 관계없이 데이터를 영속적으로 저장할 수 있도록 Docker는 두가지 옵션을 제공합니다.
1) Docker 볼륨(volume)
2) 바인드 마운트(bind mount)
이번 포스팅에서는 Docker 컨테이너에 데이터를 저장하는데 사용되는 이 두가지 방법에 대해서 알아보도록 하겠습니다.
1. Volumes
Volumes은 Dokcer에 의해서 관리됩니다.
Volumes은 host machine(내 컴퓨터)에서 관리되는 폴더이며, 컨테이너 내부의 폴더들과 마운트되어 있습니다.
또한 Docker(Linux에서는 /var/lib/docker/volume/)가 관리하는 Host File System의 일부에 Data가 저장됩니다.
참고로 위에서 언급한 /var/lib/docker/volume/ 경로는 Docker의 가상머신 상의 경로입니다.
Host상의 경로가 아닙니다. 따라서 실재로 Host에 매핑되는 경로를 찾기는 매우 힘듭니다.
우선 이미지를 run 하면서 Volumes를 생성하는 명령어를 살펴봅시다.
docker run -d -p 3000:80 --rm --name shine-app -v shine:/app/shine shine-node:volumes
이미지를 실행하는데, detach 모드로 실행하며, 포트는 3000:80으로 연결하고, 컨테이너 종료시 자동으로 컨테이너가 소멸되며, 컨테이너의 이름은 shine-app이 되고, shine이라는 이름을 갖는 볼륨이 컨테이너의 "/app/shine" 경로에 생기며, 인스턴스화 할 이미지는 shine-node:volumes 버전 입니다.
볼륨을 생성하면 /var/lib/docker/volumes/~ 과 같이 호스트 파일 시스템의 일부에 도커에서 관리하는 영역에 저장된다고 위에서 언급했습니다.
따라서 개발자는 내 컴퓨터상의 어떤 경로에 데이터들이 저장되는지는 전혀 알 수 없습니다.
애당초 내 컴퓨터 어딘가에 저장된 데이터는 개발자기 직접 보거나, 편집하기 위한 것이 아니기 때문이죠~
만약 직접 편집하거나, 봐야 한다면 Bind Mounts 를 사용해야 합니다!
컨테이너 내부의 애플리케이션이 동작하면서 데이터를 Volumes에 write 하면, 이는 우리 Host PC의 어딘가 특정 경로상에 동일하게 저장됩니다. 데이터를 영속화 시키는 것 이죠!
우선 2가지 종류의 Volumes이 있습니다.
- Anonymous Volumes:
- "-v /some/path/in/container"과 같이 -v 옵션을 통한 명령을 통해 생성합니다.
- 컨테이너에 마운트될 때 도커가 도커 내에서 고유하도록 보장되는 임의의 이름을 지정해줍니다
- --rm 옵션으로 이미지를 run시킨 경우, 컨테이너가 종료될때 Volumes도 함께 자동으로 소멸됩니다.
- --rm 옵션 없이 이미지를 run시킨 경우, 자동으로 소멸되지 않습니다.
- Named Volumes:
- "-v name:/some/path/in/container" 과 같이 name: 을 추가하여 Volumes의 이름을 지정할 수 있다.
- 자동으로 삭제되지 않는다.
일반적으로 데이터를 영구적으로 저장하기 위해서는 Named Volumes을 사용하는 것 이 좋은데,
왜냐하면, 데이터가 단순히 컨테이너 안에만 저장되는 것 이 아니라, Host의 컴퓨터에도 저장되기 때문에 컨테이너를 종료하더라도 Named Volumes의 경우 데이터가 유지되기 때문입니다.
만약 Named Volumes을 삭제하고 싶은 경우 다음과 같이 명령을 해줘야 합니다.
docker volume rm VOL_NAME
2. Bind Mounts
Bind Mounts는 Volumes과 유사하지만 다릅니다.
가장 큰 차이점은 Bind Mounts는 개발자가 직접 host machine에서 저장될 경로를 지정할 수 있다는 점 입니다.
사용 예시는 다음과 같습니다.
-v /absolute/path/on/your/host/machine:/some/path/inside/of/container
: 을 기준으로 앞쪽에는 host의 절대 경로를, 뒤쪽에는 container의 경로를 지정하면 됩니다.
또는 다음과 같이 절대경로를 지정할수도 있습니다.
-v "${pwd}":/some/path/inside/of/container
이러면 pwd, 즉 현 디렉토리의 절대경로가 입력되게 됩니다.
Bind Mount는 컨테이너가 실행되는 동안 변경될 수 있는 데이터, 예를 들어 개발환경에서 실행중인 컨테이너가 사용하는 소스코드를 Host와 공유하면서 개발자가 수정을 가할 수 있습니다.
다만 Bind Mount는 단지 데이터 저장을 위해서는 사용하지 않는것이 좋습니다.
이런경우 그냥 Named Volume을 사용하면 되거든요!
3. 추가사항
우선 다음과 같은 dockerfile이 있다고 해보자.
FROM node:14
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
EXPOSE 80
CMD ["node", "server.js"]
이후 다음 명령어로 컨테이너를 run시킨다.
docker run -d -p 3000:80 --name feedback-app -v feedback:/app/feedback -v /Users/shine/study/docker-study:/app feedback-node:volumes
하지만 위 명령어로 이미지를 인스턴스화 시키려 하면 바로 실패한다.
dockerfile을 보면 "/app"으로 현 디렉터리의 파일들을 COPY 하기도 하고, npm install 명령도 수행한다.
npm install을 통해 "/app"이하에 필요한 의존성들 또한 전부 설치하게 됩니다.
따라서 우리의 이미지에는 이미 다운되어있는 많은 파일들이 존재합니다.
하지만 실행하면서 Bind Mount를 통해 컨테이너의 "/app"내부의 모든 파일을 "/Users/shine/study/docker-study"으로 덮어씌우기 때문입니다.
이를 해결하기 위해 Docker에게 외부로부터 덮어쓰지 말아야 하는 폴더를 알려줘야 합니다.
이때 익명 볼륨을 사용하게 됩니다.
다음 코드를 봅시다!
-v /Users/shine/study/docker-study:/app -v /app/node_modules
우선 앞부분은 Bind Mount를 지정하였고, 뒤쪽은 익명 볼륨을 선언하고 있습니다.
앞부분은 컨테이너의 "/app"과 마운트 하고, 뒤쪽은 익명 볼륨인 "/app/node_modules"와 마운트 합니다.
이런경우 선택의 기준은 더 세밀한 경로가 선택되는데, 따라서 "/app/node_modules"는 Bind Mount에 의해 덮어쓰기가 되지 않습니다.
내용을 보존하게 되는 것 이죠!
4. 읽기 전용으로 만들기
Bind Mount를 생각해보면, Host에서 소스코드를 수정할 수 있고 변경사항들은 컨테이너 내부에서 가져다 사용할수가 있습니다.
하지만 컨테이너가 Host의 파일을 수정하면 안됩니다. 이것이 읽기 전용으로 사용해야 하는 이유이죠!
기본값으로 Volume은 읽기/쓰기 가 둘다 가능합니다.
따라서 옵션을 추가하여 읽기전용으로 만들어 봅시다! "ro"만 추가해주면 됩니다!
docker run -d -p 3000:80 --name feedback-app -v feedback:/app/feedback -v /Users/shine/study/docker-study:/app:ro -v /app/node_modules feedback-node:volumes
5. 출처
'DevOps > Docker' 카테고리의 다른 글
[Docker] 컨테이너 통신 (0) | 2022.09.18 |
---|---|
[Docker] 도커의 환경변수 설정 (1) | 2022.09.15 |
[Docker] 외부에서 컨테이너로, 컨테이너에서 외부로 파일 복사하기 (0) | 2022.09.07 |
[Docker] 도커의 Attached, Detached 컨테이너 (1) | 2022.09.07 |
[Docker] 도커 이미지 레이어 (Docker Image Layer) (0) | 2022.09.05 |
댓글