Cómo abordar 'OSError: libc no encontrado' surgido en el exeje Gunicorn de la aplicación Flask dentro del contenedor acoplable Alpine

13

Estoy trabajando en una aplicación Flask basada en la aplicación Microblog del mega tutorial de Miguel Grinberg. El código vive aquí: https://github.com/dnilasor/quickgig . Tengo una implementación de Docker que funciona con un contenedor MySQL 5.7 vinculado. Hoy agregué una función de Vista de administrador usando el módulo Flask-Admin. Funciona maravillosamente servido localmente (OSX) en el servidor Flask a través de 'flask run', pero cuando construyo y ejecuto la nueva imagen del acoplador (basada en python: 3.8-alpine), se bloquea en el arranque con un OSError: libc not founderror, cuyo código parece indicar una biblioteca desconocida

Me parece que Gunicorn no puede servir la aplicación después de mis adiciones. ¡Mi compañero de clase y yo estamos perplejos!

Originalmente recibí el error usando la imagen base python: 3.6-alpine y lo intenté con 3.7 y 3.8 en vano. También noté que estaba agregando redundantemente PyMySQL, una vez en require.txt especificando la versión no. y nuevamente explícitamente en el dockerfile sin especificación. Se eliminó la entrada require.txt. También intenté incrementar la versión Flask-Admin no. arriba y abajo. También intenté limpiar las migraciones de mi base de datos, ya que he visto varios archivos de migración que hacen que el contenedor no se inicie (es cierto que esto fue cuando usé SQLite). Ahora solo hay un único archivo de migración y, según el seguimiento de la pila, parece que flask db upgradefunciona bien.

Una cosa que aún tengo que probar es una imagen base diferente (¿menos mínima?), Puede probar pronto y actualizar esto. Pero el problema es tan misterioso para mí que pensé que era hora de preguntar si alguien más lo había visto :)

Encontré este error de socket que parecía potencialmente relevante, pero se suponía que estaba completamente solucionado en Python 3.8.

También para su información, seguí algunos de los consejos aquí sobre importaciones circulares e importé mi función de controlador de administrador en el interior create_app.

Dockerfile:

FROM python:3.8-alpine

RUN adduser -D quickgig

WORKDIR /home/quickgig

COPY requirements.txt requirements.txt
RUN python -m venv venv
RUN venv/bin/pip install -r requirements.txt
RUN venv/bin/pip install gunicorn pymysql

COPY app app
COPY migrations migrations
COPY quickgig.py config.py boot.sh ./
RUN chmod +x boot.sh

ENV FLASK_APP quickgig.py

RUN chown -R quickgig:quickgig ./
USER quickgig

EXPOSE 5000
ENTRYPOINT ["./boot.sh"]

boot.sh:

#!/bin/sh
source venv/bin/activate
while true; do
    flask db upgrade
    if [[ "$?" == "0" ]]; then
        break
    fi
    echo Upgrade command failed, retrying in 5 secs...
    sleep 5
done
# flask translate compile
exec gunicorn -b :5000 --access-logfile - --error-logfile - quickgig:app

Implementación en init .py:

from flask_admin import Admin
app_admin = Admin(name='Dashboard')

def create_app(config_class=Config):
  app = Flask(__name__)
  app.config.from_object(config_class)
...
  app_admin.init_app(app)

...
  from app.admin import add_admin_views
  add_admin_views()
...
  return app

from app import models

admin.py:

from flask_admin.contrib.sqla import ModelView
from app.models import User, Gig, Neighborhood
from app import db
# Add views to app_admin

def add_admin_views():
    from . import app_admin
    app_admin.add_view(ModelView(User, db.session))
    app_admin.add_view(ModelView(Neighborhood, db.session))
    app_admin.add_view(ModelView(Gig, db.session))

requerimientos.txt:

alembic==0.9.6
Babel==2.5.1
blinker==1.4
certifi==2017.7.27.1
chardet==3.0.4
click==6.7
dominate==2.3.1
elasticsearch==6.1.1
Flask==1.0.2
Flask-Admin==1.5.4
Flask-Babel==0.11.2
Flask-Bootstrap==3.3.7.1
Flask-Login==0.4.0
Flask-Mail==0.9.1
Flask-Migrate==2.1.1
Flask-Moment==0.5.2
Flask-SQLAlchemy==2.3.2
Flask-WTF==0.14.2
guess-language-spirit==0.5.3
idna==2.6
itsdangerous==0.24
Jinja2==2.10
Mako==1.0.7
MarkupSafe==1.0
PyJWT==1.5.3
python-dateutil==2.6.1
python-dotenv==0.7.1
python-editor==1.0.3
pytz==2017.2
requests==2.18.4
six==1.11.0
SQLAlchemy==1.1.14
urllib3==1.22
visitor==0.1.3
Werkzeug==0.14.1
WTForms==2.1

Cuando ejecuto el contenedor en la terminal interactiva, veo el siguiente seguimiento de pila:

(venv) ****s-MacBook-Pro:quickgig ****$ docker run -ti quickgig:v7
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 1f5feeca29ac, test
Traceback (most recent call last):
  File "/home/quickgig/venv/bin/gunicorn", line 6, in <module>
    from gunicorn.app.wsgiapp import run
  File "/home/quickgig/venv/lib/python3.8/site-packages/gunicorn/app/wsgiapp.py", line 9, in <module>
    from gunicorn.app.base import Application
  File "/home/quickgig/venv/lib/python3.8/site-packages/gunicorn/app/base.py", line 12, in <module>
    from gunicorn.arbiter import Arbiter
  File "/home/quickgig/venv/lib/python3.8/site-packages/gunicorn/arbiter.py", line 16, in <module>
    from gunicorn import sock, systemd, util
  File "/home/quickgig/venv/lib/python3.8/site-packages/gunicorn/sock.py", line 14, in <module>
    from gunicorn.socketfromfd import fromfd
  File "/home/quickgig/venv/lib/python3.8/site-packages/gunicorn/socketfromfd.py", line 26, in <module>
    raise OSError('libc not found')
OSError: libc not found

Me gustaría que la aplicación se inicie / sea servida por gunicorn dentro del contenedor para poder continuar desarrollando con mi equipo utilizando la implementación de Docker y aprovechando MySQL dockerizado frente al dolor de MySQL local para el desarrollo. Me puede aconsejar

Dnilasor
fuente

Respuestas:

7

En tu Dockerfile:

RUN apk add binutils libc-dev
Clay Hardin
fuente
Esto parece funcionar. Desafortunadamente, aumenta dramáticamente el tamaño de la imagen.
dcart1234
1
¡Gracias! Edité para incluir binutils y libc-dev, haciendo que la imagen sea más pequeña. No sé qué necesita binutils, pero parece ser fundamental.
Clay Hardin
3

Sí, Gunicorn 20.0.0 requiere el paquete libc-dev .

Entonces esto funciona para mí:

RUN apk --no-cache add libc-dev
Fabrizio Fubelli
fuente
Quería que esto funcionara y lo intenté primero (odio degradar / especificar versiones explícitas) pero no lo hizo: (
Dnilasor
apk add libc-devtampoco funcionó para mí.
Devy
3

Este fue un problema con gunicorn 20.0.0, rastreado aquí: https://github.com/benoitc/gunicorn/issues/2160

El problema se soluciona en 20.0.1 y en adelante. Entonces, cambia esto:

RUN venv/bin/pip install gunicorn pymysql

a esto:

RUN venv/bin/pip install 'gunicorn>=20.0.1,<21' pymysql

Si la actualización no es una opción, como solución alternativa puede agregar la siguiente línea:

RUN apk --no-cache add binutils musl-dev

Desafortunadamente, esto agrega aproximadamente 20 MB al contenedor de acopladores resultante, pero no hay ninguna otra solución conocida en este momento.

cheeseandcereal
fuente
2

Este problema parece estar relacionado con una nueva versión de Gunicorn 20.0.0. Intenta usar uno anterior 19.9.0

Dmitrii Dmitriev
fuente
1
python3 ctypes.util.find_library ('c') no funciona correctamente en python: alpine
Dmitrii Dmitriev
Sí, python3 -c "from ctypes.util import find_library; print(find_library('c'))"regresaNone
Devy
0

He resuelto este problema:

  1. Dockerfile: elimine esta instalación "EJECUTAR venv / bin / pip install gunicorn"
  2. require.txt: agrega esta línea "gunicorn == 19.7.1"
Bảo Nguyễn Cao
fuente
Sip. utilizado 19.9.0 pero, sí
Dnilasor