I'm trying to containerize a simple python app which stores amount of time a site has been visited. Redis seems to work but Flask is refusing to lunch. I get this error on running docker-compose up --build :
web-fe_1 exited with code 0
Below are my Dockerfile, docker-compose.yml & app.py
FROM python:3.6-alpine
ENV FLASK_APP app.py
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD [ "flask","run","--host=0.0.0.0","--port=5000"]
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
version: "3.5"
services:
web-fe:
build: .
command: python app.py
ports:
- target: 5000
published: 5000
networks:
- counter-net
volumes:
- type: volume
source: counter-vol
target: /code
redis:
image: "redis:alpine"
networks:
counter-net:
networks:
counter-net:
volumes:
counter-vol:
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
import os
from flask import Flask
from flask_redis import FlaskRedis
app = Flask(__name__)
app.config['REDIS_URL'] = 'redis://redis:6379/0'
redis = FlaskRedis(app)
@app.route('/')
def counter():
return '{0} {1} {2}'.format('Hello! You have visited me:',str(redis.incr('web2_counter')),' times.')
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
This is almost identical to Poulton's counter-app on https://github.com/nigelpoulton/counter-app .. with only difference that my app.py has no call function (if__name__== “main” ).. And the problem is that I would like to make this work without modification to app.py and solve this only through Dockerfile / docker-compose
CodePudding user response:
About your docker-compose.yml
defining networks is not necessary as bridge
network is the default already. You can update your docker-compose.yml
to:
version: "3.5"
services:
web-fe:
build: .
command: python app.py
ports:
- target: 5000
published: 5000
volumes:
- type: volume
source: counter-vol
target: /code
redis:
image: "redis:alpine"
volumes:
counter-vol:
And I geuss changing line app.config['REDIS_URL'] = 'redis://redis:6379/0'
to app.config['REDIS_URL'] = 'http://redis:6379'
CodePudding user response:
You're missing the final 2 lines of his app.py which makes the app listen for connections. When you don't have those 2 lines, your app exits immediately and your container stops.
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
I'm not very good with python. Can you just leave out the 'if' line and keep the 'app.run' line so it always runs?
CodePudding user response:
In your Dockerfile you specify a CMD
that tells the container to flask run
your application. That reads in the app.py
file (from $FLASK_APP
) and launches a Web server. In the docker-compose.yml
file, though, you override this with command: python app.py
which just runs the Python file, without the Flask wrapper.
One way to address this is with @HansKillian's approach to make app.py
call app.run()
itself, but it'd be easier to strip out all of the unnecessary parts from the docker-compose.yml
file. Especially deleting the command:
override should resolve this.
version: "3.5"
services:
web-fe:
build: .
# command: python app.py <-- CMD in the Dockerfile
ports:
- target: 5000
published: 5000
# networks: <-- Compose provides a "default" network
# - counter-net
# volumes: <-- Code is in the image and does not need
# - type: volume to be hidden with a volume
# source: counter-vol
# target: /code
redis:
image: "redis:alpine"
# networks: <-- Compose provides a "default" network
# counter-net:
# networks: <-- Unused
# counter-net:
# volumes: <-- Unused
# counter-vol:
(Compose automatically provides a network named default
for you, so you don't usually need to specify networks:
. The volumes:
declaration mounts a Docker named volume over your application code, so you're not actually running the code in the image. This particular setup will apparently work the first time but ignore any changes if you docker-compose build
the image again.)