Docker Flask, stuck at "Waiting response from localhost" - docker

Im trying to run a test Flask in Docker, but for some reason, i cant connect to it from the host machine, the composition of files is:
pyweb/
|app.py
|Dockerfile
|___app/
|__init__.py
The files content:
Dockerfile:
FROM python:2.7
COPY . /pyweb
WORKDIR /pyweb
RUN pip install flask
RUN export FLASK_APP=app.py
ENTRYPOINT ["python"]
CMD ["app.py"]
app.py:
from flask import Flask
from app import app
app/init.py:
from flask import Flask
app = Flask(__name__)
#app.route('/')
#app.route('/index')
def index():
return "Hello, World!"
app.run(host='0.0.0.0')
After running the docker file, and starting the container with docker run -d -p 5000:5000, the response is
* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
But i cant connect form the host machine, it doesnt respond

Ok so I had that same issue during an interview a bit more than a year ago and it still puzzles me to this day.
I don't know why it's not working as expected when running the flask app with app.run().
Somehow it works fine when starting the app with the flask command line directly.
The Dockerfile would look like this:
FROM python:2.7
COPY . /pyweb
WORKDIR /pyweb
RUN pip install flask
ENV FLASK_APP=app.py
CMD ["flask", "run", "--host", "0.0.0.0"]
And you can drop app.run(host='0.0.0.0') from the __init__.py file.
I'll probably spend some time later trying to understand why your original implementation doesn't work as expected. I don't know much about flask but I don't see anything wrong in your code.

You should mention the port in flask app and set debug = True
app.run(host='0.0.0.0', port=5000, debug = True)
You should connect to the same port
docker run -p 3000:5000
Now you can access your app at http://localhost:3000/

This might not answer the OP's question but might answer others' questions who came here..
For me, the Flask output showed that the application was running after launching the Docker container. It showed this line, for example:
Running on http://172.17.0.2:5000/ (Press CTRL+C to quit)
So, I clicked this link and expected it to work.
However, you need to connect to the Docker container --- not the Flask app. Going to http://172.17.0.2:5000/ connects to the Flask app directly, which won't work. You need to go to http://0.0.0.0:5000/, which connects to the Docker container, which connects to the Flask app.
So going to http://0.0.0.0:5000/ worked.

Related

How to use SSL key and cert files in docker?

I have FastAPI app with uvicorn as starter. This app is in docker container and works fin.
Now I want to run uvicorn with SLL so i need PEM- and KEY-files inside of container. On dev machine theese files are /ssl/localhost.pem and /ssl/localhost.key, On prod server they are /ssl/certs/prod.pem and /ssl/private/prod.key.
My idea was to define SSL_KEY and SSL_PEM env vars with system path to that files and use it in Dockerfile:
RUN cp SSL_KEY /ssl.key
...
CMD uvicorn ... --ssl-keyfile=/ssl.key ...
But it doesnt work I do not know why.
Do you have any ideas about how to implement this case? Please :-)

Cloud Run Deploy fails: Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable

