Как работать с постоянным хранилищем (например, базами данных) в Docker

993

Как люди обращаются с постоянным хранилищем для ваших контейнеров Docker?

В настоящее время я использую этот подход: построить образ, например, для PostgreSQL, а затем запустить контейнер с

docker run --volumes-from c0dbc34fd631 -d app_name/postgres

ИМХО, у этого есть недостаток, что я никогда не должен (случайно) удалять контейнер "c0dbc34fd631".

Другая идея заключалась бы в том, чтобы подключить тома хоста "-v" в контейнер, однако, идентификатор пользователя в контейнере не обязательно совпадает с идентификатором пользователя с хоста, и тогда разрешения могут быть испорчены.

Примечание: Вместо того , --volumes-from 'cryptic_id'вы можете также использовать , --volumes-from my-data-containerгде my-data-containerэто имя, назначенное в контейнер данных только, например , docker run --name my-data-container ...(см обслуживаемого ответ)

juwalter
источник
Извините, я неправильно сформулировал это, я хотел сказать: все мои будущие экземпляры из этого изображения зависят от этого контейнера. Если я удаляю этот контейнер случайно, у меня проблемы.
Ювальтер
@AntonStrogonoff - да, ошибка формулировки - я хотел сказать: мне нужно убедиться, что я никогда не буду удалять этот (возможно) старый контейнер, потому что тогда ссылка на «постоянное» хранилище также исчезнет
juwalter
так и должно быть --name. у вас есть-name
Shammel Lee

Ответы:

986

Докер 1.9.0 и выше

Использовать том API

docker volume create --name hello
docker run -d -v hello:/container/path/for/volume container_image my_command

Это означает, что шаблон контейнера только для данных должен быть оставлен в пользу новых томов.

На самом деле API тома - это только лучший способ достичь того, что было шаблоном контейнера данных.

Если вы создаете контейнер с помощью -v volume_name:/container/fs/pathDocker, он автоматически создает именованный том, который может:

  1. Быть перечисленным через docker volume ls
  2. Быть идентифицированным через docker volume inspect volume_name
  3. Резервное копирование как обычный каталог
  4. Резервное копирование, как и раньше, через --volumes-fromсоединение

Новый API томов добавляет полезную команду, которая позволяет определять висячие тома:

docker volume ls -f dangling=true

А затем удалите его через его имя:

docker volume rm <volume name>

Как подчеркивает @mpugach в комментариях, вы можете избавиться от всех висячих томов с помощью одной строки:

docker volume rm $(docker volume ls -f dangling=true -q)
# Or using 1.13.x
docker volume prune

Докер 1.8.x и ниже

Подход, который лучше всего работает для производства, заключается в использовании контейнера только для данных .

Контейнер только для данных запускается на изображении barebones и фактически ничего не делает, кроме предоставления объема данных.

Затем вы можете запустить любой другой контейнер, чтобы иметь доступ к томам контейнера данных:

docker run --volumes-from data-container some-other-container command-to-execute
  • Здесь вы можете получить хорошее представление о том, как организовать различные контейнеры.
  • Здесь есть хорошее понимание того, как работают тома.

В этом сообщении блога есть хорошее описание так называемого контейнера как шаблона объема, в котором разъясняется основной смысл наличия контейнеров только для данных .

Документация Docker теперь содержит ОПРЕДЕЛИТЕЛЬНОЕ описание контейнера в виде тома / с .

Ниже приведена процедура резервного копирования / восстановления для Docker 1.8.x и ниже.

РЕЗЕРВНЫЙ:

sudo docker run --rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
  • --rm: удалить контейнер при выходе
  • --volumes-from DATA: присоединить к томам, совместно используемым контейнером DATA
  • -v $ (pwd): / backup: bind смонтировать текущий каталог в контейнер; записать файл tar в
  • busybox: небольшое простое изображение - хорошо для быстрого обслуживания
  • tar cvf /backup/backup.tar / data: создает несжатый tar-файл из всех файлов в каталоге / data

