Как подключиться к базе данных MySQL на локальном хосте из скрипта Python в Docker-контейнере - PullRequest
0 голосов
/ 05 января 2019

У меня база данных mysql работает на локальном хосте (Ubuntu 16.04). На том же хосте у меня есть докер-контейнер, в котором работает скрипт Python. Этот скрипт должен подключиться к mysqldb на локальном хосте. Как было описано в этих постах ( post1 , post2 ), я установил bind-address = 0.0.0.0 для своей локальной базы данных, нашел ip-адрес моего локального хоста и использовал его в мой скрипт на python для подключения к базе данных, но он не работает. Ниже я покажу свою настройку и то, как я запускаю Docker-контейнер. Мой скрипт на python (analysis.py) выглядит следующим образом:

import pandas as pd
import sqlalchemy as db

def find_max_age():
   cnx = db.create_engine('mysql+mysqlconnector://root:password@172.17.0.1:3306/datasets')
   cnx_res = db.create_engine('mysql+mysqlconnector://root:password@172.17.0.1:3306/results')
   df = pd.read_sql("select * from test_table", cnx)
   idx = df['age'].idxmax() == df.index
   df_res = df[idx]

   df_res.to_sql('max_age4', con=cnx_res, index=False)


if __name__ == '__main__':
   find_max_age()

Мой Dockerfile выглядит следующим образом:

FROM python:2.7-slim
EXPOSE 80 3306
WORKDIR /app
COPY requirements.txt /app
RUN pip install -r requirements.txt
COPY analysis.py /app
CMD python analysis.py

Наконец, файл require.txt выглядит как

mysql-connector-python
sqlalchemy
pandas

Я создаю образ докера следующим образом:

docker build -t max_age_app .

Затем я запускаю контейнер, используя это изображение следующим образом:

docker run -d max_age_app:latest

Контейнер выходит с кодом выхода 1, и когда я просматриваю соответствующий журнал контейнера, я нахожу в нем следующую ошибку:

> Traceback (most recent call last):
  File "analysis.py", line 24, in <module>
    find_max_age()
  File "analysis.py", line 11, in find_max_age
    df = pd.read_sql("select * from test_table", cnx)
  File "/usr/local/lib/python2.7/site-packages/pandas/io/sql.py", line 397, in read_sql
    chunksize=chunksize)
  File "/usr/local/lib/python2.7/site-packages/pandas/io/sql.py", line 1063, in read_query
    result = self.execute(*args)
  File "/usr/local/lib/python2.7/site-packages/pandas/io/sql.py", line 954, in execute
    return self.connectable.execute(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 2074, in execute
    connection = self.contextual_connect(close_with_result=True)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 2123, in contextual_connect
    self._wrap_pool_connect(self.pool.connect, None),
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 2162, in _wrap_pool_connect
    e, dialect, self)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1476, in _handle_dbapi_exception_noconnection
    exc_info
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 265, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 2158, in _wrap_pool_connect
    return fn()
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/pool.py", line 400, in connect
    return _ConnectionFairy._checkout(self)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/pool.py", line 788, in _checkout
    fairy = _ConnectionRecord.checkout(pool)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/pool.py", line 529, in checkout
    rec = pool._do_get()
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/pool.py", line 1193, in _do_get
    self._dec_overflow()
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 66, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/pool.py", line 1190, in _do_get
    return self._create_connection()
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/pool.py", line 347, in _create_connection
    return _ConnectionRecord(self)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/pool.py", line 474, in __init__
    self.__connect(first_connect_check=True)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/pool.py", line 671, in __connect
    connection = pool._invoke_creator(self)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/strategies.py", line 106, in connect
    return dialect.connect(*cargs, **cparams)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 412, in connect
    return self.dbapi.connect(*cargs, **cparams)
  File "/usr/local/lib/python2.7/site-packages/mysql/connector/__init__.py", line 172, in connect
    return CMySQLConnection(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/mysql/connector/connection_cext.py", line 78, in __init__
    self.connect(**kwargs)
  File "/usr/local/lib/python2.7/site-packages/mysql/connector/abstracts.py", line 731, in connect
    self._open_connection()
  File "/usr/local/lib/python2.7/site-packages/mysql/connector/connection_cext.py", line 179, in _open_connection
    sqlstate=exc.sqlstate)
sqlalchemy.exc.DatabaseError: (mysql.connector.errors.DatabaseError) 2003 (HY000): Can't connect to MySQL server on '172.17.0.1' (111) (Background on this error at: http://sqlalche.me/e/4xp6)

Чтобы определить ip локального хоста, я использовал команду ifconfig, которая выглядела примерно так:

docker0   Link encap:Ethernet  HWaddr 02:42:a2:a6:d7:ff  
          inet addr:172.17.0.1 

enp0s3    Link encap:Ethernet  HWaddr 08:00:27:bb:7e:b5  
          inet addr:10.0.2.15 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1 

Итак, я попытался 172.17.0.1 для подключения к локальной базе данных из контейнера, но это не сработало.

Должен ли я сопоставлять какие-либо порты между контейнером и локальным узлом с помощью параметра -p при запуске контейнера?

Буду признателен за любую помощь.

Ответы [ 2 ]

0 голосов
/ 05 января 2019

Чтобы решить эту проблему, необходимо правильно настроить базу данных mysql на локальном хосте. В дополнение к тому, что обсуждалось выше, необходимо выполнить следующие шаги:

  • Найдите IP-адрес вашего док-контейнера с помощью приложения python. Вы можно использовать docker inspect <container_name>.
  • Создайте в своей локальной базе данных mysql нового пользователя (и соответствующего пароль) для этого IP-адреса. Информацию о том, как это сделать, вы можете найти в это сообщение . Как установить политику паролей в MySQL, описано здесь .

После этого простого запуска контейнера с помощью команды docker run -d max_age_app будет достаточно для сценария python для записи данных в базу данных на локальном хосте.

0 голосов
/ 05 января 2019

Вы не должны EXPOSE порт 3306 на контейнере, так как сервер MySQL прослушивает вне его, на локальном хосте. Я подозреваю, что это проблема с сетью, поэтому попробуйте проверить, есть ли у localhost интерфейс с адресом 172.17.0.1 и можете ли вы получить этот адрес изнутри вашего контейнера (например, попробуйте docker exec -ti _your_container_name /bin/sh, а затем попробуйте ping 172.17.0.1). Вам также следует проверить логи mysql, чтобы увидеть, есть ли там сообщения об ошибках.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...