[Docker] 볼륨 (Volume)

J_Coder·2025년 2월 7일

Docker

목록 보기
3/4
post-thumbnail

5줄 요약

  1. 컨테이너는 원래 상태로 돌아가고자 하기 때문에 컨테이너 내부 데이터 영속성을 부여하기 위해서는 볼륨을 사용해야 한다.
  1. 태초 마을을 보기 싫다면 볼륨을 사용하도록 하자.
  1. MySQL과 Redis 같은 이미지에서 Dockerfile에 VOLUME 명령을 넣어놨기에 컨테이너를 생성하면 자동으로 VOLUME이 만들어진다
  1. 볼륨 생성 방식은 3가지(create 명령, run 명령, Dockerfile 작성) 방식이 있다. 연결 방식은 2가지(익명, HostOS)다.
  1. 볼륨도 export해서 다른 사람에게 공유가 가능하고, 이미지로 만들수도 있다. 또한 Docker Hub에 이미지 형식으로 올릴 수 있다.

학습 배경

  • Linux에 대해 선행적으로 알고 있어야 이해하기 쉽다.
  • Docker에 대한 개념은 존재해야 한다. 이미지와 컨테이너에 대해서는 꼭 알고 있어야 한다.
    시리즈를 참고해서 이전 포스팅을 보고 와주세요!

학습 계기

  • 네이버 부스트 캠프에서 만든 최종 프로젝트 🎋Denamu에 도커를 적용하던 중, 개발 환경 이미지를 구축해야 했다.
    개발 환경이라 하면, 작업을 하고 나서 작업 내역이 사라지면 안 된다. Volume을 사용 안 했을 때, 컨테이너 내에서 작업했을 경우 작업이 날라가는 문제가 있었다.

  • MySQL이나 Redis 같은 데이터 영속성을 필요로 하는 이미지들을 이용하여 컨테이너를 생성하면 자동으로 볼륨이라는 것이 생성된다. 볼륨이 무엇인지 알아본다.


볼륨

  • 정의: 컨테이너의 데이터를 영속적으로 저장하기 위해 만드는 공간이다.

저번 포스팅에서 이미지를 만들고, 컨테이너를 실행하는 명령어에 대해서 간략하게 알아봤다.

프로젝트 소스 코드를 포함하며 서버를 동작하게 하는 이미지를 만들었다고 가정해보자.

컨테이너를 생성하고 원격 탐색기 (필자는 VSCode의 원격 탐색기 익스텐션을 사용했다.)를 접속하면 컨테이너 내부에 소스 코드가 존재할 것이다.

  • 원격 탐색기

  • 원격 탐색기로 접속한 컨테이너 내부

만약 개발 환경 구축을 위해 이미지를 Docker Hub에 업로드 하고, 다른 환경에서 Docker Hub에 업로드한 이미지를 Pull하여 컨테이너를 생성한다고 가정하자.

이후 컨테이너 내에서 아무 생각 없이 작업을 수행하고 컨테이너를 껐다 켜면?

'피카츄 저기봐 태초마을이야.'

컨테이너는 원래 상태로 돌아가기 때문에 컨테이너를 재실행하면 작업한 내역이 전부 사라지고
야근을 하면 된다. 아니면 눈물 베개

이때 사용하는 영속적인 공간을 볼륨이라고 한다.

볼륨 저장 위치

볼륨은 그럼 컨테이너에 저장되는 걸까?
아니다. 볼륨은 HostOS에 존재하게 된다.
정확히 말하자면 호스트 OS의 /var/lib/docker/volumes(Docker 엔진 스토리지) 디렉토리 안에 저장된다.

컨테이너 안에 볼륨이 있다는 건 이상할 것이다. 컨테이너는 원래 상태로 돌아가기 때문이다. 그렇기에 컨테이너 외부에 존재해야 한다.

대충 볼륨의 개념은 호스트 OS에 있는 디렉토리와 컨테이너 내의 디렉토리를 연동하기에 컨테이너를 꺼도, 작업 내역은 호스트 OS에 남게 되며, 컨테이너를 다시 켜면 호스트 OS에 있는 데이터가 컨테이너로 적용된다고 생각하면 된다.

이렇게 컨테이너의 디렉토리와 호스트 OS의 디렉토리를 볼륨으로 연결하면, 컨테이너 내에서 작업을 해도 태초 마을을 안 봐도 된다.

나중에 도커 볼륨을 만들었을 때

$ docker volume inspect [볼륨_이름] # 볼륨 정보 명령

명령어를 통해 볼륨의 실제 위치를 볼 수 있다.

컨테이너 작업 내역을 저장하기

