Docker

Stian Mathiassen

The Dream!


docker run myapp

Virtualization is NOT the point

Image and container


Image:

A snapshot of a disk image. Can be created by commiting a container.


Container

A program running in docker, which uses an image as a base image. Each container start from scratch from the base image.

Lifecycle in Docker

Get a base image

docker pull ubuntu:latest

Pulls an image from hub.docker.com

List all images


docker images

REPOSITORY TAG    IMAGE ID     CREATED     VIRTUAL SIZE
ubuntu     latest 9cd978db300e 7 weeks ago 204.4 MB
	

Image layers

Start a container

docker run ubuntu echo "Hello World"
Hello World

List containers

docker ps --all

CONTAINER ID IMAGE         COMMAND          CREATED       STATUS ...
2529384fabd4 ubuntu:latest echo Hello World 8 minutes ago Exit 0 ...
	

A useful container

docker run --interactive --tty ubuntu /bin/bash

root@a9f2bd405f9e:/# echo "Hello World" > /somefile.txt
root@a9f2bd405f9e:/# exit
	

Container has died

docker ps --all

CONTAINER ID IMAGE         COMMAND          CREATED        STATUS ...
a9f2bd405f9e ubuntu:latest /bin/bash        3 minutes ago  Exit 0 ...
2529384fabd4 ubuntu:latest echo Hello World 20 minutes ago Exit 0 ...
	

Restart a container

Will re-run the same command. Will re-use same disk.

docker start --attach --interactive a9f2bd405f9e

root@a9f2bd405f9e:/# echo "Hello World" > /anotherfile.txt
root@a9f2bd405f9e:/# exit
	

Diff changes to container

Will show changes from base image and the container

docker diff a9f2bd405f9e

A /.bash_history
A /anotherfile.txt
C /dev
C /dev/console
C /dev/core
C /dev/fd
C /dev/ptmx
C /dev/stderr
C /dev/stdin
C /dev/stdout
A /somefile.txt
	

Create a new image

Base the new image on a container. Will create a new layer on top of the base image

docker commit a9f2bd405f9e myimage:mytag

dbf0e2a6421dfcb3d2194c5e2c3daf2132bd0c172cdaaa3ab90f27d5a0273ba8
	

docker images --tree

└─511136ea3c5a Virtual Size: 0 B
  └─6170bb7b0ad1 Virtual Size: 0 B
    └─9cd978db300e Virtual Size: 204.4 MB Tags: ubuntu:latest
      └─dbf0e2a6421d Virtual Size: 204.4 MB Tags: myimage:mytag
	

Setup for assignment

  • We are using Vagrant for the assignments
  • Really just a virtual machine in VirtualBox
  • vagrant up Starts your virtual machine
  • vagrant destroy Resets your virtual machine
  • vagrant ssh Log in to the virtual machine
  • /vagrant inside the virtual machine is a shared folder

Assignment #1

  1. Run echo "Hello world" in a container based on the Ubuntu image
  2. Run an interactive bash in a container
  3. Install node.js (nodejs) in a container (using interactive bash)
    • apt-get update Updates list of available software
    • apt-get install Install software
  4. Create an image called assig1 with node.js installed
  5. Try to run nodejs --version using your new image

Summary

  1. docker run --interactive --tty ubuntu /bin/bash
  2. (do stuff in container)
  3. docker commit CONTAINER_ID

Dockerfile

The Recipe

Dockerfile


FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -y nodejs npm
	

Each RUN-command creates a new layer. Layers are re-used

Build image

docker build --tag="ubuntu-nodejs" .


$> docker images
REPOSITORY     TAG      IMAGE ID      CREATED        VIRTUAL SIZE
ubuntu-nodejs  latest   34b580498f7b  2 minutes ago  248.2 MB
	

Assignment #2

Do the following using a Dockerfile ...

  1. Create an image with nodejs and npm installed
  2. Tag your image as ubuntu-nodejs
  3. Create a container based on that image, and run nodejs --version to check that it is installed correctly

Dockerfiles pt. 2

ADD, ENTRYPOINT, USER, WORKDIR and EXPOSE

ADD

Copy a file from the host to the image


FROM ubuntu-nodejs

ADD ./src /var/apps/nodejs/
	

Same as running docker cp

USER

Run command as user


FROM ubuntu-nodejs
ADD ./src /var/apps/nodejs/

