On the web are dozens of posts on how to dockerize the flask app that describes how to create a container with an embedded flask app. But it is not suitable for development purposes, as you need to change the sources and restart the flask on the fly.
Setting up the python dev environment in Flask is only appropriate when you are not going to play with your app venv (install new packages or upgrade packages or python version). In that case, when you need to build the environment for your app you should set up classic venv on your desktop. The dockerized developer environment is useful when you only want to develop your code having frozen 3rd part packages or in the case of a larger team, to have the quick setup and the same dev env.
Do not put Docker files into subdirectories in your project. It should be at the root of your project otherwise you will run into problems with paths.
Project - docker_compose.yml - Dockerfile - Postgresql - Dockerfile - app (Flask App) - venv - requirements.txt
docker build -f ./Docker/web.Dockerfile .
According to Docker documentation:
The path must be inside the context of the build; you cannot COPY ../something /something, because the first step of a docker build is to send the context directory (and subdirectories) to the docker daemon.
The development files are quite simple and notice, that we cannot copy the sources to the image. We will mount them as a volume so we can edit the sources in the running container.
FROM python:3.9-bullseye COPY requirements.txt requirements.txt RUN pip install -r requirements.txt
Test the build
docker build .
Test the build
docker build ./Postgresql
Note that for accessing the database from the flask container you should provide the address IP to the database container. Instead of
SQLALCHEMY_DATABASE_URI = 'postgresql+psycopg2://lhcom4:firstname.lastname@example.org/lhcom4'
Now we have got ready images to run containers.
But we need to run containers with parameters (eg. database cluster, python sources etc.)
We can prepare shell scripts to run our infrastructure but the better way is to create the
version: '2' services: web4: build: . ports: - "5000:5000" depends_on: - postgres postgres: restart: always build: Postgresql volumes: - /Users/lukasz/docker_volumes/postgres:/var/lib/postgresql/data:z environment: - POSTGRES_PASSWORD=pass expose: - "5432" ports: - "5432:5432"
This file is also simplified for Pycharm. On MacOS remember to disable AirPlay to make 5000 port available: Resources.
Set the Project Interpreter to run the configuration form the compose file.
/opt/project is the dir where PyCharm helper will mount automatically our project.
The next step is to create Run configuration for our flask project. The example microblog.py file is the file that creates our flask app.
You should see output similar to:
FLASK_APP = microblog.py FLASK_ENV = development FLASK_DEBUG = 0 In folder /Users/lukasz/PycharmProjects/lhcom4 /usr/local/bin/docker-compose -f /Users/lukasz/PycharmProjects/lhcom4/docker-compose.yml -f /Users/lukasz/Library/Caches/JetBrains/PyCharm2022.1/tmp/docker-compose.override.209.yml up --exit-code-from web4 --abort-on-container-exit web4 Recreating lhcom4_postgres_1 ... Recreating lhcom4_web4_1 ... Attaching to lhcom4_web4_1 web4_1 | * Serving Flask app "microblog.py" web4_1 | * Environment: development web4_1 | * Debug mode: off web4_1 | * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
...and you will not be able to open the http://127.0.0.0.:5000 :), as it is run inside the container and listens on the container's localhost. We want to access it from the outside (our workstation). So we need to change the Flask app to listen on all the interfaces (0.0.0.0) by passing the argument
Edit the autogenerated PyCharm runtime and change the:
- Additional options
Now in the output you will see changes:
FLASK_DEBUG = 1 web4_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
As I wrote before the
docker-compose.yml for Pycharm could be simplified as we need to do the configuration in PyCharm itself an take advantage of its automatiztion. The docker-compose for running manually could look like:
version: '2' services: web4: build: . ports: - "5000:5000" environment: - FLASK_APP=/usr/src/microblog.py - FLASK_DEBUG=1 volumes: - .:/usr/src/ command: flask run --host=0.0.0.0 --port=5001 depends_on: - postgres postgres: restart: always build: Postgresql volumes: - /Users/lukasz/docker_volumes/postgres:/var/lib/postgresql/data:z environment: - POSTGRES_PASSWORD=pass expose: - "5432" ports: - "5432:5432"