From dfcc4561203b18fb1136594b210ba0789c617093 Mon Sep 17 00:00:00 2001 From: Dmitry Dementev Date: Thu, 8 Jan 2026 22:24:24 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=80?= =?UTF-8?q?=D0=B5=D1=88=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 2 + README.md | 8 + TESTING.md | 4 +- docker-compose.yml | 4 +- docs/internal/pxf_bookings.md | 268 +++++++---------------- plans/greenplum-pxf-custom-image-plan.md | 35 +++ pxf/init/10_pxf_bookings.sh | 17 +- 7 files changed, 138 insertions(+), 200 deletions(-) diff --git a/.env.example b/.env.example index 34c614a..c9f95a2 100644 --- a/.env.example +++ b/.env.example @@ -33,7 +33,9 @@ GP_CONN_ID=greenplum_conn GP_USE_AIRFLOW_CONN=true # PXF (optional) +# PXF_SEED_OVERWRITE=1 — принудительно перезаписать seed-файлы из образа в PXF_BASE (полезно после правок в pxf/) PXF_SEED_OVERWRITE=0 +# PXF_SYNC_ON_START=1 — выполнять `pxf cluster sync` при старте контейнера (дольше, но гарантирует актуальные конфиги) PXF_SYNC_ON_START=0 # CSV Pipeline diff --git a/README.md b/README.md index 34a3692..1b6a046 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,9 @@ make gp-psql # Подключение к Greenplum - создаются каталоги `PXF_BASE/run` и `PXF_BASE/logs`; - `CREATE EXTENSION pxf` выполняется автоматически, когда Greenplum становится доступен. +Healthcheck сервиса `greenplum` учитывает не только готовность Greenplum, но и запуск PXF — +это нужно, чтобы Airflow не стартовал раньше PXF. + Сборка и запуск: - `make build` — собрать образ (явно); @@ -163,6 +166,11 @@ make gp-psql # Подключение к Greenplum - для принудительной перезаписи файлов в `PXF_BASE` используйте `PXF_SEED_OVERWRITE=1`; - для принудительного `pxf cluster sync` при старте используйте `PXF_SYNC_ON_START=1`. +Проверка PXF: + +- статус: `docker compose exec greenplum bash -lc "su - gpadmin -c '/usr/local/pxf/bin/pxf cluster status'"`; +- логи: `greenplum_data:/data/pxf/logs` (внутри контейнера — `/data/pxf/logs`). + --- ### Локальное окружение разработчика diff --git a/TESTING.md b/TESTING.md index 4249521..3aaced4 100644 --- a/TESTING.md +++ b/TESTING.md @@ -20,7 +20,7 @@ - `cp .env.example .env` (если файла ещё нет) и проверьте переменные: - `GP_PORT` — внутренний порт Greenplum в Docker-сети (по умолчанию 5432, менять не нужно); внешний порт для подключения с хоста фиксирован на `5435`, поэтому локальный PostgreSQL на 5432 не помешает. - `GP_USE_AIRFLOW_CONN=true` при желании использовать Airflow Connection; `false` — fallback на ENV. -- `make up` — поднимаем все сервисы. Важно дождаться статуса `healthy` у `pgmeta` и `greenplum` (`docker compose ps`); инициализация Airflow (`airflow-init`) произойдёт автоматически при первом старте. +- `make up` — поднимаем все сервисы. Важно дождаться статуса `healthy` у `pgmeta` и `greenplum` (`docker compose ps`); `greenplum` считается `healthy` только когда поднят и Greenplum, и PXF. - `make logs` — следим, пока webserver и scheduler не перейдут в рабочее состояние (`Listening at: http://0.0.0.0:8080`). ## 4. Smoke тесты DAG в Airflow UI @@ -48,6 +48,8 @@ ## 5. Проверка данных в Greenplum - `make gp-psql` — запустить psql в контейнере от имени `gpadmin`. +- (опционально) Проверить, что PXF действительно запущен: + - `docker compose exec greenplum bash -lc "su - gpadmin -c '/usr/local/pxf/bin/pxf cluster status'"` - Команды внутри psql: - `\dt public.*` — таблицы схему public. - `SELECT COUNT(*) FROM public.orders;` — оценка объёма. diff --git a/docker-compose.yml b/docker-compose.yml index f481e34..64231c4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -84,7 +84,9 @@ services: - greenplum_data:/data # Простая проверка доступности: psql откликается healthcheck: - test: [ "CMD-SHELL", "/usr/local/greenplum-db/bin/pg_isready -h 127.0.0.1 -p 5432 -U ${GP_USER:-gpadmin} -d ${GP_DB:-gp_dwh}" ] + # Ждём не только доступность GPDB, но и готовность PXF, + # чтобы Airflow не стартовал раньше PXF. + test: [ "CMD-SHELL", "/usr/local/greenplum-db/bin/pg_isready -h 127.0.0.1 -p 5432 -U ${GP_USER:-gpadmin} -d ${GP_DB:-gp_dwh} && su - ${GP_USER:-gpadmin} -c '/usr/local/pxf/bin/pxf cluster status' >/dev/null 2>&1" ] interval: 10s timeout: 5s retries: 30 diff --git a/docs/internal/pxf_bookings.md b/docs/internal/pxf_bookings.md index 5199e39..0283146 100644 --- a/docs/internal/pxf_bookings.md +++ b/docs/internal/pxf_bookings.md @@ -1,228 +1,110 @@ -# Временное ТЗ по PXF для чтения данных из bookings (черновик) +# PXF для bookings в учебном стенде (актуально) -_Этот файл внутренний, удалить перед итоговой сдачей._ +Этот документ описывает **текущую реализацию** PXF в проекте: чтение данных из демо‑БД +`bookings` (Postgres, сервис `bookings-db`) в Greenplum через JDBC. -## 1. Цель и границы +## 1. Что должно работать -- Минимальная цель: настроить PXF в контейнере Greenplum так, чтобы из базы `bookings` (Postgres в сервисе `bookings-db`) можно было делать `SELECT` по одной внешней таблице в Greenplum. -- На этом этапе **не** делаем загрузку в постоянные таблицы Greenplum, только чтение и ручные smoke‑проверки. -- Изменения в коде/конфигурации пока планируем «на бумаге»; реализацию и правки `docker-compose.yml`/SQL/DAG делаем отдельным шагом. +- В Greenplum доступны внешние таблицы: + - `public.ext_bookings_bookings` (создаётся `make ddl-gp`); + - `stg.bookings_ext` (создаётся DAG `bookings_stg_ddl`). +- PXF должен быть готов **после каждого старта** контейнера `greenplum`. -## 2. Архитектура на уровне контейнеров +## 2. Почему мы делаем свой образ Greenplum -- `bookings-db` — Postgres 16, демо‑БД `demo` из репозитория `demodb` (источник). Доступен внутри сети Docker по имени `bookings-db` и порту `5432`. -- `greenplum` — контейнер `woblerr/greenplum:6.27.1` (GPDB 6, Ubuntu 22.04). В нём уже есть: - - Greenplum в режиме singlenode; - - установленный PXF (`/usr/local/pxf`, `pxf version release-6.10.1`); - - стартовый скрипт `/start_gpdb.sh`, который умеет включать PXF по флагу `GREENPLUM_PXF_ENABLE=true`. -- Внешний мир (IDE/pytest) подключается к Greenplum по порту `5435` на хосте (см. `docker-compose.yml`), а к `bookings-db` — по порту `${BOOKINGS_DB_PORT}` (см. `.env`). +Изначально PXF‑скрипты/конфиги монтировались в контейнер как bind‑mount `:ro`. +Базовый entrypoint образа Greenplum пытается делать `chown` файлов в +`/docker-entrypoint-initdb.d/`, из‑за чего контейнер иногда падал с ошибкой: -## 3. Включение PXF в нашем стенде (дизайн) +`chown: changing ownership ... Read-only file system` -Планируемые изменения (позже будут внесены в `docker-compose.yml`): +Снять `:ro` тоже нежелательно — можно получить проблемы с правами на файлах хоста +(файл становится `root`, IDE перестаёт сохранять, появляются лишние изменения в git). -- В сервисе `greenplum` в секцию `environment` добавить: - - `GREENPLUM_PXF_ENABLE: "true"`. -- При первом старте с этим флагом скрипт `/start_gpdb.sh` сделает за нас: - - инициализацию PXF (`pxf cluster prepare`, `pxf cluster register`, `pxf cluster sync`); - - создание расширения `pxf` в базе `${GREENPLUM_DATABASE_NAME}` (у нас это `${GP_DB}`, по умолчанию `gp_dwh`); - - запуск `pxf cluster start` и привязку остановки/старта PXF к жизненному циклу Greenplum. -- База конфигов PXF (`PXF_BASE`) будет располагаться в `${GREENPLUM_DATA_DIRECTORY}/pxf`, в нашем compose — это `/data/pxf` на томе `greenplum_data`. - - Важно: `make down` сейчас делает `docker compose down -v`, поэтому при полном сбросе томов будут теряться и данные GP, и конфиги PXF (включая JDBC‑драйвер и `servers/*`). +Решение для учебного стенда: -## 4. JDBC‑драйвер для Postgres: где и как хранить +- собрать **свой образ** Greenplum (`Dockerfile.greenplum`); +- «вшить» в образ seed‑файлы и скрипты PXF; +- на каждом старте контейнера идемпотентно докладывать файлы в `PXF_BASE`, + который живёт на persistent volume. -Задача: PXF должен уметь ходить по JDBC в `bookings-db` (Postgres). Для этого нужен PostgreSQL JDBC драйвер (`postgresql-*.jar`). +## 3. Где что хранится -Варианты хранения драйвера: +**Внутри образа (immutable):** -1. **Коммитить JAR в репозиторий** и монтировать в контейнер. - - Плюсы: стенд самодостаточен, не зависит от внешних скачиваний, повторяемость выше (особенно на офлайн‑машинах или при падении зеркал). - - Минусы: лишний бинарник в учебном репо, периодически нужно обновлять версию. -2. **Скачивать JAR внутрь контейнера один раз вручную** и хранить его в томе `greenplum_data` внутри `PXF_BASE/lib`. - - Плюсы: нет бинарников в Git. - - Минусы: дополнительный шаг для студентов, зависимость от сети, нужно повторять после полного сброса томов. +- seed для PXF: `/opt/pxf-seed/` (JDBC‑JAR и `servers/bookings-db/jdbc-site.xml`); +- скрипты: + - `/opt/pxf-scripts/ensure_pxf_bookings.sh` (подготовка `PXF_BASE`); + - `/start_greenplum_with_pxf.sh` (startup wrapper). -Для учебного стенда окончательно выбираем вариант **(1) — JAR в репозитории**: +**На persistent volume (переживает рестарты):** -- В репозитории заводим каталог, например `pxf/` или `pxf/jdbc/`, и кладём туда файл `postgresql-42.7.3.jar` (фиксируем версию 42.7.3 как актуальную на момент разработки). -- В `docker-compose.yml` (на этапе реализации) смонтируем этот JAR внутрь контейнера `greenplum` в каталог `$PXF_BASE/lib`, например: - - `./pxf/postgresql-42.7.3.jar:/data/pxf/lib/postgresql-jdbc.jar:ro`. -- PXF по документации поддерживает размещение JDBC‑драйвера в `$PXF_BASE/lib` (общий для всех серверов) или в `$PXF_BASE/servers//lib` (локальный для сервера). Для простоты используем общий каталог `$PXF_BASE/lib`. -- Для студентов не будет лишних подготовительных шагов: после `make up` и инициализации конфигов PXF драйвер уже на месте. +- `PXF_BASE` по умолчанию: `${GREENPLUM_DATA_DIRECTORY}/pxf` → в нашем compose это + `/data/pxf` на томе `greenplum_data`. -Договорённость для реализации: +Важно: так как `PXF_BASE` лежит на томе, обновления seed‑файлов из нового образа +**не перезатирают** файлы в `PXF_BASE` автоматически (это сделано намеренно, чтобы +не ломать ручные правки студентов). -- Путь в репозитории: условно `pxf/postgresql-42.7.3.jar`. -- Путь внутри контейнера: `/data/pxf/lib/postgresql-jdbc.jar` (через bind‑mount, read‑only). -- Обновление драйвера в будущем — ручная операция (заменить JAR в `pxf/` и скорректировать путь в `docker-compose.yml` при необходимости). +## 4. Что происходит при старте контейнера `greenplum` -## 5. Сервер PXF для bookings-db (jdbc-site.xml) +1) Docker запускает контейнер с базовым entrypoint образа и командой +`/start_greenplum_with_pxf.sh` (она задана в `Dockerfile.greenplum` как `CMD`). -PXF использует концепцию «серверов» (`servers/<имя>`), где для каждого сервера хранится свой конфиг подключения (в т.ч. JDBC). +2) `/start_greenplum_with_pxf.sh` выполняет подготовку PXF: -План: +- запускает ensure‑скрипт `/opt/pxf-scripts/ensure_pxf_bookings.sh`; +- параллельно пытается выполнить `CREATE EXTENSION IF NOT EXISTS pxf` + в базе `${GP_DB}` (по умолчанию `gp_dwh`), когда Greenplum начинает принимать + подключения. -- Создать сервер с именем `bookings-db` (название привязываем к сервису Docker, чтобы не путаться). -- Конфиг храним в репозитории, например в файле: - - `pxf/servers/bookings-db/jdbc-site.xml`. -- В контейнере этот файл будет доступен как: - - `/data/pxf/servers/bookings-db/jdbc-site.xml` (bind‑mount read‑only). -- Внутри прописываем параметры подключения к демо‑БД `demo` в Postgres `bookings-db`. +3) Затем управление передаётся оригинальному старту Greenplum: `exec /start_gpdb.sh`. -Черновой шаблон `jdbc-site.xml` (значения логина/пароля берём из `.env.example`, блок `BOOKINGS_DB_*` — для учебного стенда допускаем хардкод тех же дефолтных значений): +4) Healthcheck сервиса `greenplum` ждёт и готовность Greenplum, и то, что PXF уже +запущен (`pxf cluster status`). Это нужно, чтобы Airflow не стартовал раньше PXF. -```xml - - +## 5. Управляющие переменные окружения - - jdbc.driver - org.postgresql.Driver - +Все переменные можно задать в `.env` (см. `.env.example`): - - jdbc.url - jdbc:postgresql://bookings-db:5432/demo - +- `PXF_SEED_OVERWRITE=1` — принудительно перезаписать seed‑файлы из образа в `PXF_BASE` + (обычно нужно после правок в каталоге `pxf/`). +- `PXF_SYNC_ON_START=1` — выполнять `pxf cluster sync` при старте контейнера + (делает старт чуть дольше, но гарантирует актуальные конфиги на хостах кластера). - - jdbc.user - ${BOOKINGS_DB_USER} - +## 6. Быстрая ручная проверка - - jdbc.password - ${BOOKINGS_DB_PASSWORD} - +1) Дождаться `healthy` у `greenplum`: - -``` +`docker compose ps` -Замечания: +2) Проверить статус PXF (PXF CLI запускается только под пользователем `gpadmin`): -- В реальном файле `pxf/servers/bookings-db/jdbc-site.xml` логин и пароль будут прописаны строками, совпадающими с дефолтами из `.env.example` (`BOOKINGS_DB_USER=bookings`, `BOOKINGS_DB_PASSWORD=bookings`). Это упрощает старт стенда для студентов. -- Если студент поменяет креды `BOOKINGS_DB_USER`/`BOOKINGS_DB_PASSWORD` в своём `.env`, он должен **также** поменять их в `pxf/servers/bookings-db/jdbc-site.xml`, иначе PXF не сможет подключиться к источнику. -- Адрес `bookings-db:5432` — имя сервиса и внутренний порт Postgres внутри сети `docker compose`. Внешний порт (`${BOOKINGS_DB_PORT:-5434}`) здесь не используется. -- При стандартном сценарии (конфиг монтируется read‑only) PXF подхватывает `jdbc-site.xml` при первой инициализации/старте. Если конфиг внутри контейнера всё‑таки меняли вручную, для надёжности можно выполнить: - ```bash - pxf cluster sync - pxf cluster restart - ``` - чтобы PXF подхватил новые настройки. +`docker compose exec greenplum bash -lc "su - gpadmin -c '/usr/local/pxf/bin/pxf cluster status'"` -## 6. Внешняя таблица в Greenplum (только для чтения) +3) После применения DDL (`make ddl-gp`) проверить чтение через PXF: -Задача: завести одну external‑таблицу в Greenplum, которая читает данные из демо‑БД `demo` через PXF/JDBC. +- `make gp-psql` +- `SELECT COUNT(*) FROM public.ext_bookings_bookings;` -Дизайн: +## 7. Типовые ошибки -- Имя таблицы в Greenplum: `public.ext_bookings_bookings` (подчёркиваем, что это внешнее представление таблицы `bookings.bookings` из Postgres). -- Схема колонок должна совпадать со схемой исходной таблицы в `demo` (её нужно будет аккуратно выписать отдельным шагом, через `\d bookings.bookings` в `bookings-db`). -- Локация PXF: - - `PROFILE=JDBC` — используем JDBC‑профиль. - - `SERVER=bookings-db` — имя сервера из `jdbc-site.xml`. +- `protocol "pxf" does not exist` + - причина: не создано расширение `pxf` в базе Greenplum; + - решение: перезапустить `greenplum` (скрипт сделает `CREATE EXTENSION IF NOT EXISTS pxf`) + или выполнить вручную `CREATE EXTENSION pxf;`. +- `Connection refused` к порту `5888` + - причина: PXF не поднялся/не успел подняться; + - решение: проверить `pxf cluster status`, посмотреть логи PXF в `/data/pxf/logs`, + перезапустить сервис `greenplum`. +- PXF «не подхватывает» изменения конфигов + - причина: файлы уже лежат в `PXF_BASE` на томе, а seed из образа по умолчанию не перетирает их; + - решение: `make build` + restart `greenplum` + (при необходимости) `PXF_SEED_OVERWRITE=1`. -Черновой шаблон DDL (без конкретных типов, заполним позже по реальной схеме; предполагается, что финальный DDL ляжет в `sql/ddl_gp.sql`, чтобы применяться через `make ddl-gp`): +## 8. Связанные файлы -```sql -CREATE EXTERNAL TABLE public.ext_bookings_bookings ( - -- TODO: колонки как в bookings.bookings (будет уточнено) -) -LOCATION ('pxf://bookings.bookings?PROFILE=JDBC&SERVER=bookings-db') -FORMAT 'CUSTOM' (formatter='pxfwritable_import'); -``` - -Комментарии: - -- На этапе реализации нужно будет: - - в `bookings-db` посмотреть структуру основного факт‑табличного объекта (скорее всего `bookings.bookings`) и перенести DDL; - - проверить типы дат/чисел, чтобы избежать сюрпризов на стороне GP. -- Для MVP достаточно одной таблицы; позже можно добавить ещё 1–2 внешние таблицы для примеров (например, справочники). - -## 7. План тестирования (без дополнительных make‑таргетов) - -Цель тестов: показать студентам, что PXF настроен корректно и позволяет читать данные; при этом не плодить отдельные `make`‑цели, а использовать уже существующие (`make up`, `make bookings-init`, `make gp-psql`). - -### 7.1. Позитивный сценарий (smoke) - -Предварительные условия: - -- `.env` скопирован из `.env.example` и не изменял дефолтные креды для `bookings-db` (`BOOKINGS_DB_USER=bookings`, `BOOKINGS_DB_PASSWORD=bookings`). -- В `docker-compose.yml` включён PXF (`GREENPLUM_PXF_ENABLE=true` в сервисе `greenplum`). -- Для `bookings-db` уже выполнен `make bookings-init` (есть данные в `demo`). -- JAR драйвера (`pxf/postgresql-42.7.3.jar`) и файл `jdbc-site.xml` (`pxf/servers/bookings-db/jdbc-site.xml`) присутствуют в репозитории (они будут автоматически смонтированы в `/data/pxf/lib` и `/data/pxf/servers/bookings-db`). -- DDL внешней таблицы `public.ext_bookings_bookings` добавлен в `sql/ddl_gp.sql` и применяется через `make ddl-gp`. - -Шаги (в будущем попадут в `TESTING.md`): - -1. Поднять стенд: - - `make up` - - дождаться healthcheck‑ов `pgmeta` и `greenplum`. -3. Подготовить демо‑БД bookings: - - `make bookings-init`. -4. Применить DDL в Greenplum (создать таблицы, включая внешнюю `public.ext_bookings_bookings`): - - `make ddl-gp`. -5. Зайти в Greenplum: - - `make gp-psql`. -6. Проверить, что расширение PXF присутствует: - - `\dx pxf`. -7. Выполнить простые запросы: - - `SELECT COUNT(*) FROM public.ext_bookings_bookings;` - - `SELECT * FROM public.ext_bookings_bookings LIMIT 5;` - -Ожидаемый результат: - -- Запросы выполняются без ошибок, возвращают ненулевое количество строк. -- Структура данных визуально совпадает с данными в `bookings-db` (можно дополнительно открыть `bookings-psql` и сравнить). - -### 7.2. Негативный сценарий (отказ источника) - -Цель: показать, как выглядит ошибка, если источник недоступен, и что с этим делать. - -Шаги: - -1. При работающем стенде остановить только `bookings-db`: - - `docker compose stop bookings-db`. -2. В `make gp-psql` попробовать снова: - - `SELECT 1 FROM public.ext_bookings_bookings LIMIT 1;` - -Ожидаемый результат: - -- Запрос падает с ошибкой подключения к Postgres (через JDBC/pxf). -- В `TESTING.md` планируем добавить короткую подсказку: «если видите ошибку подключения — убедитесь, что запущен сервис `bookings-db` (`docker compose start bookings-db`) и повторите запрос». - -### 7.3. Идея для автоматического smoke‑теста (на будущее) - -На будущее (не в рамках текущего этапа) можно добавить простой e2e‑тест в `tests/`, который: - -- с помощью `psycopg2` коннектится к Greenplum (`GP_*` из `.env`); -- выполняет `SELECT 1 FROM public.ext_bookings_bookings LIMIT 1`; -- помечен как «integration» и запускается только по явному желанию (например, через отдельный маркер или переменную окружения). - -Пока это остаётся идеей: сначала реализуем базовую конфигурацию PXF и ручной smoke‑чек‑лист. - -## 8. Открытые вопросы / TODO - -- Уточнить целевую таблицу(ы) в `demo` для внешнего представления (скорее всего `bookings.bookings`), аккуратно выписать DDL и обновить шаблон из раздела 6. -- При переносе DDL проверить типы дат/времени, чтобы не получить неожиданный сдвиг по часовому поясу (см. `docs/internal/bookings_tz.md`). -- При необходимости добавить интеграционный тест по мотивам раздела 7.3 (по отдельному маркеру/флагу). - -## 9. Практические детали и нюансы - -- **Таймзона**: - - Для единообразия логов и данных задаём `TZ=Europe/Moscow` (GMT+3) в `.env.example` и пробрасываем эту переменную в контейнеры `pgmeta`, `bookings-db`, `greenplum`, `airflow-webserver`, `airflow-scheduler`. - - При проверке данных через PXF имеет смысл сравнивать выборки по времени между `bookings-db` и Greenplum, опираясь на договорённости из `docs/internal/bookings_tz.md`. -- **Поведение при `make down`**: - - `make down` вызывает `docker compose down -v`, что удаляет все тома, включая `greenplum_data` (`/data` в контейнере). - - При следующем `make up` Greenplum и PXF будут инициализироваться с нуля, но: - - JAR и `jdbc-site.xml` возьмутся из репозитория и снова смонтируются в `/data/pxf/...`; - - `make ddl-gp` снова создаст внешнюю таблицу `public.ext_bookings_bookings`. - - То есть после полного ресета студенту достаточно повторить цепочку `make up` → `make bookings-init` → `make ddl-gp`. -- **Где искать логи при проблемах с PXF**: - - Логи PXF: в контейнере `greenplum` под пользователем `gpadmin` в каталоге `${PXF_BASE}/logs` (по умолчанию `/data/pxf/logs`). - - Логи Greenplum: в `${GREENPLUM_DATA_DIRECTORY}/master/.../pg_log` (например, `/data/master/gpseg-1/pg_log` для GP6). - - При ошибках подключения к `bookings-db` полезно: - - проверить, что контейнер `bookings-db` работает (`docker compose ps`); - - сверить креды в `.env` и `pxf/servers/bookings-db/jdbc-site.xml`; - - посмотреть сообщения в `/data/pxf/logs`. +- `Dockerfile.greenplum` +- `docker-compose.yml` (сервис `greenplum`: `build`, `hostname`, env, healthcheck) +- `pxf/init/10_pxf_bookings.sh` (ensure‑логика) +- `pxf/init/start_greenplum_with_pxf.sh` (старт контейнера) +- `README.md` (раздел «Greenplum + PXF: свой образ») diff --git a/plans/greenplum-pxf-custom-image-plan.md b/plans/greenplum-pxf-custom-image-plan.md index 8e6a4c0..10ce36a 100644 --- a/plans/greenplum-pxf-custom-image-plan.md +++ b/plans/greenplum-pxf-custom-image-plan.md @@ -105,3 +105,38 @@ - Вернуться к использованию `image: woblerr/greenplum:6.27.1` в `docker-compose.yml`. - Вернуть mount’ы PXF, если нужно (но это вернёт риск с `:ro`). +--- + +## Статус (реализовано) + +- Добавлен кастомный образ Greenplum: `Dockerfile.greenplum` (seed PXF + startup wrapper). +- Ensure‑скрипт перенесён в образ и стал идемпотентным: `pxf/init/10_pxf_bookings.sh`. +- Стартовый скрипт контейнера включает ensure и создаёт `EXTENSION pxf`: `pxf/init/start_greenplum_with_pxf.sh`. +- В `docker-compose.yml`: + - `greenplum` собирается через `build: Dockerfile.greenplum`; + - добавлен `hostname: gpdbsne`; + - убраны PXF bind-mount’ы (jar/config/init); + - healthcheck ждёт не только GPDB, но и готовность PXF. +- Обновлены инструкции: `README.md`, `.env.example`. +- Проблема с генератором demodb (пустая `bookings.bookings`) зафиксирована в `TODO.md`. + +## Проверка (как воспроизвести) + +Команды для ручной проверки: + +- Пересобрать и перезапустить Greenplum: + - `make build` + - `docker compose up -d --force-recreate greenplum` +- 3–10 рестартов: + - `docker compose restart greenplum` + - дождаться `healthy` в `docker compose ps` +- Проверить PXF: + - `docker compose exec greenplum bash -lc "su - gpadmin -c '/usr/local/pxf/bin/pxf cluster status'"` +- Проверить DAG, который использует PXF: + - `docker exec -i gp_airflow_scheduler airflow dags test bookings_stg_ddl` + +Текущий результат: + +- `bookings_stg_ddl` проходит (PXF и `protocol pxf` доступны). +- `bookings_to_gp_stage` падает не из-за PXF, а из-за пустого источника + (`demo.bookings.bookings` = 0 строк). Это отдельная задача (см. `TODO.md`). diff --git a/pxf/init/10_pxf_bookings.sh b/pxf/init/10_pxf_bookings.sh index b2f91d9..522d36c 100755 --- a/pxf/init/10_pxf_bookings.sh +++ b/pxf/init/10_pxf_bookings.sh @@ -13,6 +13,8 @@ PXF_BASE_DEFAULT="${GREENPLUM_DATA_DIRECTORY:-/data}/pxf" PXF_BASE="${PXF_BASE:-$PXF_BASE_DEFAULT}" PXF_SEED_OVERWRITE="${PXF_SEED_OVERWRITE:-0}" PXF_SYNC_ON_START="${PXF_SYNC_ON_START:-0}" +PXF_CLI="${PXF_CLI:-/usr/local/pxf/bin/pxf}" +GP_USER="${GREENPLUM_USER:-gpadmin}" log_info() { echo "INFO - $*" @@ -83,11 +85,16 @@ copy_seed_file \ "pxf-profiles.xml" if [ "${PXF_SYNC_ON_START}" = "1" ]; then - if command -v pxf >/dev/null 2>&1; then - if ! pxf cluster sync; then - log_warn "pxf cluster sync завершился с ошибкой" - fi + if [ ! -x "${PXF_CLI}" ]; then + log_warn "pxf cli не найден: ${PXF_CLI}, пропускаем pxf cluster sync" + exit 0 + fi + + # PXF CLI не запускается под root, поэтому выполняем синхронизацию под gpadmin. + # PXF_BASE передаём явно, т.к. `su -` сбрасывает окружение. + if ! su - "${GP_USER}" -c "PXF_BASE='${PXF_BASE}' '${PXF_CLI}' cluster sync"; then + log_warn "pxf cluster sync завершился с ошибкой" else - log_warn "pxf не найден в PATH, пропускаем pxf cluster sync" + log_info "pxf cluster sync выполнен" fi fi