[docker] docker 볼륨 - storage drivers
카테고리: docker
태그: docker
🎯목표
- Docker가 이미지를 빌드하는 방법
- Docker가 이미지를 저장하는 방법
- Docker가 이미지를 사용하는 방법
스토리지 드라이버 vs 볼륨
스토리지 드라이버
- Docker는 스토리지 드라이버를 사용하여 이미지 레이어를 저장하고 컨테이너의 쓰기 가능한 레이어에 데이터를 저장합니다.
- 컨테이너의 쓰기 가능 계층은 컨테이너가 삭제된 후에는 지속되지 않지만 런타임 시 생성되는 임시 데이터를 저장하는 데 적합합니다.
- 스토리지 드라이버는 공간 효율성에 최적화 되어있어 쓰기 속도는 기본 파일 시스템 성능보다 느립니다. (특히 copy-on-write(COW) 파일 시스템을 사용하는 스토리지 드라이버의 경우)
볼륨
- 컨테이너의 수명을 넘어 지속되어야 하는 데이터 및 컨테이너 간에 공유되어야 하는 데이터에는 볼륨을 사용해야합니다.
- 데이터베이스 스토리지와 같은 쓰기 집약적인 애플리케이션은 기존 데이터가 읽기 전용 계층에 있는 경우 성능 오버헤드가 발생할 수 있습니다.
- 이런 경우 해당 데이터는 볼륨에 저장되도록 해야합니다
이미지와 레이어
Docker 이미지는 일련의 레이어로 구성되며 맨 마지막 레이어를 제외한 각 레이어는 읽기 전용입니다. 다음은 Dockerfile에서 각 명령이 새로운 이미지 계층을 만드는 과정을 보여줍니다.
# syntax=docker/dockerfile:1
FROM ubuntu:18.04
LABEL org.opencontainers.image.authors="org@example.com"
COPY . /app
RUN make /app
RUN rm -r $HOME/.cache
CMD python /app/app.py
FROM: ubuntu18.04 이미지 레이어를 가져와 컨테이너의 베이스 이미지로 사용합니다.LABEL: 이미지의 메타데이터만 수정하고 새 계층을 생성하지 않습니다.COPY: Docker 호스트의 현재 디렉터리의 내용을 컨테이너의 /app 디렉터리에 복사하고 결과를 새 계층에 기록합니다.RUN:make명령을 통해 /app 디렉터리를 빌드하고 결과를 새 계층에 기록합니다.RUN: 두 번째RUN명령은 캐시 디렉터리를 제거하고 결과를 새 계층에 기록합니다.CMD: 마지막CMD명령은 컨테이너 내에서 실행할 명령을 지정할 이미지의 메타데이터만 수정하고 새로운 이미지 계층을 생성하지 않습니다.
Note:
각 레이어는 이전 레이어와의 차이 집합일 뿐입니다. 파일을 추가하거나 제거하면 새 레이어가 생성됩니다. 위의 예에서 $HMOE/.cache 디렉터리는 제거되지만 이전 레이어에서 계속 사용할 수 있으며 이미지의 전체 크기에 추가됩니다.
이미지 레이어 다이어그램
- 새 컨테이너를 만들 때 기본 레이어 위에 쓰기 가능한 새 레이어를 추가합니다. 이 계층은 종종 “컨테이너 계층”이라고 합니다.
- 새 파일을 작성하거나 기존 파일 수정, 삭제와 같이 실행 중인 컨테이너에 대한 모든 변경 사항은 이 쓰기 가능 계층에 기록됩니다.
- 아래 다이어그램은
ubuntu:15.04이미지를 기반으로 하는 컨테이너를 보여줍니다.

스토리지 드라이버는 이러한 계층이 서로 상호 작용하는 방식에 대한 세부 정보를 처리합니다. 다양한 스토리지 드라이버를 사용할 수 있으며 상황에 따라 장점과 단점이 있습니다.
쓰기 가능 계층
각 컨테이너에는 쓰기 가능한 계층이 있고 모든 변경 사항은 이 컨테이너 계층에 저장되기 때문에 여러 컨테이너가 동일한 기본 이미지를 공유하면서도 고유한 데이터 상태를 가질 수 있습니다.

