Docker in Action - Development to Delivery, Part 1
This is a guest post by Michael Herman from Real Python - learn Python programming and web development through hands-on, interesting examples that are useful and fun!
Let's face it: If your development environment varies from production, you never really know how your application will perform once deployed.
Docker solves this problem. It lets you easily spin up isolated development environments (containers) that are near exact snapshots of the production environment in which it's deployed. Then when you're done developing and testing, you can rest assured that your application will behave the same in production since you deploy the entire snapshot (an image), not just the code.
This three part series will teach you everything you need to know about developing with Docker - from setting up your environments and utilizing Flask on Docker to detailing a powerful development workflow that covers setting up a fully functional development environment, on your Mac, and managing continuous integration and delivery.
Let's begin Part 1...
Tools used: Python v2.7.8, Flask v0.10.1, Docker v1.3.0, boot2docker v1.3.0
First, some Docker-specific terms:
- A Dockerfile is a file that contains a set of instructions used to create an image.
- An image is used to build and save snapshots (the state) of an environment.
- A container is an instantiated, live image that runs a collection of processes.
With that, let's get started!
Since Darwin (the kernel for OS X) does not have the Linux kernel features required to run Docker containers, we need to install boot2docker - which is a lightweight Linux distribution designed specifically to run Docker. In essence, it starts a small VM that's configured to run Docker containers.
Make sure you have VirtualBox installed then create a new directory called "flask-docker" to house your Flask project. Download the zip fle from the project repo. Unzip the file and add the contents to the "flask-docker" file.
Next follow the instructions from Docker to install both Docker and the official boot2docker package.
To get the boot2docker ISO image and set up the VM, initialize boot2docker:
$ boot2docker init
Again, make sure you have VirtualBox installed, and then run the following command to start the VM and run the Docker daemon:
$ boot2docker start
This command should return the
DOCKER_HOST environment variables, which should look something like this:
To connect the Docker client to the Docker daemon, please set:
Copy and paste them directly in your terminal to set the variables. Optional: To make these stick (so they load each time you open your terminal), add them to your bash profile.
Add a new file called Dockerfile in the project directory and add the following:
start with a base image
FROM ubuntu:14.10 MAINTAINER Real Python firstname.lastname@example.org
RUN apt-get update RUN apt-get install -y nginx RUN apt-get install -y supervisor RUN apt-get install -y python3-pip RUN pip3 install uwsgi flask
update working directories
ADD ./app /app ADD ./config /config
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf RUN rm /etc/nginx/sites-enabled/default
RUN ln -s /config/nginx.conf /etc/nginx/sites-enabled/ RUN ln -s /config/supervisor.conf /etc/supervisor/conf.d/
EXPOSE 80 CMD ["supervisord", "-n"] ```
Here we start with an Ubuntu base, install the necessary dependencies on top of it, and then build the Flask application. This file is literally all we need in order to "Dockerize" our app. For more info, check out the official documentation.
Build and run
Let's get the app up and running!
Build the image
$ docker build --rm -t flask-docker-workflow .
Grab a cup of coffee. Or two. This will take some time to build. That said, since Docker caches each step (or layer) of the build process from the Dockerfile, rebuilding will be much quicker because only the steps that have changed since the last build are rebuilt.
Run the container
With the image built, you can now run an instance of your image (the container):
$ docker run -p 80:80 flask-docker-workflow
Docker should now be running a supervisord session.
Open your web browser and navigate to the IP address associated with the
DOCKER_HOST variable - i.e., http://192.168.59.103/, in this example. (Run
boot2docker ip to get the address.) You should see the text "Flask is running on Docker!" in your browser. Try out the
/data endpoint as well.
Conclusion and Next Steps
Once done, kill supervisor (Ctrl-C), then run
boot2docker down to (gracefully) shutdown the VM. Commit your changes locally, and then push to Github.
Next time we'll look at a workflow for continuous integration. Cheers!
Also, be sure to check out these excellent resources for more Docker fun:
Want more on deploying faster without sacrificing code quality? Read our ebook on Getting to Continuous Deployment for tips from experts on moving faster without breaking things.