Docker

Docker is an easy way of packaging your application deployment bundle of code and platform and OS dependencies in one distributable package container. There is nothing for the DevOps to install or configure on bare metal hardware or cloud. It’s as simple as copying the docker package onto the machine and running Docker which will automatically do everything for you.

Docker containers wrap a piece of software in a complete filesystem that contains everything needed to run: code, runtime, system tools, system libraries – anything that can be installed on a server. This guarantees that the software will always run the same, regardless of its environment.

Getting started

Install Docker or use the Toolbox if your PC doesn’t support Hyper-V. Windows 10 Home Edition doesn’t support Hyper-V so you will need to use Docker Toolbox which uses VirtualBox as a subsystem. On Ubuntu Docker requires a 64-bit installation so type the following command to see 32-bit (“i686” or “i386”) or 64-bit (“x86_64”).

01_uname_a_command

For Ubuntu Trusty, Wily, and Xenial, it’s recommended to install the linux-image-extra-* kernel packages. The linux-image-extra-* packages allows you use the aufs storage driver. Follow the instructions given in the links below.

 

CheatSheet

Command Description Example
docker run <image on Docker Hub website><command to run inside container>
  • docker run runs a container.
  • ubuntu is the image you run, for example the Ubuntu operating system image. When you specify an image, Docker looks first for the image on your Docker host. If the image does not exist locally, then the image is pulled from the public image registry Docker Hub.
  • /bin/echo is the command to run inside the new container.

$ docker run ubuntu /bin/echo ‘Hello world’

Hello world

docker run -t -i <image on Docker Hub website><command to run inside container>
  • docker run runs a container.
  • ubuntu is the image you would like to run.
  • -t flag assigns a pseudo-tty or terminal inside the new container.
  • -i flag allows you to make an interactive connection by grabbing the standard in (STDIN) of the container.
  • /bin/bash launches a Bash shell inside our container.

Now, you can play around inside this container. When completed, run theexit command or enter Ctrl-D to exit the interactive shell. Once the Bash shell process has finished, the container stops.

$ docker run -t -i ubuntu /bin/bash

root@ec616158f02c:/# cat /etc/os-release
NAME=”Ubuntu”
VERSION=”16.04.1 LTS (Xenial Xerus)”
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME=”Ubuntu 16.04.1 LTS”
VERSION_ID=”16.04″
HOME_URL=”http://www.ubuntu.com/”
SUPPORT_URL=”http://help.ubuntu.com/”
BUG_REPORT_URL=”http://bugs.launchpad.net/ubuntu/”
UBUNTU_CODENAME=xenial
root@ec616158f02c:/#

  • The OPTIONS “-it” tell Docker to make the container interactive and provide a tty (i.e., attach a terminal)
  • The IMAGE is the “ubuntu:latest” image we pulled down. Note the repository:tag format, which is used throughout docker. By default, the “latest” tag is used, but if we were to use “ubuntu:precise” we’d be using Ubuntu 12.04.
  • The COMMAND is “/bin/bash”, which starts a shell where you can log in
docker run -d ubuntu <image on Docker Hub website><command to run inside container>
  • docker run runs the container.
  • -d flag runs the container in the background (to daemonize it).
  • ubuntu is the image you would like to run.
  • Docker automatically generates names for any containers started

$ docker run -d ubuntu /bin/sh -c “while true; do echo hello world; sleep 1; done”

// a container ID reference is returned

docker ps
  • docker ps – Lists containers.

The docker ps command queries the Docker daemon for information about all the containers it knows about.

$ docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

1e5535038e28 ubuntu /bin/sh -c ‘while tr 2 minutes ago Up 1 minute insane_babbage

docker logs <container name>
  • docker logs – Shows us the standard output of a container.

docker logs looks inside the container and returns hello world.

$ docker logs insane_babbage hello world hello world hello world . . .
docker stop <container name>
  • docker stop – Stops running containers.

The docker stop command tells Docker to politely stop the running container and returns the name of the container it stopped.

$ docker stop insane_babbage

insane_babbage

 docker run -d -P <image on Docker Hub website><command to run inside container>

 The -P flag is new and tells Docker to map any required network ports inside our container to our host. This lets us view our web application.

You can see you’ve specified a new flag, -l, for the docker pscommand. This tells the docker ps command to return the details of thelast container started.

If you want to see stopped containers too use the -a flag.

 $ docker run -d -P training/webapp python app.py

$ docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bc533791f3f5 training/webapp:latest python app.py 5 seconds ago Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morse

 docker run -d -p <local host port>:<inside docker host container port> <image on Docker Hub website><command to run inside container>

 Network port bindings are very configurable in Docker. In our last example the -P flag is a shortcut for -p 5000 that maps port 5000 inside the container to a high port (from ephemeral port range which typically ranges from 32768 to 61000) on the local Docker host. We can also bind Docker containers to specific ports using the -p flag, for example:

This would map port 5000 inside our container to port 80 on our local host. You might be asking about now: why wouldn’t we just want to always use 1:1 port mappings in Docker containers rather than mapping to high ports? Well 1:1 mappings have the constraint of only being able to map one of each port on your local host.

This means you can have more than one containers running but accessed through different ports.

 $ docker run -d -p 80:5000 training/webapp python app.py

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
498dbe34b319 training/webapp “python app.py” 8 seconds ago Up 9 seconds 0.0.0.0:80->5000/tcp agitated_heisenberg
4eac80bc6771 training/webapp “python app.py” 10 minutes ago Up 10 minutes 0.0.0.0:32768->5000/tcp tiny_bhabha

 docker-machine ip <your_vm_name>

Note: If you have been using a virtual machine on OS X, Windows or Linux, you’ll need to get the IP of the virtual host instead of using localhost.

In this case you’d browse to http://192.168.99.100:32768

 $ docker-machine ip

192.168.99.100

docker port <your_vm_name> <port> To use docker port we specify the ID or name of our container and then the port for which we need the corresponding public-facing port.

$ docker port agitated_heisenberg 5000

0.0.0.0:32768

In this case you’ve looked up what port is mapped externally to port 5000 inside the container.

docker logs -f <your_vm_name> This time though you’ve added a new flag, -f. This causes the docker logs command to act like the tail -f command and watch the container’s standard out. We can see here the logs from Flask showing the application running on port 5000 and the access log entries for it. $ docker logs -f agitated_heisenberg
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
docker top <your_vm_name> In addition to the container’s logs we can also examine the processes running inside it using the docker top command. $ docker top agitated_heisenberg
PID USER COMMAND
4238 root python app.py

docker inspect <your_vm_name>

docker inspect -f {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}

We can take a low-level dive into our Docker container using thedocker inspect command. It returns a JSON document containing useful configuration and status information for the specified container.

We can also narrow down the information we want to return by requesting a specific element, for example to return the container’s IP address we would.

