In this guide, we're going to build a simple Flask application using Docker, more specifically with Docker Compose. A powerful and convenient way to work with and configure Docker containers & services.
We'll be using Nginx as our HTTP webserver and uWSGI as our application server, just like in the previous guide to deploying a Flask app on a virtual machine.
Step #2: Create a docker volume. Next, we create a docker volume that holds the static files. To create a docker volume, run: docker volume create webstatic Step #3: Create the web application service. In this step, we will have to create 3 replicas of the flaskgunicornapp, and put it behind the load balancer. Docker is a very popular container platform that lets you easily package, deploy, and consume applications and services. It has gained a lot of traction in the. VS Code’s docker extension helps in making a basic Dockerfile along with its corresponding image. We and third parties use cookies or similar technologies ('Cookies') as described below to collect and process personal data, such as your IP address or browser information. Docker Compose reads the dockercompose.yml file and builds the applicable ‘docker run’ commands (in the correct order!) to create the multi-container application. While it is possible to create a series of ‘docker run’ commands to build up the multi-container application, Docker Compose simplifies this process significantly.
We're going to cover everything from scratch so don't worry if you've never worked with Docker or Docker Compose before, just make sure you've got them both installed on your machine and we'll try our best to cover the concepts as we go.
To install Docker, head to the link below:
To install Docker compose, head to the link below:
Armed and ready with Docker and Docker Compose? Let's get started!
Application structure
Here's an overview of how our application is going to look:
We'll get started by creating a new directory for our new project and move into it. We'll call ours
app
but feel free to name it whatever you like:Inside of our
app
parent directory, we're going to create a couple more directorires, one for each container - flask
and nginx
:While we're here, let's create our
docker-compose.yml
file here in the app
directory. We'll use this file to define our application services shortly:Feel free to create a
.gitignore
and readme.md
too if you're going to be pushing this project up to Github!Your project should now look something like this:
Let's start off by building the basic Flask app and testing it locally before we do anything else.
The Flask app
Move into the
flask
directory:We'll start by creating a typical Flask project structure that you're likely to be familiar with, but first, let's create a virtual environment:
Activate it:
The only dependencies we require are
flask
and uwsgi
, let's install them with pip
:Once the packages are installed, we'll generate a
requirements.txt
:Now we can move on to building out out app!
Go ahead and create a file called
run.py
. This will be the entrypoint to our app:Open up
run.py
and add the following:run.py
We also need an
ini
file for our uWSGI
configuration, go ahead and create app.ini
and add the following:app.ini
Let's quickly touch on a few of the settings in
app.ini
:wsgi-file = run.py
- The file containing the callable (app
)callable = app
- The callable object itselfsocket = :8080
- The socketuwsgi
will listen on (More on that later!)
You can read more about the
uwsgi
config hereWe need a directory for our application module to live, go ahead and create a new directory called
app
and move into it:We need an
__init__.py
file. Create it, open it up and add the following:app/__init__.py
__init__.py
simply imports Flask
, creates the app
object and imports our views.py
file.The last file we need here is
views.py
containing our app routes. Go ahead and create it and add the following:app/views.py
It's a simple route with the addition of
app_name = os.getenv('APP_NAME')
, which will become apparent later when we use docker-compose.yml
to set some enviromment variables.Your
flask
directory should now look like this:At this point, we're ready to test our application locally!
Testing the Flask app locally
Move back up to the
flask
directory:Just like when we normally run a Flask app, we need to set a few environment variables. Make sure you're in the
flask
directory and run the following:Now, run the app:
Head to http://127.0.0.1:5000/ in your browser and you should see:
If everything worked, use
Ctrl + c
to kill the Flask development server.Flask Dockerfile
A
Dockerfile
is a special type of text file that Docker will use to build our containers, following a set of instruction that we provide.We need to create a
Dockerfile
for every image we're going to build. In this case, both one for Flask and one for Nginx.Make sure you're in the
flask
directory, create a Dockerfile
:Add the following:
flask/Dockerfile
Let's touch on the contents of our
Dockerfile
FROM python:3.7.2-stretch
- Pull thepython:3.7.2-stretch
container base imageWORKDIR /app
- Sets our working directory as/app
ADD . /app
- Copies everything in the current directory to/app
in our containerRUN pip install -r requirements.txt
- Installs the packages fromrequirements.txt
CMD ['uwsgi', 'app.ini']
- Starts theuwsgi
server
You can read the Dockerfile reference here
At this point, your
flask
directory should look like this:The
ADD . /app
instruction in our Dockerfile
is going to copy everything in the flask
directory into the new container, but we don't need it to copy our virtual environment or any cached Python files.Drupal 8 jquery. To prevent this, we can create a
.dockerignore
file, just like how you'd create a .gitignore
file , prioviding a list of file or directory names that we don't want docker to copy over2 to our image.Go ahead and create it:
Add the following:
At this point, your finished
flask
directory should look like this:We're going to use the
docker-compose.yml
file to instruct Docker to build this image shortly, however we still need to setup Nginx.Nginx
Go ahead and move into the
nginx
directory we created in the base of our application:We'll start by creating an Nginx config file that we'll use to setup a server block and route traffic to our application.
Go ahead and create a new file called
nginx.conf
:Open it up and add the following:
nginx/nginx.conf
Inside of the server block:
listen 80;
- Instructs Nginx to listen for requests on port 80 (HTTP)include uwsgi_params;
- Incluses theuwsgi_params
file
To map the server block to an IP address, you'd set the
server_name
value to your servers' IP and place it just under listen 80;
:To map the server block to a domain:
uwsgi_pass flask:8080;
is where things get a little interesting!In our last Flask guide, we deployed a Flask app to a virtual machine, also with Nginx and uWSGI and our Nginx server block looked like this:
You'll notice the
uwsgi_pass
value is differet between the two.On the virtual machine (I.e not using Docker containers) the value for
uwsgi_pass
is unix:/home/username/app/app.sock
, a full path to a local socket file.In this case, HTTP requests coming in are handled by Nginx and proxied to
unix:/home/username/app/app.sock;
where a uwsgi
application server is listening and waiting to handle and requests.However, in the case of our Docker example, we have both Flask and Nginx each in their own container. So how do they communicate?
Docker Compose sets up a single network for our application, where each container is freely reachable by any other container on the same network, and discoverable by their container name.
Naming our Flask container as
flask
will give it a hostname of flask
. Naming our Nginx container nginx
will give it that hostname and so on.We configured
uwsgi
to listen on socket :8080
in the app.ini
file, so now any HTTP requests received by Nginx are proxied to the Flask container using uwsgi_pass flask:8080;
.We name our containers in
docker-compose.yml
so we'll touch more on that shortly.On a side note - we'll cover how to setup a custom domain and HTTPS using certbot in a future guide.
You can learn more about networking in Compose here
To finish up our basic Nginx container, we need to create a
Dockerfile
to build the image.Nginx Dockerfile
Make sure you're in the
nginx
directory and create a Dockerfile
:Open it up and add the following:
nginx/Dockerfile
We've only got 3 instructions in our Nginx
Dockerfile
:FROM nginx
- Pulls the oficial Nginx container imageRUN rm /etc/nginx/conf.d/default.conf
- Removes the default Nginx config fileCOPY nginx.conf /etc/nginx/conf.d/
- Copies thenginx.conf
file we just created into the container
At this point, your
nginx
directory should look like this:Lest thing to do now is create our
docker-compose.yml
.Docker compose
Docker Compose is a powerful tool with lots of features and configuration options available, allowing us to define, build and configure our services & containers all from one place.
We're only touching on some of the basics in this guide but we'd definitely recommend having a read through the documentation here to get a better understanding of the features and options of Compose.
Open up the
docker-compose.yml
file you created earlier and add the following:docker-compose.yml
Let's go through what we've got here and briefly touch on some of the concepts:
Every
docker-compose.yml
file must start with the version, followed by the services we want to build using services:
and indenting any individual services thereafter. In our case - version: '3.7'
.We've defined 2 individual services in the
services
block and named them flask
and nginx
respectively.build: ./flask
- Instructs Docker to build the image using theDockerfile
found in theflask
directory (relative to thedocker-compose.yml
file)container_name: flask
- Gives our container the name offlask
, also assigning it that hostname as we mentioned earlierrestart: always
- Makes the container always restartenvironment
- A place for us to define environment variables for the container.expose
- Exposes internal ports to other containers and services on the same network
You'll see we have a similar setup with the
nginx
service with the only difference being ports
instead of expose
, the two of which serve a fundamentally diffefrent purpose.ports
are mapped as HOST:CONTAINER
and will expose ports to the outside world, which in our case has mapped port 80 on the host machine to port 80 of our Nginx container.expose
on the other hand has simply opened up port 8080
internally, allowing our Nginx container to communicate with the uwsgi
server inside of the flask
container listening on socket 8080
!Right now, your project should be looking like so:
Save the file and jump back into your terminal. We're going to build and test out our app.
Building & testing
Run the following command in the same directory as
docker-compose.yml
to build the services:And now run the following to create and start the containers:
You can optionally run the following to achieve the same result:
You'll notice we didn't have to pass a filename to the command. Compose will look in the current directory for a
docker-compose.yml
file to build!Open up http://127.0.0.1/ or http://localhost/ to see your Flask app in action. You should see:
To stop the service, hit
Ctrl + c
.Docker compose commands
docker-compose
comes with quite a large number of commands and options which can be found by running:We're not going to cover many ot the commands in this guide, so be sure to read the documentation or at least run
docker-compose
and have a read.![Flask docker image Flask docker image](/uploads/1/3/7/7/137789355/768457390.png)
Run the following to list any running images:
docker-compose ps
will list any running containers:LG Smart TV with Magic Mobile offers convenient ways to link compatible smartphones, tablets and more to the television using Bluetooth and Miracast™. Tv cast lg for windows. 1) Download the LG TV app 'TV Cast' on your TV. You can find it in the LG App Store (Smart World / LG Content Store) either in the entertaiment category or by searching for 'TV Cast'. Video & TV Cast For LG Smart TV. Stream Videos to LG Smart TV Play the video and learn how to stream web videos and personal media from your mobile phone or tablet to your LG Smart TV. Connect Video & TV Cast on your phone or tablet with your TV or streaming device.
To stop our services:
Making changes
If you make any changes to the application, you'll have to rebuid the images by running:
The best way to build and test your app is to use the virtual environment we created earlier and the Flask development server.
Docker Flask Api
Once you're happy with how your application is running on the development server, you can test it locally by building the services with Docker Compose.
Next steps
This guide was designed as a gentle introduction to building a basic flask application and running it begind Nginx and uWSGI using containers and Docker Compose, along with some of the Docker and Compose concepts.
Practically speaking, most applications are likely to have more services running alongside them, such as a database, cache, task queue etc, in addition to a domain name, certificates and served over HTTPS.
Some services are also likely to require persistent data, which can be achieved by configuring
volumes
for things such as database data, logs or any other data we'd like to make available between containers. Any data stored in a container will be destroyed when we rebuild it, however we can setup a volume on the host machine as a safe and persistent place to store it. When the containers are destroyed and rebuilt, our data remains!
The great thing about Docker is that now we can simply bolt on additional services, build new images and bring them together using Docker Compose.
In a future part of this series we'll be adding additional services, including:
- Setting up a MongoDB database container
- Setting up Redis container as a cache
- Setting up Certbot to generate a self signed certificate
- Deploying the application
Thanks for reading!
Previous articleDeploying a Flask app on a virtual machine | Learning Flask Ep. 23
Next articleIntroduction to uWSGI | Learning Flask Ep. 25
Flask Docker Compose
Did you find this article useful?
Related items
Building scalable Flask applications from the start using the application factory pattern, blueprints and the current_app proxy
Flask Dockerhub
Using HTTP request methods as the primary means of access control
Python Flask Docker Image
Debugging and connecting to an Azure Cosmos DB using the MongoDB API using PyMongo, PyMODM and MongoEngine
Harnessing the power of Pythons enumerations and exploring the enum module