ВОССТАНОВИТЬ:

# Create a new data container
$ sudo docker run -v /data -name DATA2 busybox true
# untar the backup files into the new container᾿s data volume
$ sudo docker run --rm --volumes-from DATA2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
data/
data/sven.txt
# Compare to the original container
$ sudo docker run --rm --volumes-from DATA -v `pwd`:/backup busybox ls /data
sven.txt

Вот хорошая статья от отличного Брайана Гоффа, объясняющая, почему хорошо использовать одно и то же изображение для контейнера и контейнера данных.

tommasop
источник
8
Это другой инструмент для другой потребности. --volumes-fromпозволяет вам совместно использовать дисковое пространство --linkпозволяет вам совместно использовать сервисы.
Tommasop
3
Есть еще один проект в работах, специально предназначенных для такого рода вещей, может быть, добавить его к этому ответу в качестве ссылки для просмотра? github.com/ClusterHQ/flocker
Андре
9
Контейнеры данных не имеют никакого смысла и действительно плохая идея! Контейнер означает что-то, только когда в нем запущен процесс, иначе это просто часть файловой системы хоста. Вы можете просто смонтировать том с -v, это единственный и лучший вариант. У вас есть контроль над файловой системой и используемым физическим диском.
Boynux
11
Да, начиная с Docker 1.9, создание именованных томов с помощью API томов ( docker volume create --name mydata) предпочтительнее, чем контейнер томов данных. Сами люди в Docker полагают, что контейнеры томов данных « больше не считаются рекомендуемым шаблоном », « именованные тома должны иметь возможность заменять тома только для данных в большинстве (если не во всех) случаях » и « нет причин, которые я вижу, чтобы использовать контейнеры только для данных ».
Куинн Комендант
8
@ кодирование, мне грустно, что тебе грустно, отчасти потому, что ты судишь ответы с 3-летней задержкой, а отчасти потому, что ответ по существу прав во всей своей истории. Если у вас есть какие-либо советы, не стесняйтесь комментировать, чтобы я мог интегрировать ответ и помочь людям не грустить
Tommasop
75

В выпуске Docker v1.0 привязка монтирования файла или каталога на главном компьютере может быть выполнена с помощью данной команды:

$ docker run -v /host:/container ...

Вышеуказанный том можно использовать в качестве постоянного хранилища на хосте, на котором работает Docker.

amitmula
источник
3
Это должен быть рекомендуемый ответ, так как он гораздо менее сложен, чем подход с использованием контейнера с объемом, который на данный момент имеет больше голосов
августа
2
Мне бы хотелось, чтобы при использовании этой команды монтирования тома был установлен флажок для указания сопоставления host-uid: container-uid и host-gid: container-gid.
Рэмпион
35

В Docker Compose 1.6 теперь улучшена поддержка томов данных в Docker Compose. Следующий файл compose создаст образ данных, который будет сохраняться между перезапусками (или даже удалением) родительских контейнеров:

Вот объявление в блоге: Compose 1.6: Новый файл Compose для определения сетей и томов.

Вот пример составного файла:

version: "2"

services:
  db:
    restart: on-failure:10
    image: postgres:9.4
    volumes:
      - "db-data:/var/lib/postgresql/data"
  web:
    restart: on-failure:10
    build: .
    command: gunicorn mypythonapp.wsgi:application -b :8000 --reload
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    links:
      - db

volumes:
  db-data:

Насколько я понимаю: это создаст контейнер тома данных ( db_data), который будет сохраняться между перезапусками.

Если вы запустите: docker volume lsвы должны увидеть свой том в списке:

local               mypthonapp_db-data
...

Вы можете получить более подробную информацию об объеме данных:

docker volume inspect mypthonapp_db-data
[
  {
    "Name": "mypthonapp_db-data",
    "Driver": "local",
    "Mountpoint": "/mnt/sda1/var/lib/docker/volumes/mypthonapp_db-data/_data"
  }
]

Некоторое тестирование:

# Start the containers
docker-compose up -d

# .. input some data into the database
docker-compose run --rm web python manage.py migrate
docker-compose run --rm web python manage.py createsuperuser
...

# Stop and remove the containers:
docker-compose stop
docker-compose rm -f

# Start it back up again
docker-compose up -d

# Verify the data is still there
...
(it is)

# Stop and remove with the -v (volumes) tag:

docker-compose stop
docker=compose rm -f -v

# Up again ..
docker-compose up -d

# Check the data is still there:
...
(it is).

Ноты:

  • Вы также можете указать различные драйверы в volumesблоке. Например, вы можете указать драйвер Flocker для db_data:

    volumes:
      db-data:
        driver: flocker
    
  • Поскольку они улучшают интеграцию между Docker Swarm и Docker Compose (и, возможно, начинают интегрировать Flocker в экосистему Docker (я слышал, что Docker купил Flocker), я думаю, что этот подход должен стать все более мощным.

Отказ от ответственности: этот подход многообещающий, и я успешно использую его в среде разработки. Я бы опасался использовать это в производстве только сейчас!

toast38coza
источник
Флокер был закрыт, и на репозитории github
Кришна,
17

Если из обновления 5 выбранного ответа неясно, как в Docker 1.9, вы можете создавать тома, которые могут существовать без привязки к определенному контейнеру, что делает шаблон «контейнер только для данных» устаревшим.

См. Только для данных контейнеры устарели с Docker 1.9.0? # 17798 .

Я думаю, что сопровождающие Docker поняли, что шаблон контейнера только для данных был чем-то вроде запаха проекта, и решили сделать тома отдельной сущностью, которая может существовать без связанного контейнера.

ben_frankly
источник
13

Хотя это все еще часть Docker, которая требует некоторой работы , вы должны поместить том в Dockerfile с помощью инструкции VOLUME, чтобы вам не нужно было копировать тома из другого контейнера.

Это сделает ваши контейнеры менее взаимозависимыми, и вам не придется беспокоиться об удалении одного контейнера, влияющего на другой.

Тим Дорр
источник
Аргумент обратной стороны заключается в том, что контейнеры «только данные» в конечном итоге становятся последней ссылкой на том данных (Docker уничтожает тома данных после удаления последнего контейнера, ссылающегося на этот том docker rm)
WineSoaked
2
Это официальное руководство от Docker предлагает иное: docs.docker.com/userguide/dockervolumes/… " Тома данных предназначены для сохранения данных, независимо от жизненного цикла контейнера. Поэтому Docker никогда не удаляет тома автоматически при удалении контейнера, равно как и не будет Тома «сборки мусора», на которые больше не ссылается контейнер ».
Алекс
12

При использовании Docker Compose просто подключите именованный том, например:

version: '2'
services:
  db:
    image: mysql:5.6
    volumes:
      - db_data:/var/lib/mysql:rw
    environment:
      MYSQL_ROOT_PASSWORD: root
volumes:
  db_data:
Царь Пино
источник
9

Ответ @ tommasop хорош и объясняет некоторые механизмы использования контейнеров только для данных. Но как человек, который изначально думал, что контейнеры данных были глупы, когда можно было просто привязать монтирование тома к хосту (как предложено несколькими другими ответами), но теперь понимает, что на самом деле контейнеры только для данных довольно аккуратны, я могу предложить свой сообщение в блоге на эту тему: Почему контейнеры данных Docker (тома!) хороши

См. Также: мой ответ на вопрос « Каков (лучший) способ управления разрешениями для общих томов Docker? » Для примера того, как использовать контейнеры данных, чтобы избежать таких проблем, как разрешения и сопоставление uid / gid с хостом.

Для решения одной из первоначальных проблем ФП: не следует удалять контейнер данных. Даже если контейнер данных будет удален, сами данные не будут потеряны, пока любой контейнер имеет ссылку на этот том, т. Е. Любой контейнер, через который монтируется том --volumes-from. Таким образом, если все связанные контейнеры не будут остановлены и удалены (можно считать это случайным rm -fr /), данные будут в безопасности. Вы всегда можете воссоздать контейнер данных, выполнив --volumes-fromлюбой контейнер, имеющий ссылку на этот том.

Как всегда, делайте резервные копии, хотя!

ОБНОВЛЕНИЕ: теперь в Docker есть тома, которыми можно управлять независимо от контейнеров, что еще больше упрощает управление.

Раман
источник
9

Существует несколько уровней управления постоянными данными в зависимости от ваших потребностей:

  • Храните его на своем хосте
    • Используйте флаг, -v host-path:container-pathчтобы сохранить данные каталога контейнера в каталоге хоста.
    • Резервное копирование / восстановление выполняется путем запуска контейнера резервного копирования / восстановления (такого как tutumcloud / dockup), смонтированного в том же каталоге.
  • Создайте контейнер данных и подключите его тома к контейнеру вашего приложения.
    • Создайте контейнер, который экспортирует том данных, используйте --volumes-fromдля монтирования этих данных в контейнер приложения.
    • Резервное копирование / восстановление аналогично вышеуказанному решению.
  • Используйте плагин для Docker, поддерживающий внешний / сторонний сервис
    • Плагины тома Docker позволяют вашему источнику данных поступать откуда угодно - NFS, AWS (S3, EFS и EBS)
    • В зависимости от плагина / сервиса, вы можете прикрепить один или несколько контейнеров к одному тому.
    • В зависимости от услуги, резервное копирование / восстановление могут быть автоматизированы для вас.
    • Хотя это может быть затруднительно, если делать это вручную, некоторые решения для оркестровки, такие как Rancher , запекутся и просты в использовании.
    • Конвой является самым простым решением для этого вручную.
Уилл Стерн
источник
8

Если вы хотите переместить ваши объемы вокруг, вы также должны посмотреть на Flocker .

Из README:

Flocker - это менеджер томов данных и инструмент управления кластером с несколькими хостами Docker. С его помощью вы можете контролировать свои данные, используя те же инструменты, которые вы используете для приложений без сохранения состояния, используя возможности ZFS в Linux.

Это означает, что вы можете запускать базы данных, очереди и хранилища значений ключей в Docker и перемещать их так же легко, как и все остальное приложение.

Иоганн Ромфор
источник
1
Спасибо, Иоганн. Я работаю в ClusterHQ и просто хочу отметить, что мы вышли за пределы только хранилища на основе ZFS. Теперь вы можете использовать Flocker с хранилищем, таким как Amazon EBS или Google Persistent Disk. Вот полный список вариантов хранения: docs.clusterhq.com/en/latest/supported/…
ferrantim
1
Flocker прекращено и не должно быть использован portworx.com/...
jesugmz
5

Это зависит от вашего сценария (это не совсем подходит для производственной среды), но есть один способ:

Создание MySQL Docker-контейнера

Суть этого в том, чтобы использовать каталог на вашем хосте для сохранения данных.

Бен Шварц
источник
6
Спасибо Бен, однако - одна из проблем, которые я вижу при таком подходе: ресурс файловой системы (каталог, файлы) будет принадлежать uid из контейнера docker / lxc (guest) - тот, который может столкнуться с uid на хосте ...
juwalter
1
я думаю, что вы достаточно безопасны, так как он запускается пользователем root, но я согласен, что это хак - в лучшем случае подходящий для тестирования локальной разработки / эфемерной интеграции Это определенно та область, в которой я хотел бы видеть больше моделей / мышления. Вы должны проверить / опубликовать этот вопрос в google-группе docker-dev
Бен Шварц
Бен, спасибо за это решение! Я бы не назвал это хаком, он кажется гораздо более надежным, чем контейнер как объем . Видите ли вы какие-либо недостатки в случае, когда данные используются исключительно из контейнера? (UID в данном случае не имеет значения)
johndodo
3

Недавно я написал о возможном решении и приложении, демонстрирующем технику. Я считаю, что это довольно эффективно во время разработки и производства. Надеюсь, что это помогает или вызывает некоторые идеи.

Репо: https://github.com/LevInteractive/docker-nodejs-example
Статья: http://lev-interactive.com/2015/03/30/docker-load-balanced-mongodb-persistence/

slth
источник
1

Я просто использую предопределенный каталог на хосте для сохранения данных для PostgreSQL. Кроме того, таким образом можно легко перенести существующие установки PostgreSQL в контейнеры Docker: https://crondev.com/persistent-postgresql-inside-docker/

Ален Комлен
источник
0

Мое решение состоит в том, чтобы использовать новый docker cp, который теперь может копировать данные из контейнеров, независимо от того, работает он или нет, и совместно использовать том хоста в том же месте, где приложение базы данных создает свои файлы базы данных внутри контейнера. , Это двойное решение работает без контейнера только для данных, прямо из исходного контейнера базы данных.

Поэтому мой сценарий инициализации systemd выполняет резервное копирование базы данных в архив на хосте. Я поместил отметку времени в имени файла, чтобы никогда не переписывать файл.

Это делает это на ExecStartPre:

ExecStartPre=-/usr/bin/docker cp lanti-debian-mariadb:/var/lib/mysql /home/core/sql
ExecStartPre=-/bin/bash -c '/usr/bin/tar -zcvf /home/core/sql/sqlbackup_$$(date +%%Y-%%m-%%d_%%H-%%M-%%S)_ExecStartPre.tar.gz /home/core/sql/mysql --remove-files'

И он делает то же самое на ExecStopPost:

ExecStopPost=-/usr/bin/docker cp lanti-debian-mariadb:/var/lib/mysql /home/core/sql
ExecStopPost=-/bin/bash -c 'tar -zcvf /home/core/sql/sqlbackup_$$(date +%%Y-%%m-%%d_%%H-%%M-%%S)_ExecStopPost.tar.gz /home/core/sql/mysql --remove-files'

Кроме того, я открыл папку с хоста как том в том же месте, где хранится база данных:

mariadb:
  build: ./mariadb
  volumes:
    - $HOME/server/mysql/:/var/lib/mysql/:rw

Он отлично работает на моей виртуальной машине (я создаю для себя стек LEMP): https://github.com/DJviolin/LEMP

Но я просто не знаю, является ли это «пуленепробиваемым» решением, когда ваша жизнь зависит от него на самом деле (например, интернет-магазин с транзакциями в любых возможных миллисекундах)?

Через 20 минут 20 секунд после официального видео с докером докладчик делает то же самое с базой данных:

Начало работы с Docker

«Для базы данных у нас есть том, поэтому мы можем быть уверены, что при увеличении и уменьшении базы данных мы не теряем данные, когда контейнер базы данных останавливается».

Lanti
источник
Что вы подразумеваете под "... использовать ..." ? И "... транзакции в любых возможных миллисекундах" ?
Питер Мортенсен
0

Используйте постоянную заявку на объем (PVC) от Kubernetes, которая является инструментом управления и планирования контейнеров Docker:

Постоянные тома

Преимущества использования Kubernetes для этой цели заключаются в том, что:

  • Вы можете использовать любое хранилище, такое как NFS или другое хранилище, и даже когда узел не работает, хранилище не должно быть.
  • Более того, данные в таких томах можно настроить так, чтобы они сохранялись даже после уничтожения самого контейнера, чтобы при необходимости их можно было восстановить другим контейнером.
Сантану Дей
источник