$ docker inspect agitated_heisenberg
[
{
“Id”: “498dbe34b3196368c95f586bd366c26ae1fa30c04072c352f1ebd4e98cf0fc7a”,
“Created”: “2016-09-30T11:13:31.478641067Z”,
“Path”: “python”,
“Args”: [
“app.py”
],
“State”: {
“Status”: “running”,
“Running”: true,…….
docker stop / start /restart <your_vm_name> Restart does a stop and then start on the container.
docker rm <your_vm_name>

Removes container. Stop it first beforehand.

And now our container is stopped and deleted.

$ docker stop agitated_heisenberg

agitated_heisenberg

$ docker rm agitated_heisenberg

agitated_heisenberg

docker images List the images you have locally on our host. $ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest c73a085dc378 4 days ago 127.1 MB
hello-world latest c54a2cc56cbb 3 months ago 1.848 kB
training/webapp latest 6fae60ef3446 16 months ago 348.8 MB
docker pull Pre-load Docker image from Docker Hub repo.

$ docker pull centos

Using default tag: latest latest: Pulling from library/centos f1b10cd84249: Pull complete c852f6d61e65: Pull complete 7322fbe74aa5: Pull complete Digest: sha256:90305c9112250c7e3746425477f1c4ef112b03b4abe78c612e092037bfecc3b7 Status: Downloaded newer image for centos:latest

$ docker run -t -i centos /bin/bash

bash-4.1#

docker search Find Docker images on:

Source: hub.docker.com/

docker commit

Update a container created from an image and commit the results to an image given the image ID.

The -m flag allows us to specify a commit message, much like you would with a commit on a version control system. The -aflag allows us to specify an author for our update.

Specify the container you want to create this new image from, 0b2616b0e5a8 (the ID you recorded earlier) and you’ve specified a target for the image:

ouruser/sinatra:v2

$ docker commit -m “Added json gem” -a “Kate Smith” \ 0b2616b0e5a8 ouruser/sinatra:v2

4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c

docker inspect You can also use docker inspect with the container’s name. Container names must be unique. That means you can only call one container web. If you want to re-use a container name you must delete the old container (with docker rm) before you can reuse the name with a new container. Go ahead and stop and remove your old web container.

$ docker inspect web

[ { “Id”: “3ce51710b34f5d6da95e0a340d32aa2e6cf64857fb8cdb2a6c38f7c56f448143”, “Created”: “2015-10-25T22:44:17.854367116Z”, “Path”: “python”, “Args”: [ “app.py” ], “State”: { “Status”: “running”, “Running”: true, “Paused”: false, “Restarting”: false, “OOMKilled”: false, …

docker network Docker includes support for networking containers through the use ofnetwork drivers. By default, Docker provides two network drivers for you, the bridge and the overlay drivers. You can also write a network driver plugin so that you can create your own drivers but that is an advanced task.

Every installation of the Docker Engine automatically includes three default networks. You can list them:

$ docker network ls

NETWORK ID NAME DRIVER 18a2866682b8 none null c288470c46f6 host host 7b369448dccb bridge bridge

 

Inspecting the network is an easy way to find out the container’s IP address.

$ docker network inspect bridge [ { “Name”: “bridge”, “Id”: “f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f”, “Scope”: “local”, “Driver”: “bridge”, “IPAM”: { “Driver”: “default”, “Config”: [ { “Subnet”: “172.17.0.1/16”, “Gateway”: “172.17.0.1” } ] },

docker-machine ls Commands:
active Print which machine is active
config Print the connection config for machine
create Create a machine
env Display the commands to set up the environment for the Docker client
inspect Inspect information about a machine
ip Get the IP address of a machine
kill Kill a machine
ls List machines
provision Re-provision existing machines
regenerate-certs Regenerate TLS Certificates for a machine
restart Restart a machine
rm Remove a machine
ssh Log into or run a command on a machine with SSH.
scp Copy files between machines
start Start a machine
status Get the status of a machine
stop Stop a machine
upgrade Upgrade a machine to the latest version of Docker
url Get the URL of a machine
docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default * virtualbox Running tcp://192.168.99.100:2376 v1.12.1

 

 

Building a Docker File

Each instruction creates a new layer of the image

# This is a comment


FROM ubuntu:14.04


MAINTAINER Kate Smith <ksmith@example.com>


RUN apt-get update && apt-get install -y ruby ruby-dev


RUN gem install sinatra

 

Note: You use # to indicate a comment

The first instruction FROM tells Docker what the source of our image is, in this case you’re basing our new image on an Ubuntu 14.04 image. The instruction uses the MAINTAINER instruction to specify who maintains the new image.

Lastly, you’ve specified two RUN instructions. A RUN instruction executes a command inside the image, for example installing a package. Here you’re updating our APT cache, installing Ruby and RubyGems and then installing the Sinatra gem.

 

Examine what your Dockerfile does. Each instruction prefixes a statement and is capitalized.

INSTRUCTION statement

 

Now let’s take our Dockerfile and use the docker build command to build an image.

$ docker build -t ouruser/sinatra:v2 .

Note: This is just a brief introduction to creating images. We’ve skipped a whole bunch of other instructions that you can use. We’ll see more of those instructions in later sections of the Guide or you can refer to the Dockerfile reference for a detailed description and examples of every instruction. To help you write a clear, readable, maintainable Dockerfile, we’ve also written aDockerfile Best Practices guide.

 

Docker Compose

Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a Compose file to configure your application’s services. Then, using a single command, you create and start all the services from your configuration. To learn more about all the features of Compose see the list of features.

Compose is great for development, testing, and staging environments, as well as CI workflows. You can learn more about each case in Common Use Cases.

Using Compose is basically a three-step process.

  1. Define your app’s environment with a Dockerfile so it can be reproduced anywhere.
  2. Define the services that make up your app in docker-compose.yml so they can be run together in an isolated environment.
  3. Lastly, run docker-compose up and Compose will start and run your entire app.

A docker-compose.yml looks like this:

version:‘2’services: web: build: . ports:“5000:5000” volumes: .:/code – logvolume01:/var/log links: redis redis: image: redis volumes: logvolume01: {}

For more information about the Compose file, see the Compose file reference

Compose has commands for managing the whole lifecycle of your application:

  • Start, stop and rebuild services
  • View the status of running services
  • Stream the log output of running services
  • Run a one-off command on a service

See:

Overview of Docker Compose

Introduction and Overview of Compose

Source: docs.docker.com/compose/overview/

 

References