Docker는 스토리지 드라이버를 사용하여 기본 이미지 레이어와 쓰기 가능한 컨테이너 계층의 콘텐츠를 관리합니다. 각 스토리지 드라이버는 구현을 다르게 처리하지만 모든 드라이버는 스택 가능한 이미지 레이어와 CoW 전략을 사용합니다.
컨테이너 크기
실행중인 컨테이너의 대략적인 크기를 보려면 docker ps -s 명령을 사용할 수 있습니다. -s 옵션을 덧붙이면 두 개의 새로운 열이 출력됩니다.
size: 각 컨테이너의 쓰기 가능한 계층에 사용되는 데이터의 양virtual size: 읽기 전용 이미지 계층의 데이터와 쓰기 가능한 계층에서 사용되는 데이터를 합친 크기입니다. 동일한 이미지에서 시작된 여러 개의 컨테이너는 같은 읽기 전용 계층을 공유하고 실제 디스크에서 사용 중인 크기는 하나의 이미지 크기입니다.- 컨테이너와 관련된
size와virtual size크기 계산에 포함되지 않는 목록도 있습니다.- 로깅 드라이버에 의해 저장되는 로그 파일에 사용되는 디스코 공간
- 컨테이너에서 사용하는 호스트 볼륨 및 도커 볼륨
이미지 레이어 공유
- 두 개의 Dockerfile을 이용하여 두 개의 이미지를 만듭니다.
# acme/my-base-image:1.0 FROM alpine RUN apk add --no-cache bash # acme/my-base-final:1.0 FROM acme/my-base-image:1.0 COPY . /app RUN chmod +x /app/hello.sh CMD /app/hello.sh - 첫 번째 이미지를 빌드합니다.
$ docker build -t acme/my-base-image:1.0 -f Dockerfile.base . - 두 번째 이미지를 빌드합니다.
$ docker build -t acme/my-final-iamge:1.0 -f Dockerfile . - 이미지의 크기를 확인합니다.
$ docker images --format "table \t\t" IMAGE ID REPOSITORY SIZE 7e378a742edd acme/my-final-image 9.29MB be79c158a01c acme/my-base-image 9.29MB - 각 이미지의 기록을 확인합니다.
$ docker image history acme/my-base-image:1.0 IMAGE CREATED CREATED BY SIZE COMMENT be79c158a01c 3 minutes ago /bin/sh -c apk add --no-cache bash 2.24MB 49176f190c7e 6 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B <missing> 6 weeks ago /bin/sh -c #(nop) ADD file:587cae71969871d3c… 7.05MB $ docker image history acme/my-final-image:1.0 IMAGE CREATED CREATED BY SIZE COMMENT 7e378a742edd 3 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/app… 0B a824b61197f6 3 minutes ago /bin/sh -c chmod +x /app/hello.sh 39B 0579d758da9e 3 minutes ago /bin/sh -c #(nop) COPY dir:7d0c2712efd6bd685… 222B be79c158a01c 4 minutes ago /bin/sh -c apk add --no-cache bash 2.24MB 49176f190c7e 6 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B <missing> 6 weeks ago /bin/sh -c #(nop) ADD file:587cae71969871d3c… 7.05MB
Note:
- 일부 단계는 크기(0B)가 없으며 메타데이터 전용 변경 사항으로, 이미지 레이어를 생성하지 않고 메타데이터 자체외에 다른 크기를 차지하지 않습니다.
- 최종 이미지에는 첫 번째 이미지의 2개 레이어와 두 번째 이미지에 추가된 2개 레이어 모두 포함됩니다.
- 처음 두 레이어는 두 이미지에서 동일합니다. 공유 이미지 레이어는 한 번만 저장됩니다. 이미지를 이미지 레지스트리로 pull 하거나 push 하는 경우에도 공유됩니다
- 따라서 공유 이미지 레이어는 네트워크 대역폭과 스토리지를 줄일 수 있습니다.
이미지 레이어 크기
- 컨테이너를 시작하면 쓰기 가능 계층이 이미지 레이어 위에 추가됩니다. 컨테이너에서 이루어지는 대부분의 쓰기 작업은 이 쓰기 가능 계층의 새로운 공간에 쓰여집니다.
- 컨테이너가 변경하지 않는 파일은 이 쓰기 가능한 계층에 복사되지 않습니다. 이것은 쓰기 가능한 레이어가 가능한 작다는 것을 의미합니다.
- 컨테이너의 기존 파일이 수정되면 스토리지 드라이버는 CoW 작업을 수행합니다. 관련된 특정 단계는 특정 스토리지 드라이버에 따라 다릅니다.
overlay2,overlay및aufs드라이버의 경우 CoW 작업은 대략적으로 다음의 순서를 따릅니다.- 업데이트할 파일의 이미지 레이어를 검색합니다. 검색은 최신 레이어에서 시작하여 한 번에 한 레이어씩 이미지 레이어로 내려갑니다.
- 처음으로 찾은 파일의 복사본을 컨테이너의 쓰기 가능 계층에 복사합니다.
- 이 파일 사본에 수정이 이루어지며 컨테이너는 하위 계층에 존재하는 파일의 읽기 전용 사본을 볼 수 없습니다.
- CoW가 작동하는 방식을 이해하기 위해 다음 절차를 참고하세요.
- acme/my-final-image:1.0 이미지를 기반으로 하는 5개의 컨테이너를 가동합니다.
$ docker run -dit --name my_container_1 acme/my-final-image:1.0 bash \ && docker run -dit --name my_container_2 acme/my-final-image:1.0 bash \ && docker run -dit --name my_container_3 acme/my-final-image:1.0 bash \ && docker run -dit --name my_container_4 acme/my-final-image:1.0 bash \ && docker run -dit --name my_container_5 acme/my-final-image:1.0 bash - 각 컨테이너의 크기를 확인합니다. 이를 통해 각 컨테이너는 이미지 레이어를 공유하고 쓰기 가능 계층에는 아무런 데이터가 추가되지 않았음을 알 수 있습니다.
$ docker ps --size --format "table \t\t\t" CONTAINER ID IMAGE NAMES SIZE 0015627b8341 acme/my-final-image:1.0 my_container_5 0B (virtual 9.29MB) 4af1078b876e acme/my-final-image:1.0 my_container_4 0B (virtual 9.29MB) 17c41d4edc4a acme/my-final-image:1.0 my_container_3 0B (virtual 9.29MB) 18200fc60af5 acme/my-final-image:1.0 my_container_2 0B (virtual 9.29MB) 73ebdfc9d5e4 acme/my-final-image:1.0 my_container_1 0B (virtual 9.29MB) - “hello” 라는 단어를 my_container_1, my_container_2, my_container_3의 쓰기 가능 계층에 저장합니다.
$ for in in {1..3}; do docke exec my_container_$i sh -c 'printf hello > /out.txt'; done - 다시 각 컨테이너의 크기를 확인합니다. 이를 통해 이미지 레이어는 영향을 받지 않으면 여전히 모든 컨테이너에서 공유되지만 1,2,3 컨테이너에 쓰인 데이터는 고유하며 공유되지 않음을 알 수 있습니다.
$ docker ps --size --format "table \t\t\t" CONTAINER ID IMAGE NAMES SIZE 0015627b8341 acme/my-final-image:1.0 my_container_5 0B (virtual 9.29MB) 4af1078b876e acme/my-final-image:1.0 my_container_4 0B (virtual 9.29MB) 17c41d4edc4a acme/my-final-image:1.0 my_container_3 5B (virtual 9.29MB) 18200fc60af5 acme/my-final-image:1.0 my_container_2 5B (virtual 9.29MB) 73ebdfc9d5e4 acme/my-final-image:1.0 my_container_1 5B (virtual 9.29MB)
Note:
- CoW는 공간을 절약할 뿐만 아니라 컨테이너 시작 시간도 줄여줍니다. 컨테이너를 생성할 때 동일한 이미지 레이어가 이미 저장되어 있다면 Docker는 쓰기 가능 계층만 생성하면 됩니다.
- Docker가 새 컨테이너를 생성할 때마다 기본 이미지 스택의 전체 복사본을 만들어야 한다면 컨테이너 생성 시간과 사용되는 디스크 공간이 크게 증가할 것입니다.
- 쓰기 작업이 많은 애플리케이션의 경우 컨테이너에 데이터를 저장하면 안됩니다. 데이터베이스와 같은 애플리케이션은 특히 기존 데이터가 읽기 전용 계층에 존재할 때 문제가 될 수있습니다. 이는 CoW 작업을 생각해보면 금방 이해할 수 있습니다.
- 컨테이너 계층에 쓰는 대신 Docker 볼륨을 사용하십시오. 볼륨은 컨테이너 간에 공유가 용이할 뿐만아니라 컨테이너의 쓰기 가능 계층 크기를 늘리지 않습니다.
📌출처
👍 개인 공부 기록용 블로그입니다. 오류나 조언이 있으시면 언제든지 댓글 혹은 메일로 남겨주시면 감사하겠습니다! 😄
댓글남기기