USER daemon
	

ENTRYPOINT

Command to run when starting the container


FROM ubuntu-nodejs
ADD ./src /var/apps/nodejs/
USER daemon

ENTRYPOINT ["nodejs", "/var/apps/nodejs/index.js"]
	

WORKDIR

Change current working directory


FROM ubuntu-nodejs
WORKDIR /
RUN rm -fr *

	

EXPOSE

Specify which ports the container should make available


FROM ubuntu-nodejs
ADD ./src /var/apps/nodejs/
USER daemon
ENTRYPOINT ["nodejs", "/var/apps/nodejs/index.js"]

EXPOSE 8888
	

Publish ports

Ports are not automatically published

docker run -p 8888:8888 ubuntu-nodejs

Maps ports 8888 on host machine to 8888 on container

Assignment #3

Based on the ubuntu-nodejs image created in Assignment #2:

  1. Add /vagrant/app/src to /var/apps/nodejs inside the image
  2. Run npm install in /var/apps/nodejs directory in the container
  3. The application is started with nodejs /var/apps/nodejs/index.js
  4. The application is running on port 8888
  5. Start the container with the port mapped to port 8888 on the host machine
  6. Check that the application is running on http://localhost:8888

Volumes

VOLUME

Add a data volume


FROM ubuntu:14.04
...
ENTRYPOINT mongod

VOLUME /data/db

Mounting volumes

docker run --volume /data:/data/db ubuntu-mongo

Linking containers

Container #1: MongoDB

FROM ubuntu:14.04

RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
RUN echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list
RUN apt-get update
RUN apt-get --yes install mongodb-org

VOLUME /data/db
EXPOSE 27017

ENTRYPOINT mongod
$ docker build --tag ubuntu-mongo /path/to/mongodb/Dockerfile
$ docker run --volume /data:/data/db 
             --name mongodb 
             --detach ubuntu-mongo

MongoDB is running!

$ docker ps
CONTAINER ID  IMAGE         COMMAND               PORTS      NAMES
43a1d9173209  mongo:latest  /bin/sh -c mongod /b  27017/tcp  mongodb
	

Using --link to get environment properties


$ docker run -t -i --link="mongodb:mongodb" ubuntu bash

root@541474c8ccd4:/# env
...
MONGODB_PORT_27017_TCP=tcp://172.17.0.30:27017
MONGODB_PORT=tcp://172.17.0.30:27017
MONGODB_PORT_27017_TCP_PORT=27017
MONGODB_PORT_27017_TCP_PROTO=tcp
MONGODB_PORT_27017_TCP_ADDR=172.17.0.30
...
	

Using the environment variables

In our node app:


var mongoPort = process.env.MONGODB_PORT_27017_TCP_PORT;
var ip = process.env.MONGODB_PORT_27017_TCP_ADDR;

var connectionString = 'mongodb://' + ip + ':' + mongoPort + '/local';
mongoose.connect(connectionString);
    

Container #2: our NodeJS app

FROM ubuntu:14.04

RUN apt-get update
RUN apt-get --yes install nodejs npm

ADD ./src /var/apps/nodejs/
RUN cd /var/apps/nodejs/; npm install

EXPOSE 8888

CMD nodejs /var/apps/nodejs/index.js
	
$ docker build --tag ubuntu-nodejs /path/to/nodejs/Dockerfile
$ docker run --publish 8888:8888 
             --link="mongodb:mongodb" 
             --detach ubuntu-nodejs

Our Nodejs app is now connected to MongoDB


$ docker ps
IMAGE                 COMMAND               PORTS                    NAMES
ubuntu-nodejs:latest  /bin/sh -c 'nodejs /  0.0.0.0:8888->8888/tcp   lonely_goldstine
mongo:latest          /bin/sh -c mongod /b  27017/tcp                drunk_ptolemy/mongodb,lonely_goldstine/mongodb,mongodb
	

Assignment #4

  1. Build an image with MongoDB running

    (Create the new Dockerfile in a seperate directory. Remember to EXPOSE the port)

  2. Run a container based on the newly created Mongod-image

    (remember to give it a --name)

  3. Start the Nodejs application with the --link option
  4. Verify that the application is connected to MongoDB by visiting http://localhost:8888

Bonus assignment

Build images that you find useful!

https://hub.docker.com/

Building on Docker

Thank you!

Stian Mathiassen