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

205

В моем файле docker compose есть три контейнера: web, nginx и postgres. Postgres выглядит так:

postgres:
  container_name: postgres
  restart: always
  image: postgres:latest
  volumes:
    - ./database:/var/lib/postgresql
  ports:
    - "5432:5432

Моя цель - смонтировать том, который соответствует локальной папке, называемой ./databaseвнутри контейнера postgres as /var/lib/postgres. Когда я запускаю эти контейнеры и вставляю данные в postgres, я проверяю, что они /var/lib/postgres/data/base/полны данных, которые я добавляю (в контейнер postgres), но в моей локальной системе ./databaseполучает только dataпапку в ней, т.е. ./database/dataсоздается, но она пуста , Зачем?

Ноты:

ОБНОВЛЕНИЕ 1

По предложению Ника, я сделал docker inspectи нашел:

    "Mounts": [
        {
            "Source": "/Users/alex/Documents/MyApp/database",
            "Destination": "/var/lib/postgresql",
            "Mode": "rw",
            "RW": true,
            "Propagation": "rprivate"
        },
        {
            "Name": "e5bf22471215db058127109053e72e0a423d97b05a2afb4824b411322efd2c35",
            "Source": "/var/lib/docker/volumes/e5bf22471215db058127109053e72e0a423d97b05a2afb4824b411322efd2c35/_data",
            "Destination": "/var/lib/postgresql/data",
            "Driver": "local",
            "Mode": "",
            "RW": true,
            "Propagation": ""
        }
    ],

Это создает впечатление, что данные украдены другим томом, который я сам не кодировал. Не уверен, почему это так. Является ли изображение postgres тем объемом для меня? Если да, есть ли способ использовать этот том вместо тома, который я монтирую при перезапуске? Иначе, есть ли хороший способ отключить этот другой том и использовать мой собственный ./database?

ОБНОВЛЕНИЕ 2

Я нашел решение, благодаря Нику! (и еще один друг) Ответ ниже.

Алекс Ленаил
источник
Вы уже запускаете initdbкомандную строку для инициализации кластера базы данных?
Себастьян Уэббер
Вы уверены, что ваш подкаталог данных действительно пуст? Это может иметь особые права доступа.
Ярослав
Спасибо, что ответили мне так быстро! Я использую приложение опоки, так что я from app import dbи db.create_all()от А docker runпосле запуска контейнеров. Я не initdbпрямо из командной строки.
Алекс Ленаил
1
@YaroslavStavnichiy Я не знаю, как еще проверить это, чем sudo su -и посмотреть ./database/data. Насколько я могу судить, там ничего нет.
Алекс Ленаил
Кто-то может найти это полезным: пример файла составления, сохраняющий postgres, упругий поиск и данные мультимедиа, stackoverflow.com/a/56475980/5180118
ArdentLearner

Ответы:

254

Как ни странно, решение закончилось тем, что изменилось

volumes:
  - ./postgres-data:/var/lib/postgresql

в

volumes:
  - ./postgres-data:/var/lib/postgresql/data
Алекс Ленаил
источник
45
Просто быстрое «почему» для этого ответа (который работает). По мнению пользователей postgres, каталог данных по умолчанию /var/lib/postgresql/data- вы можете прочитать примечания к переменным PGDATA здесь: store.docker.com/images/…
Мэтт Павел
2
В вышеупомянутом вопросе OP говорит, что он работал для него без / data в конце. Это правильно?
Сид
2
И добавьте локальный каталог в свой .dockerignoreфайл, особенно если вы когда-нибудь добавите его в рабочий образ. См. Codefresh.io/blog/not-ignore-dockerignore для обсуждения.
ДСЗ
4
это все еще не работает для меня (Mac OS X High
Sierra
1
@ OlliD-Metz Я должен был сделать, docker rm my_postgres_container_1прежде чем это сработало (также High Sierra).
Богатые
101

Вы можете создать общий том для всех данных Postgres

 docker volume create pgdata

или вы можете установить его в файл композиции

   version: "3"
   services:
     db:
       image: postgres
       environment:
         - POSTGRES_USER=postgres
         - POSTGRES_PASSWORD=postgress
         - POSTGRES_DB=postgres
       ports:
         - "5433:5432"
       volumes:
         - pgdata:/var/lib/postgresql/data
       networks:
         - suruse
   volumes: 
     pgdata:

Он создаст имя тома pgdata и подключит этот том к пути контейнера.

Вы можете проверить этот объем

docker volume inspect pgdata

// output will be
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/pgdata/_data",
        "Name": "pgdata",
        "Options": {},
        "Scope": "local"
    }
]
Нищит Дханани
источник
8
Комментировать немного поздно, но я не смогу очистить эти данные, если я это сделаю docker-compose down -v. И каково решение этого?
Сид
3
@ Сид, да, будет! Просто будьте осторожны с этой опцией.
olidem
1
так с docker-compose [down] громкость больше не сохраняется? Есть ли полная очистка даже от объема?
Пол
2
@Sid Комментируя даже позже, но вы можете использовать docker-compose down --rmi all без по -vвыбору , и она будет очистить «все» за исключением объемов, т.е. контейнеров, сети, изображения и т.д. Я , что при развертывании, позволяя сохранение данных.
code_dredd
13

Я бы не использовал относительный путь. Помните, что docker - это отношения демон / клиент.

Когда вы выполняете compose, он просто разбивается на различные клиентские команды docker, которые затем передаются демону. Это ./databaseотносится к демону , а не к клиенту.

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

Короче говоря, не используйте относительный путь, используйте абсолютный путь.

Ник Берк
источник
Спасибо за этот ответ! К сожалению, я не думаю, что это сработало. Я изменил строку на абсолютный путь, и после вставки данных database/dataпапка все еще пуста = (
Alex Lenail
K. Далее следует запустить docker inspectконтейнер и убедиться, что контейнер знает о томе (на случай, если compose запутался или что-то в этом роде). (примечание: у docker inspect могут быть конфиденциальные данные, поэтому не вставляйте их сюда, не обнажая ;-) После этого нужно проверять разрешения (хотя обычно это
Ник Берк,
Ага! @ Ник Берк Я думаю, ты что-то нашел. Я обновил вопрос.
Алекс Ленаил
2

Я думаю, что вам просто нужно создать свой том вне докера сначала с помощью docker create -v /location --nameа затем использовать его повторно.

И к тому времени, когда я часто использовал docker, было невозможно использовать статический том docker с определением dockerfile, поэтому я предлагаю попробовать командную строку (в конце концов, с помощью скрипта).

Джоэл Б
источник