볼륨을 생성해보도록 하자.
볼륨 생성 방식은 3개다.

  1. docker volume create 사용
    $ docker volume create [볼륨_이름] # 볼륨 생성 명령
  2. 컨테이너 생성할 때 -v(volume) 옵션으로 넣어주기
  3. Dockerfile에 VOLUME 명령 넣기

생성된 볼륨 목록은 다음과 같이 볼 수 있다.

$ docker volume ls # 볼륨 목록 확인 명령

그럼 볼륨을 이용하여 컨테이너를 실행하도록 해보자.

이때, 두 가지 방법의 볼륨 링크 방식이 있다.

두 가지의 방법을 동시에 사용할 수도 있다.

추가로 볼륨 삭제 명령어는 다음과 같다.

$ docker volume rm [볼륨_이름] # 볼륨 삭제 명령
$ docker volume prune # 사용하지 않는 볼륨 정리 명령

❗ 컨테이너와 연결되어 있는 볼륨은 삭제할 수 없다. 컨테이너를 먼저 지우고 볼륨을 제거해야 한다.

잉여 볼륨이 쌓이다 보면 용량을 많이 차지하니 필요없는 부분은 지우도록 하자.

1. 익명 볼륨 생성

$ docker run -it -v [컨테이너_내부_디렉토리_경로] (이미지) 

컨테이너를 생성할 때, 해싱된 이름의 볼륨을 생성하게 된다. 그리고 이 볼륨은 컨테이너 경로와 연결된다.
위에서 본 볼륨 생성 명령어를 입력하지 않아도 자동으로 생성해준다.

컨테이너 내의 [컨테이너_내부_디렉토리_경로] 내에서 파일을 추가, 변경, 삭제를 하면 Volume에도 연동이 되어 저장된다.
/var/lib/docker/volumes/해싱 이름으로 저장된다.

볼륨을 눌러보면, Container in-use 탭에서 볼륨을 사용하는 컨테이너 위치를 볼 수 있다.

현재 이미지에서는 denamu-dev-feed-crawler-1이라는 컨테이너에서 사용하고 있다.

단점
해당 방식은 Dockerfile에서 간단하게 VOLUME으로 익명 볼륨을 생성할 수 있는 장점이 있다. 하지만, 이 볼륨을 사용하는 컨테이너가 지워진다고 생각해보자.
해싱된 이름을 가진 볼륨의 용도를 알 수 있을까? 이미 컨테이너가 지워졌기에 볼륨 탭의 Container in-use에 어느 컨테이너에서 사용중인지 볼 수 없다. 그렇기에 판단하기 상당히 어렵다.
또한, 이 방식은 파일 하나에 대해서는 Volume을 연결할 수 없다. 무조건 디렉토리 단위로 연결해야 한다.

그래서 Host OS와 연결하는 방식을 사용하는 경우가 많다. 다만, 정답은 아니다. 상황에 따라서 알잘딱하게 사용하도록 하자.

💡 도커 볼륨 이름 지정하기
도커 볼륨에 이름을 지정하고 싶으면 docker volume create를 먼저 수행하여 이름을 가진 볼륨을 생성하고 다음과 같이 수행해야 한다.

$ docker run -v [볼륨_이름]:[컨테이너_내부_디렉토리_경로]

2. HostOS와 링크 볼륨 생성

$ docker run -it -v [호스트_OS_경로]:[컨테이너_경로] (이미지) 

위 1번 방식의 단점을 보완하는 방법이다.
2번의 방식은 호스트 OS의 디렉토리 경로를 컨테이너 경로에서 사용할 수 있게 한다.

이 방식은 컨테이너가 지워져도 호스트 OS의 원하는 경로에 남기 때문에 데이터 파악을 하기 쉽다.
또한, 1번 방식이 단위가 디렉토리 였다면, 2번 방식은 개별 파일로도 가능하다.
그래서 더 세밀한 볼륨 범위 설정이 가능하다.

Dockerfile 작성하기

❗ Dockerfile에서 사용하는 VOLUME 명령은 볼륨 생성 1번 방식으로만 사용할 수 있다.
HostOS와 연결하고 싶다면 2번 방식으로 컨테이너 실행 시, 옵션을 넣어줘야 한다.

컨테이너를 실행할 때 볼륨 옵션을 넣을 수도 있고, Dockerfile(이미지 빌드 파일)에도 첨부할 수 있다.

Dockerfile(이미지 빌드 파일)에 첨부할 경우 컨테이너에 별 다른 볼륨 옵션을 넣지 않아도 볼륨이 생성된다.

Dockerfile에서 다음과 같이 작성하면 된다.

FROM 베이스 이미지

