Docker Bind Mount

namkun·2022년 5월 8일
0

Docker & Kubernetes

목록 보기
15/16

Bind Mount

바인드 마운트는 도커의 외장 데이터 저장소 방법 중 하나인데,

볼륨과 비슷하지만 또 다르다.

우리는 도커에 의해서 관리되는 볼륨의 위치, 즉 호스트 머신의 파일 시스템 상 어디에 파일이 저장되고 관리되는지에 우리가 지정할 수는 없지만,

(docker volume inspect 명령어로 위치는 확인할 수 있다.)

바인드 마운트는 호스트 머신상에 매핑될 컨테이너의 경로를 설정할 수 있고, 그렇기에 데이터에 대해서 편집이 자유로워진다.

그렇기에, 만약 소스코드들을 바인드 마운트 안에 넣으면, 컨테이너는 이를 인식해서 소스 코드를 실제로 스냅샷(우리가 처음에 이미지를 빌드할 때의 코드 상태)에서 복사하는게 아니라, 바인드 마운트내에서 복사할 수 있다.

그렇게 하면 컨테이너는 항상 최신 코드에 엑세스할 수 있게 된다.

그럼 간단하게 바인트 마운트에 대해서 세팅을 해보도록 하자.

$ docker run ~~~~ -v "[source dir or file]:[target dir or file]"

이렇게 하면 원하는 경로를 컨테이너와 연동할 수 있게 된다.

주의점으로는 source 경로 또는 파일에 특수문자나 공백과 같은 것이 있다면, "" 으로 감싸주자.

아니 그냥 애초에 감싸주자..그래서 위에서도 감싸두었다..그게 맘 편할 것이다.

Read-Only

Bind-Mount 는 기본적으로 호스트머신에 대해서 Read-Write 권한을 갖고 있다.
그렇지만, 우리 호스트머신에 연결된 파일에 뭔가 덮어쓰이지 않는 것을 바란다면 Read-Only 옵션을 줄 수 있다.

사용법은 다음과 같다.

$ docker run ~~~~ -v "[source dir or file]:[target dir or file]:ro"

그냥 바인드마운트 될 내부 경로 뒤에 :ro 만 붙여주면 된다.

문제점

이렇게 바인드 마운트 한 경로가 문제가 되는 일이 있다.

예를 들어서...Dockerfile이 이렇게 생긴 경우

FROM node:14

WORKDIR /app

COPY package.json /app

RUN npm install

COPY . /app

EXPOSE 80

CMD ["node","server.js"]

위에서 /app 이라는 폴더 하단에서 npm install이라는 명령어를 통해서 종속성을 설치하는 것을 볼 수 있다.

그런데 이렇게 이미지에서 설치를 한 뒤에, run 명령어에서 바인드 마운트를 해주면,

docker run -d -p 3000:80 -v feedback:/app/feedback -v "$(pwd):/app" --name feedback-app node-volume-app:volume

이 /app 경로를 통째로 소스 경로로 바인드마운트를 하면...기존에 컨테이너 안에서 빌드되어서 설치된 종속성들이 있는 경로 (node_modules) 가 사라지고 소스 경로 통째로 덮어써진다.

그렇기에 node의 경우 필요한 module이 없다고 에러를 발생시킬 것이다.

$ docker logs feedback-app
internal/modules/cjs/loader.js:905
  throw err;
  ^

Error: Cannot find module 'express'
Require stack:
- /app/server.js
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:902:15)
    at Function.Module._load (internal/modules/cjs/loader.js:746:27)
    at Module.require (internal/modules/cjs/loader.js:974:19)
    at require (internal/modules/cjs/helpers.js:101:18)
    at Object.<anonymous> (/app/server.js:5:17)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:12)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '/app/server.js' ]
}

이렇게 말이다...

이런 경우에는 따로 도커에게 외부에서 덮어쓰면 안되는 부분이 있다는 것을 알려줘야만 한다.

이럴때는 익명의 볼륨을 사용해보자.

$ docker run -d -p 3000:80 -v feedback:/app/feedback -v "$(pwd):/app" -v /app/node_modules --name feedback-app node-volume-app:volume

자 아까와 다른 점이 있다면

-v /app/node_modules 이 추가되었다는 점이다.

이렇게 두 가지의 볼륨이 있다면, 도커는 항상 더 긴 '내부'경로를 갖고 있는 것을 우선으로 한다.

그러므로, /app 보다는 /app/node_modules가 더 긴 내부 경로를 갖고 있어, 우선적으로 해당 폴더와 볼륨을 마운트한다.

자 그럼 그 뒤로 순서는 다음과 같다. 머리아프니 잘 따라와보자.

  1. 컨테이너가 시작된다.
  2. 익명의 볼륨은 따로 /app/node_modules를 우선적으로 마운팅한다.(볼륨에 데이터가 저장된다.)
  3. 그 다음에 우리가 따로 경로를 지정한 바인드 마운트(-v "$(pwd):/app")가 실행된다. 즉, 현재 경로의 파일들이 /app 에 덮어씌워진다.
  4. 컨테이너는 내부에 마운트된 볼륨쪽 파일이 없다면 볼륨에서 파일을 가져온다.
  5. 그렇기에 현재 컨테이너에 마운트된 볼륨중, 익명의 볼륨에 저장된 /app/node_modules 폴더가, /app 하단으로 가져와진다. (없는 node_modules경로 위에 덮어쓴다..라고 생각하면 된다.)

간단히 말하면, npm install을 사용해서 이미지 생성 중에 생성된 node_modules 폴더는 살아남아서 바인드 마운트와 함께 공존하게 된다.

하이고 복잡해! 😫

profile
개발하는 중국학과 사람

0개의 댓글