docker

DOCKER FUNDAMENTALS

Docker is a platform for developing shipping and running application using container virtualization technology.

Docker platform consist of

Docker Engine

Docker Hub

Docker Machine

Docker Swarm

Docker Compose

Kitematic

Introduction of Containers:

Consider container as a box, app+dependencies which runs on container engine that uses the OS-kernal.

Container based virtualisation uses the kernel on the host's operating system to run multiple guest instances.

Each guest instance is called container

Each container consists of

a. Root filesystem

b. Processes

c. Memory

d. Devices

e. Network ports

Outside it looks like VM but it is not VM.

Containers Vs VM

1. Containers are lightweight

2. No need to install guest OS

3. Less CPU, RAM storage space required

4. More containers per machine than VMs

5. Greater Portability

Docker has become the de-facto standard for containers. Docker is not the only solution for containers. LXC has existed for many years. Linux systemd has systemd-nspawn, which also is a solution to run containers.

Docker Concepts and Terminologies

DOCKER ENGINE:

Docker engine is a program that enables containers to be built, shipped and run

Docker engine uses Linux kernel namespaces and control groups.

Namespaces gives us isolated workspace

We go pid for process isolation, the net namespace to managing network stack, ipc namespace, mnt namespace for managing mount points and UTS namespace give us isolated work space which we call Container.

To Install Docker

wget -qo- https://get.docker.com/ | sh

The URL is going to return a shell script, where we pass the output to 'sh'. Potentially running all commands to install docker.

Provide sudo permission for the user so we can run docker commands without sudo.

sudo usermod -aG docker <username>

Docker Client and Demon:

- Client Server Architecture

- Client takes input and sends them back to the demon

(ex when we say docker run, run is the client which sends input to the demon)

- Daemon builds, runs and distributes container.

- Client and Demon can run on same or different host.

- CLI client and GUI(Kinematic - has a graphical interface)

docker version - gives you the version of docker

DOCKER CONTAINER AND IMAGES:

Images:

- Read only template used to create containers

- Built by you or other docker users

( there are official images that we can use, within the image there are set of instructions for creating the containers such as what programme to install, what folders and files to create, and what file volume to mount etc. )

- Stored in docker hub or local Registry

Container:

- Isolated application platform

- Contains everything needed to run your application

- Based on one or more images.

We create containers from images and run the container. We have everything to run the images - example all necessary libraries and binaries.

Registry and Repository

Registry is where we store our images. We can run our own registry or use docker hub registry which is called docker hub. Inside the registry, images are stored in repositories.

DOCKER ORCHESTRATION

Orchestration is about automated arrangements co-ordination, and management of complex computer systems, middleware and services.

Three tools for Orchestrating distributed application with Docker

1. Docker Machine: Tool that provision Docker hosts and install the Docker engine on them.

2. Docker Swarm: Tool that clusters many Engines and schedules containers

3. Docker Compose: Tool to create and manage multi-container applications.

BENEFITS OF DOCKER

Separation of concerns

Developers focus on building their apps.

System admins focus on deployments

Fast development cycles

Application portability

Build in one environment, ship to another

Scalability

Easily spin more containers if needed.

Runs more apps on one host machine.

Image Tags:

Images are specified in repository:tag

The same image might have multiple tags

The default tag is latest(ie. is no tag is specified, the image will be tagged as latest)

CREATING A CONTAINER

Use docker run command

Syntax

sudo docker run [options] [image] [command] [args]

