Docker

 

Online Playground

* Play with Docker: https://labs.play-with-docker.com/

Overview

* Docker leverages Linux OS features (x64/3.10):
– process isolation
– filesystem isolation
* Docker editions:
– Docker EE (Enterprise Edition)
– Docker CE (Community Edition)
* Default port: 3275
* Socket file: /var/run/docker.sock

Docker Advantages

* No OS virtualization for Docker means:
– Smaller disk footprint
– Faster setup/startup/stop time
– Can be pulled from repository and pushed to targets
– Cost savings
* Supports:
– Microservices

Windows Docker Containers

* Different from Linux based containers
* Supported in:
– all versions of Windows Server 2016 (Full, Core, Nano)
– Windows 10 Enterprise/Professional edtions
– Azure
* Containers can be deployed/managed from any Docker client, e.g.
– command line
– Powershell
* Supports:
– Docker image format/Docker API
* Two types:
– Windows Server container (on Windows Server)s
|- shared OS kernel
|- pros: performance/efficiency
|- cons: weak isolation/security
– Hyper-V container (on Windows Nano Server)
|- dedicated OS kernel/memory
|- pros: strong isolation/security

Install Docker Engine CE

* Auto install script:

sudo curl -sSL https://get.docker.io/ # -s: silent, -S: show errors, -L: location
sudo wget -qO- https://get.docker.io/ # -q: quiet, O-: output to stdout

Ubuntu Manual Install

# Update repo
sudo apt-get update
 
# Add Docker repo to apt sources
sudo sh -c "echo deb https://apt.dockerproject.org/repo \
  ubuntu-xenial main > /etc/apt/sources.list.d/docker.list"
 
	# Add GPG key
sudo apt-key adv --keyserver \
	 hkp://p80.pool.sks-keyservers.net:80 --recv-keys \    
	 58118E89F3A912897C070ADBF76221572C52609D
 
	 # Resync repo
sudo apt-get update
 
# Install Docker and start Docker service
sudo apt-get install -y docker-engine
 
# Verify install
sudo docker version
sudo docker info

Download and Install Docker Image

# Download and install hello-world image
sudo docker pull hello-world
 
# Show/verify install/images
sudo docker images
 
# Run hello-world image
docker run hello-world
 
# Download/install/Run ubuntu in interactive mode
docker run -it ubuntu bash

Docker Lifecycle Commands

# List docker processes
docker ps -a
 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS          PORTS               NAMES
16d1621a6ceb        ubuntu              "bash"              3 minutes ago       Exited (0) 6 seconds ago            happy_tesla
 
# Start by ID
sudo docker start 16d1621a6ceb
 
# Start by Name
sudo docker start happy_tesla
 
# Attach
sudo docker attach id/name
 
# Detach:
CtrlP + CtrlQ
 
# Start but remove when state is exited
sudo docker run -it --rm ubuntu:16.04 /bin/bash
 
# Restart
sudo docker restart id/name
 
# Pause
sudo docker pause id/name
 
# UnPause
sudo docker unpause id/name
 
# Remove docker image
sudo docker rm id/name
 
# Remove all stoped images
sudo docker rm $(sudo docker ps -aq -f status=exited)
sudo docker container prune

Troubleshooting

# Check status
sudo service docker status
 
# Restart Docker
sudo service docker restart
 
# Extract Docker log
journalctl -u docker
 
# List Docker processes
sudo docker ps
sudo docker ps -a

Manage Docker Containers

Terms

Docker Image

* Docker image is:
– a collection of all the files that make up an executable software app (compare to dll and jar files for software but at app level)
– readonly template (compare to Java class)
* Includes:
– libraries
– binaries
– other dependencies
* Capabilities can be added as layers to existing image

Docker Container

* Running instance of a Docker image (compare to Java class instance)
– A writeable layer is added on top of the image to maintain the app state

Docker Registry

* Images can be pushed to or pulled from registry
* Can be public or private
* Example registries:
– Docker Hub: index.docker.io
– Quay
– Google Container Registry
– AWS Container Registry

* Search for an image

sudo docker search mysql | head -10

* Pull an image

# Pull busybox image from Docker Hub
sudo docker pull busybox
 
# Pull version 1.2 of busybox image from Docker Hub
sudo docker pull busybox:1.2
 
# Pull version 1.2 of busybox image from Docker Hub under developer named dockerguy
sudo docker pull dockerguy/busybox:1.2
 
# Pull version 1.2 of busybox image from my local registry
sudo docker pull registry.mylocal.com/busybox:1.2
 
# Examing pulled image
sudo docker images
 
# You can diff images
sudo docker diff id/name
 
# Commit image
sudo docker commit id mydocker/ubuntu_wget # Don't use

* Run image in interactive mode

-a=[]           : Attach to `STDIN`, `STDOUT` and/or `STDERR`
-t              : Allocate a pseudo-tty
--sig-proxy=true: Proxy all received signals to the process (non-TTY mode only)
-i              : Keep STDIN open even if not attached

– Example:

