Як боротися з постійним зберіганням (наприклад, базами даних) у Docker


992

Як люди поводяться з постійним зберіганням ваших контейнерів 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 ...(див. Прийняту відповідь)


Вибачте, я неправильно сформулював це, я хотів сказати: усі мої майбутні екземпляри цього зображення залежать від цього контейнера. Якщо я видаляю контейнер випадково, я переживаю проблеми.
juwalter

@AntonStrogonoff - так, фразова помилка - я мав намір сказати: мені потрібно переконатися, що я ніколи не видаляю цей (можливо) старий контейнер, тому що тоді посилання на "стійке" сховище також не піде
juwalter

так і має бути --name. у вас-name
Шаммель Лі

Відповіді:


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 і нижче

Підхід, який, здається, найкраще працює у виробництві, - це використовувати контейнер лише для даних .

Контейнер, що містить лише дані, працює на зображенні без кісток і фактично не робить нічого, окрім викриття обсягу даних.

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

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: вийміть контейнер під час його виходу
  • - об'єми - від DATA: приєднати до томів, що поділяються контейнером DATA
  • -v $ (pwd): / резервне копіювання: прив’язати монтувати поточний каталог у контейнер; написати файл tar на
  • busbox: невелике простіше зображення - добре для швидкого обслуговування
  • 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

Ось приємна стаття від відмінного Брайана Гоффа, в якій пояснюється, чому добре використовувати однакові зображення для контейнера та контейнера даних.


8
Це різний інструмент для іншої потреби. --volumes-fromнехай ви поділяєте місце на диску, --linkнехай ви ділитесь послугами.
tommasop

3
Є ще один проект у творах, спеціально призначений для такого роду речі, можливо, додайте його до цієї відповіді як орієнтир для перегляду? github.com/ClusterHQ/flocker
Андре

9
Контейнери для даних не мають ніякого значення і насправді погана ідея! Контейнер означає лише щось, коли в ньому працює процес, інакше це лише фрагмент файлової системи хоста. Ви можете просто встановити гучність за допомогою -v, це єдиний і найкращий варіант. Ви маєте контроль над використовуваною файловою системою та фізичним диском.
Boynux

11
Так, на Докер 1.9, створення іменованих томів за допомогою API томів ( docker volume create --name mydata) є кращим перед контейнером обсягу даних. Люди з Docker самі припускають, що контейнери обсягу даних " більше не вважаються рекомендованою схемою ", " названі томи повинні мати можливість замінювати лише томи даних у більшості (якщо не у всіх) випадках ", і " жодна причина, яку я бачу використовувати контейнери лише для даних . "
Квінн Комендант

8
@ кодування, мені сумно, ти сумуєш, частково тому, що ти судиш відповіді із затримкою на 3 роки, а частково через те, що ця відповідь суттєво правильна у всій історії. Якщо у вас є поради, не соромтесь коментувати, щоб я міг інтегрувати відповідь і допомогти людям не сумувати
tommasop

75

У випуску Docker v1.0 прив'язування файлу або каталогу на хост-машині може бути виконано даною командою:

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

Вищевказаний том можна використати як постійне сховище на хості, що працює на Docker


3
Це має бути рекомендованою відповіддю, оскільки він набагато менш складний, ніж підхід об’ємно-контейнерний, який наразі має більше голосів
insitusec

2
Я хотів би, щоб тут було встановлено прапор, який би вказав host-uid: container-uid та host-gid: map-gid mapping, використовуючи цю команду mount volume.
чемпіон

35

Станом на Docker Compose 1.6, в Docker 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 (я чув слух, що Докер купив Flocker), я думаю, що цей підхід повинен набувати все більшого впливу.

Відмова: Цей підхід є перспективним, і я його успішно використовую в середовищі розвитку. Я б з побоюванням використовував це ще у виробництві!


Flocker був закритий і там не багато активності на GitHub репо
Krishna

17

Якщо з оновлення 5 обраної відповіді не зрозуміло, станом на Docker 1.9, ви можете створити томи, які можуть існувати, не асоціюючись із певним контейнером, тим самим зробивши шаблон "контейнера лише для даних" застарілим.

