LINUX.ORG.RU
решено ФорумAdmin

при сборке контейнера ломается база

 , ,


0

2

Происходит какая-то магия, условие для которой — пересобрать контейнер с приложением. Причём нужно чтобы в коде были изменения, иначе не прокатывает. В логе вижу вот это:

PostgreSQL Database directory appears to contain a database; Skipping initialization

2024-09-17 18:07:49.175 UTC [1] LOG:  starting PostgreSQL 16.4 (Debian 16.4-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
2024-09-17 18:07:49.175 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
2024-09-17 18:07:49.175 UTC [1] LOG:  listening on IPv6 address "::", port 5432
2024-09-17 18:07:49.178 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2024-09-17 18:07:49.183 UTC [28] LOG:  database system was interrupted; last known up at 2024-09-16 22:50:19 UTC
2024-09-17 18:07:49.258 UTC [28] LOG:  database system was not properly shut down; automatic recovery in progress
2024-09-17 18:07:49.261 UTC [28] LOG:  redo starts at 0/1D7BCB8
2024-09-17 18:07:49.261 UTC [28] LOG:  invalid record length at 0/1D7BDA0: expected at least 24, got 0
2024-09-17 18:07:49.261 UTC [28] LOG:  redo done at 0/1D7BD68 system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
2024-09-17 18:07:49.264 UTC [26] LOG:  checkpoint starting: end-of-recovery immediate wait
2024-09-17 18:07:49.268 UTC [26] LOG:  checkpoint complete: wrote 3 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.002 s, sync=0.001 s, total=0.006 s; sync files=2, longest=0.001 s, average=0.001 s; distance=0 kB, estimate=0 kB; lsn=0/1D7BDA0, redo lsn=0/1D7BDA0
2024-09-17 18:07:49.272 UTC [1] LOG:  database system is ready to accept connections

И база становится девственно чиста. Собираю вот так:

sudo docker compose build
sudo docker compose up -d

хост:

Linux hostname 6.8.0-41-generic #41-Ubuntu SMP PREEMPT_DYNAMIC Fri Aug  2 20:41:06 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

Пробовал снести все файлы — не помогло. Как они вообще могут пересекаться? Само приложение ничего странного не делает (вроде бы). Это VPS, поэтому железо протестировать не могу. Обновлял систему, перезагружал — всё работает и не ломается, даже база.

В логах приложения (на django) ничего интересного не вижу, все запросы проходят без ошибок, включая миграции. У моделей только CRUD, там просто нечему насиловать базу.

★★★★★

Обновлял систему, перезагружал — всё работает и не ломается, даже база.

А попробуй остановить все и удалить контейнер с базой (файлы БД же на отдельном volume?). После запуска ошибка будет та же?

router ★★★★★
()
Ответ на: комментарий от InterVi

После запуска ошибка будет та же? так и делал, не помогло

Ну, ок :)

Есть предположение, что при обновлении приложения compose либо пересоздает все, либо принудительно вытягивает новый image

Если при этом версия postgres ещё и не зафиксирована, новая версия может не согласиться восстанавливать БД после краша старой версии

router ★★★★★
()
Ответ на: комментарий от lx1

docker-compose.yml:

version: "3.9"

services:
  db:
    image: postgres:latest
    volumes:
      - ./.data/postgresql:/var/lib/postgresql/data
      - ./postgres.sql:/docker-entrypoint-initdb.d/init.sql
    environment:
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    env_file: ".env"
    networks:
      - db
    hostname: db
    restart: unless-stopped
    logging:
      driver: json-file
      options:
        max-size: 50m
    healthcheck:
      test: ["CMD-SHELL", "pg_isready", "-d", "${DB_NAME}", "-U", "postgres"]
      interval: 10s
      timeout: 10s
      retries: 5
      start_period: 10s
  app:
    build: .
    volumes:
      - ./.data/app:/app/data
    depends_on:
      db:
        condition: service_healthy
    env_file: ".env"
    restart: unless-stopped
    logging:
      driver: json-file
      options:
        max-size: 50m
    networks:
      - app
      - db
  caddy:
    image: caddy:latest
    restart: unless-stopped
    container_name: caddy_proxy
    env_file: ".env"
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./.data/caddy_data:/data
      - ./.data/caddy_config:/config
    networks:
      - app

networks:
  app:
  db:

Dockerfile приложения:

