도커 데이터
- 우리가 도커 파일을 작성할 때 복사했던 소스코드 이미지, 변경 불가. (read-only)
- 새 소스 코드로 업데이트하려면 이미지를 새로 생성해야함.
- 임시 애플리케이션 데이터. (컨테이너) (read-write)
- 애플리케이션이 실행되는 동안 생성. → 사용자가 입력 폼에 뭔가 입력한다거나..할 때 컨테이너가 처리할 때 임시 데이터
- 컨테이너가 종료될 때 데이터가 없어져도 상관 없음. 말 그대로 임시 데이터.
- 영구 애플리케이션 데이터 (read-write)
- 파일에 저장하거나 데이터베이스에 데이터를 컨테이너에 그 데이터를 가져와 저장
- 컨테이너가 삭제되더라도 살아있어야하는 데이터. (유저 데이터라던지)
- 그것은 “볼륨”
💡 이미지는 read-only, 컨테이너는 read-write. 컨테이너는 이미지와 격리된 상태기 때문에 같은 이미지로 만들어진 컨테이너여도 서로 다른 데이터를 가지고 있을 수 있다. 하지만 이것은 다르게 말하면 컨테이너가 종료될 때 → 컨테이너에 저장되어 있는 데이터들은 삭제된다는 것!
그래서 우리는 영구 애플리케이션 데이터를 저장할 “Vloume”이 필요하다!
도커 볼륨
호스트 머신(컴퓨터)의 디렉토리. 호스트 컴퓨터에 장착된 하드 드라이브에 존재. (그러나 어디있는지는..) 컨테이너와 “매핑”됨.
→ 하지만 참고로 arm (애플 실리콘)은 리눅스 위에 도커를 설치하기 때문에 경로가 내 맥이 아니라 리눅스 위에 있음…참고…ㅎ
- 도커 호스트의 하드 드라이브에 존재. (컨테이너 외부에 존재)
- 컨테이너가 종료되어도 데이터 삭제 X
- 컨테이너와 매핑 가능.
- 볼륨에 있는 데이터 read-write 가능 !
주의
exists(finalFilePath, async (exists) => {
if (exists) {
res.redirect('/exists');
} else {
// 이전에는 파일을 이동시킬 수 있었지만, 볼륨이 추가된 이후에는 파일을 "이동" 시키는 것은 불가능.
// await fs.rename(tempFilePath, finalFilePath);
await fs.copyFile(tempFilePath, finalFilePath); // 파일을 복사 후
await fs.unlink(tempFilePath); // 수동 삭제
res.redirect('/');
}
});
- 도커는 컨테이너 파일을 다른 폴더로 이동시키지 않음. 컨테이너 밖으로 이동시킬뿐.
- 만약 이처럼 파일을 볼륨으로 “이동” 시키는 코드가 있을 경우
- 복사 → 이전 파일 삭제 시켜야 함.
볼륨 종류 (type)
- 익명 볼륨
- 명명 볼륨
Anonymous 익명 볼륨
- VOLUME [ "/app/feedback" ] → 호스트 경로를 매핑하지 않았기 때문에 익명 볼륨으로 생성
- 도커가 관리하기 때문에 컨테이너가 내려가면 볼륨도 삭제 됨
Named 익명 볼륨
- 영구적이어야 하는 데이터, 편집하거나 직접 볼 필요 없는 데이터를 저장하자!
- 실제로 엑세스 할 필요 없는 데이터.
- 컨테이너가 내려가도 폴더, 볼륨 그대로 사용 가능.
- 새 컨테이너를 시작해도 볼륨이 그대로 유지.
익명 볼륨 추가
FROM node:14
WORKDIR /app
COPY package.json .
RUN npm install
COPY . /app
EXPOSE 80
# 볼륨 생성 명령어
# /app/feedback -> 컨테이너 외부 폴더와 매핑할 컨테이너 내부 폴더
VOLUME [ "/app/feedback" ]
CMD [ "node", "server.js" ]
- /app/feedback → 컨테이너 내부 폴더와 매핑된다.
명명 볼륨 추가
FROM node:14
WORKDIR /app
COPY package.json .
RUN npm install
COPY . /app
EXPOSE 80
# 볼륨 생성 명령어 주석 처리
# VOLUME [ "/app/feedback" ]
CMD [ "node", "server.js" ]
# 실행 명령어
docker run -d -p 3000:80 --rm --name feedback-app -v feedback:/app/feedback feedback-node:volumes
- -v feedback:/app/feedback
- -v 볼륨 추가 명령어
- feedback:/app/feedback 볼륨이름:컨테이너내부폴더경로
- 컨테이너를 삭제해도 존재함을 확인 가능!
볼륨 삭제
docker volume rm 볼륨이름
# 안쓰는 볼륨들 전부 삭제
docker volume prune
바인드 마운트
볼륨과는 다르게 직접 호스트 머신과 경로 매핑 → 소스 코드를 넣을 수도 있어, 컨테이너 재배포를 하지 않더라도 소스코드 변경 가능?!
- 영구적이고 편집 가능한 데이터에 적합.
- 이미지가 변경되는 것이 아니라, 컨테이너에만 변경되는 것 ! → 이미지가 아닌 컨테이너와 연결되어있으니
- 도커가 로컬 호스트 폴더를 덮어쓰지 않음.
# 마운트 명령어
-v 호스트머신실제경로:컨테이너내부폴더경로
# 명명 볼륨 외에, 내 호스트 프로젝트 폴더에 바인드 마운트 해버리기
# 모든 호스트 폴더를 /app 폴더에 바인딩 한다는 것을 명심하기 ! -> 그저 덮어씌우기만 하는 게 아님
docker run -d -p 3000:80 --rm --name feedback-app -v feedback:/app/feedback
-v /Users/holidayk/Desktop/docker-study/data-volumes-03/Docker-Volume:/app feedback-node:volumes
# OS 에 따라 전체 경로를 복사하지 않고 아래 명령어로 대체 가능 !
# macOS / Linux
-v $(pwd):/app
# Windows
-v "%cd%":/app
주의
- 공유 폴더에 도커가 엑세스 권한이 있는지 확인 → Docker Decktop 에서 확인 가능
- 경로 문자에 특수문자 등이 있으면 문자가 깨질 수 있음, 따옴표 안에 넣어도 좋아요!
- -v "/Users/holidayk/Desktop/docker-study/data-volumes-03/Docker-Volume:/app"
- 덮어씌우기만 하는 게 아니라 ‘바인딩’ 한다는 것 명심.
오류
# 이 명령어로 컨테이너를 생성, 실행하게 되면
docker run -d -p 3000:80 --rm --name feedback-app -v feedback:/app/feedback
-v /Users/holidayk/Desktop/docker-study/data-volumes-03/Docker-Volume:/app feedback-node:volumes
FROM node:14
WORKDIR /app
COPY package.json .
RUN npm install
COPY . /app
# 위의 '복사' 명령어들이 의미가 없음
# -> 어차피 컨테이너 생성할 때 /app 폴더로 내 로컬 프로젝트를 바인드 마운트 하기 때문...
# -> 그래서 종속성 설치 (npm install) 명령어가 무효화되기 때문에 에러 발생 !
# -> 도커에게 덮어쓰지 말아야 할 파일이 있다는 것을 알려줘야 함. -> 익명 볼륨으로 해결!
EXPOSE 80
# 볼륨 생성 명령어 주석 처리
# VOLUME [ "/app/feedback" ]
CMD [ "node", "server.js" ]
오류 해결
FROM node:14
WORKDIR /app
COPY package.json .
RUN npm install
COPY . /app
EXPOSE 80
# 여기에서 익명 볼륨을 생성해줘도 되지만, 이미지를 리빌드해야하니 컨테이너 실행 명령어에서 익명 볼륨 생성
# VOLUME [ "/app/feedback" ]
CMD [ "node", "server.js" ]
# 컨테이너 실행
docker run -d -p 3000:80 --rm --name feedback-app -v feedback:/app/feedback \\n
-v /Users/holidayk/Desktop/docker-study/data-volumes-03/Docker-Volume:/app \\n
-v /app/node_modules \\n
feedback-node:volumes \\n
- -v /app/node_modules
- 충돌이 있을 경우 더 길고 구체적인 경로에 바인딩함.
- 즉, /app/node_modules 폴더는 도커가 사용하는 폴더로 덮어씀 (예외로 살아남음)
- 나머지 코드는 내코드 + 종속성 다운로드 디렉토리만 도커가 설치한 종속성 사용하기 !
→ 이렇게 하면 도커를 사용해도 html 파일은 고냥 바로 업데이트 가능!
💡 하지만 이렇게 해도 js 코드를 바꾸는 건 적용되지 않는다. 어떻게 하면 적용할 수 있을까용?
컨테이너 재시작 없이 Node.js 코드 바로 적용하기
컨테이너 재시작하지 않고 노드 코드도 바로 적용할 수 있도록 해봅시다!
package.json
{
"name": "data-volume-example",
"version": "1.0.0",
"description": "",
"main": "server.js",
"author": "Maximilian Schwarzmüller / Academind GmbH",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1"
},
"scripts": {
// nodemon 으로 server.js 실행 (서버 시작)
"start": "nodemon server.js"
},
"devDependencies": {
// 서버 변경 감지 종속성
"nodemon": "3.1.0"
}
}
Dockerfile
FROM node:14
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
EXPOSE 80
# nodemon 으로 서버 시작
CMD [ "npm", "start" ]
# CMD [ "node", "server.js" ]
- 이제 server.js 에서 코드를 바꾸면 변경을 감지하여 서버가 자동으로 재시작.
요약
# 익명 볼륨
docker run -v /app/data
# 명명 볼륨 (이름 추가)
docker run -v data:/app/data
# 바인드 마운트 (로컬 호스트 머신 절대 경로 추가)
docker run -v /path/to/code:/app/code
익명 볼륨 | 명명 볼륨 | 바인드 마운트 | |
설명 | 컨테이너에 연결 된 볼륨 | 이름이 있는 볼륨 도커 파일에서 생성 불가 컨테이너를 실행할 때 -v 로만 생성 |
호스트 머신에 연결된 볼륨(데이터 저장 위치 알고 있음) |
컨테이너 제거 | 볼륨도 함께 제거 | 볼륨 존재 | 볼륨 존재 |
볼륨 제거 | 컨테이너가 제거되면 함께 제거 | CLI 명령으로 제거 | 실제로 호스트 머신에서 삭제해야 함. |
컨테이너 간 데이터 공유 | 불가 (컨테이너가 종료되면 제거) | 가능 | 가능 |
데이터 저장 | 부적합 | 적합 | 적합 |
용도 | 컨테이너에 이미 존재하는 특정 데이터 잠금 (덮어씌움 방지) 외부 경로보다 컨테이너 내부 경로의 우선 순위를 높이는데에 사용.(바인드 마운트와 함께) |
컨테이너간의 데이터 공유 | 컨테이너 리빌드 없이 라이브 데이터 제공 |
정리
- 볼륨이란?
- 컨테이너 외부 특정 폴더에 연결된 Docker 컨테이너 내부의 폴더 또는 파일
- 볼륨은 도커에서 관리하므로 호스트 폴더(컨테이너 내부 경로에 매핑된)가 어디에 있는지 반드시 알 필요는 없음.
- 익명 볼륨은 --rm 으로 시작된 컨테이너가 중지되면 제거됨.
- 컨테이너가 중지될 때 삭제하는 구문
- 명명 볼륨의 장점
- 컨테이너를 제거해도 살아남는다.
- 바인드 마운트란?
- 내가 인지하고 있는 특정 호스트 머신 상의 경로, 일부 컨테이너 내부 경로에 매핑 됨.
- 컨테이너에 라이브 뎅터 제공 (리빌드 필요 X)
- 익명 볼륨의 쓰임
- 외부 경로보다 컨테이너 내부 경로의 우선 순위를 높이는 데에 사용 가능.
읽기 전용 볼륨 (read-only)
docker run -d -p 3000:80 --rm --name feedback-app -v feedback:/app/feedback
-v /Users/holidayk/Desktop/docker-study/data-volumes-03/Docker-Volume:/app:ro
-v /app/node_modules feedback-node:volumes
# :ro 를 붙이면 read-only 로, 도커가 해당 폴더에 쓸 수 없음.
-v /localhost/path:/app:ro
- 바인드 마운트 할 때, :ro 추가하면 read-only 적용
- 도커가 쓰기 불가능
→ 만약 read-only 때문에 이후 /app/node_module 폴더를 쓸 수 없다고 뜨면 프로젝트 폴더에 node_module 폴더를 만들어둔 후 명령어 실행하면 정상 동작.
- read-only 라 도커가 직접 폴더를 만들 수 없어서 write-read 허용하는 디렉토리는 호스트가 직접 만들어놔야하는듯.
명령어
# 활성화 중인 모든 볼륨 listing
# 바인드 마운트는 도커가 관리하는 게 아니라 로컬 폴더를 컨테이너 내부 폴더에 바인딩하는 거라, ls 해도 안 뜸
docker volume ls
# 자체 볼륨 생성 (도커에 맡길 때가 많긴 함. 직접 생성할 이유 없다면 굳이?)
docker volume create [OPTIONS] [VOLUME]
# 도커 제어 정보 가져오기
# 생성 날짜, 드라이버, 이름, 옵션 등...
docker volume inspect 도커
# 볼륨 제거
# 볼륨을 특정 컨테이너가 사용하고 있다면 컨테이너 중지 후 제거 가능
docker volume rm 도커이름
# 지금 사용하지 않는 모든 볼륨 제거
docker volume prune
“COPY” vs 바인드 마운트
바인드 마운트를 하는데도 굳이 이미지가 생성될 때 COPY 명령어로 스냅샷에서 복사하는 이유가 뭘까?
- docker run 으로 개발 중에 바운드 마운트를 사용해서 실행 중인 컨테이너에 즉시 반영
- 개발을 마치면 실제로 이 컨테이너를 가져와 서버에 넣음.
- 하지만 이 땐 바인드 마운트 사용하지 않음
- 그래서 COPY 명령어로 스냅샷 이미지 유지 !
728x90
'개발공부 개발새발 > Docker' 카테고리의 다른 글
Docker ) Network (0) | 2024.03.29 |
---|---|
Docker ) ARG 와 ENV (0) | 2024.03.18 |
Docker ) 이미지, 컨테이너 관리. (0) | 2024.03.03 |
Docker ) 도커 이미지 기초 (1) | 2024.02.28 |
Docker ) 도커 이미지를 만들고 컨테이너를 실행하자. with Dockerfile (1) | 2024.02.26 |