Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.15.0 causes OSError: [Errno 8] Exec format error: in Docker for Windows #1482

Closed
penner42 opened this issue Mar 20, 2019 · 19 comments
Closed
Milestone

Comments

@penner42
Copy link

penner42 commented Mar 20, 2019

The new 0.15.0 does not run in Docker for Windows. Have not tried Docker on other platforms.

Minimal example with Flask.

app.py

from flask import Flask
 
app = Flask(__name__)
 
 
@app.route('/')
def hello_world():
    return 'Hello, world!'
 
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

Dockerfile

FROM python:3-onbuild
COPY . /usr/src/app
CMD ["python", "app.py"]

requirements.txt

# Werkzeug==0.14.1
Flask

Run docker build -t flask_test . and then docker run flask_test.
Error in container:

λ docker run flask_test
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
 * Restarting with stat
Traceback (most recent call last):
  File "app.py", line 11, in <module>
    app.run(debug=True, host='0.0.0.0')
  File "/usr/local/lib/python3.6/site-packages/flask/app.py", line 943, in run
    run_simple(host, port, self, **options)
  File "/usr/local/lib/python3.6/site-packages/werkzeug/serving.py", line 988, in run_simple
    run_with_reloader(inner, extra_files, reloader_interval, reloader_type)
  File "/usr/local/lib/python3.6/site-packages/werkzeug/_reloader.py", line 332, in run_with_reloader
    sys.exit(reloader.restart_with_reloader())
  File "/usr/local/lib/python3.6/site-packages/werkzeug/_reloader.py", line 176, in restart_with_reloader
    exit_code = subprocess.call(args, env=new_environ, close_fds=False)
  File "/usr/local/lib/python3.6/subprocess.py", line 267, in call
    with Popen(*popenargs, **kwargs) as p:
  File "/usr/local/lib/python3.6/subprocess.py", line 709, in __init__
    restore_signals, start_new_session)
  File "/usr/local/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: '/usr/src/app/app.py

Uncomment the first line in requirements.txt and it runs properly after rebuild.

@shinuza
Copy link

shinuza commented Mar 21, 2019

Hi same issue here. Tested on

  • Centos 7.4 with python 3.6
  • Mac OSX 10.14.3 with python 3.7

This is caused by the changes in _get_args_for_reloading() in _reloading.py.

@shinuza
Copy link

shinuza commented Mar 21, 2019

Given the code above in a file called app.py, with cwd() being /home/user/Projects/test/

_get_args_for_reloading() yields the following:

With 0.14.1:

['/home/user/.virtualenvs/test-ChRUEUMK/bin/python', 'app.py']

With 0.15.0

['/home/user/Projects/test/app.py']

Prepending /home/user/.virtualenvs/test-ChRUEUMK/bin/python to the path does fix the issue.

@kamyanskiy
Copy link

@shinuza check if app.py is executable, if yes - set chmod 644 app.py. Or second way, add shebang on the top of app.py like #!/usr/bin/env python

@kamyanskiy
Copy link

@shinuza there https://github.com/pallets/werkzeug/blob/0.15.x/src/werkzeug/_reloader.py#L90 lines 90-94 the "'/home/user/.virtualenvs/test-ChRUEUMK/bin/python'" was removed if app.py executable.
and OSError: [Errno 8] Exec format error: '/usr/src/app/app.py happened because app.py doesn't have shebang line (https://stackoverflow.com/questions/27606653/oserror-errno-8-exec-format-error)

@shinuza
Copy link

shinuza commented Mar 21, 2019

@kamyanskiy I just figured this out reading the code but the error should be as cryptic as it is right now.

@shinuza
Copy link

shinuza commented Mar 21, 2019

Also, if I explicitly run python app.py, then the subprocess should not make any assumption and change the way I run the application. i.e: working with a virtual machine with shared folder makes every files executable by default.

@kamyanskiy
Copy link

@shinuza I don't think its a critical bug, in other words its a bit stricter now than before. So I shouldn't have executable app.py without shebang, it doesn't make sense. And second I shouldn't run executable with shebang like "python app.py". But I agree, probably that was unexpected for you as for me :) To workaround just add shebang to your app.py, I hope this will help.

@davidism
Copy link
Member

davidism commented Mar 21, 2019

If you mark a script as executable, you should add a corresponding interpreter comment to the top. You can use a tool like pre-commit's check-executables-have-shebangs hook to enforce that.

If you don't intend for a script to be directly executable, and want to require python script.py instead, then you should not mark it executable.

@shinuza
Copy link

shinuza commented Mar 21, 2019

As I said, I agree with the main logic here. I disagree with the way the error is dealt with as well as the fact that the error message is unintelligible unless you know the know the technical details or read the code. It should at least be documented in the changelog.

@davidism
Copy link
Member

davidism commented Mar 21, 2019

We have no control over the error message, that comes from Linux. The fact that we changed how executable files are handled is listed in the changelog:

The reloader will not prepend the Python executable to the command line if the Python file is marked executable. This allows the reloader to work on NixOS. #1242

@penner42
Copy link
Author

penner42 commented Mar 21, 2019

Making the file not executable works. The shebang line does not, for me. I get file not found errors, instead. That was the first thing I tried.

