Docker by Example

By: Seve, Joey, and Richi

Rensselaer Center for Open Source

Outline

  • What is docker?
  • Installing docker
  • What are containers? What are images?
  • Why do developers use docker?
  • How to run containers
  • How to run applications via containers
  • How to make a docker image
  • Docker Compose overview

Examples

This presentation will frequently break to execute examples.

 

To follow along, clone the docker-examples repo:

https://github.com/rcos/docker-examples

 

Warning: Docker will download images for these demonstrations, these images can be removed but may take up 1-3gb

What is Docker ?

Wikipedia Definition

Docker is an open-source project that automates the deployment of applications inside software containers, by providing an additional layer of abstraction and automation of operating-system-level virtualization on Linux.

... nice, thanks, and ?

Linux Containers

Docker is based on LXC (Linux Containers) which allows

it to isolate containers from each other.

 

LXC use mainly two Linux Kernel features:

 

  • Namespaces (Isolation of resources)
  • Cgroups (Isolation of resource usage, as CPU/RAM)

Docker World

Docker can be split in multiple different parts :

 

  • Docker Engine
  • Docker Hub
  • Docker Company

Container VS VM

Container VS Image

Image

An image is an inert snapshot of a container.

 

When runned (with a docker run command) it becomes a container.

 

As images can be quite heavy they are designed to be composed of layers of other images which allows to minimize an image weight, and those layers can be reused between images.

 

Images are stored (mainly) on Docker Hub.

Container VS Image

Image

An image is built from a Dockerfile. A file describing how the image is supposed to behave, what it extends from, ...

 

docker images command lists all local images :

➜  image2 git:(master) ✗ docker images
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
ekkinox/image2                latest              99575a3e62ce        19 minutes ago      126.6 MB
ekkinox/image1                latest              e4d90038788c        32 minutes ago      126.6 MB
doclersfbasicworkshop_nginx   latest              e40e5460d6cb        18 hours ago        183.2 MB
doclersfbasicworkshop_php     latest              29c570fb5d03        18 hours ago        392.3 MB
tianon/true                   latest              2cf9735a9162        19 hours ago        125 B
nazarpc/phpmyadmin            latest              5e14ef86056e        44 hours ago        433.5 MB
php                           5.6-fpm             c90bf43470d1        46 hours ago        362.7 MB
phpmyadmin/phpmyadmin         latest              de9568a72415        2 days ago          116.2 MB
mysql                         5.6                 72bb9d97fb75        11 days ago         328.9 MB
nginx                         stable              5c9792e3619e        2 weeks ago         182.8 MB
ubuntu                        16.04               bd3d4369aebc        3 weeks ago         126.6 MB
ubuntu                        14.04               4a725d3b3b1c        3 weeks ago         188 MB

Container VS Image

Container

Programmatically speaking, if an image is a class, then a container would be an instance of this class.

 

So, you can launch multiple containers for the same image (multiple instances).

docker ps command lists all running containers :

➜  image2 git:(master) ✗ docker ps
CONTAINER ID        IMAGE                         COMMAND                  CREATED             STATUS              PORTS                         NAMES
396fa752515e        ekkinox/image2                "/bin/bash"              20 minutes ago      Up 20 minutes                                     high_panini
aa60196275a3        ekkinox/image1                "/bin/bash"              29 minutes ago      Up 29 minutes                                     reverent_fermi
c7f259822acb        ubuntu:16.04                  "/bin/bash"              36 minutes ago      Up 36 minutes                                     awesome_elion
70ef83fa7097        ubuntu:14.04                  "/bin/bash"              37 minutes ago      Up 37 minutes                                     silly_mclean
698cd8bd50fe        nazarpc/phpmyadmin            "/home/entrypoint.sh"    17 hours ago        Up 17 hours         0.0.0.0:1234->80/tcp          doclersfbasicworkshop_phpmyadmin_1
4c5dd41b5a55        doclersfbasicworkshop_nginx   "nginx -g 'daemon off"   18 hours ago        Up 18 hours         0.0.0.0:80->80/tcp, 443/tcp   doclersfbasicworkshop_nginx_1
e58a4384d27a        mysql:5.6                     "docker-entrypoint.sh"   18 hours ago        Up 18 hours         0.0.0.0:3306->3306/tcp        doclersfbasicworkshop_db_1
faf8aba5cd3c        doclersfbasicworkshop_php     "php-fpm"                18 hours ago        Up 18 hours         9000/tcp                      doclersfbasicworkshop_php_1

Technical Details

Why

  • Run everywhere
    • Regardless of kernel version
    • Regardless of host distro.
    • Physical or virtual, cloud or not
    • Container and host architecture must match...
  • Run anything
    • If it can run on the host, it can run in the container
    • If it can run on a Linux kernel, it can run in the container

What

  • High level: a lightweight VM
    • Own process space
    • Own network interface
    • Can run stuff as root
    • Can have its own /sbin/init (different from host)
  • ​Low Level: Chroot on steroids
    • Can also not have its own /sbin/init
    • Container = isolated processes
    • Share kernel with host

Why Developers Care

  • ​A clean, safe, hygienic, portable runtime environment for your app.
  • No worries about missing dependencies, packages and other pain points during subsequent deployments.
  • Run each app in its own isolated container, so you can run various versions of libraries and other dependencies for each app without worrying.
  • Automate testing, integration, packaging... anything you can script.
  • Reduce/eliminate concerns about compatibility on different platforms.
  • Cheap, zero-penalty containers to deploy services. A VM without the overhead of a VM. Instant replay and reset of image snapshots.
  • Makes the entire lifecycle more efficient, consistent, and repeatable