Image is specified with repository:tag (example: docker run ubuntu:14.04 echo "Hello World!"

Running a Container:

docker run ubuntu:14.04 echo "hello world"

will print 'hello world'

Unable to find image 'ubuntu:14.04' locally 14.04: Pulling from library/ubuntu 96c6a1f3c3b0: Pull complete ed40d4bcb313: Pull complete b171f9dbc13b: Pull complete ccfc4df4fbba: Pull complete Digest: sha256:9274d908eb6d9a3784e93290fcc49f3c5618db9e1b0174ee27f9fc75aa3c0fb0 Status: Downloaded newer image for ubuntu:14.04 hello world

First time when we run the command since the ubuntu images is not found locally the ubuntu image was downloaded from the docker hub.

docker run ubuntu:14.04 ps ex

PID TTY STAT TIME COMMAND

1 ? Rs 0:00 ps ax

Second time it will be very fast as the images is present locally.

Container with Terminal

Use -i and -t flag with docker run

The -i flag tells docker to connect to STDIN on the container

The -t flag tells docker to get a pseudo terminal

Note: You need to run a terminal process as your command (eg /bin/bash)

Example: docker run -i -t ubuntu:latest /bin/bash

Container Process:

- A container only run as long as the process from your specified docker run command is running.

- Your command process is always 1 inside the container.

To test this, run

docker run ubuntu -it bash

now by pressing Ctrl P + Q to keep the process running and to exit from the container.

If you look at the ps command the pid of the bash will be having a separate pid and the parent id will be docker pid.

Container ID:

Containers can be specified by their ID or name. There are LongID and Short ID.

Short ID can be obtained by docker ps command and Long id can be obtained by inspecting the container.

Find Container:

docker ps to list all running containers

docker ps -a list all the containers.

Run in Detached mode:

Also know as run in the background or as a deemon

Use -d flag.

To observe log output use

docker logs [container id] command. ( -f will tail the log)

Example: docker run -d ubuntu:40.04 ping 127.0.0.1 -c50

To inspect docker log <containerid>

Port Mapping:

User -P command to map a port

Example: docker run -d -P tomcat:7 (no command means default command will be used)

When you do docker ps command it will show which port tomcat is mapped to (like 0.0.0.0.45838-->8080/tcp). First port is the host port where you can access tomcat from the browser using port 45838 and 8080 is the container port.

IMAGE LAYER

Images are comprised of multiple layers

A layer is also just another image

Every image contains a base image

Docker uses a copy on write system

Layers are read-only

Containers Writable Layer

Docker provides a top level writable layer for containers.

Parent images are read-only

All changes are made in the writable layer.

If any changes in the apache image(in the below image). Docker uses copy of the read-only image to the writable layer. The original read-only version is still present, but hidden. And changes happen on the writable layer. The copy of the write system is what it makes it so fast to spin up containers.

Docker Commit

doctor commit command saves changes in container as new image

Syntax

docker commit [options] [container ID] [repository:tag]

Repository name should be username/application

Can reference the container with container name instead of ID.

Example: docker commit 984d29e88 user/myapp:1.0

Here 1.0 is the tag.

Docker FILE

DOCFILE IS A CONFIGURATION FILE THAT CONTAINS INSTRUCTIONS FOR BUILDING DOCKER IMAGE

Provides a more effective way to build images compared to using docker commit

Easily fits into your continuous integration and deployment process

DocFile Instructions:

- Instructions specify what to do when building images

- FROM instruction specifies what the base image should be.

- RUN instruction specifies a command to execute

Example:

FROM ubuntu:14.04

RUN apt-get install vim

Each RUN instruction creates a commit on top of writable layer, to avoid multiple commits, the RUN commands can be combined together

Example:

RUN apt-get update && apt-get install -y \

curl \

vim \

openjdk-7-jdk

DOCKER BUILD

Syntax

docker build [options] [path]

Common option to tag the build

docker build -t [repository:tag] [path]path is the build context. Say you want to add source code, the path of the source code should be specified.

docker build -t sbbabu/project:1.2 .

CMD INSTRUCTIONS

CMD defines a default instruction to execute when container is created

CMD reforms no action during the image build

Shell format and EXEC format

Can only be specified once in the Dockerfile

CAN BE OVERRIDDEN AT RUNTIME

Shell Format

CMD ping 127.0.0.1 -c 30

EXEC Format

CMD ["ping","127.0.0.1", "-c", "30"]

Example:

Dockerfile - below will update and install curl and vim in RUN command and CMD command will ping for 30times

FROM ubuntu:14.04

RUN apt-get update && apt-get install -y curl

\ vim

CMD ["ping","127.0.0.1", "-c", "30"]

Build the file using the below command

build -t bsb/dkfile:1.1 .

Run the image - This will print the ping out for 30times.

docker run bsb/dkfile:1.1

PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.

64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.039 ms

64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.053 ms

64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.053 ms

We can override the CMD command by passing the command while running, in which case it will override the CMD command specified in the Dockerfile

Ex: docker run bsb/dkfile:1.1 echo "hello world"

ENTRY POINT INSTRUCTIONS

Defines the command that will run when a container is executed.

Runtime arguments and CMD instruction are passed as parameters to ENTRYPOINT instruction.

EXEC form preferred as shell form cannot accept arguments at runtime.

Container essentially runs as and executable.

Note: We cannot override instruction during runtime unlike CMD instruction.

Example: We have added ENTRYPOINT instruction and set to run 'ping'. During run time we will need to provide the arguments for ping

FROM ubuntu:14.04

RUN apt-get update && apt-get install -y curl \ vim

ENTRYPOINT "ping"

After building Run by executing below command.

docker run bsb/dkfile:1.1 127.0.0.1 -c 5

Note that we are not specifying the ping command but the arguments passed are sent to the ENTRYPOINT as parameters.

MANAGING IMAGES AND CONTAINERS

Find the containers first with docker ps command and note the ID and name of the container.

Start container using

docker start <containerid> - This could be useful when the container is running in detached mode.

Stop Container

doctor stop <containerid> - To stop the container

GETTING TERMINAL ACCESS

Say our server is running tomcat or other web server to get the terminal access use the EXEC command. This starts another process within our container.

Execute with /bin/bash to get the bash shell

docker exec -it [container id] /bin/bash

If you exit the terminal it will not exit the container. As the bash is not the container id '1'.

DELETING CONTAINER

To delete a container use

docker rm <container id> or name

Note that only stopped containers can be deleted.

Remove container with filter

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

DELETING LOCAL IMAGES

Use docker rmi [imageid] or

docker rmi [repo:id]

If an image is tagged multiple times, remove each tag.

TAGGING IMAGES

Used to rename the local image repository before pushing to Docker hub. Docker hub require tag names to be same as the docker hub tag.

Syntax

docker tag [image id] [repo:tag] or

docker tag [local repo:id] [Docker Hub repo:tag]

Example:

docker tag 51316840fa8c sbbabu/dkfile:1.2 or

docker bsb/dkfile:1.2 sbbabu/dkfile:1.2

Push to Docker Hub

docker push sbbabu/dkfile:1.1

VOLUMES

A volume is a designated directory in a container, which is designed to persist data, independent of the container's lifecycle.

Volume changes are excluded when updating the image

i.e when a mount a file system to a container at a certain folder we add files and commit the folder as new image. The files added to the image will not be included.

Persist when a container is deleted

Can be mapped to a host folder

Can be shared between containers.

REX-Ray is an open source, storage management solution designed to support container runtimes - check this link

http://rexray.readthedocs.io/en/stable/

MOUNT A VOLUME

Volumes are mounted when creating or executing a container

Can be mapped to host directory.

Volume paths must be absolute.

Execute a new container and mount the folder /myvolume into its filesystem

docker run -d -P -v /myvolume ubuntu14.04

Execute a new container and map the /data/src folder from the host into /test/src folder in the container

docker run -it -v /data/src:/test/src ubuntu14.04

Use -u command to set the user

ie. docker run -it -v /data/src:/test/src -u 1000:1000 ubuntu14.04

where 1000:1000 are ids of user/group respectively.

VOLUMES IN DOCKErFILE

VOLUME instruction creates a mount point

Can specify argument JSON array or string

Cannot map volume to host directory

Volumes are initiated when the container is executed.

Example:

String example

VOLUME /myvol

String example with multiple volume

VOLUME /www/site1/ /www/site2/

JSON example

VOLUME ["myvol1","myvol2"]

USES OF VOLUMES

De-couple the data that is stored from the container which created the data. Say your containers runs an app which creates many log files, if you store them in a volume you can access them even when the container is shutdown.

Good for sharing data between containers

Can setup a data containers which has a volume you mount to other containers

Mounting folders from the host is good for testing but generally not recommended in production environment.

Example

Create a mount point for ubuntu image

docker run -d -it -P -v /www/site1 ubuntu14.04

Remove unwanted volumes

docker volume rm $(docker volume ls -qf dangling=true)

CONTAINER NETWORKING

MAPPING PORT:

Ports can be manually mapped or auto mapped

Using -P will assign a port automatically. Host port number used go from 49153 to 65535. Only works for ports defined in EXPOSE instruction

Using -p , we can specify which port to map.

docker run -d -p 8080:80 nginx

EXPOSE INSTRUCTION

Configure which ports a container will listen on at runtime. Ports still need to be mapped when container is executed.

FROM ubuntu:14.04

RUN apt-get update

RUN apt-get install -y nginx

EXPOSE 80 443

CMD["nginx","-g","daemon off;"]

LINKING CONTAINERS

Linking container is a communication method between containers which allow them to securely transfer data from one to another.

Recipient containers have access to data on source containers

Links are established based on container names.

Creating Link

Create source container first

Create the recipient container and use the --link option

Syntax

Create source container

docker run -d --name database posture

Create recipient container

docker run -d -P --link database:db nginix ( here 'db' is the alias provided for the link)

docker run -d --name dbms postgres (run posters and assign name dbms)

docker run -it --name website --link dbms:db ubuntu:14.04 bash (link the dbms to the website container)

In the dbms container the host file will have an entry

cat /etc/hosts

127.0.0.1 localhost

::1 localhost ip6-localhost ip6-loopback

fe00::0 ip6-localnet

ff00::0 ip6-mcastprefix

ff02::1 ip6-allnodes

ff02::2 ip6-allrouters

172.17.0.4 db ba815a7a88ea dbms

172.17.0.2 1a3c31715b70

This can be verified by using the inspect command

docker inspect dbms |grep IPAddress

"SecondaryIPAddresses": null,

"IPAddress": "172.17.0.4",

DOCKER OPERATIONS

Trouble Shooting Containers:

docker logs <containername or id>

To tail logs

docker logs -f <containername or id>

To Run Docker with non-root user

#usermod -aG docker $USER

MONITORING DOCKER

cADVISOR (from google)

cAdvisor (Container Advisor) provides container users an understanding of the resource usage and performance characteristics of their running containers. It is a running daemon that collects, aggregates, processes, and exports information about running containers. Specifically, for each container it keeps resource isolation parameters, historical resource usage, histograms of complete historical resource usage and network statistics. This data is exported by container and machine-wide.

To run cAdvisor

sudo docker run \ --volume=/:/rootfs:ro \ --volume=/var/run:/var/run:rw \ --volume=/sys:/sys:ro \ --volume=/var/lib/docker/:/var/lib/docker:ro \ --publish=8080:8080 \ --detach=true \ --name=cadvisor \ google/cadvisor:latest

WORKING WITH REDIS IMAGE

Download and start redis. This will expose port 6379

$ docker run --name some-redis -d redis

Start redis with persistent storage

$ docker run --name some-redis -d redis redis-server --appendonly yes

Connect to redis from an application

$ docker run --name some-app --link some-redis:redis -d application-that-uses-redis

Using redis.conf in docker run

$ docker run -v /myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf --name myredis redis redis-server /usr/local/etc/redis/redis.conf

Where /myredis/conf/ is a local directory containing your redis.conf file. Using this method means that there is no need to have Dockerfiel for reais container.

Alternatively if you want to create your own Dockerfile, use the below command that adds a redis.conf from the context into /data

FROM redis COPY redis.conf /usr/local/etc/redis/redis.conf CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]