FROM python:3 AS pre-build-stage
RUN apt-get update && apt-get install -y --no-install-recommends \
    nano \
    netcat-traditional \
    parallel \
    && rm -r /var/lib/apt/lists/*

FROM pre-build-stage AS requirements-stage
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE 1
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt

FROM requirements-stage AS build-stage
WORKDIR /app
COPY . .

FROM build-stage AS test-stage
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE 1
WORKDIR /app
RUN python manage.py test --exclude-tag=requests

FROM test-stage AS release-stage
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE 1
WORKDIR /app
ENTRYPOINT [ "/app/entrypoint.sh" ]
CMD parallel -u --halt=now,fail=1 < execute.txt

entrypoint.sh:

#!/usr/bin/env sh
set -e

while ! nc -z db 5432; do
  sleep 0.1
done

export DJANGO_SUPERUSER_USERNAME="admin"
export DJANGO_SUPERUSER_PASSWORD="admin"
echo "migrations"
python /app/manage.py migrate

echo "create superuser"
python /app/manage.py createsuperuser --username admin --noinput --email 'admin@example.com' || echo "User is already created"

echo "collect static"
mkdir -p /app/data
mkdir -p /app/data/static
echo yes | python /app/manage.py collectstatic

exec "$@"
InterVi ★★★★★
() автор топика
Ответ на: комментарий от InterVi

Cкорее всего ошибка в ./postgres.sql

One common problem is that if one of your /docker-entrypoint-initdb.d scripts fails (which will cause the entrypoint script to exit) and your orchestrator restarts the container with the already initialized data directory, it will not continue on with your scripts.

https://hub.docker.com/_/postgres

Запусти docker compose up без -d, будет написано

masa
()
Ответ на: комментарий от shell-script

Как root / root. В этом проекте есть одно отличие — обычно используется единая база, которая root. Но в неё постгрес срёт какой-то своей метадатой, из-за чего ломаются бэкапы. Поэтому я создал отдельную базу под приложение.

InterVi ★★★★★
() автор топика
Ответ на: комментарий от InterVi

Это понятно, что это пользователь django. Но откуда он берётся? Из компоса, докерфайла и ентрипоинт не видно, чтобы он где-то создавался. Или это только я не вижу? :) Значит что-то где-то проводит ещё какие-то манипуляции над базой. Может в списке команд, которые у тебя из parallel дёргаются?

shell-script ★★★★★
()
Последнее исправление: shell-script (всего исправлений: 1)
Ответ на: комментарий от shell-script

https://stackoverflow.com/questions/6244382/how-to-automate-createsuperuser-on-django

Тут команда немного кривая, но сути это не меняет. Пользователь создаётся после миграций, если его нет. Миграции тоже не проходят, если база не вайпалась.

InterVi ★★★★★
() автор топика
Ответ на: комментарий от lx1
  • снёс все данные докера, которые в /var/lib/docker и /var/docker
  • снёс .data/postgresql
  • избавился от postgres.sql, перешёл на переменные окружения
  • заменил postgres:latest на postgres:alpine

Не помогло. А могут биться файлы при монтировании?

InterVi ★★★★★
() автор топика
Ответ на: комментарий от InterVi

ну, вероятность такая есть, но кажется, что вряд ли.

грубо говоря, вот прям гарантировано работающий в моем окружении вариант (linux на хосте, ext4 в качестве ФС)

services:
  db:
    container_name: psql
    image: postgres:16-alpine
    volumes:
      - ./data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    env_file:
      - .env

После перезапусков ничего не ломается, все ок.

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

lx1
()
Последнее исправление: lx1 (всего исправлений: 1)
Ответ на: комментарий от shell-script

execute.txt:

gunicorn --threads 20 -b 0.0.0.0:8000 boltz.wsgi:application
python schedule_jobs.py

И это стартует только после отработки entrypoint.sh, видно же по скрипту и докерфайлу.

Собираю так:

sudo docker compose stop
git pull my master
sudo docker compose build
sudo docker compose up -d
InterVi ★★★★★
() автор топика
Ответ на: комментарий от lx1

Вынес в volumes, не помогло. Всё равно та же ошибка на старте, файлы постреса бьются. И это только на сервере. Локально тот же конфиг и никакой магии, всё работает.

InterVi ★★★★★
() автор топика

тред не читал. пальцем в небо.

1 воспроизведи на другой машине

2 посмотри docker ps нет ли лишнего чего

3 попробуй в композе для бдшного сервиса указать volume именем, чтобы композе сам в /var/lib их создавал на основе project name и номера экземпляра

asdpm
()
Ответ на: комментарий от asdpm

теперь так:

volumes:
  db:
services:
  db:
    image: postgres:alpine
    volumes:
      - db:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=${DB_NAME}
    env_file: ".env"
    networks:
      - db
    hostname: db
    restart: unless-stopped
    logging:
      driver: json-file
      options:
        max-size: 50m
    healthcheck:
      test: ["CMD-SHELL", "psql -U ${DB_USER} -d ${DB_NAME} -c 'SELECT 1' || exit 1"]
      interval: 10s
      timeout: 10s
      retries: 5
      start_period: 10s

И всё равно вайп. В ps только мои контейнеры, ничего странного. Баг локально не воспроизводится.

InterVi ★★★★★
() автор топика
Ответ на: комментарий от InterVi

Погоди, а у тебя разве не трутся в процессе docker compose down волумы? Они ведь не external. То есть не

volumes:
  db:
    external: true

Но в этом случае нужно будет создать его отдельно.

docker volume create db

lx1
()
Ответ на: комментарий от InterVi

ну тут остается перебирать уже все возможные варианты.

типа чтобы исключить проблемность диска хоста поместить этот volume на tmpfs, но не tmpfs storage driver всмысле а вручную созданное.

или воспроизводить весь сценарий руками без композы, командами docker run

собирать, но не стартовать app контейнер если есть подозрение что как-то связано, или сделать его инертным (tail -f там поставить типа)

asdpm
()
Ответ на: комментарий от InterVi

заказчик что-то взял у рег.ру

Пальцем в небо: когда я с ними сталкивался, они дико оверселлили IO на обычных vps-ках, посмотри, может, есть таймаут остановки контейнера, за который он не успевает остановиться и прибивается?

Dimez ★★★★★
()
Ответ на: комментарий от asdpm

Таки нашёл. Баг вдруг проявился локально и тут я заподозрил неладное. Выяснилось, что я умудрился просмотреть в .env параметр с именем дефолтной базы — это нужно, чтобы без лишних ковыряний запускаться на sqlite3 локально. Но локально как раз был пострес, а на проде — sqlite3. Файлик с ним благополучно затирался при пересборке контейнера.

Но зато я попутно зарефакторил весь проект, наладил секьюрность, дописал проверку — теперь при таких настройках на проде происходит краш.

InterVi ★★★★★
() автор топика
Последнее исправление: InterVi (всего исправлений: 1)