Example 00

Installing Docker

Install Docker: https://docs.docker.com/engine/installation/

Go ahead and install Docker and we'll help you out if you have any problems/question

Build our first container

$ docker run -itd ubuntu:16.04

To create a container from the official ubuntu image :

To enter into a container with your terminal (logged as root):

$ docker exec -it CONTAINERID bash

To check your running containers and their ids :

$ docker ps

Example 01

Run cowsay in an ubuntu container!

Containers on Docker Hub

Many applications put containers on docker hub.

 

Docker hub usually gives simple instructions for running the image, independent of the host operating system!

Example Docker Hub Image

Example 02

Running a docker application from existing images

Turning containers into images

As said before : 

 An image is a snapshot of a container

Let's take a snapshot of our container :

$ docker commit -m "First commit" CONTAINERID ekkinox/image1

Build a container

You can now create as many container from this image as you want :

$ docker run -dit ekkinox/image1

-d : Daemonized

-it : Allocate TTY

Image name

Dockerfile

This approach is nice but as developers

we highly prefer working in files than terminals, right ?

 

That's why Docker uses Dockerfiles.

Dockerfile

A Dockerfile is a translation of what the image will be :

FROM ubuntu:16.04

MAINTAINER Jonathan VUILLEMIN <ekkinox@gmail.com>

RUN mkdir -p /home/ekkinox

To build an image from this Dockerfile :

$ docker build -t ekkinox/image2 .

Container

To create a container from our new image :

$ docker run -dit ekkinox/image2

-d : Daemonized

-it : Allocate TTY

Image name

Example 03

Build a Dockerfile

How to Dockerize Your Application! 

 

Process:

  1. Pick a base image (ubuntu, node, python, etc.)
  2. Copy your application
  3. Install your dependencies
  4. Run your Application

 

Dockerfile

# Choose base image
FROM node:argon

# Copy application files
COPY . /usr/src/app

# Set working directory
WORKDIR /usr/src/app

# Install app dependencies
RUN npm install

# Expose Container's port 
EXPOSE 3001

# Run the application
CMD [ "node", "app.js" ]

Code changes impacts

A better solution ? volumes

First, remove the COPY directive from our Dockerfile:

# Choose base image
FROM node:argon

# Set working directory
WORKDIR /usr/src/app

# Install app dependencies
RUN npm install

# Expose Container's port 
EXPOSE 3001

# Run the application
CMD [ "node", "app.js" ]

And build & run the container with a volume (-v)

$ docker build -t exampleApp .
$ docker run -v .:/usr/src/app exampleApp

And now we can see the changed behavior !

Docker Commands

Useful Docker Commands

# List docker images
docker images

# List running docker containers
docker ps

# Retrieve, Log and Follow output from docker container
docker logs -f <container-id>

# Enter terminal of container
docker exec -it <container-id> bash

Docker Hub

Docker Hub contains a lot of images for various purposes.

 

Docker Hub provides a free storage facility for your public images and a paying storage facility for your private images (GitHub style).

Login to Docker Hub

docker login

Build your image

docker build -t seveibar/exampleApp .

Push on Docker Hub

$ docker push seveibar/exampleApp

Pull from Docker Hub

$ docker pull seveibar/exampleApp

Automated Builds

Docker Hub allows you to link a GitHub repository to a Docker Hub repository.

 

Your GitHub repository should contain a Dockerfile on the root directory.

 

Each time you push on GitHub, Docker Hub (through webhooks) will pull your repository and build an image into your Docker Hub repository.

Orchestration

So, running all containers by hand can

be really messy and complicated... saw it.

 

"Damned, i'll never use this Docker stuff..."

Orchestration

For the moment our simple application requires us to do those kind of commands :

$ docker run \
--name mysql \
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_DATABASE=ekkinox \
-d \
mysql

$ docker run \
-v /home/nox/Dev/docker_workshop/php-fpm/script:/usr/src/myscript \
my-php-script2

$ ... and more and more pain 0_x !

Orchestration

Solutions ?

 

  • Put those commands into a README ?
  • Put those commands into a bash script ?

 

No. Bad idea.

 

The solution is Docker compose

Orchestration

Docker compose works by putting a single yaml file in your project.

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.

Orchestration

version: '2'
services:
  web:
    build: .
    ports:
    - "5000:5000"
    volumes:
    - .:/code
    - logvolume01:/var/log
    links:
    - redis
  redis:
    image: redis
volumes:
  logvolume01: {}

A docker-compose.yml looks like this:

 

Orchestration

Some docker useful commands:

# Stops all containers
$ docker stop $(docker ps -a -q)


# Delete all containers
$ docker rm $(docker ps -a -q)


# Delete all images
$ docker rmi $(docker images -q)

Orchestration

Some docker-compose useful commands:

$ docker-compose up -d
$ docker-compose down
$ docker-compose build
$ docker-compose logs -f
$ docker-compose restart

Example 04

Building a simple docker-compose application 

Scalability

Docker compose allows you to multiply a container by using the scale command :

$ docker-compose scale nginx=5

To allow links to properly function you have to stop and remove your nginx container and relaunch it :

$ docker-compose stop nginx
$ docker-compose rm nginx
$ docker-compose run -d nginx

Thanks

  • RPI and RCOS
  • Professor Goldschmidt
  • Professor Moorthy
  • Professor Turner
  • Docker
  • Red Hat
  • Microsoft
Made with Slides.com