UNDERSTANDING HOW CONTAINERS WORK

When a process is started the kernel makes lots of information available to it.

Containers are simply process that are given their own isolated view of the information via namespaces.

There are 6 namespaces

  1. Mount namespace

  2. UTS namespace - Unix Timesharing Namespace

  3. IPC namespace - Inter Process Communication

  4. NET namespace

  5. PID namespace

  6. USER namespace

USHARE - Is a tool which runs program with some namespaces unshared from parent.

When a process with pid 1 is killed all other process running in the container will be killed.

For example, you run a container with bash process and 2 sleep processes to test that the process is running. When you kill the bash process which is pid 1, the sleep processes will be deleted as well.

Normally the kernel shuts down the process when you have do Ctrl+c, but that is not true.

Say you run a container with

docker run -it -rm --name sleepy debian sleep 10000

when you try to kill the process using CTRL+C, the process will not stop and you will need to stop the process. You should use the docker rm -f sleepy, to kill the process.

UTS NAMESPACE - Unix Timesharing Namespace

Each container has its own hostname. How this is done in docker can be explained using the unshare tool.

testuser$ sudo unshare -u bash

$ hostname newhostname

After the commands if you switch to other tab, you can find that the namespace is not changed.

Network Namespace: Allocates another copy the entire networking stack, with its own routes, firewall routes and network devices.

