Ответ
Основной принцип — отделить данные от контейнера с помощью Docker Volumes или Bind Mounts. Контейнер должен быть эпиhemeral (временным), а данные — persistent (постоянными). В production-среде для Node.js приложений я всегда настраиваю том для данных СУБД.
Способ 1: Named Volumes (рекомендуется для Docker)
# docker-compose.yml для Node.js приложения и PostgreSQL
version: '3.8'
services:
postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: strongpassword
volumes:
- postgres_data:/var/lib/postgresql/data # Named volume
networks:
- app-network
app:
build: .
depends_on:
- postgres
environment:
DATABASE_URL: postgresql://user:strongpassword@postgres:5432/myapp
networks:
- app-network
volumes:
postgres_data: # Volume объявляется здесь
networks:
app-network:
driver: bridge
Способ 2: Bind Mounts (для разработки или специфичных путей на хосте)
volumes:
- ./postgres-data:/var/lib/postgresql/data
Ключевые практики для Node.js окружения:
- Используйте
.envфайлы или секреты Docker для хранения паролей БД, никогда не хардкодьте их. - Настройте регулярные бэкапы самого тома (например,
pg_dumpв cron-задаче внутри отдельного контейнера). - Для stateful-сервисов в оркестраторах (K8s) используйте PersistentVolumeClaims.
- Тестируйте процедуру восстановления из бэкапа на staging-окружении.
Почему это важно: При обновлении образа базы данных или перезапуске контейнера том с данными остается нетронутым. Удаление контейнера postgres не приведет к потере данных, так как они хранятся в volume postgres_data.
Ответ 18+ 🔞
А, ну это же классика, ёпта! Слушай сюда, я тебе сейчас на пальцах объясню, как не наступить на эти грабли, чтобы потом не орать «ёбааать, где моя база?!».
Представь себе: ты накатал своё Node.js приложение, запустил в контейнере, базу туда же запихнул. Всё летает, красота. А потом — бац! — контейнер упал, пересоздался, или ты образ обновил. И тут выясняется, что твоя PostgreSQL, которая внутри контейнера жила, взяла и накрылась медным тазом. Все данные — в пизду. Пользователи, заказы, логи — всё, чих-пых тебя в сраку. Почему? Потому что контейнер — он как одноразовый стаканчик. Выкинул — и всё, что внутри, тоже на свалку.
Так как же быть? А вот как: надо отделить мух от котлет, а данные — от контейнера. Контейнер должен быть временным (ephemeral), а данные — вечными (persistent). Для этого есть два основных способа, и я тебе про оба расскажу, но один — прям золотой стандарт.
Способ 1: Named Volumes (То, что доктор прописал для прода)
Это как снять отдельную квартиру для своих данных. Docker сам её создаст и будет присматривать. Удобно, надёжно, переносимо. Вот смотри, как это в docker-compose.yml для твоего Node.js и Postgres выглядит:
version: '3.8'
services:
postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: strongpassword
volumes:
- postgres_data:/var/lib/postgresql/data # Вот эта строка — магия! Том с именем.
networks:
- app-network
app:
build: .
depends_on:
- postgres
environment:
DATABASE_URL: postgresql://user:strongpassword@postgres:5432/myapp
networks:
- app-network
volumes:
postgres_data: # Объявляем том здесь. Docker: «О, понял, ща сделаю!»
networks:
app-network:
driver: bridge
Что происходит? Данные базы живут теперь не в контейнере, а в этом самом томе postgres_data. Удалишь контейнер postgres — том останется. Поднимешь новый — он прицепится к тому же тому, и все твои таблички будут на месте, как ни в чём не бывало. Удобно, правда? Доверия к такому подходу — не ноль ебать, а вполне себе высокое.
Способ 2: Bind Mounts (Для разработки, когда надо ковыряться)
Это как прорубить дыру из контейнера прямо в папку на твоём компьютере. Очень удобно для разработки, потому что видишь файлы сразу, но для продакшна — так себе идея, слишком уж привязано к конкретной машине.
volumes:
- ./postgres-data:/var/lib/postgresql/data # Связываем папку на хосте с папкой в контейнере.
Закинул так — и всё, что база пишет, летит прямиком в ./postgres-data на твоём диске. Перезапустил контейнер — данные на месте. Но если папку эту случайно удалишь... ну, ты понял, будет тебе хиросима.
А теперь, чувак, главные правила, чтобы не было мучительно больно:
- Пароли — в тайне. Никогда, слышишь, НИКОГДА не пихай пароли от базы прямо в код или
docker-compose.yml. Это пиздопроебибна идея. Используй.envфайлы или, что ещё круче, Docker Secrets. Иначе какой-нибудь полупидор их утянет, и будет тебе веселье. - Бэкапы, блядь! Настроил том — и расслабился? Не, не работает так. Настрой регулярные дампы базы (
pg_dump). Можно в отдельном контейнере-кронзадаче. Данные-то живут в томе, но от человеческого фактора или багов в коде они не застрахованы. - Проверяй восстановление. Сделал бэкап — отлично. А теперь на тестовом стенде попробуй из этого бэкапа всё восстановить. Потому что если не проверишь, в момент Х может вылезти какая-нибудь ядрёна вошь, и окажется, что твой бэкап — просто куча бесполезных файлов.
- Для Kubernetes — свои заморочки. Если вдруг переползёшь на K8s, там вместо томов будут свои штуки — PersistentVolumeClaims. Принцип тот же, но реализация другая. Голова должна думать, э бошка!
Итог: Используй Named Volumes для прода, Bind Mounts для разработки, если удобно. И помни главное: контейнер с базой — это просто процесс и временная обёртка. Все твои ценные данные должны жить снаружи. Тогда и спать будешь спокойнее, и волнение ебать не будет мучить каждый раз при деплое.