Дивіться контейнери, що містять дані, застарілі за допомогою docker 1.9.0? №17798 .

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


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 .

З ПРОЧИТАННЯ:

Flocker - це менеджер обсягів даних та інструмент управління кластерами з багатохостим докером. За допомогою нього ви можете керувати своїми даними за допомогою тих же інструментів, які використовуєте для програм без громадянства, використовуючи потужність ZFS в Linux.

Це означає, що ви можете запускати свої бази даних, черги та сховища ключових значень у Docker та переміщувати їх так само легко, як і решта вашої програми.


1
Дякую Йохан. Я працюю в ClusterHQ, і я просто хотів зазначити, що ми вийшли за межі лише сховища на основі ZFS. Тепер ви можете використовувати Flocker із сховищем даних, як Amazon EBS або Google Persistent Disk. Ось повний перелік варіантів зберігання: docs.clusterhq.com/en/latest/supported/…
ferrantim

1
Flocker припиняється, і його не слід використовувати portworx.com/…
jestegmz

5

Це залежить від вашого сценарію (це не дуже підходить для виробничого середовища), але ось один із способів:

Створення контейнера Docker для MySQL

Це суть у тому, щоб використовувати каталог вашого хоста для збереження даних.


6
Дякую Бену, однак - одне із проблем, які я бачу при такому підході: ресурсом файлової системи (каталогом, файлами) буде належати uid з контейнера docker / lxc (guest) - той, який, можливо, може зіткнутися з uid на господарі ...
juwalter

1
Я думаю, ти досить безпечний, оскільки він працює під коренем, але я згоден, що це злом - підходить для локального тестування інтеграції dev / ephemeral в кращому випадку. Це, безумовно, область, яку я хотів би побачити більше моделей / мислення. Ви повинні перевірити / опублікувати це питання в групі Google
docker

Бен, дякую за це рішення! Я б не назвав це злом, хоча це здається набагато надійнішим, ніж контейнер, як об'єм . Чи бачите ви недоліки у випадку, коли дані використовуються виключно з контейнера? (У цьому випадку UID не має значення)
johndodo

3

Нещодавно я писав про потенційне рішення та додаток, що демонструє техніку. Я вважаю це досить ефективним під час розвитку та у виробництві. Сподіваюсь, що це допоможе або іскрить якісь ідеї.

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



0

Моє рішення полягає в тому, щоб використовувати нове docker cp, яке тепер може копіювати дані з контейнерів, незалежно від того, працює він чи ні, і поділитися томом хосту в тому самому місці, де додаток баз даних створює файли бази даних всередині контейнера . Це подвійне рішення працює без контейнера, доступного лише для даних, безпосередньо з оригінального контейнера бази даних.

Тож мій системний скрипт init бере на себе завдання резервного копіювання бази даних в архів на хості. Я розмістив часову позначку в імені файлу, щоб ніколи не переписувати файл.

Це робиться на 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

Він чудово працює на моєму VM (я будую стек LEMP для себе): https://github.com/DJviolin/LEMP

Але я просто не знаю, чи це "куленепробивне" рішення, коли ваше життя залежить саме від цього (наприклад, веб-магазин з транзакціями за будь-які можливі мілісекунди)?

Через 20 хвилин 20 секунд від цього офіційного основного відео докера ведучий робить те саме, що і з базою даних:

Початок роботи з Докером

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


Що ви маєте на увазі під "... користуватися ..." ? І "... транзакції за будь-які можливі мілісекунди" ?
Пітер Мортенсен

0

Використовуйте стійку заявку на об'єм (ПВХ) від Kubernetes, яка є інструментом управління та планування контейнерів Docker:

Стійкі обсяги

Перевагами використання Kubernetes для цієї мети є:

  • Ви можете використовувати будь-яке сховище, наприклад NFS або інший накопичувач, і навіть коли вузол вниз, зберігання не повинно бути.
  • Крім того, дані в таких томах можуть бути налаштовані для збереження навіть після того, як сам контейнер знищений - щоб він міг бути відтворений, якщо необхідно, іншим контейнером.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.