Como resolver 'OSError: libc not found' gerado no exec Gunicorn do aplicativo Flask dentro do contêiner Alpine docker

13

Estou trabalhando em um aplicativo Flask baseado no aplicativo Microblog do mega-tutorial de Miguel Grinberg. O código mora aqui: https://github.com/dnilasor/quickgig . Eu tenho uma implementação de docker de trabalho com um contêiner MySQL 5.7 vinculado. Hoje eu adicionei uma função Admin View usando o módulo Flask-Admin. Ele funciona lindamente servido localmente (OSX) no servidor Flask via 'flask run', mas quando eu construo e executo a nova imagem do docker (baseada em python: 3.8-alpine), ela trava na inicialização com um OSError: libc not founderro, cujo código parece indica uma biblioteca desconhecida

Parece-me que o Gunicorn não pode servir o aplicativo após minhas adições. Meu colega e eu estamos perplexos!

Originalmente, recebi o erro usando a imagem base python: 3.6-alpine e tentei com 3.7 e 3.8 sem sucesso. Também notei que estava adicionando redundantemente o PyMySQL, uma vez no requirements.txt, especificando a versão no. e novamente explicitamente no arquivo docker sem especificação. Removida a entrada requirements.txt. Também tentei incrementar a versão do Flask-Admin no. para cima e para baixo. Também tentei limpar minhas migrações de banco de dados, pois vi vários arquivos de migração causando falha na inicialização do contêiner (é certo que isso acontecia ao usar SQLite). Agora, existe apenas um único arquivo de migração e, com base no rastreamento da pilha, parece que flask db upgradefunciona bem.

Uma coisa que ainda tenho que tentar é uma imagem base diferente (menos mínima?), Pode tentar em breve e atualizar isso. Mas a questão é tão misteriosa para mim que achei que era hora de perguntar se mais alguém a viu:)

Eu encontrei esse bug de soquete que parecia potencialmente relevante, mas deveria ser totalmente corrigido no python 3.8.

Também para sua informação, segui alguns conselhos aqui sobre importações circulares e importei minha função de controlador administrativo para dentro 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

Implementação em 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

Quando executo o contêiner no terminal interativo, vejo o seguinte rastreamento de pilha:

(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

Eu gostaria que o aplicativo inicializasse / fosse atendido pelo gunicorn dentro do contêiner, para que eu pudesse continuar desenvolvendo com minha equipe usando a implementação do docker e aproveitando o MySQL dockerized versus a dor do MySQL local para desenvolvimento. Você pode aconselhar?

Dnilasor
fonte

Respostas:

7

No seu Dockerfile:

RUN apk add binutils libc-dev
Clay Hardin
fonte
Isso parece funcionar. Infelizmente, aumenta drasticamente o tamanho da imagem.
dcart1234
11
Obrigado! Editei para incluir apenas binutils e libc-dev, tornando a imagem menor. Não sei o que precisa de binutils, mas parece ser crucial.
Clay Hardin
3

Sim O Gunicorn 20.0.0 requer o pacote libc-dev .

Então, isso funciona para mim:

RUN apk --no-cache add libc-dev
Fabrizio Fubelli
fonte
Eu queria que este trabalho e tentou fazê-lo primeiro (ódio desclassificação / especificando versões explícitas), mas isso não aconteceu: (
Dnilasor
apk add libc-devtambém não funcionou para mim.
Devy #
3

Esse foi um problema do gunicorn 20.0.0, rastreado aqui: https://github.com/benoitc/gunicorn/issues/2160

O problema foi corrigido em 20.0.1 e em diante. Então, mude isso:

RUN venv/bin/pip install gunicorn pymysql

para isso:

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

Se a atualização não for uma opção, como alternativa, você pode adicionar a seguinte linha:

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

Infelizmente, isso adiciona cerca de 20 MB ao contêiner do docker resultante, mas não há nenhuma outra solução conhecida no momento.

cheeseandcereal
fonte
2

Esse problema parece relacionado a uma nova versão do Gunicorn 20.0.0. Tente usar um anterior 19.9.0

Dmitrii Dmitriev
fonte
11
python3 ctypes.util.find_library ('c') não funciona corretamente no python: alpine
Dmitrii Dmitriev
Sim, python3 -c "from ctypes.util import find_library; print(find_library('c'))"retornaNone
Devy
0

Eu resolvi este problema:

  1. Dockerfile: remova esta instalação "RUN venv / bin / pip install gunicorn"
  2. Requisito.txt: adicione esta linha "gunicorn == 19.7.1"
Bảo Nguyễn Cao
fonte
Sim. Você pode usar o seguinte comando: 19.9.0 mas, yup
Dnilasor /