# Run Ubuntu image in interactive mode
sudo docker run -it ubunbu:16.04 # -i: interactive, -t: terminal emulation
 
# Detach from interactive session with CtrlP + CtrlQ
 
# Attach back into interactive session
sudo docker attach id/name
 
# Terminate Docker container with exit command

* Run image in detached mode

sudo docker run -d ubuntu

Building Images using Dockerfile

Example

* Create a file named: Dockerfile

FROM busybox:latest
CMD echo Hello World!!

* Build using Dockerfile file in current directory with name busybox2

sudo docker build -t mybusybox .

Dockfile Instructions

* Specify escaple character, default is \

# escape='

* FROM

FROM <image>[:<tag>|@<digest>]
 
# Examples
FROM centos
FROM ubuntu:16.04
FROM ubuntu@sha256:xxxxxx

* MAINTAINER

MAINTAINER <author's detail>
 
# Example
MAINTAINER Jimmy LI <jimmy@yahoo.com>

* COPY

COPY <src> ... <dst>
 
# Examples
COPY html /var/www/html

* ADD
– handles tar and remote files in addition to copy

ADD <src> ... <dst>
 
e.g.
ADD web-page-config.tar /
# ENV: sets env var
ENV DEBUG_LVL 3 
ENV APACHE_LOG_DIR /var/log/apache
 
# ARG: defines build arguments
ARG usr 
ARG uid=1000
#Usage: docker build --build-arg usr=app --build-arg uid=100 .
ARG BUILD_VERSION 
#Usage: LABEL com.example.app.build_version=${BUILD_VERSION} 
 
# USER: setup startup user ID or username
#USER <UID>|<UName> 
USER 73
 
# WORKDIR: setup working dir
WORKDIR /var/log
 
# VOLUME
VOLUME ["<mountpoint>"]
VOLUME <mountpoint>
 
# EXPOSE: opens up a container network port
# Defaults to TCP port
EXPOSE 7373/udp 8080
 
# LABEL
LABEL org.label-schema.schema-version="1.0"  
      org.label-schema.version="2.0"  
      org.label-schema.description="Learning Docker Example"
 
# RUN: executed during build process
RUN apt-get update && \ 
		apt-get install -y apache2 && \
		apt-get clean 
 
# CMD: executed when container is launched
CMD ["echo", "Dockerfile CMD demo"]
 
# ENTRYPOINT: 
# - executed when container is launched
# - container is terminated when command stops
ENTRYPOINT ["echo", "Dockerfile ENTRYPOINT demo"]
 
# HEALTHCHECK
# - runs health check command
# HEALTHCHECK [<options>] CMD <command> 
HEALTHCHECK --interval=5m --timeout=3s  
  CMD curl -f http://localhost/ || exit 1
HEALTHCHECK NONE 
 
# ONBUILD
# - triggered at next build
#ONBUILD <INSTRUCTION>
ONBUILD ADD config /etc/appconfig
 
# STOPSIGNAL
#STOPSIGNAL <signal>
 
# SHELL
# - overrides the default shell
# SHELL ["<shell>", "<arg-1>", ..., "<arg-n>"]

* .dockerignore file

# Ignore .git directory and all files ending with .tmp
.git 
*.tmp

* Check image history

sudo docker history apache2

* Best practices for writing a Dockerfile:
https://docs.docker.com/articles/dockerfile_best-practices/.

Publishing Images

Docker Hub

* Can be used for:
– public
– private
* Features:
– image repo
– user auth
– manage org and groups
– auto image build
– integrate with GibHub and Bitbucket
* URL: https://hub.docker.com
– Docker ID: jxxliextpie1
* Automate build process for images
* Local repo
– see ref: https://github.com/docker/docker-registry
* Supports REST API

Private Docker Infrastructure

Docker Registry

* Listening on: TCP 5000
* Storage path: /var/lib/registry
* Install and start registry

# Start
sudo docker run -d -p 5000:5000 \
--restart=always --name registry registry:2
 
# Check
sudo docker ps -a

* Get and tag an image

# Get image
sudo docker pull hello-world
 
# Tag image
sudo docker tag hello-world localhost:5000/hello-world

* Push image

sudo docker push localhost:5000/hello-world

* Pull image

sudo docker pull localhost:5000/hello-world

* Stop and delete registry

sudo docker stop registry  && sudo docker rm -v registry

* Restart registry

sudo docker run -d -p 5000:5000 --restart=always --name registry -v `pwd`/data:/var/lib/registry registry:2

Sharing Data with Container

* Data persistence approaches:
– use volumes created using Docker’s volume management
– mount host directory inside container
– use data-only container

Data Volume

* Mount data volume manually

docker run -v /datavol -it ubuntu:16.04

* Or create Dockerfile and specify a data volume:

FROM ubuntu:16.04
VOLUME /datavol

* Build image

docker build -t datavol1 .

* Check

docker inspect datavol1

* Test run

docker run --rm -it datavol1
 
# List datavol1
ls -ld /datavol
drwxr-xr-x 2 root root 6 Apr 10 18:32 /datavol
 
