Volume
- host machine 의 dir 로, 컨테이너나 이미지에 존재하지 않는다
- host 에 장착된 드라이브에 존재하거나, 컨테이너로 매핑된다
- host 상에서 매핑된 주소는 docker 가 관리하고, 우리는 알 수 없다
- 컨테이너가 삭제되어도 유지되어야 할 데이터가 있을 때 사용
COPY 와의 차이?
- COPY 는 복사 당시의 snapshot 을 일회성으로 복사하는 것
- volume 은 컨테이너 내부의 폴더를 host 상의 폴더에 연결
Cross Device Error
- volume 을 다루면서 흔하게 볼 수 있는 오류다
- 장치 간 링크가 허용되지 않는다는 의미를 가진다
- docker 는 파일을 컨테이너 내의 다른 폴더로 이동시키지 않는다
조회, 제거
docker volume ls: volume 목록 조회
docker volume rm <VOLUME_NAME>: 특정 volume 제거
docker volume prune: 미사용 volume 제거
Anonymous Volume
Dockerfile 의 VOLUME 명령어에 경로를 특정할 수 있다.
FROM node:16
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
EXPOSE 80
VOLUME [ "/app/feedback" ]
CMD [ "node", "server.js" ]
/app/feedback 이 컨테이너 내부 경로가 되었다
- 이 경로는 컨테이너 외부에서 매핑될 내부 위치다
Dockerfile 을 토대로 이미지를 빌드해보자
docker build -t feedback-node:volumes .
- 이미지를 토대로 컨테이너를 실행하자
docker run -d -p 3000:80 --rm --name feedback-app feedback-node:volumes
- 이렇게 이름이 지정되지 않은 것을 anonymous volume 이라고 한다
- 하지만, 이름을 모르기 때문에 우리가 접근할 수 없다
- 또한, 익명이기에 컨테이너가 삭제되면 삭제된다
--rm 옵션을 사용해 run 을 했을 때 해당하는 말이다
--rm 없이 run 후 rm 을 사용하면 volume 은 남아있다
docker prune 이 필요한 이유가 이것이다
Named Volume
- 볼륨에 접근하기 위해 이름을 붙인 named volume 을 사용한다
- 또한, 컨테이너 종료 후에도 볼륨을 유지할 수 있다
- named volume 은 영구적이어야 하는 데이터나, 직접 볼 필요가 없는 데이터에 적합하다
- named volume 은 Dockerfile 에선 생성할 수 없고, 컨테이서 실행 시 생성한다
* 앞에서 추가한 VOLUME 을 제거하자
docker run --name <CONTAINER_NAME> -v <VOLUME_NAME>:<VOLUME_PATH> <IMAGE_NAME>
- named volume 은 여러 컨테이너에 연결 가능하다
Bind Mounts
- 개발자가 직접 컨테이너 경로를 주고 관리하는 저장소
- 이미지의 성질에 의해
build 이후의 수정사항은 반영되지 않는다
- bind mount 는 이로 인한 제약을 해결한다
- 컨테이너는 파일을 스냅샷이 아닌 binding mount 에서 복사한다
- 이로 인해 영구적이고, 편집 가능한 데이터를 관리할 때 적합
binding mount 적용
- 컨테이너에 적용되기 때문에
run 에서 명시
docker run --name feedback-app -v feedback:/app/feedback -v "<FILE_PATH>:/app" feedback-node:volumes
- 이 때 bind 되는 host 상의 경로는 절대경로여야 한다
- named volume 선언과 유사하나,
: 앞이 경로다
Volume 병합
- 위에서 우리는 컨테이너의
/app 을 지정한 host 상의 dir 로 덮어썼다
- 이로 인해, 이미지
build 시 실행한 npm install 로 인해 생긴 node_modules dir 이 삭제된다
- 이를 해결하기 위해 덮어쓰지 않을 부분을 명시한다
docker run --name feedback-app -v feedback:/app/feedback -v "<FILE_PATH>:/app" -v /app/node_modules feedback-node:volumes
- 이로 인해
app/node_modules 는 anonymous volume 이 되었다
- docker 는 충돌의 경우 더 구제척인 내부 경로를 우선시해,
app/node_modules 로 매핑된 경로를 우선시해 유지시킨다
Read Only Volume
- 우리가 파일을 변경할 수 있는 곳은 오로지 host 상이다
- 컨테이너가 host 상의 파일을 변경하는 것을 방지해야 할 때가 있다.
- 이를 위해 bind mount 를 read only 로 설정한다
docker run --name feedback-app -v feedback:/app/feedback -v "<FILE_PATH>:/app:ro" -v /app/node_modules feedback-node:volumes
Volume 관리
생성
- 컨테이너 실행 시
-v 이용
- 수동으로 생성도 가능
docker volume create <VOLUME_NAME>
확인
- 모든 볼륨 확인
docker volume ls
- 볼륨의 자세한 정보 확인
docker volume inspect <VOLUME_NAME>
사용
run 명령에 미리 만든 볼륨 이름 명시
docker run --name <CONTAINER_NAME> -v <VOLUME_NAME>:<VOLUME_PATH> <IMAGE_NAME>
삭제
- 개별 삭제
`docker volume rm <VOLUME_NAME>
- 사용하지 않는 볼륨 모두 삭제
docker volume prune
ENV 사용
Dockerfile 에 명시하는 방법
ENV PORT=80
EXPOSE $PORT
- 이후
--e 로 컨테이너 실행 시 명시해준다
- 아래와 같이 여러 개의 변수 설정도 가능
docker run -d -p 3000:8000 --e PORT=8000 --e ENV2=7000 --e ENV3=6000 --rm --name <CONTAINER_NAME> <IMAGE_NAME>
.env 파일 이용
PORT=8000
- 이후
--env-file 로 컨테이너 실행에서 사용
`docker run -d -p 3000:8000
--env-file ./.env
--rm
--name <CONTAINER_NAME> <IMAGE_NAME>
ARG 사용
FROM node:14
ARG DEFAULT_PORT=80
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
ENV PORT $DEFAULT_PORT
EXPOSE $PORT
CMD [ "node", "server.js" ]
- 같은
Dockerfile 을 이용한 두 이미지가 다른 port 를 가지게 할 수 있다
docker build -t feedback-node:web-app .
docker build -t feedback-node:dev --build-arg DEFAULT_PORT=8000 .