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

Как люди справляются с постоянным хранением ваших контейнеров докеров? В настоящее время я использую этот подход: постройте изображение, например. для Postgres, а затем запустите контейнер с помощью

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

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

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

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

Ответ 1

Докер 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/path, вы автоматически создадите именованный том для вас, который может:

  • Перечислите через docker volume ls
  • Определяться через docker volume inspect volume_name
  • Резервное копирование как обычный каталог
  • Резервное копирование по-прежнему через соединение --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 и ниже

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

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

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

docker run --volumes-from data-container some-other-container command-to-execute

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

Документация Docker теперь имеет DEFINITIVE описание контейнера как шаблон volume/s.

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

BACKUP:

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

RESTORE:

# 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

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

Ответ 2

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

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

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

Ответ 3

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

Вот объявление в блоге: https://blog.docker.com/2016/02/compose-1-6/

Здесь приведен пример файла:

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), я думаю, что этот подход должен стать все более мощным.

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

Ответ 4

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

См. https://github.com/docker/docker/issues/17798

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

Ответ 5

Пока это все еще часть docker которая нуждается в некоторой работе, вы должны поместить том в файл Docker с помощью VOLUME, поэтому вам не нужно копировать тома из другого контейнера. Это сделает ваши контейнеры менее взаимозависимыми, и вам не нужно беспокоиться об удалении одного контейнера, влияющего на другой.

Ответ 6

@tommasop ответ хороший, и объясняет некоторые из механиков использования контейнеров только для данных. Но как тот, кто изначально считал, что контейнеры данных глупы, когда можно просто привязать монтирование к хосту (как это было предложено несколькими другими ответами), но теперь понимает, что на самом деле контейнеры только для данных довольно аккуратные, я могу предложить свои собственные сообщение в блоге на эту тему: https://medium.com/@ramangupta/why-docker-data-containers-are-good-589b3c6c749e

Смотрите также: мой ответ на вопрос "Каков (лучший) способ управления разрешениями для разделяемых томов докеров" для примера использования контейнеров данных, чтобы избежать проблем, таких как разрешения и сопоставление uid/gid с хостом.

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

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

UPDATE: теперь у Docker есть тома, которые можно управлять независимо от контейнеров, что дополнительно упрощает управление.

Ответ 7

Если вы хотите перемещать тома вокруг, вы также должны посмотреть https://github.com/clusterhq/flocker

из README:

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

Ответ 8

Зависит от вашего сценария (это не подходит для среды prod), но здесь один из способов: http://txt.fliglio.com/2013/11/creating-a-mysql-docker-container/

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

Ответ 9

При использовании docker-compose просто присоедините объем данных i.e.

version: '2'
services:
  db:
    image: mysql:5.6
    volumes:
      - db_data:/var/lib/mysql:rw
    environment:
      MYSQL_ROOT_PASSWORD: root
volumes:
  db_data:

Ответ 10

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

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

Ответ 11

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

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

Ответ 12

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

Ответ 13

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

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

Он делает это на 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

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

В 20:20 из этого официального видеозаписей Docker ведущий делает то же самое с db:

https://www.youtube.com/watch?v=klzLdzpPcQw

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

Ответ 14

Использовать постоянную претензию по томам от Kubernetes, которая представляет собой инструмент управления контейнером и диспетчером docker

http://kubernetes.io/docs/user-guide/persistent-volumes/

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

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