12 KiB
PXF для bookings в учебном стенде (актуально)
Этот документ описывает текущую реализацию PXF в проекте: чтение данных из демо‑БД
bookings (Postgres, сервис bookings-db) в Greenplum через JDBC.
1. Что должно работать
- В Greenplum доступны внешние таблицы:
public.ext_bookings_bookings(создаётсяmake ddl-gp);stg.bookings_ext(создаётся DAGbookings_stg_ddl).
- PXF должен быть готов после каждого старта контейнера
greenplum.
2. Почему мы делаем свой образ Greenplum
Изначально PXF‑скрипты/конфиги монтировались в контейнер как bind‑mount :ro.
Базовый entrypoint образа Greenplum пытается делать chown файлов в
/docker-entrypoint-initdb.d/, из‑за чего контейнер иногда падал с ошибкой:
chown: changing ownership ... Read-only file system
Снять :ro тоже нежелательно — можно получить проблемы с правами на файлах хоста
(файл становится root, IDE перестаёт сохранять, появляются лишние изменения в git).
Решение для учебного стенда:
- собрать свой образ Greenplum (
Dockerfile.greenplum); - «вшить» в образ seed‑файлы и скрипты PXF;
- на каждом старте контейнера идемпотентно докладывать файлы в
PXF_BASE, который живёт на persistent volume.
3. Где что хранится
Внутри образа (immutable):
- 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).
На persistent volume (переживает рестарты):
PXF_BASEпо умолчанию:${GREENPLUM_DATA_DIRECTORY}/pxf→ в нашем compose это/data/pxfна томеgreenplum_data.
Важно: так как PXF_BASE лежит на томе, обновления seed‑файлов из нового образа
не перезатирают файлы в PXF_BASE автоматически (это сделано намеренно, чтобы
не ломать ручные правки студентов).
4. Что происходит при старте контейнера greenplum
-
Docker запускает контейнер с базовым entrypoint образа и командой
/start_greenplum_with_pxf.sh(она задана вDockerfile.greenplumкакCMD). -
/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 начинает принимать подключения.
-
Затем управление передаётся оригинальному старту Greenplum:
exec /start_gpdb.sh. -
Healthcheck сервиса
greenplumждёт и готовность Greenplum, и то, что PXF уже запущен (pxf cluster status). Это нужно, чтобы Airflow не стартовал раньше PXF.
5. Управляющие переменные окружения
Все переменные можно задать в .env (см. .env.example):
PXF_SEED_OVERWRITE=1— принудительно перезаписать seed‑файлы из образа вPXF_BASE(обычно нужно после правок в каталогеpxf/).PXF_SYNC_ON_START=1— выполнятьpxf cluster syncпри старте контейнера (делает старт чуть дольше, но гарантирует актуальные конфиги на хостах кластера).
6. Быстрая ручная проверка
- Дождаться
healthyуgreenplum:
docker compose ps
- Проверить статус PXF (PXF CLI запускается только под пользователем
gpadmin):
docker compose exec greenplum bash -lc "su - gpadmin -c '/usr/local/pxf/bin/pxf cluster status'"
- После применения DDL (
make ddl-gp) проверить чтение через PXF:
make gp-psqlSELECT COUNT(*) FROM public.ext_bookings_bookings;
7. Типовые ошибки
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+ restartgreenplum+ (при необходимости)PXF_SEED_OVERWRITE=1.
- причина: файлы уже лежат в
9. Известная проблема: protocol "pxf" does not exist на «холодном старте» (исправлено)
Раньше (воспроизводилось в ./scripts/e2e_smoke.sh) при первом make ddl-gp можно было получить:
ERROR: protocol "pxf" does not exist
Почему так происходило
В базовом /start_gpdb.sh из образа Greenplum создание расширения pxf связано с проверкой
файла ${PXF_BASE}/conf/pxf-env.sh:
- если
pxf-env.shотсутствует, скрипт выполняетpxf cluster prepare/registerи затемCREATE EXTENSION IF NOT EXISTS pxf; - если
pxf-env.shуже существует, этот блок пропускается, и расширение может не появиться.
При этом наш ensure‑скрипт pxf/init/10_pxf_bookings.sh копировал pxf-env.sh в ${PXF_BASE}
ещё до запуска Greenplum, из‑за чего базовый скрипт считал PXF “уже настроенным” и
пропускал создание расширения.
Что изменили
- создание
extension pxfвынесено вstart_greenplum_with_pxf.shи обёрнуто ретраями; pxf-env.shпо‑прежнему копируется вPXF_BASE, чтобы/start_gpdb.shне пытался выполнятьpxf cluster prepareна непустомPXF_BASE;- healthcheck
greenplumждёт не только PXF, но и наличиеextension pxf. - добавлен экспорт
PGPASSWORDдляpxf cluster start, чтобыdocker compose stop/startне ломал запуск из‑заpassword authentication failedдляgpadmin.
Если ошибка всё ещё возникает
-
Пересоберите образ и перезапустите контейнер
greenplum:make build && make down && make up -
Проверьте наличие extension:
docker compose exec greenplum bash -lc "su - gpadmin -c '/usr/local/greenplum-db/bin/psql -d gp_dwh -t -A -c \"SELECT extname FROM pg_extension WHERE extname = ''pxf'';\"'"
8. Связанные файлы
Dockerfile.greenplumdocker-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: свой образ»)
10. Известная проблема: после docker compose stop/start Greenplum может упасть (auth для PXF)
Симптом
После docker compose stop, затем docker compose start контейнер greenplum иногда уходит в Exited (1).
В логах видно, что GPDB поднялся, но упал на старте PXF:
INFO - pxf cluster startERROR: Could not connect to GPDBFATAL: password authentication failed for user "gpadmin"
Текущее понимание причины (почему это “иногда”)
- При старте GPDB образ
woblerr/greenplumгенерирует/дописываетpg_hba.confна persistent volume. - В
pg_hba.confприсутствует trust‑правило для конкретного IP контейнера в docker‑сети (пример из диагностики:host all gpadmin 172.21.0.2/32 trust). - После
docker compose stop/startDocker может выдать контейнеру другой IP (например,172.21.0.3). Тогда trust‑правило больше не подходит, и подключение начинает идти поmd5. pxf cluster startподключается к GPDB по TCP наhost=gpdbsne(hostname контейнера), то есть попадает именно вpg_hba.conf(а не в local‑auth).- В результате при “не совпавшем IP” получаем
md5+ пароль (возможно пустой/не тот) → падение на28P01.
Эта проблема выглядит флапающей, потому что IP после stop/start иногда совпадает с захардкоженным trust‑/32,
а иногда нет.
Как подтвердить при следующем воспроизведении
-
Посмотреть логи
greenplum:docker compose logs --tail=200 greenplum -
Найти реальный IP клиента в master‑логах GPDB (на томе):
Password does not match ...обычно содержит адрес вида172.21.0.X. -
Сравнить его с trust‑строкой в
pg_hba.confна томе:/data/master/gpseg-1/pg_hba.conf
Если IP в ошибке (например, 172.21.0.3) не совпадает с trust‑/32 (например, 172.21.0.2/32) —
это почти наверняка корень падения.
Что с этим делать дальше (варианты решения, без реализации здесь)
Основная цель — убрать зависимость от “случайного IP после stop/start”:
- заставить
pxf cluster startподключаться к GPDB через127.0.0.1(тогда работает существующий trust на localhost); - или перестать добавлять в
pg_hba.conftrust на конкретный172.21.0.2/32и заменить на более стабильное правило (например, на подсеть docker‑сети или наsamehost); - или закрепить IP контейнера в compose (static IP), чтобы он не “плавал”;
- или отказаться от
stop/startв пользу сценария, который не меняет сетевое окружение (но это хуже для UX студентов).