Docker

Table of Contents

Install docker package and start the service by

systemctl start docker
systemctl enable docker

We can build Debian image easily on Arch:

mkdir jessie-chroot
# debootstrap jessie ./jessie-chroot http://http.debian.net/debian/
# cd jessie-chroot
# tar cpf - . | docker import - debian
# docker run -t -i --rm debian /bin/bash

Re-launch a stopped container can be done by docker start <container> and will be detached by default if it is run by that.

You can assign a name to the container so that you can better remember and reference it.

1 Compose

It is installed seperately with docker.

It must be run inside the folder containing docker-compose.yml

Commands

  • docker-compose up: up the service. It will not exit. Use C-c to exit and the docker-compose down command will be sent.
    • The second time you up the compose, it will not up, but update current. If all current are up to date, nothing will happen.
  • docker-compose up -d: up the service and exit. You need to shutdown it maually
  • docker-compose down: shutdown the services

A sample compose file:

version: '2'
services:
  srcml-server-container:
    image: "lihebi/srcml-server"
  helium:
    image: "lihebi/arch-helium"
    tty: true
    volumes:
      - data:/data
  benchmark-downloader:
    # this is used to download benchmarks to the shared volume
    image: "lihebi/benchmark-downloader"
    tty: true
    volumes:
      - data:/data
volumes:
  # create a volume with default
  data:

1.1 service

A service is a container. Setting tty to true to prevent it from stopping. That is the same effect when you pass -t to docker run.

The containers can be seen by docker ps, with names prefixed and suffixed by compose_XXX_1

Change to the container will not preserve after the compose down. The containers will be deleted. Next up will create new containers.

1.2 TODO volumes

Under any volume, if external option is set to true, docker compose will find it outside, and signal error if it does not exist.

1.3 TODO network

Once the compose is up, docker create a bridge network called compose_default. All services (containers) are attached to that.

2 Network

  • docker network ls
  • docker network inspect <network-name>

3 Volume

A volume must be locally available if you create a local volume.

3.1 Create Volume

You can create a volume like this:

docker volume create hello

Volumes can also be created upon creating a container.

3.2 Mount volume to a container

You have to mount at the time you create the container. You cannot remount anything to it without commiting it to an image and create again.

docker run -v /mnt <image>
docker run -v my-named-vol:/mnt <image>
docker run -v /absolute/path/to/host/local/path:/mnt/in/container <image>

If only inner path is provided, the volume will still be created, but with a long named directory under /var/lib/docker/volumes.

3.3 Manipulate Volume

The volumes will never be automatically deleted, even if the container is deleted.

3.3.1 TODO Will it be updated or not?

docker volume inspect <volume-full-name>
docker volume ls
docker volume prune # remove all unused volumes

4 General operations

docker images
list images
docker images <name>
list images whose name is "name" (can have different) tags
docker run [option] <image> /bin/bash
run a fresh container based on the image.
-i
interactive
-d
detach (opposite to -i)
-t
assign a tty. Even when using -d, you need this.
-p <port>
export the port <port> of the container. The host port will be randomly assigned. Running docker ps will show the port binding information. If the port is not set when running a container, you have to commit it, and run it again to assign a port or another port.
-v /volumn
create a mount at /volumn
-v /local/dir:/mnt
mount local dir to the /mnt in container. The default is read-write mode, if you want read only, do this: -v /local/dir:/mnt:ro. The local dir must be ABSOLUTE path.
docker exec <ID> echo "hello"
run some command with arguments on the already run container <ID>
  • ID can be the UUID or container name
  • you can use -it as well, e.g. docker exec -it <ID> /bin/bash
docker start <ID>
start an already stopped container
docker diff <ID>
show the difference made from the base image
docker commit <ID> lihebi/my-container
create a new image based on the container <ID>
docker login
login so that you can push
docker push lihebi/my-container
push to docker hub
docker pull lihebi/my-container
pull from the internet

Alternatively, you can write a Dockerfile to specify how to build a image.

FROM ubuntu 15.04
RUN ech o"hello" > /tmp/newfile

In the folder containing Dockerfile, run to build the image:

docker build -t my-ubuntu .

use –no-cache to avoid using cache

docker history <image>
show which layers are used to create <image>

4.1 Docker stop

docker stop will send SIGTERM to the app, then wait for it to stop. The default wait time is 10 seconds. You can change this by

docker stop -t 1 <container-ID>

This will change the timeout to be 1 second.

The reason for a container to resist stopping may be it ignores the SIGTERM request. Python did this, so for a python program, you should handle this signal yourself:

  import sys
  import signal

  def handler(signum, frame):
      sys.exit(1)

  def main():
      signal.signal(signal.SIGTERM, hanlder)
      # your app

Next thing is the entry point and commands. If you use shell form, it is started by sh -c, and shell will not pass the signal to the app either. So change it to json form.

Finally, docker stop tries to terminate the app gracefully by sending SIGTERM, you can choose to force kill using docker kill

5 Remove sudo

sudo groupadd docker
sudo gpasswd -a ${USER} docker
sudo service docker restart
newgrp docker

6 Dockerfile

I'm trying a docker file for srcml container.

FROM debian
RUN apt-get -y update & apt-get install -y libarchive-dev libcurl4-openssl-dev
RUN wget http://131.123.42.38/lmcrs/beta/srcML-Ubuntu14.04-64.deb srcml.deb
RUN dpkg -i srcml.deb

6.1 Commands

  • FROM: a base image
  • ENV key=value
  • ADD: ADD <src> .. <dst> The difference from copy:
    • ADD allows src to be url
    • ADD will decompress an archive
  • COPY: COPY <src> .. <dst> all srcs on the local machine will be copied to dst in the image. The src can use wildcards. The src cannot be out of the current build directory, e.g. .. is not valid.
  • USER: USER daemon The USER instruction sets the user name or UID to use when running the image and for any RUN, CMD and ENTRYPOINT instructions that follow it in the Dockerfile.
  • WORKDIR: The WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile
    • if it does not exist, it will be created
    • it can be used multiple times, if it is relative, it is relative to the previous WORKDIR
  • ENTRYPOINT ["executable", "param1", "param2"]: configure the container to be run as an executable.

7 TODO Docker hub

When pushing and pulling, what exactly happens?

docker tag local-image lihebi/my-image
docker push lihebi/my-image

8 Tricks

Stop all containers

docker stop $(docker ps -a -q)

Remove all containers (will not remove non-stopped ones, but give errors)

docker rm $(docker ps -a -q)

9 Trouble Shooting

9.1 I have to type double C-p to take effect

C-p C-q is the default binding for detaching a container. This blocks C-p, I have to type it twice, must change. In ~/.docker/config.json, add:

{
"detachKeys": "ctrl-],ctrl-["
}

Restart docker daemon to take effect. This can also be set by --detach-keys option.

9.2 Docker exec tty is not a real tty

I cannot connect to emacs server through emacsclient -t, and error message is terminal is not found. You can not open tmux also. But the problem does not appear when using docker run command.

The solution is when starting a exec command, use script to run bash:

docker exec -it my-container script -q -c "/bin/bash" /dev/null
docker exec -it my-container env TERM=xterm script -q -c "/bin/bash" /dev/null

The TERM is not necessary here because in my case docker always set it to xterm. I actually change it to screen-256color in my bashrc file to get the correct colors.