# Check mount
mount|grep datavol
/dev/sdb on /datavol type xfs (rw,relatime,attr2,inode64,prjquota)
 
# Check host dir
docker inspect -f '{{json .Mounts}}' 52c437babf62
 
{"Type":"volume","Name":"15a7fecfbca850863cbfa61e679d9b33bf765c1087ddf621115ee82da4ab545a","Source":"/var/lib/docker/volumes/15a7fecfbca850863cbfa61e679d9b33bf765c1087ddf621115ee82da4ab545a/_data","Destination":"/datavol","Driver":"local","Mode":"","RW":true,"Propagation":""}]

* Remove host directory for associtated volume when shutting down container

docker rm -v 52c437babf62
 
# Force removal of volume when removing container
docker rm -fv 52c437babf62

Volume Management

* Volume plugins:
https://docs.docker.com/engine/extend/legacy_plugins/#volume-plugins
* docker volume

# Create a volume named datavol2
docker volume create --name datavol2
 
# List volumes
docker volume list
 
# Inspect volumes
docker volume inspect datavol2
 
[
    {
        "CreatedAt": "2018-04-10T19:05:30Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/datavol2/_data",
        "Name": "datavol2",
        "Options": {},
        "Scope": "local"
    }
]
 
# Remove volume
docker volume rm datavol2

Sharing Host Data

* docker run -v options:

-v <container mount path>
-v <host path>:<container mount path>
-v <host path>:<container mount path>:<read write mode>
-v <volume name>:<container mount path>
-v <volume name>:<container mount path>:<read write mode>

* Example, mount host /datavol as /datavol inside container:

docker run -v /datavol:/datavol -it ubuntu:16.04

Sharing Data Between Containers

* Use run –volume-from option:
–volumes-from=””: Mount all volumes from the given container(s)

Data Only Container

* Launch a busybox image as a data only container
– container in stopped state

docker run --name datavol -v /DataMount busybox:latest /bin/true

* Launch an ubuntu image and mount all volumes from datavol container

docker run -it --volumes-from datavol ubuntu:latest /bin/bash

Pit Falls

* Directory leaks
– always inspect images for data volumes
– always use docker rm -v option to remove any data volume created for the container
– keep a log of data volumes to keep
* Don’t use data volume as a storage during the build process

Container Orchestration

Internal DNS

* Container DNS: 127.0.0.11

* Create a network bridge
docker network create mybridge
docker network inspect mybridge
* Launch a container using mybridge
docker container run -itd –net mybridge –name testdns ubuntu
– Check network setup
docker container inspect –format ‘{{.NetworkSettings.Networks.mybridge.IPAddress}}’ testdns
docker container exec testdns cat /etc/resolv.conf

* Ping from another container
docker container run –rm –net mybridge busybox ping -c 2 testdns

Linking Containers

Container Orchestration with docker-compose

* docker-compose file: docker-compose.yml
– see Compose file version 3 reference

version: "<version>" 
services: 
  <service>: 
    <key>: <value> 
    <key>: 
       - <value> 
       - <value> 
networks: 
  <network>: 
    <key>: <value> 
 
volumes: 
  <volume>: 
    <key>: <value>

* docker-compose command
– see here

docker-compose [<options>] <command> [<args>...]

Example

Files

* Dockerfile

FROM node:latest
RUN npm install redis
ADD example.js /myapp/example.js

* docker-compose.yml

version: "3.1"
services:
  web:
    build: .
    command: node /myapp/example.js
    depends_on:
    - redis
    ports:
    - 8080:80
  redis:
    image: redis:latest

* example.js

// A Simple Request/Response web application
 
// Load all required libraries
var http = require('http');
var url = require('url');
var redis = require('redis');
 
// Connect to redis server running
// createClient API is called with
//  -- 6379, a well-known port to which the
//           redis server listens to
//  -- redis, is the name of the service (container)
//            that runs redis server
var client = redis.createClient(6379, 'redis');
 
// Set the key value pair in the redis server
 
// Here all the keys proceeds with "/", because
// URL parser always have "/" as its first character
client.set("/", "Welcome to Docker-Compose helper\nEnter the docker-compose command in the URL for help\n", redis.print);
client.set("/build", "Build or rebuild services", redis.print);
client.set("/kill", "Kill containers", redis.print);
 
var server = http.createServer(function (request, response) {
  var href = url.parse(request.url, true).href;
  response.writeHead(200, {"Content-Type": "text/plain"});
 
  // Pull the response (value) string using the URL
  client.get(href, function (err, reply) {
    if ( reply == null ) response.write("Command: " + href.slice(1) + " not supported\n");
    else response.write(reply + "\n");
    response.end();
  });
});
 
console.log("Listening on port 80");
server.listen(80);

Commands

cd exmaple
docker-compose build
docker-compose pull
docker-compose up

References

* Learning Docker – Second Edition by Jeeva S. Chelladhurai; Pethuru Raj; Vinod Singh
* Docker run reference
* Play with Docker

This entry was posted in docker and tagged . Bookmark the permalink.