In my last post, we learned some basic concepts related to Docker, and we learned a few basic operations for using Docker containers. In this post, we will develop a simple application using Docker. Along the way we will learn how to use Dockerfiles and Docker’s amazing ‘compose’ feature to link multiple containers together.
We will be building a simple clone of Reddit’s very awesome and mysterious “The Button”. The application will be written in Python using the Flask web framework, and will use Redis as it’s storage backend. If you do not know Python or Flask, fear not, the code is very readable and you are not required to understand the code to follow along with the Docker-specific sections.
Before we get started, we need to create a few files and directories. First, go ahead and create a Dockerfile, requirements.txt (where we will specify project-specific dependencies), and a main app.py file.
touch Dockerfile requirements.txt app.py
Next we will create a simple endpoint that will return “Hello World”. Go ahead and edit your app.py file to look like such:
from flask import Flask app = Flask(__name__) @app.route('/') def main(): return 'Hello World!' if __name__ == '__main__': app.run('0.0.0.0')
Now we need to tell Docker how to build a container containing all the dependencies and code needed to run the app. Edit your Dockerfile to look like such:
1 FROM python:2.7 2 3 RUN mkdir /code 4 WORKDIR /code 5 6 ADD requirements.txt /code/ 7 RUN pip install -r requirements.txt 8 9 ADD . /code/
11 EXPOSE 5000
Before we move on, let me explain the basics of Dockerfiles.
A Dockerfile is a configuration file that specifies instructions on how to build a Docker container. I will now explain each line in the Dockerfile we just created (I will reference individual lines).
1: First, we specify the base image to use as our starting point (we discussed this in more detail in the last post). Here we are using a stock Python 2.7 image.
3: Dockerfiles can container a few ‘directives’ that dictate certain behaviors. RUN is one such directive. It does exactly what it sounds like – runs an arbitrary command. Here, were are just making a working directory.
4: We use WORKDIR to specify the main working directory.
6: ADD allows us to selectively add files to the container during the build process. Currently, we just need to add the requirements file to tell Docker while dependencies to install.
7: We use the RUN command and python’s pip package manager to install all the needed dependencies.
9: Here we add all the code in our current directory into the Docker container (add /code).
11: Finally we ‘expose’ the ports we will need to access. In this case, Flask will run on port 5000.
Building from a Dockerfile
We are almost ready to build an image from this Dockerfile, but first, let’s specify the dependencies we will need in our requirements.txt file.
I am using specific versions here to ensure that your version will work just like mine does. Once we have all these pieces in place we can build the image with the following command.
> docker build -t thebutton .
We are ‘tagging’ this image with an easy-to-remember name that we can use later. Once the build completes, we can run the container and see our message in the browser.
> docker run -p 5000:5000 thebutton python app.py
We are doing a few things here: The -p flag tells Docker to expose port 5000 inside the container, to port 5000 outside the container (this just makes our lives easier). Next we specify the image name (thebutton) and finally the command to run inside the container – python app.py – this will start the web server and server for our page.
We are almost ready to view our page but first, we must discover which IP the site will be on. For linux-based systems, you can use localhost but for Mac you will need to run boot2docker ip to discover the IP address to visit.
Navigate to your site (in my case it’s 192.168.59.103:5000) and you should see “Hello World” printed. Congrats! You are running your first site from inside a Docker container.
Putting it All Together
Now, we are going to complete the app, and use Docker Compose to launch the entire project for us. This will contain two containers, one running our Flask app, and another running an instance of Redis. The great thing about docker-compose is that you can specify a system to create, and how to connect all the containers. Let’s create our docker-compose.yml file now.
redis: image: redis:2.8.19 web: build: . command: python app.py ports: - "5000:5000" links: - redis:redis
This file specifies the two containers (web and redis). It specifies how to build each container (we are just using the stock redis image here). The web container is a bit more involved since we first build the container using our local Dockerfile (the build: . line). Than we expose port 5000 and link the Redis container to our web container. The awesome thing about linking containers this way, is that the web container automatically gets information about the redis container. In this case, there is an /etc/host called ‘redis’ that points to our Redis container. This allows us to configure Redis easily in our application:
db = redis.StrictRedis('redis', 6379, 0)
To test this all out, you can grab the complete source here. All you will need to run is docker-compose up and than access the site the same way we did before.
Congratulations! You now have all the tools you need to use docker effectively!
About the author
Julian Gindi is a Washington DC-based software and infrastructure engineer. He currently serves as Lead Infrastructure Engineer at [iStrategylabs](isl.co) where he does everything from system administration to designing and building deployment systems. He is most passionate about Operating System design and implementation, and in his free time contributes to the Linux Kernel.