Я пытаюсь прочитать данные из локальной базы данных Oracle (база данных Oracle 11g, версия 11.2.0.4.0 — 64-битная версия).
Я создал свой собственный образ докера:
# Use the base Apache Airflow image
FROM apache/airflow:2.8.3
# Set environment variables for the Oracle Instant Client
ENV ORACLE_HOME=/opt/oracle
ENV LD_LIBRARY_PATH=$ORACLE_HOME/lib
# Switch to the root user temporarily
USER root
# Install required packages
RUN apt-get update && apt-get install -y \
unzip \
libaio1 \
&& rm -rf /var/lib/apt/lists/*
# Create the Oracle directory with proper permissions
RUN mkdir -p $ORACLE_HOME && chown -R airflow: $ORACLE_HOME
# Create the tmp directory with proper permissions
RUN mkdir -p /tmp && chown -R airflow: /tmp
# Switch back to a non-root user (e.g., "airflow")
USER airflow
# Install Python packages required for Oracle client and Airflow Oracle provider
RUN pip install oracledb apache-airflow-providers-oracle pandas sqlalchemy
# Download and install the Oracle Instant Client
# https://www.oracle.com/de/database/technologies/instant-client/linux-x86-64-downloads.html
COPY instantclient-basic-linux.x64-19.22.0.0.0dbru.zip /tmp/
COPY instantclient-sdk-linux.x64-19.22.0.0.0dbru.zip /tmp/
RUN unzip /tmp/instantclient-basic-linux.x64-19.22.0.0.0dbru.zip -d $ORACLE_HOME && \
unzip -o /tmp/instantclient-sdk-linux.x64-19.22.0.0.0dbru.zip -d $ORACLE_HOME
# Delete ZIP Files
RUN rm -rf /tmp/instantclient-basic-linux.x64-19.22.0.0.0dbru.zip /tmp/instantclient-sdk-linux.x64-19.22.0.0.0dbru.zip
# Set environment variables for Oracle Instant Client
ENV PATH=$PATH:$ORACLE_HOME
ENV ORACLE_VERSION=19.22
Вкратце: в стандартный образ добавлены oracledb apache-airflow-providers-oracle pandas sqlalchemy, а также Instantclient-basic-linux.x64-19.22.0.0.0dbru.zip с oracle.com.
Сборка docker compose работает, init docker compose работает, компоновка docker работает без ошибок.
Oracle отображается как тип соединения, и я создал соединение:
Мой тестовый DAG выглядит так:
from datetime import datetime
from airflow import DAG
from airflow.decorators import task
from airflow.providers.oracle.hooks.oracle import OracleHook
table_name = "DB.TABLE"
@task
def get_data_from_oracle():
oracle_hook=OracleHook(oracle_conn_id='Oracle_***')
data = oracle_hook.get_pandas_df(sql=f"SELECT COUNT(1) FROM {table_name}")
return data.to_dict()
with DAG('oracle_test', start_date=datetime(2022, 1, 1), schedule_interval='@once') as dag:
data = get_data_from_oracle()
Если я запущу указанный DAG, я получу ошибки, которые не смогу устранить. Он работает около минуты и завершается с такими ошибками: (я предполагаю, что время ожидания истекло)
[2024-03-21T10:27:31.754+0000] {standard_task_runner.py:107} ОШИБКА — не удалось выполнить задание 8 для задачи get_data_from_oracle (DPY-6005: невозможно подключиться к базе данных (CONNECTION_ID=P26GiMCTIFWWPDhhkB4vZQ==). DPY-4011: база данных или сеть закрыли соединение. [Errno 104] Сброс соединения с помощью узла Помощь: https://python-oracledb.readthedocs.io/en/latest/user_guide/troubleshooting.html#dpy-4011; 534)
Или, в зависимости от конфигурации: (без тайм-аута)
[2024-03-21, 16:57:08 CET] {standard_task_runner.py:107} ОШИБКА — не удалось выполнить задание 16 для задачи get_data_from_oracle (DPY-6005: невозможно подключиться к базе данных (CONNECTION_ID=Ma2uz0YYUUhkdOMBsNNS0w==). DPY-6003: SID «**» не зарегистрирован в прослушивателе на хосте «10...» через порт 1524. (Аналогично ORA-12505); 5827)
Я дважды проверил IP, пинг, SID (через запрос) и так далее.
Я предполагаю, что делаю что-то ужасно неправильное либо
В любом случае интернет-исследования не привели к решению. Если кто-нибудь может дать мне советы или рабочий способ подключения к базе данных Oracle, я был бы благодарен. Пожалуйста, не заставляйте меня возвращаться в SSIS.
Обновление: тот же запрос к БД с Oracle Database 12c Release 12.1.0.1.0 — 64-битная версия работает без проблем. Похоже, проблема в версии/драйверах.
Да, я проверил дважды и трижды. Я могу подключиться к указанному порту через DBeaver (и взаимодействовать с базой данных), а также TNSPING имени и получить порт 1524 в качестве ответа. У меня нет объяснений, почему этот порт был перенесен... может быть, нескольким экземплярам/службам на одном хосте Linux требуются разные порты? Попробую 1521 очень быстро, просто чтобы исключить это.
Интересно: если я изменю порт, ошибка изменится: правый порт: на порту не зарегистрирован SID... неправильный порт: невозможно подключиться к БД. Итак, я предполагаю, что БД каким-то образом реагирует или, по крайней мере, до него доходит воздушный поток.
Согласно python-oracledb.readthedocs.io/en/latest/user_guide/…, одна из возможных причин DPY-4011 заключается в том, что БД применяет собственное сетевое шифрование (NNE), которое не поддерживается в тонком режиме. Не могли бы вы запустить запрос SELECT network_service_banner FROM v$session_connect_info;
в своей базе данных Oracle, чтобы проверить, включен ли NNE?
Кроме того, пробовали ли вы подключиться к Oracle из автономного сценария Python, работающего локально (как описано в python-oracledb.readthedocs.io/en/latest/user_guide/… )? Теоретически может возникнуть проблема с версией, поскольку версия сервера 11.2.0.4 действительно старая, хотя в документации Oracle предлагается подключиться к 11.2.0.4 с клиентом 19c, это должно работать, см. stackoverflow.com/a/64908713/610979 )
Я не уверен, как связать эту таблицу с «моей» попыткой подключения: > ВЫБЕРИТЕ ОТЛИЧНЫЙ OSUSER FROM v$session_connect_info Адаптер протокола TCP/IP NT для Linux: версия 11.2.0.4.0 — производственная Oracle Advanced Security: служба криптографического контрольного суммирования для Linux: версия 11.2.0.4.0 — производственная версия Oracle Advanced Security: служба шифрования для Linux: версия 11.2.0.4.0 — рабочая версия (обратите внимание на различия)
База данных Oracle 12c, выпуск 12.1.0.1.0 — 64-битная версия <- Кажется, эта версия работает?! Так это похоже на проблему с версией БД?! Буду тестировать дальше.
Я наконец понял это: соединение с правильным параметром (я допустил ошибку, потому что копипаст из tnsping, похоже, по умолчанию дает 2 хоста) дает вам эту ошибку:
DPY-3010: подключения к этой версии сервера базы данных не поддерживаются python-oracledb в тонком режиме.
Оракул утверждает:
Например, Oracle Call Interface 21 может подключаться к базе данных Oracle 12.1 или более поздней версии, а Oracle Call Interface 19.3 — к базе данных Oracle 11.2 или более поздней версии. Некоторые инструменты могут иметь другие ограничения.
Источник: https://www.oracle.com/de/database/technologies/instant-client/linux-x86-64-downloads.html
Проблема с переходом на более раннюю версию заключается в том, что вы можете столкнуться с проблемами совместимости с более новыми версиями oracle или airflow. Таким образом, обходной путь заключается в использовании «толстого режима», который поддерживает более старые версии oracle.
С помощью Ошибка DPY-3010 при подключении python-oracledb к Oracle DB 11.2 вы попадаете на https://airflow.apache.org/docs/apache-airflow-providers-oracle/stable/connections/oracle. html, в котором объясняется, как получить доступ к базе данных Oracle через «толстый режим» в DAG:
def get_data_from_oracle():
oracle_hook=OracleHook(oracle_conn_id='Connection_Name', thick_mode=True)
data = oracle_hook.get_pandas_df(sql=f"SELECT COUNT(1) FROM {table_name}")
return data.to_dict()
Далее вам необходимо убедиться, что вы правильно настроили мгновенный клиент Oracle. Zip-архив oracle (instantclient-basic-linux.x64-19.22.0.0.0dbru.zip) содержит подпапку с названием версии. Если вы скопируете его содержимое в $ORACLE_HOME, airflow/python/oracle не сможет найти файлы в ожидаемой папке.
DPI-1047: Невозможно найти 64-разрядную клиентскую библиотеку Oracle: «/opt/oracle/lib/libclntsh.so: невозможно открыть общий объектный файл: нет такого файла или каталога».
Я навсегда исправил это с помощью unzip -j (сглаживание папок в ZIP) в моем файле docker:
# Use the base Apache Airflow image
FROM apache/airflow:2.8.3
# Set environment variables for the Oracle Instant Client
ENV ORACLE_HOME=/opt/oracle
ENV LD_LIBRARY_PATH=$ORACLE_HOME
# Switch to the root user temporarily
USER root
# Install required packages
RUN apt-get update && apt-get install -y \
unzip \
libaio1 \
&& rm -rf /var/lib/apt/lists/*
# Create the Oracle directory with proper permissions
RUN mkdir -p $ORACLE_HOME && chown -R airflow: $ORACLE_HOME
# Create the tmp directory with proper permissions
RUN mkdir -p /tmp && chown -R airflow: /tmp
# Switch back to a non-root user (e.g., "airflow")
USER airflow
# Install Python packages required for Oracle client and Airflow Oracle provider
RUN pip install cx_Oracle oracledb apache-airflow-providers-oracle pandas sqlalchemy
# Download and install the Oracle Instant Client
# https://www.oracle.com/de/database/technologies/instant-client/linux-x86-64-downloads.html
COPY instantclient-basic-linux.x64-19.22.0.0.0dbru.zip /tmp/
RUN unzip -j /tmp/instantclient-basic-linux.x64-19.22.0.0.0dbru.zip -d $ORACLE_HOME
# Delete ZIP Files
RUN rm -rf /tmp/instantclient-basic-linux.x64-19.22.0.0.0dbru.zip
# Set environment variables for Oracle Instant Client
ENV PATH=$PATH:$ORACLE_HOME
ENV ORACLE_VERSION=19.22
При этом соединения со «старыми» (до 12.1) системами работают до тех пор, пока вы включаете толстый режим.
Следующие шаги:
P.s. спасибо https://stackoverflow.com/users/610979/frank-schmitt за комментарии!
Некоторые дополнительные комментарии: (i) не устанавливайте ORACLE_HOME для Instant Client, поскольку это может привести к конфликтам. (ii) используйте ldconfig
вместо LD_LIBRARY_PATH, поскольку последний имеет некоторые ограничения (например, сброс в некоторых средах). Несколько советов см. в разделе Docker для приложений баз данных Oracle на Node.js и Python.
Судя по сообщению об ошибке, вы пытаетесь подключиться к Oracle через порт 1524. Вы на 100% уверены, что это правильно? Обычно Oracle работает на порту 1521.