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

Как люди обращаются с постоянным хранилищем для ваших контейнеров 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 ... (см. принятый ответ)

14 ответов

Решение

Докер 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. Быть перечисленным через 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

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

В выпуске Docker 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.

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

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

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

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

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

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

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

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

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

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

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

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

Из README:

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

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

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

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

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

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

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

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

Чтобы сохранить или хранить данные базы данных, убедитесь, что ваш docker-compose.yml будет выглядеть так, как если бы вы хотели использовать Dockerfile.

version: '3.1'

services:
  php:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 80:80
    volumes:
      - ./src:/var/www/html/
  db:
    image: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
    volumes:
      - mysql-data:/var/lib/mysql

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
volumes:
  mysql-data:

ваш docker-compose.yml будет выглядеть, если вы хотите использовать свое изображение вместо Dockerfile

version: '3.1'   

services:
  php:
    image: php:7.4-apache
    ports:
      - 80:80
    volumes:
      - ./src:/var/www/html/
  db:
    image: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
    volumes:
      - mysql-data:/var/lib/mysql

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
volumes:

если вы хотите сохранить или сохранить данные mysql, не забудьте добавить две строки в свой docker-compose.yml

volumes:
  - mysql-data:/var/lib/mysql

и

volumes:
  mysql-data:

после этого используйте эту команду

docker-compose up -d

теперь ваши данные будут постоянными и не будут удалены даже после использования этой команды

docker-compose down

дополнительно:- но если вы хотите удалить все данные, вы будете использовать

docker-compose down -v

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

docker volume ls

DRIVER              VOLUME NAME
local               35c819179d883cf8a4355ae2ce391844fcaa534cb71dc9a3fd5c6a4ed862b0d4
local               133db2cc48919575fc35457d104cb126b1e7eb3792b8e69249c1cfd20826aac4
local               483d7b8fe09d9e96b483295c6e7e4a9d58443b2321e0862818159ba8cf0e1d39
local               725aa19ad0e864688788576c5f46e1f62dfc8cdf154f243d68fa186da04bc5ec
local               de265ce8fc271fc0ae49850650f9d3bf0492b6f58162698c26fce35694e6231c
local               phphelloworld_mysql-data

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

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

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

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

Мое решение состоит в том, чтобы использовать новый 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

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

Другие вопросы по тегам