# Docker in Action

# How to control containers

# Creating a new container

docker run --detach --name web nginx:latest

This will download nginx from docker hub hand run the software in detached mode, i.e. no input or output stream.

To run an interactive container:

docker run -i -t --link web:web --name web_test busybox:latest /bin/sh

-i means --interactive. It tells docker to keep the stdin open for the container even if no terminal is attached. -t means --tty. It tells docker to allocate a virtural terminal for the container. This is usually what you want from an interactive CLI. --link web:web means that the container is linked to the web container (the NGINX).

Try to use wget to talk to web.

wget -O - http://web:80

To detach, do ctrl-p + q.

# Listing, stopping, restarting, and viewing outputs

Listing

docker ps

Restart

docker restart <NAME>

Check log. --follow or -f will display the logs and continue updating the display with changes.

docker logs <NAME>

Stop

docker stop <NAME>

Stop all containers. docker ps -q only displays container IDs.

docker stop $(docker ps -q)

Run command in an existing running container.

docker run -d --name nsA busybox:latest /bin/sh -c "sleep  30000"

! run another command "ps"
docker exec nsA ps

The docker process uses namespace or <NAME> to distinguish different containers. So two containers can have the same internal PID because they have different names (namespaces).

You can also try to use the host PID namespace.

docker run --pid host busybox:latest ps

The container name can also be replaced with the long hash ID. Save that to variable.

CID=$(docker create nginx:latest)
echo $CID

# Container state and dependencies

MAILER_CID=$(docker run -d dockerinaction/ch2_mailer)
WEB_CID=$(docker create nginx)

AGENT_CID=$(docker create --link $WEB_CID:insideweb --link $MAILER_CID:insidemailer dockerinaction/ch2_agent)

docker create only create the container but not start it. When starting it, start web first because agent has dependency on it.

docker start $WEB_CID
docker start $AGENT_CID

docker states

# Build environment agnostic systems

# Create a read-only file system

docker run -d --name wp --read-only wordpress:4

Inspect container metadata, e.g. check if wp is running:

docker inspect --format "{{.State.Running}}" wp

It's not running because doesn't have a sql database. Run the SQL database with

docker run -d --name wpdb -e MYSQL_ROOT_PASSWORD=ch2demo mysql:5

Then connect to this mysql server.

docker run -d --name wp2 -v /run/lock/apache2/ -v /run/apache2/ -v /tmp/ --link wpdb:mysql -p 80 --read-only wordpress:4

# Environment variable injection

docker run --env MY_ENV_VAR="test env var" busybox:latest env

--env (-e) means specify environment variables. The unix command env prints out current environment variables.

# Keep containers running with supervisord and startup process

supervisord is used to monitor the health condition of processes and restart them if any was killed.

# Cleanup

Show all the containers, including stopped ones.

docker ps -a

Remove a container from computer

docker rm wp

Remove all containers

docker rm -vf $(docker ps -aq)

# Software installation

# Repository

A repository holds a bucket of images with different tags. For example, quay.io/dockerinaction/ch3_hello_registry, quay.io is repository name, dockerinaction is user name, ch3_hello_registry is the short name.

# Docker Hub

There are two ways that an image auther can publish their images on Docker Hub

  • Use the commandline to push images that they built independently and on their own system. This is not trustworthy.
  • Make a Dockerfile publicly available and use Docker Hub's continuous build system.

# Search for a image

docker search postgres

# Save and load image as a file

docker pull buxybox:latest
docker save -o myfile.tar busybox:latest

docker load -i myfile.tar

# Delete images

Container uses image. So we need to delete the stopped container first.

docker rm <container>

docker rmi <image>

# Installing from a Dockerfile

Dockerfile is a script that describes steps for Docker to take to build a new image.

Listing images

docker images

# Persistent storage and shared state with vlumnes

The image file system is written / mounted to root, while program can write to another volume mounted to the host's fs.

# Example using vlumnes with Cassandra

Create a single volume container.

docker run -d --volume /var/lib/cassandra/data --name cass-shared alpine echo Data Container

This container will immediately stop and we can use it to crate a new volume running Cassandra.

docker run -d --volumes-from cass-shared --name cass1 cassandra:2.2

Then this cassandra container will have a volume mounted at /var/lib/cassandra/data.

Run cassandra client tool and connect it to the running server.

docker run -it --rm --link cass1:cass cassandra:2.2 cqlsh cass

Now you can insert some data, kill this server and create a new one. The data will still be there.

# Volume types

There are two volume types. The types differ in where the location is on the host.

  • Bind mount - bind mount volumes use any user-specific directory or file on the host operating system.
docker run --name <name> -v ~/example-docs:/usr/local/...:ro -p 80:80 httpd:latest

The :ro means read-only.

  • Managed volume - it uses locations are created by the docker daemon in space controlled by the daemon, called Docker managed space.
docker run -d -v /var/lib/cassandra/data --name ...

To find out the physical location

docker inspect -f "{{json.Volumes}}" cass-shared

You can specify multiple volumes with --volumes-from

docker run --name fowler -v ~/example-books:/library/PoEAA -v /library/DSL alpine:latest

docker run --name knuth -v /library/TAoCP.vol1 alpine:latest

docker run --name reader --volumes-from fowler --volumes-from knuth alpine:latest ls -l /library/

# Deleting volumes

docker rm -v