VOLUME ["경로"]

CMD 실행 명령

그럼 컨테이너 내의 경로와 연결된 볼륨을 자동으로 생성할 수 있게 이미지를 빌드할 수 있다.
이후 컨테이너를 생성하면 해시 이름을 가진 익명 볼륨이 생성되며 컨테이너 내부 디렉토리와 연결될 것이다.

MySQL과 Redis 이미지가 이 방식으로 작성되어 있다.

MySQL 이미지를 대표적으로 본다면, VOLUME으로 /var/lib/mysql을 저장하게 되어 있다.
그렇기에 MySQL 컨테이너를 재시작해도 DB 내부의 데이터는 안 지워지는 것이다.
그리고 MySQL 컨테이너를 생성할 때 자동으로 볼륨이 생성되는 것이다.

컨테이너끼리 볼륨 하나로 파일 공유하기

위에서 본 화면인 Volume의 Container in-use 탭을 보면 충분히 응용할 수 있다는 생각이 든다.
만약, Container in-use에 2개의 컨테이너가 있다면? 컨테이너끼리 하나의 볼륨으로 데이터를 주고 받을 수 있게 된다.

볼륨 정보 변경

$ docker volume update [옵션] [볼륨_이름] # 볼륨 정보 변경

생성한 볼륨 정보를 변경할 수 있다.

옵션은 --availability(가용성) 밖에 없다.

옵션설명
--availabilityactive(default)볼륨을 활성 상태로 존재하게 한다.
pause볼륨에 더 이상 쓰기 작업을 받지 않도록 일시 중지 상태로 설정한다.
drain볼륨에 새로운 작업을 받지 않고, 더 이상 사용되지 않게 한다.

볼륨의 상태를 변경할 수 있다. 초록색 불이 active 상태다.

볼륨 다른 사람에게 공유하기

볼륨을 빠르게 압축하여 다른 사람에게 공유할 수 있다.

export

볼륨을 눌러서 exports 탭에 들어가면 볼륨을 export 할 수 있는 것들이 있다.

Schedule export는 주기적으로 볼륨을 압축하여 압축 파일을 백업으로 두는 형식인데, Schedule을 등록하려면 돈 내야 한다.

Quick export를 누르면

이런 화면으로 뜬다.
Local file로 추출하면, 볼륨 이름의 압축 파일이 생성되고, 이것을 다른 사람들에게 공유할 수 있다.

Local Image는 볼륨 데이터를 포함하는 새로운 Docker Image를 만드는 방식이다. 볼륨 데이터는 /volume-data 경로에 저장된다.

New Image는 해당 Volume을 가진 이미지를 생성하고 Local에 유지한다.

Registry는 Docker Hub에 이미지 형식으로 Push하게 되며, 모든 사람들이 접근할 수 있게 된다.

import

export로 추출된 볼륨 파일을 import 할 수 있다.

우측 상단의 import를 누르면

로컬 파일, 로컬 이미지, Docker Hub로부터 받는 이미지 중 선택할 수 있다.


결론

볼륨을 이용하면 Docker Container 내의 데이터에 영속성을 부여할 수 있다.
개발 환경 같이 작업한 내역을 날리면 안 된다면 꼭 볼륨을 설정해두도록 해야 한다.

도커 볼륨에서 러닝 커브가 조금 있었다.
볼륨 생성 방식이 3가지고, 볼륨 연결 방식이 2가지인데, 연결에서 HostOS 연결 같은 경우 볼륨을 생성하는 건 아니라서 헷갈렸던 것 같다.

HostOS는 단순 연결만 하는 방식이다. 그래서 Docker Desktop의 Volume 탭에 볼륨이 안 뜬다.
처음에는 익명 볼륨, 네이밍 볼륨, HostOS 볼륨 3개 차이가 많이 헷갈렸는데 맨 땅에 해딩하다 보니 익숙해졌다. ㅎ.ㅎ
기술 도입을 할 때 학자형인줄 알았는데 은근 야생형인듯 하다.

정확하게 볼륨이 어떤 원리로 동작하기에 여러 Container에서 동시적으로 접근할 수 있는지는 조금 의문이 든다.

다음에 Docker 시리즈 작성을 완료하고 Docker Engine의 동작 원리에 대해서 자세하게 학습할 필요성이 있다.
대충 Cgroup, namespace을 사용하는 것 같은데 나보고 만들라하면 뇌정지가 온다. Docker 만들어 보는 것도 재밌을 듯하다.

시간 남으면 해봐야지

profile
컴퓨터 분야를 가리지 않고 즐기는 백엔드 개발자 지망생입니다.

0개의 댓글