5

I'm trying to create a small size python image with mysqlclient for a flask API, this is the dockerfile:

FROM python:3.7-slim as builder

WORKDIR /build

RUN apt update && apt install -y build-essential default-libmysqlclient-dev git

ARG MYSQLCLIENT_VERSION=v2.0.3
RUN git clone --branch ${MYSQLCLIENT_VERSION} --depth 1 https://github.com/PyMySQL/mysqlclient-python

WORKDIR /build/mysqlclient-python
RUN python /build/mysqlclient-python/setup.py --static bdist_wheel && mv ./dist/*.whl /build

RUN pip install build

WORKDIR /app
COPY . /app

RUN python -m build . --outdir /build

FROM python:3.7-slim

COPY --from=builder /build /build

RUN pip install --find-links=/build app

CMD ["flask", "run"]

This is the error I receive when trying to connect to the db:

  File "/usr/local/lib/python3.7/site-packages/MySQLdb/__init__.py", line 18, in <module>
    from . import _mysql
ImportError: /usr/local/lib/python3.7/site-packages/MySQLdb/_mysql.cpython-37m-x86_64-linux-gnu.so: undefined symbol: TLS_client_method

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/bin/flask", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.7/site-packages/flask/cli.py", line 967, in main
    cli.main(args=sys.argv[1:], prog_name="python -m flask" if as_module else None)
  File "/usr/local/lib/python3.7/site-packages/flask/cli.py", line 586, in main
    return super(FlaskGroup, self).main(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/click/core.py", line 1062, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.7/site-packages/click/core.py", line 1668, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/local/lib/python3.7/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.7/site-packages/click/core.py", line 763, in invoke
    return __callback(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/flask/cli.py", line 426, in decorator
    return __ctx.invoke(f, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/click/core.py", line 763, in invoke
    return __callback(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/app/db.py", line 26, in init_db_command
    init_db()
  File "/usr/local/lib/python3.7/site-packages/app/db.py", line 13, in init_db
    db.create_all()
  File "/usr/local/lib/python3.7/site-packages/flask_sqlalchemy/__init__.py", line 1090, in create_all
    self._execute_for_all_tables(app, bind, 'create_all')
  File "/usr/local/lib/python3.7/site-packages/flask_sqlalchemy/__init__.py", line 1082, in _execute_for_all_tables
    op(bind=self.get_engine(app, bind), **extra)
  File "/usr/local/lib/python3.7/site-packages/flask_sqlalchemy/__init__.py", line 1013, in get_engine
    return connector.get_engine()
  File "/usr/local/lib/python3.7/site-packages/flask_sqlalchemy/__init__.py", line 590, in get_engine
    self._engine = rv = self._sa.create_engine(sa_url, options)
  File "/usr/local/lib/python3.7/site-packages/flask_sqlalchemy/__init__.py", line 1023, in create_engine
    return sqlalchemy.create_engine(sa_url, **engine_opts)
  File "<string>", line 2, in create_engine
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/deprecations.py", line 298, in warned
    return fn(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/create.py", line 548, in create_engine
    dbapi = dialect_cls.dbapi(**dbapi_args)
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/dialects/mysql/mysqldb.py", line 167, in dbapi
    return __import__("MySQLdb")
  File "/usr/local/lib/python3.7/site-packages/MySQLdb/__init__.py", line 24, in <module>
    version_info, _mysql.version_info, _mysql.__file__
NameError: name '_mysql' is not defined

I know that building the wheel with static argument is supposed to deal with not having the default-libmysqlclient-dev installed.

If I build the mysqlclient module with build-essential and default-libmysqlclient-dev in same build stage it works, but I'm trying to remove those from final build as they take a lot of space.

I tryed with python 3.6-slim and this method works but couldn`t make it work for python 3.7 and higher.

What am I doing wrong?

  • Hi Andrei, great question, battled it myself and then decided to use "bloaty image". Have you resolved this? – lexeme Sep 27 '22 at 15:26

1 Answers1

0

Make sure to copy all the stuff installed by default-mysqlclient-dev library, for example, this is my multi-stage Dockefile:

FROM python:3.11-slim as builder

RUN apt-get update && apt-get install -y --no-install-recommends default-mysqlclient-dev

FROM python:3.11-slim

COPY --from=builder /usr/lib/x86_64-linux-gnu/libmysql* /usr/lib/x86_64-linux-gnu
COPY --from=builder /usr/lib/x86_64-linux-gnu/libmaria* /usr/lib/x86_64-linux-gnu
COPY --from=builder /usr/bin/mysql_config /usr/bin

Hope it works!

Anler
  • 1,793
  • 13
  • 21