With #!/usr/bin/env python3:

λ docker run flask_test
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
 * Restarting with stat
: No such file or directory

I also think making a change that works only on one Linux distribution but breaks the rest doesn't seem ideal. Making the files not executable seems like the proper solution, but this still feels broken to me.

@kamyanskiy
Copy link

kamyanskiy commented Mar 21, 2019

@penner42 try #!/usr/bin/env python

root@4541ebd677e0:/usr/src/app# ls -la /usr/local/bin/python3
lrwxrwxrwx 1 root staff 9 Mar  4 23:40 /usr/local/bin/python3 -> python3.6
root@4541ebd677e0:/usr/src/app# ls -la /usr/local/bin/python 
lrwxrwxrwx 1 root staff 7 Mar  4 23:40 /usr/local/bin/python -> python3

probably you don't have symlink on python3

@penner42
Copy link
Author

penner42 commented Mar 21, 2019

Same result. The python3 symlink is there, and just running /usr/bin/env python3 or /usr/bin/env python from a shell works.

FWIW, Docker does gives this warning when building.
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.

@davidism
Copy link
Member

Use the flask run command.

FROM python:3.7-alpine
WORKDIR /app
ENV FLASK_ENV development
ENV FLASK_APP example
EXPOSE 5000
RUN ["pip", "install", "flask"]
CMD ["flask", "run", "-h", "0.0.0.0"]
docker run --rm -p 5000:5000 -v $(pwd):/app flask/example:latest

@fazl
Copy link

fazl commented Mar 27, 2019

Did the tutorial at https://docs.docker.com/compose/gettingstarted/ used to work on Windows 7?
Is this recent change the cause why I see a similar error trying to run the example:

$ docker-compose up
Creating composetest_web_1   ... done
Creating composetest_redis_1 ... done
Attaching to composetest_web_1, composetest_redis_1
redis_1  | 1:C 27 Mar 2019 17:29:12.746 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1  | 1:C 27 Mar 2019 17:29:12.746 # Redis version=5.0.4, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1  | 1:C 27 Mar 2019 17:29:12.747 # Warning: no config file specified, using the default config. In order to specify a config file use redis-ser
ver /path/to/redis.conf
redis_1  | 1:M 27 Mar 2019 17:29:12.757 * Running mode=standalone, port=6379.
redis_1  | 1:M 27 Mar 2019 17:29:12.757 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to th
e lower value of 128.
redis_1  | 1:M 27 Mar 2019 17:29:12.758 # Server initialized
redis_1  | 1:M 27 Mar 2019 17:29:12.758 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issu
e add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
web_1    |  * Serving Flask app "app" (lazy loading)
web_1    |  * Environment: production
web_1    |    WARNING: Do not use the development server in a production environment.
web_1    |    Use a production WSGI server instead.
web_1    |  * Debug mode: on
web_1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
web_1    |  * Restarting with stat
web_1    | Traceback (most recent call last):
web_1    |   File "app.py", line 32, in <module>
web_1    |     app.run(host="0.0.0.0", debug=True)
web_1    |   File "/usr/local/lib/python3.4/site-packages/flask/app.py", line 943, in run
web_1    |     run_simple(host, port, self, **options)
web_1    |   File "/usr/local/lib/python3.4/site-packages/werkzeug/serving.py", line 988, in run_simple
web_1    |     run_with_reloader(inner, extra_files, reloader_interval, reloader_type)
web_1    |   File "/usr/local/lib/python3.4/site-packages/werkzeug/_reloader.py", line 332, in run_with_reloader
web_1    |     sys.exit(reloader.restart_with_reloader())
web_1    |   File "/usr/local/lib/python3.4/site-packages/werkzeug/_reloader.py", line 176, in restart_with_reloader
web_1    |     exit_code = subprocess.call(args, env=new_environ, close_fds=False)
web_1    |   File "/usr/local/lib/python3.4/subprocess.py", line 534, in call
web_1    |     with Popen(*popenargs, **kwargs) as p:
web_1    |   File "/usr/local/lib/python3.4/subprocess.py", line 856, in __init__
web_1    |     restore_signals, start_new_session)
web_1    |   File "/usr/local/lib/python3.4/subprocess.py", line 1464, in _execute_child
web_1    |     raise child_exception_type(errno_num, err_msg)
web_1    | OSError: [Errno 8] Exec format error
composetest_web_1 exited with code 1

@andrewv86
Copy link

Did the same tutorial and found the same issue. This fixed it for me.

I added the following shebang to the top of my app.py script

#!/usr/local/bin/python3

Which then caused permission issues. I then added the following to my Dockerfile before the CMD

RUN chmod 644 app.py

@ans1genie

This comment has been minimized.

@pallets pallets deleted a comment from fazl Apr 7, 2019
@pallets pallets locked as resolved and limited conversation to collaborators Apr 7, 2019
@davidism
Copy link
Member

davidism commented Apr 7, 2019

Changes to Docker Compose tutorial proposed in docker/docs#8609.

@davidism davidism added this to the 0.15.5 milestone Jul 15, 2019
@davidism
Copy link
Member

Fixed in Werkzeug 0.15.5.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants