Работа с томами (Volumes) в Docker

Thank you for reading this post, don't forget to subscribe!

Volumes — явля­ют­ся меха­низ­мом для сохра­не­ния дан­ных, созда­ва­е­мых и исполь­зу­е­мых Docker кон­тей­не­ра­ми (с хосте­вой маши­ны на контейнер).

Создание Volumes в Docker

Что­бы создать Volume, выполните:

$ docker volume create --name http-custom-data
http-custom-data

Про­ве­рим что име­ет­ся в докере:
$ docker volume ls

Или выве­сти толь­ко необходимый:
$ docker volume ls | grep http-custom-data
local http-custom-data

Полу­чим подроб­ную инфу:
$ docker volume inspect http-custom-data

Созда­дим index.html файл:
my custom page from Volume
Ско­пи­ру­ем создан­ный файл в вольюму:
$ cp index.html /var/lib/docker/volumes/http-custom-data/_data/
Смот­рим, есть ли файл:
$ ls -l /var/lib/docker/volumes/http-custom-data/_data/
total 4
-rw-r--r-- 1 root root 28 Oct 11 20:40 index.html
И запу­стим кон­тей­нер nginx:
$ docker run -d -P -v http-custom-data:/usr/share/nginx/html nginx
b94feb29c143eea7900965706447151e96df86539312bdcea79b42952bae701a
Посмот­рим какой порт юза­ет создан­ный контейнер:
$ docker port $(docker ps -lq)
80/tcp -> 0.0.0.0:32769
Дер­нем курл что­бы убе­дит­ся что ско­пи­ро­ван­ные дан­ные име­ют­ся в докере:
# curl 127.0.0.1:32769
my custom page from Volume

Соб­ствен­но, что и тре­бо­ва­лось дока­зать — все есть и рабо­та­ет долж­ным образом.

Создание TMPFS Volumes в Docker

Рас­смот­рим при­мер созда­ния TMPFS Volume (дан­ные хра­нят­ся в RAM) сле­ду­ю­щим образом:

$ docker volume create --driver local \ --opt type=tmpfs \
--opt device=tmpfs \
--opt o=size=100m,uid=1000 \
foo
Созда­ние BTRFS Volumes в Docker

Рас­смот­рим при­мер созда­ния BTRFS Volume (дан­ные хра­нят­ся на /dev/sda2 раз­де­ле) сле­ду­ю­щим образом:

$ docker volume create \
--driver local \
--opt type=btrfs \
--opt device=/dev/sda2 \
foo
Созда­ние NFS Volumes в Docker

Рас­смот­рим при­мер созда­ния NFS Volume (в уда­лен­ной части NFS) сле­ду­ю­щим образом:

$ docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.1,rw \
--opt device=:/path/to/dir \
foo

Монтирование Volumes  с хостевой машины в контейнер.

Добав­ле­ние Volum-ов  в контейнер(ы)  явля­ют­ся хоро­шим реше­ни­ем т.к при завер­ше­нии жиз­ни кон­тей­не­ра все ваши дан­ные будут уте­ря­ны. Если ваш кон­тей­нер гене­ри­ру­ет непо­сто­ян­ные дан­ные, рас­смот­ри­те воз­мож­ность исполь­зо­ва­ния мон­ти­ро­ва­ния tmpfs, что­бы избе­жать посто­ян­но­го хра­не­ния дан­ных в любом месте и уве­ли­чить про­из­во­ди­тель­ность кон­тей­не­ра, избе­гая запи­си на пере­за­пи­сы­ва­е­мый слой контейнера.

Рас­смот­рим пример:
$ docker run -d -p 127.0.0.1:8080:80 -v $(pwd):/var/www/html:ro httpd

Или вот еще примеры:
$ docker run --rm -v $(pwd):$(pwd) -w $(pwd) maven:3.3-jdk-8 clean package
$ docker run -d -v /var/log/httpd:/var/log/httpd httpd
$ docker run -d -v /var/log/tomcat:/usr/local/tomcat/logs tomcat
$ docker run -d -v /data:/etc/mongo mongo

Монтирование tmpfs в Docker

