Reputation: 53
I'm following the micro services course on testdriven.io. In this course I need to deploy a Flask application with Docker. To run the application I use Flask-cli, and it gives me an error on start up:
No such file or directory: '/usr/src/app/manage.py': '/usr/src/app/manage.py'
To deploy the container I use Docker-compose. I run the command on my Windows 10 machine and I use the standard Python image (python:3.7.2-alpine
). I already tried to change the permissions on the file but that didn't help.
This is how my compose file looks like:
version: '3.7'
services:
users:
build:
context: ./services/users
dockerfile: Dockerfile-dev
volumes:
- './services/users:/usr/src/app'
ports:
- 6001:6000
environment:
- FLASK_APP=project/__init__.py
- FLASK_ENV=development
- COMPOSE_CONVERT_WINDOWS_PATHS=1
My docker file:
# base image
FROM python:3.7.2-alpine
# set working directory
WORKDIR /usr/src/app
# add and install requirements
COPY ./requirements.txt /usr/src/app/requirements.txt
RUN pip install -r requirements.txt
# add app
COPY . /usr/src/app
# i tried to give it the right rights.. but it didn't help
RUN chmod +x /usr/src/app/manage.py
# run server
CMD python manage.py run -h 0.0.0.0
And my manage.py
file which will launch the application:
#!/usr/bin/python3
# services/users/manage.py
from flask.cli import FlaskGroup
from project import app
cli = FlaskGroup(app)
if __name__ == '__main__':
cli()
So i would expect that this would launch the application and make it available on port 6001, but instead it gives me the following error:
Successfully tagged testdriven-app_users:latest
Recreating testdriven-app_users_1 ... done
Attaching to testdriven-app_users_1
users_1 | * Serving Flask app "project/__init__.py" (lazy loading)
users_1 | * Environment: development
users_1 | * Debug mode: on
users_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
users_1 | * Restarting with stat
users_1 | Traceback (most recent call last):
users_1 | File "manage.py", line 11, in <module>
users_1 | cli()
users_1 | File "/usr/local/lib/python3.7/site-packages/click/core.py", line 764, in __call__
users_1 | return self.main(*args, **kwargs)
users_1 | File "/usr/local/lib/python3.7/site-packages/flask/cli.py", line 557, in main
users_1 | return super(FlaskGroup, self).main(*args, **kwargs)
users_1 | File "/usr/local/lib/python3.7/site-packages/click/core.py", line 717, in main
users_1 | rv = self.invoke(ctx)
users_1 | File "/usr/local/lib/python3.7/site-packages/click/core.py", line 1137, in invoke
users_1 | return _process_result(sub_ctx.command.invoke(sub_ctx))
users_1 | File "/usr/local/lib/python3.7/site-packages/click/core.py", line 956, in invoke
users_1 | return ctx.invoke(self.callback, **ctx.params)
users_1 | File "/usr/local/lib/python3.7/site-packages/click/core.py", line 555, in invoke
users_1 | return callback(*args, **kwargs)
users_1 | File "/usr/local/lib/python3.7/site-packages/click/decorators.py", line 64, in new_func
users_1 | return ctx.invoke(f, obj, *args, **kwargs)
users_1 | File "/usr/local/lib/python3.7/site-packages/click/core.py", line 555, in invoke
users_1 | return callback(*args, **kwargs)
users_1 | File "/usr/local/lib/python3.7/site-packages/flask/cli.py", line 771, in run_command
users_1 | threaded=with_threads, ssl_context=cert)
users_1 | File "/usr/local/lib/python3.7/site-packages/werkzeug/serving.py", line 988, in run_simple
users_1 | run_with_reloader(inner, extra_files, reloader_interval, reloader_type)
users_1 | File "/usr/local/lib/python3.7/site-packages/werkzeug/_reloader.py", line 332, in run_with_reloader
users_1 | sys.exit(reloader.restart_with_reloader())
users_1 | File "/usr/local/lib/python3.7/site-packages/werkzeug/_reloader.py", line 176, in restart_with_reloader
users_1 | exit_code = subprocess.call(args, env=new_environ, close_fds=False)
users_1 | File "/usr/local/lib/python3.7/subprocess.py", line 323, in call
users_1 | with Popen(*popenargs, **kwargs) as p:
users_1 | File "/usr/local/lib/python3.7/subprocess.py", line 775, in __init__
users_1 | restore_signals, start_new_session)
users_1 | File "/usr/local/lib/python3.7/subprocess.py", line 1522, in _execute_child
users_1 | raise child_exception_type(errno_num, err_msg, err_filename)
users_1 | FileNotFoundError: [Errno 2] No such file or directory: '/usr/src/app/manage.py': '/usr/src/app/manage.py'
testdriven-app_users_1 exited with code 1
Upvotes: 4
Views: 1508
Reputation: 21
add werkzeug==0.14.1 to requirement.txt can fix same bug appear on windows. its seems like a werkzeug bug.
Upvotes: 2
Reputation: 3758
When you execute a script, the kernel looks for the interpreter specified in the shebang (#!
). The location of the interpreter is extracted, and then the interpreter (e.g. python3
) is launched, executing the script itself. If the interpreter binary is not found, execution fails with a No such file or directory
(ENOENT
) error (as per man 2 execve
):
ERRORS
<...>
ENOENT The file filename or a script or ELF interpreter does not exist,
or a shared library needed for the file or interpreter cannot be found.
You have specified #!/usr/bin/python3
in your shebang, but in the base image you use (python:3.7.2-alpine
) the python3
binary is at different location:
$ docker run -it python:3.7.2-alpine sh
/ # which python3
/usr/local/bin/python3
So, even if your application works locally at your host (if it is Windows, it probably even does not care about the shebang), it stops working when you move it into the Docker container.
To avoid such situations, shebangs in scripts usually refer not to the interpreter itself (#!/usr/bin/python3
), but to /usr/bin/env
binary, which finds and executes the interpreter:
#!/usr/bin/env python3
When you run python3
via env
, the latter performs the search through PATH
, so it allows your shebang not to rely on specific location of python3
binary.
Finally, the correct version of your script would be as follows:
#!/usr/bin/env python3
# services/users/manage.py
from flask.cli import FlaskGroup
from project import app
cli = FlaskGroup(app)
if __name__ == '__main__':
cli()
Upvotes: 2