Install and Configure Docker

Install pre-requisites.

sudo yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2


Set up the stable respository.

sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

Returns.

adding repo from: https://download.docker.com/linux/centos/docker-ce.repo
grabbing file https://download.docker.com/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo


Install the latest version of Docker Community Edition (CE) and containerd.

sudo yum install docker-ce docker-ce-cli containerd.io


Start Docker.

sudo systemctl start docker


Enable Docker to start at bootup.

systemctl enable docker

Returns.

Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.


Verify that Docker CE is installed correctly by running the hello-world image.

sudo docker run hello-world

Returns.

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:41a65640635299bab090f783209c1e3a3f11934cf7756b09cb2f1e02147c6ed8
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.


Create the docker group.

sudo groupadd docker


Add current user to the docker group.

sudo usermod -aG docker $USER


For this change to take effect you will need to logoff and log back into the VM.   In some cases you may need to restart the VM.

az vm restart --resource-group Py4SAS --name Py4SAS-vm


Configure Docker to start on boot.

sudo systemctl enable docker

Returns:

Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.


Fetch local Docker images.

docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        5 months ago        1.84kB


Build Docker Image

Create a Docker container using a redis in-memory database to count web visitors along with flask as a Python-based web development framework.

Create new directory.

mkdir $HOME/docker-test
cd $HOME/docker-test


Create the app.py script.

from flask import Flask
from redis import Redis, RedisError
import os
import socket

# Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)

app = Flask(__name__)

@app.route("/")
def hello():
    try:
        visits = redis.incr("counter")
    except RedisError:
        visits = "<i>cannot connect to Redis, counter disabled</i>"

    html = "<h3>Hello {name}!</h3>" \
           "<b>Hostname:</b> {hostname}<br/>" \
           "<b>Visits:</b> {visits}"
    return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)


The script needs the Flask and Redis libraries.   Create the requirements.txt file to make these libraries available inside the Docker container.

Flask
Redis


To create a Docker container create a text file called Dockerfile.

# Use an official Python runtime as a parent image
FROM python:2.7-slim

# Set the working directory to /app
WORKDIR /app

# Copy the current directory contents into the container at /app
ADD . /app

# Install any needed packages specified in requirements.txt
RUN pip install -r requirements.txt

# Make port 80 available to the world outside this container
EXPOSE 80

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]


Build the Docker image with the build sub-command and give it the tag first_container.

docker build -t first_container .

Truncated output.

Successfully built 96f924107cbf
Successfully tagged first_container:latest


Verify the Docker image is built.

docker images


Returns.

REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
first_container     latest              96f924107cbf        About a minute ago   131MB
python              2.7-slim            ca96bab3e2aa        2 weeks ago          120MB
hello-world         latest              fce289e99eb9        5 months ago         1.84kB


Open port 8000.

az vm open-port --priority 1002 --resource-group Py4SAS --name Py4SAS-vm --port 8000


Run the Container

Run the app inside the container.

docker run -p 8000:80 first_container

Returns:

* Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)


The ps sub-command shows the running container.

docker ps

Returns.

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES
4ee5209e8094        first_container     "python app.py"     2 minutes ago      Up 2 minutes       0.0.0.0:8000->80/tcp   agitated_curie


Load the page on port 8000.

Cover Art

Stop the container.

docker stop 4ee5209e8094

Returns.

4ee5209e8094


Docker Commands

Show running containers.

docker ps -a


Force a container to remain running.

docker run -d -p 38080:38080 containerID tail -f /dev/null


Remove all stopped containers.

docker rm $(docker ps -q -f status=exited)


Docker Compose

For complex applications with a lot of components,   orchestrating all the containers to start up and shut down together and communications can quickly become unwieldy.   Docker Compose makes it easier for users to orchestrate the processes of Docker containers including start up,   shut down,   and setting up intra-container linking and volumes.

Download Doker Compose.

sudo curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

Returns.

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   617    0   617    0     0   1799      0 --:--:-- --:--:-- --:--:--  1798
100 15.4M  100 15.4M    0     0  25.5M      0 --:--:-- --:--:-- --:--:-- 25.5M


Make the file executable.

sudo chmod +x /usr/local/bin/docker-compose


Validate Docker compose.

docker-compose --version

Returns.

docker-compose version 1.24.1, build 4667896b


Test a deployment by creating the hello-world directory and creating the docker-compose.yml file.

mkdir ~/hello-world  && \
cd ~/hello-world


Create the docker-compose.yml file.

vi docker-compose.yml

Adding.

az-test:
  image: hello-world

Where az-test names the container and the image pulled is hello-world.


Build-up the container.

docker-compose up

Returns.

Pulling az-test (hello-world:)...
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:6540fc08ee6e6b7b63468dc3317e3303aae178cb8a45ed3123180328bcc1d20f
Status: Downloaded newer image for hello-world:latest
Creating hello-world_az-test_1 ... done
Attaching to hello-world_az-test_1
. &nbsp; . &nbsp; .
hello-world_az-test_1 exited with code 0


To list a group of Docker containers (both stopped and running),   use the following command:

 docker-compose ps -a

Returns.

        Name            Command   State    Ports
------------------------------------------------
hello-world_az-test_1   /hello    Exit 0