【问题标题】:Flask CLI throws 'OSError: [Errno 8] Exec format error' when run through docker-composeFlask CLI 在通过 docker-compose 运行时抛出 'OSError: [Errno 8] Exec format error'
【发布时间】:2019-08-11 19:19:19
【问题描述】:

我正在运行一个带有Custom Script 的Flask 应用程序。或者尝试,无论如何。

我在 Windows 10 上,应用程序应该使用以下命令在 linux Docker 容器中运行:

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 并没有解决问题。

我怎样才能避免这个错误?


ma​​nage.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'

【问题讨论】:

    标签: python windows docker flask docker-compose


    【解决方案1】:

    看起来您的 api/manage.py 没有 shebang ([Wikipedia]: Shebang (Unix)),所以默认(当前)命令处理器(一个 shell - 通常是 bash)正在尝试运行它,但(显然)失败了。

    要纠正问题,请添加 shebang(在文件的开头,确保您的编辑器添加 Nix 样式的行尾(\n, 0x0A, LF)):

    • 默认Python安装:

        #!/usr/bin/env python
      
      • 变体(明确指定Python 3):

          #!/usr/bin/env python3
        
    • 自定义Python安装:

        #!/full/path/to/your/custom/python/executable
      

    请注意,您还需要文件 (chmod +x api/manage.py) 的 exec 权限。

    例子:

    [cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q055271912]> ~/sopr.sh
    *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***
    
    [prompt]> ls
    code00.py  code01.py
    [prompt]>
    [prompt]> cat code00.py
    print("This is:", __file__)
    
    [prompt]> python3 -c "import os, subprocess;subprocess.Popen(os.path.join(os.getcwd(), \"code00.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/code00.py'
    [prompt]>
    [prompt]> cat code01.py
    #!/usr/bin/env python3
    
    print("This is:", __file__)
    
    [prompt]> python3 -c "import os, subprocess;subprocess.Popen(os.path.join(os.getcwd(), \"code01.py\")).communicate()"
    This is: /cygdrive/e/Work/Dev/StackOverflow/q055271912/code01.py
    

    另一种方法是运行解释器,后跟文件名,但我不知道如何从 Flask 执行此操作 - 实际上这需要修补 Werkzeug (_reloader.py: _get_args_for_reloading),但这只是一个蹩脚的解决方法 (gainarie) - 见下文。



    更新#0

    查看@AxelGrytt 的回答,原来这是一个已知问题:[GitHub]: pallets/werkzeug - 0.15.0 causes OSError: [Errno 8] Exec format error: in Docker for Windows(嗯,与此问题在同一天提交(和发布后 2 天):)。

    所以,我上面说的是正确的,但值得一提的是,还有另一种修复方法:删除文件的 exec 权限:

    chmod -x api/manage.py
    

    根据 Werkzeug 作者的说法,从现在开始,这是期望的行为(也适用于 v0.15.2 em>):

    • 一个文件具有 exec权限集,应该也有一个shebang
    • 文件没有 shebang不应该拥有exec权限集

    【讨论】:

    • 解决了!它对我在 OSX 上运行的同事sans shebang 有效,但我仍然不知道为什么。 Docker 命令是python manage.py run --host "0.0.0.0" --with-threads,所以我觉得它应该通过 Python 解释器运行,但我猜不是?
    • 也许 OSX 有另一种关联文件和应用程序的方式(类似于 Win)?或者他们有一些环境变量或 Flask 属性集?但我只能猜测没有更多信息。
    • 或者你的同事有一个旧的 Werkzeug 版本:)
    【解决方案2】:

    Werkzeug==0.15.4 有这个问题。

    pip install --user Werkzeug==0.16
    

    【讨论】:

      【解决方案3】:

      这是 Werkzeug 0.15 中的新行为。降级到 Werkzeug 0.14.1 可能有效,但不再支持 0.14,因此您最好按照其他答案中的说明更正文件的问题。

      【讨论】:

      • 您有更多详细信息吗?你能分享一个官方的 URL 给这个 bug 吗?
      • 我没有在requirements.txt文件中指定Werkzeug的版本(最新的是0.15.4在我的开发过程中)。当我在requirements.txt 使用Werkzeug==0.14.1 时,问题就消失了。非常感谢!
      【解决方案4】:

      如果您禁用调试模式(不要传递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(来自https://stackoverflow.com/a/55272071)。

      【讨论】:

        【解决方案5】:

        @CristiFati 的答案对我有用,需要额外的 1 个步骤:

        我还必须将 EOL 从 \r\n 更正为 \n


        对不起,我没有足够的积分来添加评论,必须打开一个新的答案...

        【讨论】:

        • _reloader.pyNix 风格 EOLNs,所以你的那个当您添加 shebang 时,您的编辑(默默地)介绍了必须替换。注意:一个不错的编辑器会检测现有文件中的行尾,并在添加新文件时与它们保持一致。
        猜你喜欢
        • 1970-01-01
        • 2017-08-02
        • 2020-02-23
        • 1970-01-01
        • 2019-08-15
        • 2019-04-20
        • 2016-12-14
        • 2016-04-15
        • 2019-08-14
        相关资源
        最近更新 更多