To test when we run

sudo unshare -n bash

root@user:/home/user# ip a

The result will only be the <loopback> interfaces.

But in docker there will be one more interface if you run the same command inside docker container, which is set by default, where you can find 'ethic' a virtual interface which allows to communicate with the containers.

User Namespace: Provides mapping from uid and gid outside the namespace to a different set inside namespace.

Docker specifically will map the uid of the specific user to be root inside container.

Say you are running the container using a non root user

$docker -it --rm -v "$(pwd)":/cwd/ debian bash

root@289388b32:/# cd /cwd

root@289388b32:/# touch test.txt

touch: cannot touch 'test.txt': Permission denied

Here though you are the root use inside container you will not be allowed to create a file inside the shared volume. This is because the user is not having proper permissions to create folders.

Caveat: When you enable username spaces or modify which uid maps to root. You have to remake or redownload all the images.

Mount Name Space: Gives processes belonging to the namespace a separate list of mount space, where it will not share with other namespaces.

CGROUP and Pivot Root

cgroup - which control access to memory, cpu and devicesand pivot root to control access to file systems.

If a process request more than the allocated memory resources it throws out of memory error.

$docker run -it --rm -m 100m debian

root@b3298f923:/# free -m

does not show that your memory is limited. To find that you have to cat the cgroup file associated with that.