I have a project which I had previously successfully deployed to Google Cloud Run, and set up with a trigger such that upon pushing to the repo's main branch on Github, it would automatically deploy. It worked great.
Then I tried to rename the github repo, which meant deleting and creating a new trigger, and now I cannot get it working again.
Everytime, the build succeeds but deployment fails with this error in Cloud Build:
Step #2 - "Deploy": ERROR: (gcloud.run.services.update) Cloud Run error: Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable. Logs for this revision might contain more information.
I have not changed anything other than the repo name, leading me to believe the fix is not with my code, but I tried some changes there anyway.
I have looked into the solutions set forth in this post. However, I believe I am listening on the correct port.
My app is using Python and Flask, and contains this:
if __name__ == "__main__":
app.run(debug=False, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
Which should use the ENV var Port (8080) and otherwise default to 8080. I also tried just using port=8080.
I tried explicitly exposing the port in the Dockerfile, which also did not work:
FROM python:3.7
#Copy files into docker image dir, and make that the current working dir
COPY . /docker-image
WORKDIR /docker-image
RUN pip install -r requirements.txt
CMD ["flask", "run", "--host", "0.0.0.0"]
EXPOSE 8080
Cloud Run does seem to be using port 8080 - if I dig into the response, I see this nested under Response.spec.container.0 :
ports: [
0: {
containerPort: 8080
name: "http1"
}
]
All that said, if I look at the logs, it shows "Now running on Port 5000".
I have no idea where that Port 5000 is coming from or being set, but trying to change the ports in Python/Flask and the Dockerfile to 5000 leads to the same errors.
How do I get it to run on Port 8080? It's very strange to me that this was working FINE prior to renaming the repo and creating a new trigger. How is this setup different? The Trigger does not give an option to set the port so I'm not sure how that caused this error.
You have mixed things. Flask command default port is effectively 5000. If you want to change it, you need to change your flask run command with the --port= parameter
CMD ["flask", "run", "--host", "0.0.0.0","--port","8080"]
In addition, your flask run command, is a flask runtime and totally ignore the standard python entrypoint if __name__ == "__main__":. If you want to use this entrypoint, use the Python runtime
CMD ["python", "<main file>.py"]

gcloud Docker error because of user input taking

I am trying to deploy a Python App using Docker on Google Cloud
After typing the command gcloud run deploy --image gcr.io/id/name, I get this error:
ERROR: (gcloud.run.deploy) Cloud Run error: Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable. Logs for this revision might contain more information.
Logs explorer:
TEST_MODE = input()
EOFError: EOF when reading a line
I know with error is caused by trying to take in user input, and with Dockers this command solves the error:
docker run -t -i
Any idea how to run this with gcloud?
Your example does not run a server and so it's not accepted by Cloud Run.
Cloud Run expects a server to be running on PORT (generally this evaluates to 8080 but you should not assume this).
While it's reasonable to want to run arbitrary containers on Cloud Run, the service expects to something to respond via HTTP.
One option would be to simply jam an HTTP server into your container that listens on PORT and then run your Python app alongside it but, Python is single-threaded and so it's less easy to do this. Plus, it's considered an anti-pattern to run multiple processes in a single container.
Therefore I propose the following:
Rewrite your app to return the input as an HTTP GET:
main.py:
from flask import Flask
app = Flask(__name__)
#app.route('/hello/<name>')
def hello(name):
return "Hello {name}".format(name=name)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8080, debug=True)
Test it:
python3 main.py
* Running on http://127.0.0.1:8080/ (Press CTRL+C to quit)
NOTE Flask is running on localhost (127.0.0.1). We need to change this when we run it in a container. It's running on 8080
NAME="Freddie"
curl http://localhost:8080/hello/${NAME}
Hello Freddie
Or browse: http://localhost:8080/hello/Freddie
Containerize this:
Dockerfile:
FROM python:3.10-rc-slim
WORKDIR /app
RUN pip install flask gunicorn
COPY main.py .
ENV PORT 8080
CMD exec gunicorn --bind 0.0.0.0:$PORT main:app
NOTE ENV PORT 8080 sets the environment variable PORT to a value of 8080 unless we specify otherwise (we'll do that next)
NOTE The image uses gunicorn as a runtime host for Flask. This time the Flask service is bound to 0.0.0.0 which permits it to accessible from outside the container (which we need) and it uses the value of PORT
Then:
# Build
docker build --tag=66458821 --file=./Dockerfile .
# Run
PORT="9999"
docker run \
--rm --interactive --tty \
--env=PORT=${PORT} \
--publish=8080:${PORT} \
66458821
[INFO] Starting gunicorn 20.0.4
[INFO] Listening at: http://0.0.0.0:9999 (1)
NOTE Because --env=${PORT}, Flask now runs on 0.0.0.0:9999 but, we remap this port to 8080 on the host. This is just to show how the PORT variable is now used by the container
Test it (using the commands as before)!
Publish it and gcloud run deploy ...
Test it!

Assigning port when building flask docker image

I recently created an app using flask and put the py file in a docker container. However I am confused with online cases where people assigned the port.
First of all on the bottom of my py file I wrote
if __name__ == "__main__":
app.run(host='0.0.0.0',port=8000, debug=True)
In some cases I saw people specify the port in CMD when making dockerfile
CMD ["python3", "app.py", "--host=0.0.0.0", "--port=8000"]
In my own experience, the port assigned in CMD didn't work on my case at all. I wish to learn the differences between the two approaches and when to use each way.
Regarding this approach:
if __name__ == "__main__":
app.run(host='0.0.0.0',port=8000, debug=True)
__name__ is equal to "__main__" when the app is launched directly with the python interpreter (executed with the command python app.py) - which is a python technicallity and nothing to do with Flask. In that case the app.run function is called, and it accepts the various arguments as stated. app.run causes the Werkzeug development server to run.
This block will not be run, if you're executing the program with a production WSGI server like gunicorn as __name__ will not be equal to "__main__" in that case, so the app.run call is bypassed.
In practice, putting the app.run call in this if block means you can run the dev server with python app.py and avoid running the dev server when the same code is imported by gunicorn or similar in production.
There are lots of older tutorials or posts which reference the above approach. Modern versions of Flask ship with the flask command which is intended to replace this. So essentially without that if block, you can launch the development server which imports your app object in a similar manner to to gunicorn:
flask run -h 0.0.0.0 -p 8000
This automatically looks for an object called app in app.py, and accepts the host and port options, as you can see from flask run --help:
Options:
-h, --host TEXT The interface to bind to.
-p, --port INTEGER The port to bind to.
One advantage of this method is that the development server won't crash if you're using the auto reloader and introduce syntax errors. And of course the same code will be compatible with a production server like gunicorn.
With the above in mind, regarding the command you pass:
python app.py --host=0.0.0.0 --port=8000
I'm not sure if you've been confused with references to the flask command's supported options, but for this one to work you'd need to manually write some code to do something with those options. This could be done with a python module like argparse, but that would probably be redundant given that the flask command actually supports this out of the box.
To conclude: you should probably remove the if block, and your Dockerfile should contain:
CMD ["flask", "run", "--host=0.0.0.0", "--port=8000"]
You may also wish to check the FLASK_ENV environment variable is set to development to use the auto reloader, and be aware that the CMD line would need to be changed within this Dockerfile to run with gunicorn or similar in production, but that's probably outwith the scope of this question.
CMD ["python3", "app.py", "--host=0.0.0.0", "--port=8000"] means: Python run application app.py and pass the --host and the --port parameters to that application. It is up to your app.py to do something with those parameters. If your app does not process those flags, then you do not need to add them to the CMD.
If in your code you have app.run(host='0.0.0.0',port=8000), then your app will always be listening to port 8000 inside the container. In this case you can just use CMD ["python3", "app.py"]
If you wanted to have the ability to change the port and host that your app is listening to, the you could add some code to read the values from the command line. Once you setup your app to look at values from the command line, then it would make sense to run CMD ["python3", "app.py", "--host=0.0.0.0", "--port=8000"]

Can't connect to a docker running flask app when network=host

I have an flask app running on docker. the host = 0.0.0.0 and the port is 5001. If I run the docker without network=host I'm able to connect to 0.0.0.0 on port 5001, but with network=host I can't. I need the network=host because I need to connect to a db outside of the docker network cluster (which I'm able to connect to).
How can I do that? I tried running the docker with proxy but that didn't help.
Steps to reproduce:
Install python and flask (I'm using 3.8.6 and 1.1.2). In your main, create a flask app and expose one REST endpoint (the Url doesn't really matter).
This is my flask_main file:
from flask import Flask, request
app = Flask(__name__)
#app.route('/')
def route():
return "got to route"
if __name__ == "__main__":
app.run(host = 0.0.0.0, port=5001)
Dockerfile:
FROM python:3.8.6
WORKDIR /
ADD . /.
RUN pip --proxy ***my_proxy*** install -r requirements.txt
EXPOSE 5001
CMD ["python", "flask_main.py"]
requirements.txt:
Flask==1.1.2
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
psycopg2==2.8.6
Werkzeug==1.0.1
click==7.1.2
I tried running the Dockerfile with and without proxy, tried to remove the host=0.0.0.0 but nothing helps.
I managed to solve the problem by removing the network=host and specifying the dns server of my company.

Resources