At Hootsuite, my team was working with a dockerized flask app. Because we hadn’t set up hot-reloading, when we were making updates to the flask app and testing locally, we had to manually tear down the containers and bring them back up between each change. This took some time, and was mildly disruptive to our […]
At Hootsuite, my team was working with a dockerized flask app. Because we hadn’t set up hot-reloading, when we were making updates to the flask app and testing locally, we had to manually tear down the containers and bring them back up between each change. This took some time, and was mildly disruptive to our workflow, so I worked on setting up hot-reloading.
First, let’s create a directory to house the code.
Create a requirements.txt file.
And add flask to the requirements.txt file
Now let’s make the actual flask app.
Check that the app is working.
We export FLASK_APP to tell flask where to find our application. flask run has to be run in the same terminal as export FLASK_APP=app.py is run.
* Serving Flask app "app"
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Visit the site, and you should see something like this:
If you skipped the previous step, you can use this starter code
We’ll have a separate dockerfile for Nginx, so let’s call this Dockerfile-flask.
We start with the base Python 3 image.
Create and designate /app as the work directory.
RUN mkdir /app
Expose the port for our app.
Because of how docker caches, it’s best to first copy the files that we don’t expect to change often. For this project, that’s the requirements.txt file.
COPY requirements.txt .
Install the requirements.
RUN pip install -r requirements.txt
Copy the rest of the files.
COPY . .
Run uwsgi with a config file.
CMD [ "uwsgi", "--ini", "app.ini" ]
Start with the Nginx image.
Expose port 80 for Nginx.
Replace the default config with a custom config
RUN rm /etc/nginx/conf.d/default.conf
COPY app.conf /etc/nginx/conf.d
image: defines the name of the image, which can be anything we want
context: tells docker where to look for files to build the image
dockerfile: defines the dockerfile to use, which is just the dockerfiles we created in the previous steps.
This mounts the root directory of our project on the host machine (./) onto a directory named app under the root directory in the container (/app).
This maps port 5000 on our machine to port 80 on the Nginx container. This is important because Nginx listens on port 80 by default, but our app is running on port 5000.
You should now be able to reach the app on localhost:5000 after running docker-compose up
If you skipped the previous steps, you can use this starter code
uwsgi has a touch-reload configuration which allows us to designate a file to cause an update whenever the touch command is applied on it. However, we can only supply one file, so we use watchman to detect updates in our python files, and run touch <FILE> to trigger the uwsgi reload. I’ll be using a dedicated file named uwsgi-reload. To do this, add touch-reload = uwsgi-reload to the app.ini file.
To check for updates to our python files, we can run watchman-make -p '**/*.py' -s 1 — run ‘touch uwsgi-reload’.
-p '**/*.py' specifies the pattern for which files to watch for changes. Specifically, we’re looking for any file that ends in .py (*.py) at any level (**/) in our project.
-run 'touch uwsgi-reload' tells watchman to run touch uwsgi-reload whenever it detects an update. This will then trigger uwsgi to reload, since it’s watching the uwsgi-reload file.
-s 1 tells watchman to wait until there is 1 second without any updates before running touch uwsgi-reload. This essentially means that it will wait for you to stop typing for 1 second before triggering the reload, so it’s not constantly triggering reloads as you’re typing.
Now, if we run the watchman-make command after docker-compose up, the project will reload whenever you make an update to a .py file. We can use make to run this automatically instead.
We run docker-compose up with the -d flag so it runs in a detached state. This allows the terminal to hit the watchman-make command without shutting down the containers.
With this makefile, we can start the project with hot-reloading with make start, and stop it with make stop (after terminating the watchman-make command).
Now if you run make start, you should be able to see your changes in real time. Try changing the 'Hello World!' to something else!
Creation of dockerized flask app based on this article