root@b3298f923: cat /sys/fs/cgroup/memory/memory.limit_in_bytes

104857600

root@b3298f923: echo "$((104857600 /1024 /1024 ))"

100

Now we can see that it is limited to 100mb.

cpu c group can cfs(completely fair schedules) - how much CPU power is it can use.

Run this in container

$docker run -it --rm --cpuset-cpus 0 debian nproc

Tell docker to access the 0th cpu.

Give more

$docker run -it --rm --cpuset-cpus 0 debian proc

1

$docker run -it --rm --cpuset-cpus 0-2,5 debian nproc

4

Given a period and a quota containers get roughly the quota dived to the period percentage relative to a single CPU core. Thus to get half a core to worth of CPU time, we can use values of for the periods 2000 and 1000.

$docker run -d --cpu-period=2000 --cpu-quota=1000 --name cpu-hog debian:jessie bash -c 'for((i=1; i< $(nproc); i++)); do bash -c "while true; do true; do true; done" & true; done; while true; do true; done'

$docker exec cpu-hog ps aux

You can see that the cpu usage is around 50.

Device cgroup

Containers does not have access to all the devices

$docker run -rm -v /dev:/hostdev debian head --bytes=100 /hostdev/sda1 |hexdump -C

--error operation not permitted

We can add cgroup to give access to that device

$docker run -rm -device /dev/sda1 debian head --bytes=100 /dev/sda1 |hexdump -C

Not you should see the fir 100 bytes of the device printed.

Pivot root -

$ mkdir rootfs

$ sudo mount -t tempfs tempos rootfs

$ mkdir rootfs/old

$ cd rootfs

Use busy boximage to get static busy box so that when we have new root we can run something

$ docker run --rm busybox cat /bin/busybox > busybox

$ chmod +x busybox

Start new shell in a new namespace (part of requirement of pivot root)

$sudo unshare --fork --mount --mount-proc --pid ./busybox.sh

