본문 바로가기
docker-kub

docker - 데이터 관리(볼륨), .dockerignore, 환경변수, 매개변수

by 오우지 2022. 10. 6.

 

1. 익명볼륨과 명명된 볼륨

이미지가 빌드되면 내부의 코드는 변경될 수 없다.

모든 명령이 실행되면 이미지는 읽기 전용이기 때문에 무언가를 변경하려면 리빌드 해야한다.

 

컨테이너에서 데이터는 세가지 종류로 분류할 수 있다.

 

하나는 어플리케이션 데이터, 두번째는 임시 데이터, 마지막은 영구 데이터

어플리케이션 데이터는 우리가 만든 웹 어플리케이션이라고 할 수 있고 이미지에 의해 변경될 수 없다.

임시 데이터는 로그와 같은 데이터로 read와 write를 할 수 있지만 컨테이너 안에 저장된다.

마지막으로 영구 데이터는 DB에 저장되는 정보 같은것을 의미하며 볼륨이라는 곳에 저장된다.

 

데이터 구조는 다음과 같이 생각하면 된다.

 

파일을 생성하는 어플리케이션을 실행시켜서 실행버튼을 누르면 로컬 머신에는 뜨지 않고 도커 컨테이너 안에서 파일이 생기는 것을 확인할 수 있는데 이는 컨테이너가 격리된 파일 시스템을 사용하기 때문이다.

 

이전에 썼던 --rm 명령어의 유무에 따라 확인 가능한데

만약 

docker run -p 3001:80 -d --name feedback-app --rm feedback-node

이렇게 써서 컨테이너를 실행시키고 stop 했다면 해당 컨테이너는 남아있지 않기 때문에 다시 docker run 했을 때 이전 어플리케이션에서 만들었던 txt 파일을 찾을 수 없다.

 

컨테이너를 삭제하지 않는다면 데이터도 사라지지 않는다. 위에 있는 read-write가 가능한 container layer에 저장된다.

 

이제 됐다 할 수도 있지만 이러면 문제가 생긴다.

파일 시스템이 새로운 커밋이 쌓일때마다 갱신된다는 문제다. 따라서 볼륨이 존재한다.

 

볼륨은 호스트 머신의 폴더와 매핑된 도커 컨테이너 내부의 폴더로 컨테이너나 이미지 안에 존재하지 않는다.

이제 볼륨을 만들어보자.

FROM node:14

WORKDIR /app

COPY package.json .

RUN npm install

COPY . .

EXPOSE 80

VOLUME [ "/app/feedback" ]

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

VOLUME ["경로"] 를 통해 컨테이너 내부의 동기화 할 폴더를 선택할 수 있다.

 

docker build -t feedback-node:volumes .
docker run -d -p 3000:80 --rm --name feedback-app feedback-node:volumes

이미지 빌드 후 컨테이너를 실행하면(볼륨을 추가해줬기 때문에 --rm을 추가해도 상관없다.)

 

정상 실행되고 본래 애플리케이션의 목적대로 파일을 만들면 무한 대기가 된다.

여기서

docker logs feedback-app

로그를 뽑아보면

장치간 링크가 허용되지 않는다는 문제다.

 

뭐 아무튼 이걸 해결해도 문제가 생길 수 밖에 없는데, 컨테이너를 중지하고 실행하면 볼륨이 사라진다.

 

볼륨에는 두 가지 종류가 있다.

익명 볼륨과 명명된 볼륨

 

아래 볼륨은 익명 볼륨으로 컨테이너가 존재하는 동안에만 존재한다. 이러면 지금 볼륨을 사용하는 이유가 없어진다.

 

볼륨에 명명하면 컨테이너를 종료했다가 다시 실행하면 볼륨이 복구된다. 볼륨은 도커가 관리하며 호스트 머신에서 우리가 임의로 접근할 수는 없다.

docker run -d -p 3000:80 --rm --name feedback-app -v feedback:/app/feedback feedback-node:volumes

2. 바인드 마운트

데이터 저장소는 세 가지 종류가 존재한다.

1. 익명볼륨 (docker run -v /app/data)

2. 명명된 볼륨 (docker run -v data:/app/data)

3. 바인드 마운트 (docker run -v /path/to/code:/app/code)

 

개발 중에 도커를 사용한다면 지금까지 배운 도커의 활용법으로는 소스코드에 변경사항이 있을 때마다 이미지를 빌드해줘야 했다. 그걸 해결하기 위한 방법이 바인드 마운트다.

 

 

바인드마운트는 호스트 머신 상에 매핑될 컨테이너의 경로를 설정한다.

 

따라서 영구적이고 편집 가능한 데이터에 적합하다.

 

여기에서 왜 볼륨이 필요할까 라는 의문이 있었다. 검색에 따르면 바인드 마운트는 호스트 머신의 디렉토리에 저장하기 때문에 도커 외부의 작업에 의해 수정되거나 손상될 수 있고 이것이 보안 문제까지 불러일으킬 수 있다. 

 

볼륨은 도커에 의해 관리되기 때문에 여러 종류의 OS에서 동시에 사용 가능하고 원격 저장소에 저장할 수도 있기 때문에 바인드 마운트에 비해 활용도가 높다고 한다.

docker run -d -p 3000:80  --name feedback-app -v feedback:/app/feedback 
-v "/Users/hojin/Desktop/git_local/docker-study/data-volumes-03-adj-node-code:/app"
feedback-node:volumes

