Photo by Rubaitul Azad on Unsplash
도커의 임시 데이터는 컨테이너에 의해서 관리되지만 영구데이터는 볼륨에 의해서 관리된다.
도커 컨테이너를 지우고 다시 image를 컨테이너에 띄우면 컨테이너에 저장되었던 데이터는 사라지고 없다.
같은 이미지를 사용한다고 해도 컨테이너를 새로 생성한다면 이전 컨테이너에 저장된 모든 데이터는 손실된다.
컨테이너는 데이터를 image에 저장하지 않기 때문이다.
해결방법은 볼륨이다!
볼륨은 컨테이너나 이미지에 존재하는 것이 아니고 내 컴퓨터의 폴더이다!
이 폴더가 도커 컨테이너 내부의 폴더에 매핑된다.
이 두 폴더의 변경사항은 서로에게 반영된다.
내 컴퓨터의 특정 폴더를 변경하면 컨테이너 내부에서 엑세스할 수 있고 물론 반대로도 가능하다.(물론 내 컴퓨터에 어디있는지도 모르고 도커가 알아서 관리하므로 내 컴퓨터에서 볼륨 폴더를 수정할 일은 대체로 없다.)
이러한 방법으로 볼륨은 컨테이너가 종료된 이후에도 지속되며 데이터를 지킬 수 있다.
컨테이너는 볼륨에 데이터를 읽고 쓸 수 있다.
폴더구조가
app
feedback
pages
public
temp
Dockerfile
package.json
server.js
로 이루어져있다고 했을 때 서버에서 피드백을 받아 저장하는 장소는 feedback 폴더다. 이 폴더를 volume으로 지정하고 싶다면 아래와 같은 코드를 도커파일에 추가해준다.
영구데이터가 존재해야하는 곳이 바로 feedback폴더이므로 볼륨으로 지정해주면 컨테이너가 종료되고 또 삭제되더라도 데이터는 내 컴퓨터에 남아있게 된다.
FROM node:14
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
EXPOSE 80
VOLUME [ "/app/feedback" ]
CMD [ "node", "server.js" ]
볼륨에는 anonymous volumes와 named volumes가 있다.
이 두가지는 마찬가지로 호스트 컴퓨터(내 컴퓨터)에 일부 폴더와 결로를 설정한다.
docker volume ls
## 이 명령어를 통해 볼륨을 리스팅할 수 있다.
→ 위의 명령어대로 볼륨을 설정한 다음 컨테이너를 종료하고 다시 볼륨리스트를 출력해보면 볼륨이 사라진 것을 볼 수 있다.
이는 볼륨이 익명이기 때문에 컨테이너가 있는동안만 존재한다.
→ 컨테이너가 지워지면 데이터가 사라진다는 점에서 별 차이가 없기 때문이다.
named volumes를 사용하면 컨테이너가 지워진 다음에도 데이터는 영구적으로 남는다.
named volumes를 사용하기 위해서는 dockerfile에서 volume 명령어를 제거하고 컨테이너를 생성할 때 태그와 함께 추가해주어야 한다.
docker run -d -p 3000:80 --rm --name feedback-app \
-v 볼륨이름:/app/feedback -> 원하는 폴더이름 컨테이너 이름:태그
## 위와 같이 -v 와 함께 볼륨이름:/폴더이름으로 묶어 컨테이너를 띄우면
## 볼륨은 내가 명명한 이름을 가지게 되고 컨테이너가 삭제되어도
## 데이터를 가진 채로 유지된다.
docker run -d -p 3000:80 --rm --name feedback-app \
-v 볼륨이름:/app/feedback -> 원하는 폴더이름 -v 내컴퓨터 폴더의 절대경로:/app 컨테이너 이름:태그
## 바인드 마운트는 host(내컴퓨터)에서 수정가능하게 폴더를 묶어준다.
## -v 내컴퓨터 폴더의 절대경로:/app 이와 같은 방식으로 '바인드' 해줄 수 있다.
## 파일 폴더 전체 모두 바인드 가능하다.
## 경로 부분에 띄어쓰기나 특수문자로 인해 오류가 발생할 수도 있다 큰 따옴표로
## "내컴퓨터 폴더의 절대경로:/app"와 같이 묶어주면 오류를 방지할 수 있다.
## 환경설정 리소수에 file sharing에 공유 가능 리소스로 추가되어 있어야 바인드를 사용할 수 있다.
## -v ${pwd}:/app처럼 축약어로 나타낼 수도 있다.
위 코드와 같이 사용하게 되면 app 폴더 전체를 덮어쓰게 되며 디펜던시의 설치가 제대로 이루어지지 않는다.
여기에서 익명 볼륨의 도움을 받을 수 있는데
docker run -d -p 3000:80 --rm --name feedback-app \
-v 볼륨이름:/app/feedback -> 원하는 폴더이름 -v 내컴퓨터 폴더의 절대경로:/app \
-v /app/node_modules 컨테이너 이름:태그
## -v /app/node_modules 코드를 추가하여 익명 볼륨을 생성한다.
## 이렇게 더 뎁스가 깊은 폴더와 덜 깊은 폴더가 있다면 도커는 뎁스가 더 깊은 폴더를 우선시한다.
## 따라서 npm install로 인해서 생겨난 node_modules라는 폴더는 바인드로 인해
## 덮어씌워지는 부분에서 제외될 수 있다.
읽기 전용 볼륨
바인드 마운트를 디폴트값으로 설정하면 도커 내부파일 또한 호스트(내컴퓨터)의 파일을 변경할 수 있는데 이를 방지하기 위해서는 ro 옵션을 넣어주어야 한다.
docker run -d -p 3000:80 --rm --name feedback-app \
-v 볼륨이름:/app/feedback -> 원하는 폴더이름 -v "내컴퓨터 폴더의 절대경로:/app:ro" \
-v /app/node_modules 컨테이너 이름:태그
## 위와 같이 :ro를 기존 바인드 문구에 추가해주면 읽기전용으로 변경되며
## 도커가 바인드 된 폴더나 그 하위폴더에 있는 파일을 변경하거나 생성할 수 없게된다.
docker volume ls
## ls로 볼륨을 리스팅할 수 있다.
docker volume create
## create명령어로 생성이 가능
docker volume inspect volume_name
## 볼륨의 정보를 볼 수 있다.
docker volume rm
## rm으로 삭제도 가능하고
docker volume prune
## prune으로 가지치기도 가능하다.
바인드 마운트 vs Dockerfile COPY
바인드 마운트로 모든 파일들을 동기화 시킬 수 있는데 굳이 이미지 빌드시에 copy할 필요가 있는가?
copy . . 은 모든 파일을 복사한다.
.dockerignore파일을 통해서 복사하지 않을 파일을 고를 수 있다.
ARG vs ENV
둘 다 계속 변경할 지도 모르는 부분을 하드코딩으로 일일이 바꿔 줄 필요가 없도록 도와준다는 장점이 있다.
서로 다른 환경, 구성에서 동일한 이미지, 컨테이너를 실행할 수 있도록 도움을 준다.