/home/username/rootfs# pivot_root .old

/# ./busybox ls

busybox old

Old root can be found in old directory

IMAGE - Remove <none> images.

You can find many <none> images when you type docker images -a, this is because of the intermediate images which docker doesn't clear automatically. This can be removed by using the below command.

docker rmi $(docker images -f "dangling=true" -q)

More details about the none images can be found at http://www.projectatomic.io/blog/2015/07/what-are-docker-none-none-images/

SET TIMEZONE

In docker run set environment variable -e TZ=Asia/Singapore

COPY FILES FROM CONTAINER

example:

docker cp <containerid>:<filepathofcontainer> <hostpath>

docker cp 53ea67f622f2:/usr/local/tomcat/conf/catalina.properties .

DOCKER SWARM

Create a swarm master using docker machine

docker-machine create -d virtualbox --swarm --swarm-master --swarm-discovery="zk://192.168.99.100:2181/swarm" --engine-opt="cluster-store=zk://192.168.99.100:2181/overlay" --engine-opt="cluster-advertise=eth1:2376" mymaster

Create a swarm node

docker-machine create -d virtualbox --swarm --swarm-discovery="zk://192.168.99.100:2181/swarm" --engine-opt="cluster-store=zk://192.168.99.100:2181/overlay" --engine-opt="cluster-advertise=eth1:2376" mynode1

Switch to swarm master and create overlay network

$ eval $(docker-machine env mymaster)

docker network create --driver overlay myoverlay-network

Deploy application on different host using Constraints

$ docker run --name myapp --net=myoverlay-network --env="constraint:mynode1" sbbabu/myapp

same way you can deploy you backend app into another host. And they should be able to communicate with each through over-lay network.

Docker can be run inside docker

There are couple of things needed the image should have docker in it and we should mount /var/run/docker.sock. If docker is not installed we can mount the local docker as shown below. (mapping docker binary many not work on some machines)

docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock -v /usr/local/bin/docker:/usr/bin/docker busybox:latest

MACVLAN

Joining Existing network with MACVLAN

Docker allow to connect to existing networks use MACVLAN. MACVLAN assigns each container its own IP. This would require PROMISCUOUS MOD E (But AWS and most cloud provides don't allow this)

Joining Existing network with IPVLAN

Crate a docker network with driver ipvalan, and this will connect to the existing network and the containers will be accessible though the underlay network.

Similar to Linux but doesn't give containers their own MAC addresses. Containers cannot ping their host. Special consideration required when working with DHCP.

docker network create -d ipvlan \

--subnet=192.168.1.0/24 \

--gateway=192.168.1.254 \

--ip-range=192.168.1.0/28 \

-o ipvlan_mode=l2 \ #(this is default layer2 - no need to specify)

-o parent=eth0 myipvnetwork

DOCKER SERVICE DISCOVERY

Every container gets a small DNS resolver which

- listens at 127.0.0.11:53

- Forwards request to DNS server on Docker host. If the docker dos cannot resolve, it will try to resolve with public dns.

VIP - every service gets a VIP and it routes to the tasks accordingly.

Ingress network is on every node and is used as routing mesh on every node. Ingress is a container (internal) used by docker.

HTTP Routing Mesh (HRM)

Builds on top of port-based /L4 routing mesh

- Allows multiple services on the same port

- Operates at the application layer (L7)

Requires Docker Datacenter ( only for docker EE)

LINKS

Create test instance to play around with docker, this has ssh access for limited hours.

http://play-with-docker.com/

To increase the size of base docker

https://community.hortonworks.com/content/kbentry/65901/how-to-increase-the-size-of-the-base-docker-for-ma.html

Check Docker Configuration

https://github.com/moby/moby/blob/master/contrib/check-config.sh

Create a Small JDK image

https://developer.atlassian.com/blog/2015/08/minimal-java-docker-containers/

FROM alpine:3.2

RUN apk --update add openjdk7-jre

CMD ["/usr/bin/java", "-version"]

--------------- NON DOCKER LINKS -----------

HTML slide show

https://remarkjs.com