Search code examples
dockerflaskdocker-image

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.


Solution

  • 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.