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

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

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

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 ... (см. принятый ответ)

14 ответов


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

  1. быть перечислены через the 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

Docker 1.8.X и ниже

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

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

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

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

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

документация Docker теперь имеет окончательное описание контейнер volume / s узор.

Ниже приведена процедура резервного копирования/восстановления для 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: присоединить к томам, совместно используемым контейнером данных
  • - v $(pwd):/backup: bind монтировать текущий каталог в контейнер; для записи файла tar в
  • busybox: небольшой простой хороший для быстрого обслуживания
  • tar cvf / резервное копирование / резервное копирование.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

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


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

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

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


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

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


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

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

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


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

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


при использовании 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:

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

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

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

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

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


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

из README:

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

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


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

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

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

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

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


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

РЕПО: https://github.com/LevInteractive/docker-nodejs-example
Article: http://lev-interactive.com/2015/03/30/docker-load-balanced-mongodb-persistence/


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


мое решение-использовать новый 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 keynote ведущий делает то же самое с базой данных:

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

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


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

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

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

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