I have two docker containers running Flask, just a simple backend/frontend example bit I was running through to learn docker and flask.
My frontend is:
from flask import Flask, jsonify
import requests
import simplejson
import json
app = Flask(__name__)
#app.route('/')
def hello():
uri = "http://127.0.0.1:5000/tasks"
try:
uResponse = requests.get(uri)
except requests.ConnectionError:
return "Connection Error"
Jresponse = uResponse.text
data = json.loads(Jresponse)
fullString = ""
title = data['tasks'][0]['title']
description = data['tasks'][0]['description']
fullString += title
fullString += "<br/>"
fullString += description
return fullString
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0", port=2000)
This works fine when I run it locally, and it also works when I run it in my docker. I'm able to go to the frontend at localhost:2000 and I see valid data.
My backend code is:
from flask import Flask,request, jsonify, make_response
from flask import abort
import csv
import json
import flask
app = Flask(__name__)
tasks = [
{
'id': 1,
'title': u'example title 1',
'description': u'example description 1',
'done': False
},
{
'id': 2,
'title': u'example title 2',
'description': u'example description 2',
'done': False
}
]
#app.route('/tasks', methods=['GET'])
def get_tasks():
return jsonify({'tasks': tasks})
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0", port=5000)
If I run both of these without docker, and I go to the frontend at localhost:2000 I get what I expect, the 0th entry of tasks description and title.
When I run these in docker, everything seems to work, but I get the Connection Error from the frontend. So, the requests.get(uri) seems to not be working once dockerized.
Here's my docker files
For Backend
FROM ubuntu:latest
MAINTAINER me
RUN apt-get update -y
RUN apt-get install -y python3-pip python3-dev build-essential
COPY . /app
WORKDIR /app
RUN pip3 install -r requirements.txt
ENTRYPOINT ["python3"]
CMD ["backend.py"]
For Frontend
FROM ubuntu:latest
MAINTAINER me
RUN apt-get update -y
RUN apt-get install -y python3-pip python3-dev build-essential
COPY . /app
WORKDIR /app
ENV FLASK_APP=/app/frontend.py
ENV FLASK_ENV=development
RUN pip3 install -r requirements.txt
ENTRYPOINT ["python3"]
CMD ["frontend.py"]
So, it appears they both work individually, but can't communicate. Why is that? As if it isn't obvious, I'm new to docker.
EDIT1
Command for frontend:
sudo docker run -d -p 2000:2000 frontend
Command for backend:
sudo docker run -d -p 5000:5000 backend
EDIT2
I moved this to docker compose, and have the same issue it appears.
docker-compose.yml
version: '3'
services:
backend:
build:
context: backend/
dockerfile: compose/lib/backend/Dockerfile
ports:
- "5000:5000"
frontend:
build:
context: lib/frontend/
dockerfile: compose/lib/frontend/Dockerfile
ports:
- "2000:2000"
No changes to Docker files. According to the docs here it is correct that I don't need specific networking, and there is a default network created. However, this still works fine under just flask, but I can't get them to attach using docker or docker-compose.
Can you share the docker run command you're using?
Are you exposing the ports with the -p flag?
docker run -p 5000:5000 ...
[Update]: Depending on your docker install and config, you may not be able to use that IP. Docker considers the 127.0.0.1 IP to mean "this container," not "this machine."
A bridged network may address this, but I'd recommend using docker-compose instead (details below).
If, for the purposes of this experiment, you are planning on running these two containers at the same time on the same machine always, you might want to look into docker-compose, which lets you run multiple containers from the same master command, and gives you nice bonus features like creating a virtual network for the two to connect to each other on, without external networks being able to access them. e.g. your data server can be visible only to your other flask container, but that one can be publicly exposed on your host machine's network interface.
In the case of docker-compose, you can use the following (untested) docker-compose.yml as a start:
version: 3
services:
backend:
build: path/to/dockerfile
ports:
- 5000:5000
frontend:
build: path/to/dockerfile
ports:
- 2000:2000
Related
I am trying to run a flask app using a docker.
Operating system Windows 11, WSL image Ubuntu-20.04.
A simple reproducible example:
https://github.com/Konrad-H/stackoverflow-question
If I run (inside a venv)
$ python app/main.py
the following message appears in the console:
Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
And I can successfully connect to the app.
On the other hand, if I try to run the repo using:
$ docker build -t s-o-question:latest .
$ docker run -p 5000:5000 s-o-question
I get the exact same message on the console, but the webpage takes a long time loading and after a while a connection timeout appears.
The error appears both inside WSL2 and inside Windows.
Source Code:
main.py
import logging
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route("/")
def index():
print("Hello World I am Sea")
return "Hello big world"
if __name__ == "__main__":
app.logger = logging.getLogger("audio-gui")
app.run( host='0.0.0.0',port=5000, debug=True)
Dockerfile
FROM python:3.8
# Working Directory
WORKDIR /app
# Copy source code to working directory
COPY . ./app /app/
# Install packages from requirements.txt
# hadolint ignore=DL3013
RUN pip install --no-cache-dir --upgrade pip &&\
pip install --no-cache-dir --trusted-host pypi.python.org -r requirements.txt
EXPOSE 5000
ENTRYPOINT [ "python" ]
CMD [ "app/main.py" ]
I had the same issue. The URL http/localhost:5000/ worked for me (5000 is my exposed port number). you can try and see if it works. Alternatively, you can also try http://<host-ip>:5000/. Note that the host-ip should be IP address of your local machine not the IP address of the docker container.
you can also check this answer
The issue is that you cannot use same port number for ex if your app runs on port 5000 it must be bind to another port like 8080 in docker .
try this docker run -p 8080:5000 s-o-question
I had the same issue on my win 11 device , i worked around this using the above solution.
I am running Hypercorn with --reload inside a Docker container. The file I am running is kept in a volume managed by Docker Compose.
When I change the file on my system, I can see that the change is reflected in the volume, e.g. with docker compose exec myapp /bin/cat /app/runtime/service.py.
However, when I change a file in this way, Hypercorn does not restart as I would have expected. Is there some adverse interaction between Hypercorn and the Docker volume? Or am I expecting something from the --reload option that I should not expect?
Example files are below. My expectation was that modifying runtime/service.py from outside the container would trigger Hypercorn to restart the server with the modified version of the file. But this does not occur.
Edit: I should add that I am using Docker 20.10.5 via Docker Desktop for Mac, on MacOS 10.14.6.
Edit 2: This might be a Hypercorn bug. If I add uvicorn[standard] in requirements.txt and run python -m uvicorn --reload --host 0.0.0.0 --port 8001 service:app, the reloading works fine. Possibly related: https://gitlab.com/pgjones/hypercorn/-/issues/185
entrypoint.sh:
#!/bin/sh
cd /app/runtime
/opt/venv/bin/python -m hypercorn --reload --bind 0.0.0.0:8001 service:app
Dockerfile:
FROM $REDACTED
RUN /opt/venv/bin/python -m pip install -U pip
RUN /opt/venv/bin/pip install -U setuptools wheel
COPY requirements.txt /app/requirements.txt
RUN /opt/venv/bin/pip install -r /app/requirements.txt
COPY requirements-dev.txt /app/requirements-dev.txt
RUN /opt/venv/bin/pip install -r /app/requirements-dev.txt
COPY entrypoint.sh /app/entrypoint.sh
EXPOSE 8001/tcp
CMD ["/app/entrypoint.sh"]
docker-compose.yml:
version: "3.8"
services:
api:
container_name: api
hostname: myapp
build:
context: .
ports:
- 8001:8001
volumes:
- ./runtime:/app/runtime
runtime/service.py:
import logging
import quart
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
app = quart.Quart(__name__)
#app.route('/')
async def handle_hello():
logger.info('Handling request.')
return 'Hello, world!\n'
#app.route('/bad')
async def handle_bad():
logger.critical('Bad request.........')
raise RuntimeError('Oh no!!!')
Here is a minimal, fully working example which does auto-reload using hypercorn:
docker-compose.yaml
services:
app:
build: .
# Here --reload is used which works as intended!
command: hypercorn --bind 0.0.0.0:8080 --reload src:app
ports:
- 8080:8080
volumes:
- ./src:/app/src
Dockerfile
FROM python:3.10-slim-bullseye
WORKDIR /app
RUN pip install hypercorn==0.14.3 quart==0.18.0
COPY src ./src
EXPOSE 8080
ENV QUART_APP=src:app
# This is the production command; docker-compose.yaml overwrites it for local development
CMD hypercorn --bind 0.0.0.0:8080 src:app
src/__init__.py
from quart import Quart
app=Quart(__name__)
#app.route('/', methods=['GET'])
def get_root():
return "Hello world!"
Run via docker-compose up and notice how hypercorn reloads once __init__.py got modified.
You likely need to use a volume mount to get the reload functionality!
This is because when you build the container, it bakes whatever you have locally into it. Further changes only affect your local filesystem.
This is arguably not intended-use (as the container becomes dependent on external files!), but likely useful for faster testing/debugging
You could also directly edit the container by connecting to it, which you may find suits your needs.
can't open file '/web/manage.py': [Errno 2] No such file or directory
exited with code 2
NOTE: Tried all similar problems solution posted, did not work.
No matter what I do, not able to get http://localhost/5000 to work. Even if the above error goes away by removing volume and command from docker-container.
Below is docker-compose.yml
services:
web:
build: ./web
command: python /web/manage.py runserver 0.0.0.0:8000
volumes:
- './users:/usr/src/app'
ports:
- 5000:5000
env_file:
- ./.env.dev
Below is Dockerfile:
# pull official base image
FROM python:3.9.5-slim-buster
# set work directory
WORKDIR /usr/src/app
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# install dependencies
RUN pip install --upgrade pip
COPY ./requirements.txt /usr/src/app/requirements.txt
RUN pip install -r requirements.txt
# copy project
COPY . /usr/src/app/
BELOW IS manage.py:
from flask.cli import FlaskGroup
from project import app
cli = FlaskGroup(app)
if __name__ == "__main__":
cli()
BELOW IS init.py:
from flask import Flask, jsonify
app = Flask(__name__)
#app.route("/")
def hello_world():
return jsonify(hello="world")
Below is the structure:
The ones marked in red appeared when I ran this command: docker-compose build
enter image description here
A couple of changes to do.
The cli command in your docker-compose.yml file needs to be:
command: python /usr/src/app/manage.py run -h 0.0.0.0 -p 8000
There the command name is run and not runserver. Also the host ip to bind and port to listen are configured as different command options.
Also the configured port mapping for the service needs to map to the container port from the command:
ports:
- 5000:8000
In your manage.py module, FlaskGroup should be provided create_app option which is factory not the app instance.
You can implement this as a lambda function.
cli = FlaskGroup(create_app=(lambda:app))
Edit
The source files are not mounted in the container volume that why you're getting "no such file manage.py".
You need to mount your source files in the container volume under /usr/src/app.
volumes:
- './web:/usr/src/app'
I'm trying to create a simple web application container within Ubuntu-WSL2 with the help of the Docker. So I've built my container creating my-simple-webapp folder and within that folder, I've created Dockerfile and app.py files;
Dockerfile
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y python python-pip
RUN pip install flask
COPY app.py /opt/
ENTRYPOINT FLASK_APP=/opt/app.py flask run --host=0.0.0.0 --port=8080
app.py
import os
from flask import Flask
app = Flask(__name__)
#app.route("/")
def main():
return "Welcome!"
#app.route('/how are you')
def hello():
return 'I am good, how about you?'
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
When I run the command docker build ./my-simple-webapp it works without error. However when I use my browser to connect my container typing 172.17.0.2:8080, o.o.o.o:8080 or localhost:8080 connection times out.
Resource : https://github.com/mmumshad/simple-webapp-flask
If all you run is docker build... then you still need to start your container with docker run....
You can open the docker dashboard (in your Windows tray) to see if your container is actually running.
To actually run your app you need to start a container. First, build the image:
docker build -t simple-webapp-flask .
Then start a container using the image, with 8080:8080 mapping from container to your host:
docker run -p 8080:8080 simple-webapp-flask
If you want to deploy your flask application, you need to choose from the following options:
https://flask.palletsprojects.com/en/1.1.x/deploying/
The way you are trying to do it, can be used only for development purposes.
I have a Docker container which runs a Flask application. When Flask receives and http request, I would like to trigger the execution of a new ephemeral Docker container which shutdowns once it completes what it has to do.
I have read Docker-in-Docker should be avoided so this new container should be run as a sibling container on my host and not within the Flask container.
What would be the solution to do this with docker-py?
we are doing stuff like this by mounting docker.sock as shared volume between the host machine and the container. This allows the container sending commands to the machine such as docker run
this is an example from our CI system:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Answering my own question. Here is a complete setup which works.
In one folder, create the following files:
requirements.txt
Dockerfile
docker-compose.yml
api.py
requirements.txt
docker==3.5.0
flask==1.0.2
Dockerfile
FROM python:3.7-alpine3.7
# Project files
ARG PROJECT_DIR=/srv/api
RUN mkdir -p $PROJECT_DIR
WORKDIR $PROJECT_DIR
COPY requirements.txt ./
# Install Python dependencies
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
docker-compose.yml
Make sure to mount docker.sock in volumes as mentioned in the previous answer above.
version: '3'
services:
api:
container_name: test
restart: always
image: test
build:
context: ./
volumes:
- ./:/srv/api/
- /var/run/docker.sock:/var/run/docker.sock
environment:
FLASK_APP: api.py
command: ["flask", "run", "--host=0.0.0.0"]
ports:
- 5000:5000
api.py
from flask import Flask
import docker
app = Flask(__name__)
#app.route("/")
def hello():
client = docker.from_env()
client.containers.run('alpine', 'echo hello world', detach=True, remove=True)
return "Hello World!"
Then open your browser and navigate to http://0.0.0.0:5000/
It will trigger the execution of the alpine container. If you don't already have the alpine image, it will take a bit of time the first time because Docker will automatically download the image.
The arguments detach=True allows to execute the container asynchronously so that Flask does not wait for the end of the process before returning its response.
The argument remove=True indicates Docker to remove the container once its execution is completed.