CLI Flask выдает "OSError: [Errno 8] Exec format error" при запуске через docker-compose
Я запускаю приложение Flask с пользовательским скриптом. Или все равно пытаюсь.
Я на Windows 10 и приложение должно работать в контейнере Docker Linux с командой:
docker-compose up api
Docker-compose - это version 1.23.2
. В dockerfile служба api
запускается с помощью команды:
command: python manage.py run --host "0.0.0.0" --with-threads
Когда он пытается запустить, я вижу исключение
OSError: [Errno 8] Exec format error: '/api/manage.py'
Сначала я думал, что это будут страшные окончания строки Windows, придите за мной еще раз, но запуск dos2unix
на всех моих исходных файлах не решил проблему.
Как я могу избежать этой ошибки?
manage.py
import click
from flask.cli import FlaskGroup
from my_app_api import create_app
def create_my_app(info):
return create_app()
@click.group(cls=FlaskGroup, create_app=create_my_app)
def cli():
pass
if __name__ == "__main__":
cli()
Полный возврат
api_1 | Traceback (most recent call last):
api_1 | File "manage.py", line 22, in <module>
api_1 | cli()
api_1 | File "/usr/local/lib/python3.6/site-packages/click/core.py", line 764, in __call__
api_1 | return self.main(*args, **kwargs)
api_1 | File "/usr/local/lib/python3.6/site-packages/flask/cli.py", line 380, in main
api_1 | return AppGroup.main(self, *args, **kwargs)
api_1 | File "/usr/local/lib/python3.6/site-packages/click/core.py", line 717, in main
api_1 | rv = self.invoke(ctx)
api_1 | File "/usr/local/lib/python3.6/site-packages/click/core.py", line 1137, in invoke
api_1 | return _process_result(sub_ctx.command.invoke(sub_ctx))
api_1 | File "/usr/local/lib/python3.6/site-packages/click/core.py", line 956, in invoke
api_1 | return ctx.invoke(self.callback, **ctx.params)
api_1 | File "/usr/local/lib/python3.6/site-packages/click/core.py", line 555, in invoke
api_1 | return callback(*args, **kwargs)
api_1 | File "/usr/local/lib/python3.6/site-packages/click/decorators.py", line 64, in new_func
api_1 | return ctx.invoke(f, obj, *args, **kwargs)
api_1 | File "/usr/local/lib/python3.6/site-packages/click/core.py", line 555, in invoke
api_1 | return callback(*args, **kwargs)
api_1 | File "/usr/local/lib/python3.6/site-packages/flask/cli.py", line 438, in run_command
api_1 | use_debugger=debugger, threaded=with_threads)
api_1 | File "/usr/local/lib/python3.6/site-packages/werkzeug/serving.py", line 988, in run_simple
api_1 | run_with_reloader(inner, extra_files, reloader_interval, reloader_type)
api_1 | File "/usr/local/lib/python3.6/site-packages/werkzeug/_reloader.py", line 332, in run_with_reloader
api_1 | sys.exit(reloader.restart_with_reloader())
api_1 | File "/usr/local/lib/python3.6/site-packages/werkzeug/_reloader.py", line 176, in restart_with_reloader
api_1 | exit_code = subprocess.call(args, env=new_environ, close_fds=False)
api_1 | File "/usr/local/lib/python3.6/subprocess.py", line 287, in call
api_1 | with Popen(*popenargs, **kwargs) as p:
api_1 | File "/usr/local/lib/python3.6/subprocess.py", line 729, in __init__
api_1 | restore_signals, start_new_session)
api_1 | File "/usr/local/lib/python3.6/subprocess.py", line 1364, in _execute_child
api_1 | raise child_exception_type(errno_num, err_msg, err_filename)
api_1 | OSError: [Errno 8] Exec format error: '/api/manage.py'
Ответы
Ответ 1
Похоже, у вашего api/manage.py нет шебанга ([Wikipedia]: Shebang (Unix)), поэтому стандартный (текущий) командный процессор (оболочка - обычно bash) пытается его запустить, что (очевидно) выходит из строя.
Чтобы исправить проблему, добавьте шебанг (в начале файла убедитесь, что ваш редактор добавляет конец строки стиля Nix (\n, 0x0A, LF)):
-
Установка Python по умолчанию:
#!/usr/bin/env python
-
Выборочная установка Python:
#!/full/path/to/your/custom/python/executable
Обратите внимание, что вам также необходимы права exec для файла (chmod +x api/manage.py
).
Пример:
[[email protected]:/cygdrive/e/Work/Dev/StackOverflow/q055271912]> ~/sopr.sh
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***
[prompt]> ls
code0.py code1.py
[prompt]>
[prompt]> cat code0.py
print("This is:", __file__)
[prompt]> python3 -c "import os, subprocess;subprocess.Popen(os.path.join(os.getcwd(), \"code0.py\")).communicate()"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/lib/python3.6/subprocess.py", line 709, in __init__
restore_signals, start_new_session)
File "/usr/lib/python3.6/subprocess.py", line 1344, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
OSError: [Errno 8] Exec format error: '/cygdrive/e/Work/Dev/StackOverflow/q055271912/code0.py'
[prompt]>
[prompt]> cat code1.py
#!/usr/bin/env python3
print("This is:", __file__)
[prompt]> python3 -c "import os, subprocess;subprocess.Popen(os.path.join(os.getcwd(), \"code1.py\")).communicate()"
This is: /cygdrive/e/Work/Dev/StackOverflow/q055271912/code1.py
Другой способ - запустить интерпретатор, за которым следует имя файла, но я не знаю, как это сделать из Flask - на самом деле это потребует исправления Werkzeug (_reloader.py: _get_args_for_reloading), но это будет просто неудачный обходной путь ( Gainarie) - см. ниже.
@EDIT0:
Глядя на ответ @AxelGrytt, выясняется, что это известная проблема: [GitHub]: pallets/werkzeug - 0.15.0 вызывает OSError: [Errno 8] Ошибка формата Exec: в Docker для Windows (хмм, отправлено в тот же день, что и этот вопрос (и через 2 дня после релиза) :)).
Итак, то, что я сказал выше, правильно, но стоит упомянуть, что есть другой способ исправить это: удалить разрешение exec для файла:
chmod -x api/manage.py
По словам авторов Werkzeug, отныне это желаемое поведение (также относится к v 0.15.2):
- Файл с установленным разрешением exec также должен иметь шебанг
- Файл без шебанга не должен иметь установленного разрешения exec
Ответ 2
Это новое поведение в Werkzeug 0.15. Понижение до Werkzeug 0.14.1 может работать, но 0.14 больше не поддерживается, поэтому вам будет лучше исправить проблему с вашим файлом, как описано в других ответах.
Ответ 3
Если вы отключите режим отладки (не передавайте debug=True
и не устанавливайте FLASK_DEBUG=0
), перегрузчик не будет использоваться, и поэтому эта проблема не возникнет. Компромисс в том, что у вас больше нет перегрузчика.
if __name__ == "__main__":
connexion_app.run(host="0.0.0.0", port=constants.API_PORT, debug=True)
Желательно исправить это, убедившись, что файлы, помеченные как исполняемые, имеют строку интерпретатора, например #!/usr/bin/env python3
(из fooobar.com/questions/17161919/...).
Ответ 4
Ответ @CristiFati работал для меня с 1 дополнительным шагом:
Я также должен был исправить EOL от \r\n
до \n
.
Извините, у меня недостаточно очков, чтобы добавить комментарий, и мне нужно открыть новый ответ...