Мон­ти­ро­ва­ние tmpfs явля­ет­ся вре­мен­ным и сохра­ня­ет­ся толь­ко в памя­ти хоста. Когда кон­тей­нер оста­но­вит­ся, мон­ти­ро­ва­ние tmpfs будет уда­ле­но, и фай­лы, напи­сан­ные там, не будут сохранены.

Огра­ни­че­ния мон­ти­ро­ва­ния tmpfs:

  • Вы не може­те шарить дан­ные мон­ти­ро­ва­ни­ем tmpfs меж­ду контейнерами.
  • Эта функ­ция доступ­на толь­ко в том слу­чае, если вы исполь­зу­е­те Docker в Linux.

При­мер запуска:
$ docker run -d -ti -p127.0.0.1:8282:8200 --name=vault_test --mount type=tmpfs,destination=/tmp vault:0.11.4

Case #1. VOLUME в Dockerfile

Созда­дим Dockerfile:

FROM nginx
RUN echo "default page" > /usr/share/nginx/html/index.html VOLUME /usr/share/nginx/html/
Собе­рем:
$ docker build -t nginx_v:1 .
Successfully built efdfe29e01fd Successfully tagged nginx_v:1
Про­ве­рим PRE-BUILT  данные:

$ docker run -d -p80:80 nginx_v:1
$ curl localhost

default page
Changing data:
$ docker exec $(docker ps -lq) \
sh -c 'echo changed page > /usr/share/nginx/html/index.html'
$ curl localhost
changed page
Оста­но­вим контейнер:
$ docker stop $(docker ps -lq)
Где мои данные?
$ docker inspect $(docker ps -lqa) | jq '.[]|.Mounts'

[codesyntax lang="php" blockstate="collapsed"]

[/codesyntax]

Чека­ем:
$ cat /var/lib/docker/volumes/395c2b4639c0a577ff25b379adc201e77a1cedbc5d50e91150149e1f51191182/_data/index.html
changed page
Уда­лим кон­тей­нер и погля­дим что вый­дет с данными:
$ docker rm $(docker ps -lqa)
$ cat /var/lib/docker/volumes/395c2b4639c0a577ff25b379adc201e77a1cedbc5d50e91150149e1f51191182/_data/index.html
changed page
Case #2. Созда­ние Volume для контейнера

Запус­ка­ем кон­тей­нер вот так:

$docker run -d -p 80:80 -v /usr/share/nginx/html nginx
$ curl localhost
<title>Welcome to nginx!</title>
Нахо­дим куда смон­ти­ру­ет­ся Volume:
$ docker inspect $(docker ps -lqa) | jq -r '.[]|.Mounts[] | .Source'
/var/lib/docker/volumes/b6400a50ad0a0e8f11fa962cb99e7d2e425ac1654c4e4ea1376ae61a05e5dbc8/_data
Чека­ем данные:
$ echo changed > $(docker inspect $(docker ps -lqa) | jq -r '.[]|.Mounts[] | .Source')/index.html
$ curl localhost
changed

Case #3. Шара данных между контейнерами

На 1-м кон­тей­не­ре, запустим:

$ docker run -d -v /usr/share/nginx/html --name c1 nginx
$ echo changed > $(docker inspect c1 | jq -r '.[]|.Mounts[] | .Source')/index.html

На 2-м кон­тей­не­ре, запустим:

$ docker run --volumes-from c1 busybox cat /usr/share/nginx/html/index.html
changed

Изменить storage driver для docker в Linux

Про­ве­рим что имеется:

$ docker info | egrep "(Cgroup|Storage) Driver"
Storage Driver: overlay2
Cgroup Driver: cgroupfs
Мож­но выпол­нить настройку:
$ cat << EOF > /etc/docker/daemon.json {
"exec-opts": [ "native.cgroupdriver=systemd"
],
"storage-driver": "devicemapper" }
EOF

Пере­за­пус­ка­ем сервис:
# systemctl daemon-reload
# systemctl restart docker.service

Ну и мож­но посмот­реть что вышло:
# docker info | egrep "(Cgroup|Storage) Driver"
Storage Driver: devicemapper
Cgroup Driver: systemd