Part 2 — Introduction to Software Deployment with Docker

John Olafenwa
Dev Planet
Published in
6 min readAug 22, 2019

In part 1 of this series, we introduced the concept of containerizing apps with docker with a focus on creating docker images, publishing and running them. In this second part, we shall explore some of the fundamental features of docker containers, including container life cycle, environment variables, and app versioning with tags.

The ultimate goal of this docker series is to give you foundation knowledge in container technologies in preparation for the next series on Kubernetes, the container management platform built for deploying containers at scale in production.

Container Lifecycle

Docker was built to enable us easily package applications as light-weight isolated processes. Every run of a docker image creates a new named container that acts independently, can be stopped, restarted and deleted as needed. To illustrate how containers run, we shall run two separate instances of our example docker image from the previous tutorial.

sudo docker run --name appone -p 80:5000 username/myapp
sudo docker run --name apptwo -p 81:5000 username/myapp

The — name parameter is new here, it enables us uniquely identify each running container, stop and restart it as needed.

Now, open a new terminal and run

sudo docker ps

As you can see above, the output of docker ps shows a number of details about each running container. The CONTAINER ID and NAME performs can both be used to restart, stop or delete the containers as needed. We shall be using the NAME throughout this tutorial.

Stopping Your Container

You can stop any of your containers as seen below

sudo docker container stop appone

If you try to access your app on localhost:80, it will no longer be accessible.

Starting Your Stopped Container

After you stop your container, you can use the docker start command to start it again.

sudo docker start appone

Now you can access your site on localhost:80 again.

Note here that unlike the docker run, with docker start we do not need to specify the port and other properties as this has already been attached when we created the container with docker run. We are just starting it back here.

Restarting Your Container

This will stop and start your container

sudo docker restart appone

Deleting Your Container

When you delete your container, it is no longer in existence and you cannot do a docker start to resume it, you will have to do a docker run to create it again.

sudo docker stop apponesudo docker rm appone

Since your container is presently running, you had to stop it before running the rm command.

You can also force-stop it in one step using

sudo docker rm apptwo -f

Environment Variables

Environment variables are used to pass important information to processes at runtime. Such variables might include access keys, service urls, tokens etc.

Here we shall demonstrate how to pass environment variables to docker containers using a simple python app.

You will find this example in the DevPlanet repo

git clone https://github.com/johnolafenwa/devplanet

The files are in samples/docker/env-variables

app.py

Dockerfile

The app.py file simply checks for the presence of an environment variable named USERNAME and prints it to the console. The Dockerfile here is very simple, since this is a basic console app, all it does is to create the /app directory, copy the app.py to it and run the file with the CMD command.

Let’s build the app.

sudo docker build -t consoleapp .

Now run the app

sudo docker run -e USERNAME="John" consoleapp

As you can see above, our app retrieved the USERNAME variable and printed our input to the console.

You can also specify default values in your Dockerfile. The default values will be used if you don’t specify the value of the variable while running your container, we will modify our Dockerfile as seen below.

Note the ENV USERNAME Jack, the ENV command is used to specify default environment variables.

Lets rebuild the image with the new docker file

sudo docker build -t consoleapp .

Now run the app without specifying the variable

sudo docker run consoleapp

And with it specified

sudo docker run -e USERNAME=”Sarah” consoleapp

Your output should be this

As you can see above, when we didn’t specify the variable, the default value of Jack was printed.

It is absolutely important to never hardcode secrets in your app source code or package them with your app image. Tokens, access keys etc should always be supplied by environment variables at runtime. This is a strongly recommended way of avoiding exposing security details. See https://12factor.net/config

Docker Image Tagging

One of the beauties of docker is how it makes it easy for us to version our applications using tags. Tagging enables you to make updates in a reliable and consistent way while ensuring you can rollback to previous versions of your app with a single command.

The standard format for a docker image is image:tag

When you build your images, you would notice outputs like this.

Successfully tagged consoleapp:latest

The default tag for your images is latest however, you can version your app by using specific tags.

Here we shall create separate versions of our webapp from part 1 of this tutorial.

The app.py for the webapp was

Now for the v2 of our app, we shall add the modifications below.

Now lets build this version

sudo docker build -t username/myapp:v2 .

Remember to replace username with your docker username

Run the app

sudo docker run -p 80:5000 username/myapp:v2 

Lets create the v3 of our app with the app.py modified as below.

Build the new version with

sudo docker build -t username/myapp:v3 .

Run the v3

sudo docker run -p 80:5000 username/myapp:v3

All of our versions exist indepently and we can run any of them at anytime.

You can push v2 to docker hub

sudo docker push username/myapp:v2

And v3

sudo docker push username/myapp:v3

You can also push all versions/tags to the docker hub in one command

sudo docker push username/myapp

Summary

Proper understanding of the fundamentals of docker is key to understanding cloud native technologies.

In this tutorial, we went through managing the state of containers, supplying important information via environment variables and lastly, we explained how docker tags makes it easy to version apps. In CI/CD pipelines, images are usually tagged with the git commit id .

In the next tutorial, we shall explain two core concepts, building stateful apps with data storage in docker and using docker compose to manage our containers.

--

--