2

I'm newbie to Docker. I've coded the dockerfile below to build my Flask app:

FROM debian

WORKDIR /code

RUN apt update
RUN apt-get update

RUN apt-get install --yes git python3

RUN apt install --yes python3-pip

COPY requirements.txt requirements.txt

RUN pip3 install -r requirements.txt

RUN apt-get install --yes libcairo2 libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 libffi-dev

COPY app .

RUN python3 /code/config_database.py dev

EXPOSE 5000

ENTRYPOINT ["python3", "/code/app.py", "dev"]

The line before EXPOSE command is where I try connecting to MySQL database in another container. The MySQL image is built using the YAML file below:

version: "3.7"
services:
  bd:
    image: "mysql"
    command: --default-authentication-plugin=mysql_native_password   
    environment:
      MYSQL_DATABASE: covid3
      MYSQL_ROOT_PASSWORD: XXX
      MYSQL_USER: root
      MYSQL_PASSWORD: XXX
    ports:
      - "3306:3306"
    container_name: bd_mysql
  web:
    build: .
    ports:
      - "5000:5000"
    depends_on:
      - bd
    container_name: app_flask

The connection url has these values:

DATABASE_URL = 'mysql+pymysql://root:XXX@bd:3306/covid3'

Note bd is the MySQL machine I'm using. I've read somewhere else I should use service name as the machine database address in Docker. I'm using SQLAlchemy. This is the code to get a connection to the database:

engine = create_engine(DATABASE_URL, echo=False)
Session = sessionmaker(bind=engine)

When I run docker compose with this command:

docker-compose up --build

The following error appears:

Step 12/14 : RUN python3 /code/config_database.py dev
 ---> Running in bfb4fd5f831a
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/pymysql/connections.py", line 583, in connect
    **kwargs)
  File "/usr/lib/python3.7/socket.py", line 707, in create_connection
    for res in getaddrinfo(host, port, 0, SOCK_STREAM):
  File "/usr/lib/python3.7/socket.py", line 748, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -2] Name or service not known

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/engine/base.py", line 2285, in _wrap_pool_connect
    return fn()
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 363, in connect
    return _ConnectionFairy._checkout(self)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 773, in _checkout
    fairy = _ConnectionRecord.checkout(pool)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 492, in checkout
    rec = pool._do_get()
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/impl.py", line 139, in _do_get
    self._dec_overflow()
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/util/langhelpers.py", line 69, in __exit__
    exc_value, with_traceback=exc_tb,
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/util/compat.py", line 178, in raise_
    raise exception
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/impl.py", line 136, in _do_get
    return self._create_connection()
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 308, in _create_connection
    return _ConnectionRecord(self)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 437, in __init__
    self.__connect(first_connect_check=True)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 657, in __connect
    pool.logger.debug("Error on connect(): %s", e)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/util/langhelpers.py", line 69, in __exit__
    exc_value, with_traceback=exc_tb,
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/util/compat.py", line 178, in raise_
    raise exception
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 652, in __connect
    connection = pool._invoke_creator(self)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/engine/strategies.py", line 114, in connect
    return dialect.connect(*cargs, **cparams)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/engine/default.py", line 490, in connect
    return self.dbapi.connect(*cargs, **cparams)
  File "/usr/local/lib/python3.7/dist-packages/pymysql/__init__.py", line 94, in Connect
    return Connection(*args, **kwargs)
  File "/usr/local/lib/python3.7/dist-packages/pymysql/connections.py", line 325, in __init__
    self.connect()
  File "/usr/local/lib/python3.7/dist-packages/pymysql/connections.py", line 630, in connect
    raise exc
pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'bd' ([Errno -2] Name or service not known)")

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/code/config_database.py", line 8, in <module>
    Base.metadata.create_all(bind=db.engine)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/sql/schema.py", line 4321, in create_all
    ddl.SchemaGenerator, self, checkfirst=checkfirst, tables=tables
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/engine/base.py", line 2057, in _run_visitor
    with self._optional_conn_ctx_manager(connection) as conn:
  File "/usr/lib/python3.7/contextlib.py", line 112, in __enter__
    return next(self.gen)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/engine/base.py", line 2049, in _optional_conn_ctx_manager
    with self._contextual_connect() as conn:
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/engine/base.py", line 2251, in _contextual_connect
    self._wrap_pool_connect(self.pool.connect, None),
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/engine/base.py", line 2289, in _wrap_pool_connect
    e, dialect, self
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/engine/base.py", line 1555, in _handle_dbapi_exception_noconnection
    sqlalchemy_exception, with_traceback=exc_info[2], from_=e
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/util/compat.py", line 178, in raise_
    raise exception
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/engine/base.py", line 2285, in _wrap_pool_connect
    return fn()
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 363, in connect
    return _ConnectionFairy._checkout(self)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 773, in _checkout
    fairy = _ConnectionRecord.checkout(pool)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 492, in checkout
    rec = pool._do_get()
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/impl.py", line 139, in _do_get
    self._dec_overflow()
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/util/langhelpers.py", line 69, in __exit__
    exc_value, with_traceback=exc_tb,
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/util/compat.py", line 178, in raise_
    raise exception
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/impl.py", line 136, in _do_get
    return self._create_connection()
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 308, in _create_connection
    return _ConnectionRecord(self)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 437, in __init__
    self.__connect(first_connect_check=True)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 657, in __connect
    pool.logger.debug("Error on connect(): %s", e)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/util/langhelpers.py", line 69, in __exit__
    exc_value, with_traceback=exc_tb,
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/util/compat.py", line 178, in raise_
    raise exception
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/pool/base.py", line 652, in __connect
    connection = pool._invoke_creator(self)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/engine/strategies.py", line 114, in connect
    return dialect.connect(*cargs, **cparams)
  File "/usr/local/lib/python3.7/dist-packages/sqlalchemy/engine/default.py", line 490, in connect
    return self.dbapi.connect(*cargs, **cparams)
  File "/usr/local/lib/python3.7/dist-packages/pymysql/__init__.py", line 94, in Connect
    return Connection(*args, **kwargs)
  File "/usr/local/lib/python3.7/dist-packages/pymysql/connections.py", line 325, in __init__
    self.connect()
  File "/usr/local/lib/python3.7/dist-packages/pymysql/connections.py", line 630, in connect
    raise exc
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2003, "Can't connect to MySQL server on 'bd' ([Errno -2] Name or service not known)")
(Background on this error at: http://sqlalche.me/e/e3q8)
ERROR: Service 'web' failed to build: The command '/bin/sh -c python3 /code/config_database.py dev' returned a non-zero code: 1

Do you have any hint of what's going wrong?

Carlos Bazilio
  • 830
  • 9
  • 20
  • 1
    Sharing the python snippt that connects to the DB might help. – Neo Anderson Aug 14 '20 at 21:38
  • @NeoAnderson, I've edit my question. I'm using SQLAlchemy. – Carlos Bazilio Aug 14 '20 at 23:06
  • 1
    @Ken White, I've edited as you asked. I've searched a lot, but none of the solutions presented worked for me. That's why the "Yet Another" expression. But I understood and agreed with your point. – Carlos Bazilio Aug 15 '20 at 00:51
  • 1
    One problem I spotted is that `config_database.py` is being executed in the Dockerfile of you web-app. I assume that script is trying to connect to the DB and eventually initialize it. If you will make the distinction between `build-time` and `run-time`, I am sure you will be able to find the answer yourself: The steps that you define in the Dockerfile, except `ENTRYPOINT`/`CMD`, are executed at `build-time`. When you execute the `docker-compose up --build`, first comes the `docker build` of the images and then the `compose up`. Conclusion is that the DB is not up during build-time. – Neo Anderson Aug 15 '20 at 05:50
  • Thanks a lot @Neo Anderson! I'll check with this distinction in mind. – Carlos Bazilio Aug 15 '20 at 15:21

1 Answers1

0

The problem seems to be related to the order of the events, in the sense that some steps are happening at build-time instead of docker run-time:

The content of config_database.py is not shared in the post, but I assume that script is trying to connect to the DB, given the error message.
RUN python3 /code/config_database.py dev will try to reach the DB container before it is up.

A common good practice is to have the DB initialized in the mysql container itself, rather than from an external script. Here is a good post the explains how to do it.

Neo Anderson
  • 5,957
  • 2
  • 12
  • 29
  • 1
    I finally solved this problem. In fact I was mixing build-time and run-time stuff. The command **python3 /code/config_database.py dev** must be run at run-time. For doing that, since I also have to call **ENTRYPOINT ["python3", "/code/app.py", "dev"]**, I've created a script sh file combining those calls. Then I've just call this script from my entrypoint statement. Insert this suggestion in your answer and then I'll accept it! ;) – Carlos Bazilio Aug 17 '20 at 13:36