Merge branch 'fix/greenplum-pxf'
This commit is contained in:
@@ -22,9 +22,10 @@ stop:
|
|||||||
docker compose -f docker-compose.yml stop
|
docker compose -f docker-compose.yml stop
|
||||||
|
|
||||||
down:
|
down:
|
||||||
docker compose -f docker-compose.yml down -v
|
docker compose -f docker-compose.yml down
|
||||||
|
|
||||||
clean: down
|
clean:
|
||||||
|
docker compose -f docker-compose.yml down -v
|
||||||
|
|
||||||
airflow-init:
|
airflow-init:
|
||||||
docker compose -f docker-compose.yml run --rm airflow-init
|
docker compose -f docker-compose.yml run --rm airflow-init
|
||||||
|
|||||||
@@ -82,11 +82,12 @@ CSV-файлы после выполнения DAG остаются в дире
|
|||||||
Если после изменений что‑то «сломалось»:
|
Если после изменений что‑то «сломалось»:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make down # Остановить и стереть данные в контейнерах
|
make down # Остановить и удалить контейнеры/сети (volumes сохраняются)
|
||||||
make up
|
make up
|
||||||
```
|
```
|
||||||
|
|
||||||
Это помогает, когда Greenplum не стартует из‑за «грязной» остановки и внутренних файлов.
|
Если проблема связана с «грязной» остановкой и данными в томах (например, Greenplum не стартует),
|
||||||
|
используйте полный reset: `make clean && make up` (данные в Docker-томах будут потеряны).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -150,10 +151,10 @@ make gp-psql # Подключение к Greenplum
|
|||||||
|
|
||||||
- базовые конфиги PXF копируются в `PXF_BASE/conf` (если их ещё нет);
|
- базовые конфиги PXF копируются в `PXF_BASE/conf` (если их ещё нет);
|
||||||
- создаются каталоги `PXF_BASE/run` и `PXF_BASE/logs`;
|
- создаются каталоги `PXF_BASE/run` и `PXF_BASE/logs`;
|
||||||
- `CREATE EXTENSION pxf` выполняется автоматически, когда Greenplum становится доступен.
|
- `CREATE EXTENSION pxf` выполняется автоматически, когда Greenplum становится доступен (с ретраями).
|
||||||
|
|
||||||
Healthcheck сервиса `greenplum` учитывает не только готовность Greenplum, но и запуск PXF —
|
Healthcheck сервиса `greenplum` учитывает не только готовность Greenplum, но и запуск PXF,
|
||||||
это нужно, чтобы Airflow не стартовал раньше PXF.
|
а также наличие `extension pxf` — это нужно, чтобы Airflow не стартовал раньше PXF.
|
||||||
|
|
||||||
Сборка и запуск:
|
Сборка и запуск:
|
||||||
|
|
||||||
@@ -240,6 +241,9 @@ make bookings-psql # Подключиться к демобазе bookings
|
|||||||
# Проверка данных
|
# Проверка данных
|
||||||
make logs # Следить за логами Airflow
|
make logs # Следить за логами Airflow
|
||||||
|
|
||||||
|
# Логи задач Airflow сохраняются в Docker-томе `airflow_logs`
|
||||||
|
# и переживают `docker compose down`/`up` (удаляются при `docker compose down -v` / `make clean`).
|
||||||
|
|
||||||
# Контроль генерации bookings
|
# Контроль генерации bookings
|
||||||
docker compose -f docker-compose.yml exec bookings-db bash -lc 'PGPASSWORD="$POSTGRES_PASSWORD" psql -U "$POSTGRES_USER" -d demo -c "SELECT busy();"'
|
docker compose -f docker-compose.yml exec bookings-db bash -lc 'PGPASSWORD="$POSTGRES_PASSWORD" psql -U "$POSTGRES_USER" -d demo -c "SELECT busy();"'
|
||||||
# busy() = t — генерация ещё идёт; f — завершена. При необходимости можно вызвать CALL abort(); и запустить генерацию заново.
|
# busy() = t — генерация ещё идёт; f — завершена. При необходимости можно вызвать CALL abort(); и запустить генерацию заново.
|
||||||
@@ -409,11 +413,12 @@ load_bookings_to_stg = PostgresOperator(
|
|||||||
| Проблема | Решение |
|
| Проблема | Решение |
|
||||||
|----------|---------|
|
|----------|---------|
|
||||||
| Airflow UI не открывается | Дождитесь сообщения `Listening at: http://0.0.0.0:8080` в логах (`make logs`) |
|
| Airflow UI не открывается | Дождитесь сообщения `Listening at: http://0.0.0.0:8080` в логах (`make logs`) |
|
||||||
|
| `database "demo" does not exist` в bookings‑DAG | Вы сделали полный reset с удалением томов (`docker compose down -v` / `make clean`), поэтому демобаза bookings не установлена. Запустите `make bookings-init` и повторите DAG. |
|
||||||
| Ошибка подключения к Greenplum | Убедитесь, что контейнер `greenplum` стал статусом `healthy` (проверьте `docker compose ps`) |
|
| Ошибка подключения к Greenplum | Убедитесь, что контейнер `greenplum` стал статусом `healthy` (проверьте `docker compose ps`) |
|
||||||
| Не открывается порт 8080/5433/5434/5435 | Проверьте, что эти порты не заняты локальными сервисами; при необходимости остановите их или измените порты в `.env`/`docker-compose.yml` |
|
| Не открывается порт 8080/5433/5434/5435 | Проверьте, что эти порты не заняты локальными сервисами; при необходимости остановите их или измените порты в `.env`/`docker-compose.yml` |
|
||||||
| Нет файла в `./data` после запуска DAG | Проверьте логи задачи `generate_csv`, убедитесь, что `CSV_DIR` смонтирован в docker-compose |
|
| Нет файла в `./data` после запуска DAG | Проверьте логи задачи `generate_csv`, убедитесь, что `CSV_DIR` смонтирован в docker-compose |
|
||||||
| Команда `make` не найдена | Используйте полные команды `docker compose` или установите make |
|
| Команда `make` не найдена | Используйте полные команды `docker compose` или установите make |
|
||||||
| Greenplum не стартует/падает при старте | Выполните `make down`, затем `make up` (очищает тома и поднимает заново, включая авто‑инициализацию Airflow) |
|
| Greenplum не стартует/падает при старте | Попробуйте `make down && make up`. Если не помогло — полный reset: `make clean && make up` (удалит тома). |
|
||||||
| `protocol "pxf" does not exist` | Перезапустите `greenplum` и повторите `bookings_stg_ddl`/`make ddl-gp` — расширение `pxf` создаётся автоматически при старте контейнера. |
|
| `protocol "pxf" does not exist` | Перезапустите `greenplum` и повторите `bookings_stg_ddl`/`make ddl-gp` — расширение `pxf` создаётся автоматически при старте контейнера. |
|
||||||
| PXF не отвечает (Connection refused к порту 5888) | Проверьте `pxf cluster status` в контейнере `greenplum` и перезапустите сервис `greenplum`. |
|
| PXF не отвечает (Connection refused к порту 5888) | Проверьте `pxf cluster status` в контейнере `greenplum` и перезапустите сервис `greenplum`. |
|
||||||
| PXF не подхватывает изменения конфигов | Пересоберите образ (`make build`) и перезапустите `greenplum`. Для принудительной перезаписи файлов задайте `PXF_SEED_OVERWRITE=1`. |
|
| PXF не подхватывает изменения конфигов | Пересоберите образ (`make build`) и перезапустите `greenplum`. Для принудительной перезаписи файлов задайте `PXF_SEED_OVERWRITE=1`. |
|
||||||
|
|||||||
+4
-3
@@ -37,14 +37,15 @@
|
|||||||
- Проверить, что все 5 задач Success и логи содержат `Проверка пройдена`.
|
- Проверить, что все 5 задач Success и логи содержат `Проверка пройдена`.
|
||||||
|
|
||||||
- DAG `bookings_to_gp_stage` (полная проверка цепочки bookings → Greenplum STG):
|
- DAG `bookings_to_gp_stage` (полная проверка цепочки bookings → Greenplum STG):
|
||||||
- предварительно выполнить один раз: `make bookings-init` (инициализация демо‑БД bookings) и `make ddl-gp` (создаёт `stg.bookings_ext` и `stg.bookings` в Greenplum);
|
- предварительно выполнить один раз: `make bookings-init` (установка демобазы `demo` в контейнере `bookings-db`) и `make ddl-gp` (создаёт `stg.bookings_ext` и `stg.bookings` в Greenplum);
|
||||||
|
- важно: DAG `bookings_stg_ddl` **не** создаёт базу `demo` в `bookings-db`; если вы делали `docker compose down -v` / `make clean`, `make bookings-init` обязателен;
|
||||||
- включить DAG `bookings_to_gp_stage` и запустить `Trigger DAG`;
|
- включить DAG `bookings_to_gp_stage` и запустить `Trigger DAG`;
|
||||||
- убедиться, что все задачи (`generate_bookings_day`, `load_bookings_to_stg`, `check_row_counts`, `finish_summary`) завершились со статусом Success;
|
- убедиться, что все задачи (`generate_bookings_day`, `load_bookings_to_stg`, `check_row_counts`, `finish_summary`) завершились со статусом Success;
|
||||||
- при желании проверить данные: в `bookings-db` появился новый день, а в Greenplum в `stg.bookings` — строки с актуальным `batch_id` (см. пример запросов в разделе 5).
|
- при желании проверить данные: в `bookings-db` появился новый день, а в Greenplum в `stg.bookings` — строки с актуальным `batch_id` (см. пример запросов в разделе 5).
|
||||||
|
|
||||||
- (опционально, для менторов/разработчиков) Smoke-тест DAG через Airflow CLI без UI:
|
- (опционально, для менторов/разработчиков) Smoke-тест DAG через Airflow CLI без UI:
|
||||||
- `docker compose -f docker-compose.yml exec gp_airflow_webserver airflow dags test bookings_to_gp_stage 2024-01-01` — прогоняет `bookings_to_gp_stage` целиком в «off-line» режиме;
|
- `docker compose -f docker-compose.yml exec airflow-webserver airflow dags test bookings_to_gp_stage 2024-01-01` — прогоняет `bookings_to_gp_stage` целиком в «off-line» режиме;
|
||||||
- `docker compose -f docker-compose.yml exec gp_airflow_webserver airflow dags trigger bookings_to_gp_stage` — создаёт реальный запуск DAG (логи и статус можно смотреть либо через UI, либо командой `airflow tasks list`/`airflow tasks logs` внутри контейнера).
|
- `docker compose -f docker-compose.yml exec airflow-webserver airflow dags trigger bookings_to_gp_stage` — создаёт реальный запуск DAG (логи и статус можно смотреть либо через UI, либо командой `airflow tasks list`/`airflow tasks logs` внутри контейнера).
|
||||||
|
|
||||||
## 5. Проверка данных в Greenplum
|
## 5. Проверка данных в Greenplum
|
||||||
- `make gp-psql` — запустить psql в контейнере от имени `gpadmin`.
|
- `make gp-psql` — запустить psql в контейнере от имени `gpadmin`.
|
||||||
|
|||||||
+8
-3
@@ -10,6 +10,7 @@ x-airflow-common-volumes: &airflow-volumes
|
|||||||
- ./airflow/dags:/opt/airflow/dags
|
- ./airflow/dags:/opt/airflow/dags
|
||||||
- ./sql:/sql:ro
|
- ./sql:/sql:ro
|
||||||
- airflow_data:/opt/airflow/data
|
- airflow_data:/opt/airflow/data
|
||||||
|
- airflow_logs:/opt/airflow/logs
|
||||||
|
|
||||||
x-airflow-common-depends: &airflow-depends
|
x-airflow-common-depends: &airflow-depends
|
||||||
pgmeta:
|
pgmeta:
|
||||||
@@ -86,7 +87,7 @@ services:
|
|||||||
healthcheck:
|
healthcheck:
|
||||||
# Ждём не только доступность GPDB, но и готовность PXF,
|
# Ждём не только доступность GPDB, но и готовность PXF,
|
||||||
# чтобы Airflow не стартовал раньше 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" ]
|
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} && PGPASSWORD=${GP_PASSWORD:-gpadmin} /usr/local/greenplum-db/bin/psql -h 127.0.0.1 -p 5432 -U ${GP_USER:-gpadmin} -d ${GP_DB:-gp_dwh} -t -A -c \"SELECT 1 FROM pg_extension WHERE extname='pxf';\" | grep -q 1 && su - ${GP_USER:-gpadmin} -c '/usr/local/pxf/bin/pxf cluster status' >/dev/null 2>&1" ]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 30
|
retries: 30
|
||||||
@@ -101,13 +102,14 @@ services:
|
|||||||
env_file: .env
|
env_file: .env
|
||||||
environment:
|
environment:
|
||||||
<<: *airflow-env
|
<<: *airflow-env
|
||||||
command: airflow webserver
|
command: bash -lc "rm -f /opt/airflow/airflow-webserver.pid && exec airflow webserver"
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- ./airflow/dags:/opt/airflow/dags
|
- ./airflow/dags:/opt/airflow/dags
|
||||||
- ./sql:/sql:ro
|
- ./sql:/sql:ro
|
||||||
- airflow_data:/opt/airflow/data
|
- airflow_data:/opt/airflow/data
|
||||||
|
- airflow_logs:/opt/airflow/logs
|
||||||
- ./airflow/requirements.txt:/opt/airflow/requirements.txt
|
- ./airflow/requirements.txt:/opt/airflow/requirements.txt
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
||||||
@@ -132,6 +134,7 @@ services:
|
|||||||
- ./airflow/dags:/opt/airflow/dags
|
- ./airflow/dags:/opt/airflow/dags
|
||||||
- ./sql:/sql:ro
|
- ./sql:/sql:ro
|
||||||
- airflow_data:/opt/airflow/data
|
- airflow_data:/opt/airflow/data
|
||||||
|
- airflow_logs:/opt/airflow/logs
|
||||||
- ./airflow/requirements.txt:/opt/airflow/requirements.txt
|
- ./airflow/requirements.txt:/opt/airflow/requirements.txt
|
||||||
depends_on:
|
depends_on:
|
||||||
<<: *airflow-depends
|
<<: *airflow-depends
|
||||||
@@ -150,10 +153,11 @@ services:
|
|||||||
- ./airflow/dags:/opt/airflow/dags
|
- ./airflow/dags:/opt/airflow/dags
|
||||||
- ./sql:/sql:ro
|
- ./sql:/sql:ro
|
||||||
- airflow_data:/opt/airflow/data
|
- airflow_data:/opt/airflow/data
|
||||||
|
- airflow_logs:/opt/airflow/logs
|
||||||
command: >
|
command: >
|
||||||
bash -lc "
|
bash -lc "
|
||||||
set -e;
|
set -e;
|
||||||
mkdir -p /opt/airflow/data && chown -R airflow:root /opt/airflow/data;
|
mkdir -p /opt/airflow/data /opt/airflow/logs && chown -R airflow:root /opt/airflow/data /opt/airflow/logs;
|
||||||
# Дожидаемся готовности БД ретрая миграции
|
# Дожидаемся готовности БД ретрая миграции
|
||||||
for i in {1..30}; do
|
for i in {1..30}; do
|
||||||
su -s /bin/bash airflow -c \"PATH='/home/airflow/.local/bin:$${PATH}' airflow db migrate\" && break || echo 'waiting for pgmeta' && sleep 3;
|
su -s /bin/bash airflow -c \"PATH='/home/airflow/.local/bin:$${PATH}' airflow db migrate\" && break || echo 'waiting for pgmeta' && sleep 3;
|
||||||
@@ -170,3 +174,4 @@ volumes:
|
|||||||
bookings_data:
|
bookings_data:
|
||||||
greenplum_data:
|
greenplum_data:
|
||||||
airflow_data:
|
airflow_data:
|
||||||
|
airflow_logs:
|
||||||
|
|||||||
@@ -101,13 +101,13 @@
|
|||||||
- причина: файлы уже лежат в `PXF_BASE` на томе, а seed из образа по умолчанию не перетирает их;
|
- причина: файлы уже лежат в `PXF_BASE` на томе, а seed из образа по умолчанию не перетирает их;
|
||||||
- решение: `make build` + restart `greenplum` + (при необходимости) `PXF_SEED_OVERWRITE=1`.
|
- решение: `make build` + restart `greenplum` + (при необходимости) `PXF_SEED_OVERWRITE=1`.
|
||||||
|
|
||||||
## 9. Известная проблема: `protocol "pxf" does not exist` на «холодном старте»
|
## 9. Известная проблема: `protocol "pxf" does not exist` на «холодном старте» (исправлено)
|
||||||
|
|
||||||
Иногда (и это воспроизводится в `./scripts/e2e_smoke.sh`) при первом `make ddl-gp` можно получить:
|
Раньше (воспроизводилось в `./scripts/e2e_smoke.sh`) при первом `make ddl-gp` можно было получить:
|
||||||
|
|
||||||
`ERROR: protocol "pxf" does not exist`
|
`ERROR: protocol "pxf" does not exist`
|
||||||
|
|
||||||
### Почему так происходит
|
### Почему так происходило
|
||||||
|
|
||||||
В базовом `/start_gpdb.sh` из образа Greenplum создание расширения `pxf` связано с проверкой
|
В базовом `/start_gpdb.sh` из образа Greenplum создание расширения `pxf` связано с проверкой
|
||||||
файла `${PXF_BASE}/conf/pxf-env.sh`:
|
файла `${PXF_BASE}/conf/pxf-env.sh`:
|
||||||
@@ -116,35 +116,26 @@
|
|||||||
`CREATE EXTENSION IF NOT EXISTS pxf`;
|
`CREATE EXTENSION IF NOT EXISTS pxf`;
|
||||||
- если `pxf-env.sh` **уже существует**, этот блок **пропускается**, и расширение может не появиться.
|
- если `pxf-env.sh` **уже существует**, этот блок **пропускается**, и расширение может не появиться.
|
||||||
|
|
||||||
При этом наш ensure‑скрипт `pxf/init/10_pxf_bookings.sh` копирует `pxf-env.sh` в `${PXF_BASE}`
|
При этом наш ensure‑скрипт `pxf/init/10_pxf_bookings.sh` копировал `pxf-env.sh` в `${PXF_BASE}`
|
||||||
ещё до запуска Greenplum, из‑за чего базовый скрипт считает PXF “уже настроенным” и
|
ещё до запуска Greenplum, из‑за чего базовый скрипт считал PXF “уже настроенным” и
|
||||||
пропускает создание расширения.
|
пропускал создание расширения.
|
||||||
|
|
||||||
Отдельно `/start_greenplum_with_pxf.sh` пытается выполнить `CREATE EXTENSION IF NOT EXISTS pxf`
|
### Что изменили
|
||||||
в фоне, но это может “не попасть” в окно готовности базы (гонка при старте), поэтому после старта:
|
|
||||||
- PXF может быть “running” (`pxf cluster status`), но
|
|
||||||
- `protocol 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`.
|
||||||
|
|
||||||
- `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'';\"'"`
|
### Если ошибка всё ещё возникает
|
||||||
|
|
||||||
Если команда ничего не вернула — расширение не создано.
|
1) Пересоберите образ и перезапустите контейнер `greenplum`:
|
||||||
|
`make build && make down && make up`
|
||||||
|
|
||||||
### Временный workaround (ручной)
|
2) Проверьте наличие 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'';\"'"`
|
||||||
1) Создать расширение:
|
|
||||||
`docker compose exec greenplum bash -lc "su - gpadmin -c '/usr/local/greenplum-db/bin/psql -d gp_dwh -c \"CREATE EXTENSION IF NOT EXISTS pxf;\"'"`
|
|
||||||
|
|
||||||
2) Повторить DDL:
|
|
||||||
`make ddl-gp`
|
|
||||||
|
|
||||||
### Что чинить в коде (идея фикса)
|
|
||||||
|
|
||||||
Сделать создание расширения `pxf` независимым от наличия `pxf-env.sh`:
|
|
||||||
- либо убрать/изменить условие в `/start_gpdb.sh` (в образе),
|
|
||||||
- либо перестать копировать `pxf-env.sh` в ensure‑скрипте и дать базовому скрипту создать его,
|
|
||||||
- либо сделать retry‑логику `CREATE EXTENSION pxf` надёжной (повторять попытки и проверять результат).
|
|
||||||
|
|
||||||
## 8. Связанные файлы
|
## 8. Связанные файлы
|
||||||
|
|
||||||
@@ -153,3 +144,58 @@
|
|||||||
- `pxf/init/10_pxf_bookings.sh` (ensure‑логика)
|
- `pxf/init/10_pxf_bookings.sh` (ensure‑логика)
|
||||||
- `pxf/init/start_greenplum_with_pxf.sh` (старт контейнера)
|
- `pxf/init/start_greenplum_with_pxf.sh` (старт контейнера)
|
||||||
- `README.md` (раздел «Greenplum + PXF: свой образ»)
|
- `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 start`
|
||||||
|
- `ERROR: Could not connect to GPDB`
|
||||||
|
- `FATAL: password authentication failed for user "gpadmin"`
|
||||||
|
|
||||||
|
### Текущее понимание причины (почему это “иногда”)
|
||||||
|
|
||||||
|
1) При старте GPDB образ `woblerr/greenplum` генерирует/дописывает `pg_hba.conf` на persistent volume.
|
||||||
|
2) В `pg_hba.conf` присутствует trust‑правило для **конкретного IP** контейнера в docker‑сети
|
||||||
|
(пример из диагностики: `host all gpadmin 172.21.0.2/32 trust`).
|
||||||
|
3) После `docker compose stop/start` Docker может выдать контейнеру **другой IP** (например, `172.21.0.3`).
|
||||||
|
Тогда trust‑правило больше не подходит, и подключение начинает идти по `md5`.
|
||||||
|
4) `pxf cluster start` подключается к GPDB по TCP на `host=gpdbsne` (hostname контейнера),
|
||||||
|
то есть попадает именно в `pg_hba.conf` (а не в local‑auth).
|
||||||
|
5) В результате при “не совпавшем IP” получаем `md5` + пароль (возможно пустой/не тот) → падение на `28P01`.
|
||||||
|
|
||||||
|
Эта проблема выглядит флапающей, потому что IP после `stop/start` иногда совпадает с захардкоженным trust‑/32,
|
||||||
|
а иногда нет.
|
||||||
|
|
||||||
|
### Как подтвердить при следующем воспроизведении
|
||||||
|
|
||||||
|
1) Посмотреть логи `greenplum`:
|
||||||
|
`docker compose logs --tail=200 greenplum`
|
||||||
|
|
||||||
|
2) Найти реальный IP клиента в master‑логах GPDB (на томе):
|
||||||
|
`Password does not match ...` обычно содержит адрес вида `172.21.0.X`.
|
||||||
|
|
||||||
|
3) Сравнить его с 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.conf` trust на конкретный `172.21.0.2/32` и заменить на более стабильное правило
|
||||||
|
(например, на подсеть docker‑сети или на `samehost`);
|
||||||
|
- или закрепить IP контейнера в compose (static IP), чтобы он не “плавал”;
|
||||||
|
- или отказаться от `stop/start` в пользу сценария, который не меняет сетевое окружение (но это хуже для UX студентов).
|
||||||
|
|
||||||
|
### Что реализовано
|
||||||
|
|
||||||
|
- В `pxf/init/start_greenplum_with_pxf.sh` добавлен шаг, который на каждом старте
|
||||||
|
обеспечивает в `pg_hba.conf` trust‑правило `host all gpadmin samehost trust`
|
||||||
|
(вставка перед `host all all 0.0.0.0/0 md5`), и делает `pg_ctl reload`, если GPDB уже запущен.
|
||||||
|
|||||||
@@ -1,9 +1,105 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Этот скрипт — "обёртка" над стандартным стартом Greenplum (exec /start_gpdb.sh),
|
||||||
|
# которая добавляет устойчивый старт PXF для учебного стенда.
|
||||||
|
#
|
||||||
|
# Задачи скрипта (почему он нужен):
|
||||||
|
# 1) Подготовить PXF_BASE на persistent volume (через ensure-скрипт).
|
||||||
|
# 2) Обеспечить стабильную аутентификацию PXF → GPDB после `docker compose stop/start`
|
||||||
|
# (не зависеть от «плавающего» IP контейнера в docker-сети).
|
||||||
|
# 3) Гарантировать наличие расширения `pxf` в БД GPDB (иначе внешние таблицы падают с
|
||||||
|
# `ERROR: protocol "pxf" does not exist`).
|
||||||
|
#
|
||||||
|
# Важно: это учебный стенд, поэтому мы сознательно выбираем простые и надёжные решения
|
||||||
|
# (например, trust для samehost), а не «боевой» hardened security.
|
||||||
|
|
||||||
ensure_script="/opt/pxf-scripts/ensure_pxf_bookings.sh"
|
ensure_script="/opt/pxf-scripts/ensure_pxf_bookings.sh"
|
||||||
|
|
||||||
|
# PXF CLI использует libpq и при `pxf cluster start` подключается к GPDB как к обычному Postgres.
|
||||||
|
# После `docker compose stop/start` может внезапно потребоваться пароль (см. ensure_pg_hba_trust ниже),
|
||||||
|
# поэтому экспортируем PGPASSWORD заранее: это уменьшает "флап" и делает поведение воспроизводимым.
|
||||||
|
if [ -z "${PGPASSWORD:-}" ]; then
|
||||||
|
export PGPASSWORD="${GREENPLUM_PASSWORD:-gpadmin}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ensure_pg_hba_trust() {
|
||||||
|
# После `docker compose stop/start` Docker может выдать контейнеру другой IP.
|
||||||
|
# У базового образа Greenplum встречается trust-правило на конкретный /32 (старый IP),
|
||||||
|
# и тогда аутентификация по TCP начинает идти через md5 → PXF падает на `28P01`.
|
||||||
|
#
|
||||||
|
# Решение: добавить правило `host all gpadmin samehost trust`, которое срабатывает для
|
||||||
|
# подключений "с этого же контейнера" (PXF запускается рядом с master).
|
||||||
|
# Это максимально простое и стабильное правило для учебного стенда.
|
||||||
|
local gp_user="${GREENPLUM_USER:-gpadmin}"
|
||||||
|
local data_dir="${GREENPLUM_DATA_DIRECTORY:-/data}"
|
||||||
|
local attempts=60
|
||||||
|
local pg_hba=""
|
||||||
|
local trust_line="host all ${gp_user} samehost trust"
|
||||||
|
|
||||||
|
find_pg_hba() {
|
||||||
|
local candidate
|
||||||
|
for candidate in "${data_dir}/master"/*/pg_hba.conf; do
|
||||||
|
if [ -f "${candidate}" ]; then
|
||||||
|
echo "${candidate}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in $(seq 1 "${attempts}"); do
|
||||||
|
pg_hba="$(find_pg_hba || true)"
|
||||||
|
if [ -n "${pg_hba}" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "${pg_hba}" ]; then
|
||||||
|
echo "WARN - pg_hba.conf не найден, пропускаем trust для ${gp_user}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -Eq "^[[:space:]]*host[[:space:]]+all[[:space:]]+${gp_user}[[:space:]]+samehost[[:space:]]+trust" "${pg_hba}"; then
|
||||||
|
echo "INFO - pg_hba.conf уже содержит trust для ${gp_user} samehost"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Вставляем trust-правило перед самым "общим" md5-правилом (0.0.0.0/0),
|
||||||
|
# чтобы samehost гарантированно матчился раньше.
|
||||||
|
awk -v trust_line="${trust_line}" '
|
||||||
|
BEGIN { added = 0 }
|
||||||
|
$0 ~ /^[[:space:]]*host[[:space:]]+all[[:space:]]+all[[:space:]]+0\.0\.0\.0\/0[[:space:]]+md5/ && added == 0 {
|
||||||
|
print trust_line
|
||||||
|
added = 1
|
||||||
|
}
|
||||||
|
{ print }
|
||||||
|
END {
|
||||||
|
if (added == 0) {
|
||||||
|
print trust_line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "${pg_hba}" > "${pg_hba}.tmp" && mv "${pg_hba}.tmp" "${pg_hba}"
|
||||||
|
|
||||||
|
echo "INFO - pg_hba.conf: добавлен trust для ${gp_user} samehost"
|
||||||
|
|
||||||
|
local master_dir="${pg_hba%/pg_hba.conf}"
|
||||||
|
# Если GPDB уже поднялся, достаточно reload, чтобы новое правило применилось без рестарта.
|
||||||
|
if /usr/local/greenplum-db/bin/pg_ctl -D "${master_dir}" status >/dev/null 2>&1; then
|
||||||
|
if ! /usr/local/greenplum-db/bin/pg_ctl -D "${master_dir}" reload >/dev/null 2>&1; then
|
||||||
|
echo "WARN - не удалось перезагрузить pg_hba.conf (pg_ctl reload)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
ensure_pxf_extension() {
|
ensure_pxf_extension() {
|
||||||
|
# В базовом /start_gpdb.sh создание `CREATE EXTENSION pxf` зависит от наличия
|
||||||
|
# `${PXF_BASE}/conf/pxf-env.sh`. В нашем стенде pxf-env.sh может быть уже создан
|
||||||
|
# ensure-скриптом (PXF_BASE на томе), и тогда /start_gpdb.sh пропускает extension.
|
||||||
|
#
|
||||||
|
# Чтобы внешние таблицы через PXF работали после любого рестарта, создаём extension сами,
|
||||||
|
# но только когда GPDB начнёт принимать подключения (с ретраями).
|
||||||
local gp_user="${GREENPLUM_USER:-gpadmin}"
|
local gp_user="${GREENPLUM_USER:-gpadmin}"
|
||||||
local gp_db="${GREENPLUM_DATABASE_NAME:-gp_dwh}"
|
local gp_db="${GREENPLUM_DATABASE_NAME:-gp_dwh}"
|
||||||
local gp_password="${GREENPLUM_PASSWORD:-gpadmin}"
|
local gp_password="${GREENPLUM_PASSWORD:-gpadmin}"
|
||||||
@@ -13,30 +109,53 @@ ensure_pxf_extension() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for _ in $(seq 1 "${attempts}"); do
|
extension_exists() {
|
||||||
|
local result
|
||||||
|
# Подключаемся к localhost: это "локальный" путь и на нём обычно уже есть trust.
|
||||||
|
result=$(PGPASSWORD="${gp_password}" /usr/local/greenplum-db/bin/psql \
|
||||||
|
-h 127.0.0.1 -p 5432 -U "${gp_user}" -d "${gp_db}" \
|
||||||
|
-t -A -c "SELECT 1 FROM pg_extension WHERE extname='pxf';" 2>/dev/null || true)
|
||||||
|
[ "${result}" = "1" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
for attempt in $(seq 1 "${attempts}"); do
|
||||||
|
# Ждём, пока master начнёт принимать подключения.
|
||||||
if /usr/local/greenplum-db/bin/pg_isready \
|
if /usr/local/greenplum-db/bin/pg_isready \
|
||||||
-h 127.0.0.1 -p 5432 -U "${gp_user}" -d "${gp_db}" >/dev/null 2>&1; then
|
-h 127.0.0.1 -p 5432 -U "${gp_user}" -d "${gp_db}" >/dev/null 2>&1; then
|
||||||
|
if extension_exists; then
|
||||||
|
echo "INFO - extension pxf уже создано"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
if PGPASSWORD="${gp_password}" /usr/local/greenplum-db/bin/psql \
|
if PGPASSWORD="${gp_password}" /usr/local/greenplum-db/bin/psql \
|
||||||
-h 127.0.0.1 -p 5432 -U "${gp_user}" -d "${gp_db}" \
|
-h 127.0.0.1 -p 5432 -U "${gp_user}" -d "${gp_db}" \
|
||||||
-v ON_ERROR_STOP=1 -c "CREATE EXTENSION IF NOT EXISTS pxf;" >/dev/null; then
|
-v ON_ERROR_STOP=1 -c "CREATE EXTENSION IF NOT EXISTS pxf;" >/dev/null 2>&1; then
|
||||||
|
if extension_exists; then
|
||||||
echo "INFO - extension pxf готово"
|
echo "INFO - extension pxf готово"
|
||||||
else
|
|
||||||
echo "WARN - не удалось создать extension pxf"
|
|
||||||
fi
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
echo "WARN - попытка ${attempt}/${attempts}: не удалось создать extension pxf"
|
||||||
|
fi
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "WARN - Greenplum не готов, пропускаем CREATE EXTENSION pxf"
|
echo "WARN - Greenplum не готов или extension pxf не создано"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 1) Подготовка PXF_BASE (копирование seed, конфигов и т.д.).
|
||||||
if [ -f "${ensure_script}" ]; then
|
if [ -f "${ensure_script}" ]; then
|
||||||
"${ensure_script}"
|
"${ensure_script}"
|
||||||
else
|
else
|
||||||
echo "WARN - не найден ensure-скрипт PXF: ${ensure_script}"
|
echo "WARN - не найден ensure-скрипт PXF: ${ensure_script}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 2) Дальше запускаем две "подстраховки" параллельно, чтобы не замедлять старт контейнера:
|
||||||
|
# - правка pg_hba.conf (как только он появится на томе);
|
||||||
|
# - создание extension pxf (как только GPDB начнёт отвечать).
|
||||||
|
ensure_pg_hba_trust &
|
||||||
|
|
||||||
ensure_pxf_extension &
|
ensure_pxf_extension &
|
||||||
|
|
||||||
|
# 3) Стартуем GPDB "как обычно". Важно использовать exec, чтобы сигналы Docker
|
||||||
|
# (stop/restart) корректно приходили в основной процесс entrypoint.
|
||||||
exec /start_gpdb.sh
|
exec /start_gpdb.sh
|
||||||
|
|||||||
Reference in New Issue
Block a user