Comment résoudre «OSError: libc not found» soulevé sur Gunicorn exec de l'application Flask dans le conteneur Alpine Docker

13

Je travaille sur une application Flask basée sur l'application Microblog du méga-tutoriel de Miguel Grinberg. Le code vit ici: https://github.com/dnilasor/quickgig . J'ai une implémentation de docker qui fonctionne avec un conteneur MySQL 5.7 lié. Aujourd'hui, j'ai ajouté une fonction Admin View en utilisant le module Flask-Admin. Cela fonctionne magnifiquement servi localement (OSX) sur le serveur Flask via 'flask run' mais quand je construis et exécute la nouvelle image docker (basée sur python: 3.8-alpine), elle se bloque au démarrage avec une OSError: libc not founderreur, dont le code semble indiquer une bibliothèque inconnue

Il me semble que Gunicorn n'est pas en mesure de diffuser l'application après mes ajouts. Mon camarade de classe et moi sommes perplexes!

À l'origine, j'ai eu l'erreur en utilisant l'image de base python: 3.6-alpine et j'ai donc essayé avec 3.7 et 3.8 en vain. J'ai également remarqué que j'ajoutais de manière redondante PyMySQL, une fois dans requirements.txt en spécifiant la version no. et encore explicitement dans le dockerfile sans spécification. Suppression de l'entrée requirements.txt. J'ai également essayé d'incrémenter la version Flask-Admin no. haut et bas. J'ai également essayé de nettoyer mes migrations de base de données car j'ai vu plusieurs fichiers de migration provoquant l'échec du démarrage du conteneur (il est vrai que c'était lors de l'utilisation de SQLite). Maintenant, il n'y a qu'un seul fichier de migration et sur la base de la trace de la pile, cela semble très bien flask db upgradefonctionner.

Une chose que je n'ai pas encore essayée est une image de base différente (moins minimale?), Peut essayer bientôt et la mettre à jour. Mais le problème est si mystérieux pour moi que j'ai pensé qu'il était temps de demander si quelqu'un d'autre l'avait vu :)

J'ai trouvé ce bug de socket qui semblait potentiellement pertinent mais il était censé être entièrement corrigé en python 3.8.

Pour info, j'ai suivi certains des conseils ici sur les importations circulaires et importé ma fonction de contrôleur d'administration à l'intérieur 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

Implémentation 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))

requirements.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

Lorsque j'exécute le conteneur dans un terminal interactif, je vois la trace de pile suivante:

(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

J'aimerais que l'application démarre / soit servie par gunicorn à l'intérieur du conteneur afin que je puisse continuer à développer avec mon équipe en utilisant l'implémentation de docker et en tirant parti de MySQL docké contre la douleur de MySQL local pour le développement. Pouvez vous conseiller?

Dnilasor
la source

Réponses:

7

Dans votre Dockerfile:

RUN apk add binutils libc-dev
Clay Hardin
la source
Cela semble fonctionner. Malheureusement, cela augmente considérablement la taille de l'image.
dcart1234
1
Merci! J'ai édité pour inclure simplement binutils et libc-dev, ce qui rend l'image plus petite. Je ne sais pas ce qui a besoin de binutils, mais cela semble être essentiel.
Clay Hardin
3

Oui Gunicorn 20.0.0 nécessite le package libc-dev .

Donc ça marche pour moi:

RUN apk --no-cache add libc-dev
Fabrizio Fubelli
la source
Je voulais que cela fonctionne et je l'ai essayé en premier (je déteste rétrograder / spécifier des versions explicites) mais ce n'est pas le cas: (
Dnilasor
apk add libc-devn'a pas fonctionné pour moi non plus.
Devy
3

C'était un problème avec gunicorn 20.0.0, suivi ici: https://github.com/benoitc/gunicorn/issues/2160

Le problème est résolu dans la version 20.0.1 et les versions ultérieures. Alors changez ceci:

RUN venv/bin/pip install gunicorn pymysql

pour ça:

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

Si la mise à niveau n'est pas une option, comme solution de contournement, vous pouvez ajouter la ligne suivante:

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

Malheureusement, cela ajoute environ 20 Mo au conteneur docker résultant, mais il n'y a pas d'autre solution connue pour le moment.

fromage et céréales
la source
2

Ce problème semble lié à une nouvelle version de Gunicorn 20.0.0. Essayez d'utiliser un précédent 19.9.0

Dmitrii Dmitriev
la source
1
python3 ctypes.util.find_library ('c') ne fonctionne pas correctement en python: alpine
Dmitrii Dmitriev
Oui, python3 -c "from ctypes.util import find_library; print(find_library('c'))"revientNone
Devy
0

J'ai résolu ce problème:

  1. Dockerfile: supprimez cette installation "RUN venv / bin / pip install gunicorn"
  2. requirements.txt: ajoutez cette ligne "gunicorn == 19.7.1"
Bảo Nguyễn Cao
la source
Ouaip. utilisé 19.9.0 mais, yup
Dnilasor