위의 명령어를 정리하자면

1. detach 모드로 포트는 로컬 3000 컨테이너는 80 포트로 연결

2. 컨테이너명은 feedback-app으로

3. 볼륨 이름은 feedback

4. 컨테이너 내의 경로는 /app/feedback

5. 바인드 마운트는 /app 디렉토리와 내 로컬의 절대경로를 묶고(절대경로는 맥 -v $(pwd):/app, 윈도우 -v "%cd%":/app 으로 사용 가능하다)

6. feedback-node:volumes 이미지를 실행한다.

 

근데 실행되지 않고 오류가 나온다. 작성해놓은 Dockerfile을 보면 이유를 알 수 있는데

FROM node:14

WORKDIR /app

COPY package.json .

RUN npm install

COPY . .

EXPOSE 80

# VOLUME [ "/app/node_modules" ]

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

위의 Dockerfile에서 설정한 /app 디렉토리로 npm install을 수행하는데  docker run 함과 동시에 바인드 마운트를 설정해 해당 디렉토리가 로컬 폴더로 대체된다.

 

이 문제는 익명 볼륨을 통해 해결할 수 있다. 주석 처리된 VOLUME을 사용할 수도 있지만 아래와 같이 설정도 가능하다.

docker run -d -p 3000:80  --name feedback-app -v feedback:/app/feedback 
-v "/Users/hojin/Desktop/git_local:/app"
-v /app/node_modules feedback-node:volumes

도커는 충돌이 있는 경우 더 상세한 내부 경로를 우선하므로바인드 마운트된 볼륨의 내용을 덮어쓴다.

 

인자 바인드 마운트를 사용해서 코드가 변경될 때마다 이미지를 재빌드 하지 않아도 바로 결과를 확인할 수 있게 됐다.

 

도커가 호스트 파일 시스템을 마음대로 바꾸지 못하게 하면서 특정 폴더에만 쓰는 기능을 주기 위해서도 익명 볼륨으로 처리할 수 있는데

docker run -d --rm -p 3000:80  --name feedback-app -v feedback:/app/feedback 
-v "/Users/hojin/Desktop/git_local/docker-study/data-volumes-03-adj-node-code:/app:ro" 
-v /app/temp -v /app/node_modules feedback-node:volumes

ro 명령어를 통해 해당 바인드 마운트에 대한 read only를 설정하고 위에서 했던대로 익명 볼륨 상세 루트를 추가해 써야 하는 디렉토리만 허용하는 방법이다.

 

도커 볼륨을 관리하는 방법은

docker volume inspect feedback

입력해주면

[
    {
        "CreatedAt": "2022-10-17T13:06:54Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/feedback/_data",
        "Name": "feedback",
        "Options": null,
        "Scope": "local"
    }
]

해당 볼륨에 대한 정보를 볼 수 있다.


3. .dockerignore

지금까지의 볼륨을 사용하는데 있어서 위의 Dockerfile에서 COPY 명령어는 결론적으로 사용되지 않았다.

COPY 명령어를 없애도 똑같이 동작하지만 배포 환경에서는 버저닝이 필요하기 때문에 COPY를 사용한다.

 

이런 COPY 작업을 할 때 copy를 원하지 않는 파일을 위해 dockerignore 파일을 만든다.

요런식

 

 


4. 인수와 환경변수

인수는 Dockerfile 내부에서 이미지 빌드 시에 삽입되는 변수이고 환경변수는 Dockerfile이나 컨테이너 실행시에 추가되는 변수로

FROM node:14

WORKDIR /app

COPY package.json .

RUN npm install

COPY . .

ENV PORT 80

EXPOSE $PORT

# VOLUME [ "/app/node_modules" ]

CMD [ "npm", "start" ]
docker run -d --rm -p 3000:8000  --env PORT=8000 -e PORT2=80 --name feedback-app 
-v feedback:/app/feedback -v "/Users/hojin/Desktop/git_local/docker-study/data-volumes-03-adj-node-code:/app:ro"
-v /app/temp -v /app/node_modules feedback-node:volumes

지금까지 했던 코드에 --env나 -e를 이용해 넣어줄 수 있다.

 

항상 이렇게 넣을 순 없으니 --env-file을 이용해 env파일을 불러올 수도 있다.

 

docker run -d --rm -p 3000:8000 --env-file ./.env --name feedback-app -v feedback:/app/feedback 
-v "/Users/hojin/Desktop/git_local/docker-study/data-volumes-03-adj-node-code:/app:ro" 
-v /app/temp -v /app/node_modules feedback-node:volumes

위의 명령어를 보면 현재 실행하고 있는 터미널의 위치를 고려해 env 파일을 지정한 것을 알 수 있다.

 

인수는 이미지를 빌드할 때 넣어줄 수 있는데

FROM node:14

ARG DEFAULT_PORT=80

WORKDIR /app

Dockerfile 아무데나 ARG로 변수를 선언해주고

이미지 빌드시에

docker build -t feedback-node:dev --build-arg DEFAULT_PORT=8000 .

넣어줄 수 있다.

'docker-kub' 카테고리의 다른 글

docker - Docker Compose, utility container  (0) 2022.11.13
docker - 멀티 컨테이너 어플리케이션  (0) 2022.10.30
docker - 네트워킹  (0) 2022.10.19
docker - 기본 명령어  (0) 2022.10.04
docker - introduction  (0) 2022.09.08