Date created: 03/03/21 12:32:27. Last modified: 03/25/22 13:03:22



# Set the restart policy when the container is first run:
$ docker run -d --restart always webserver

# To update an existing container without a restart policy:
$ docker update --restart always webserver

# To stop auto restart:
$ docker update --restart no webserver

Possible values:
no - Do not automatically restart the container. (the default)
on-failure - Restart the container if it exits due to an error, which manifests as a non-zero exit code.
always - Always restart the container if it stops. If it is manually stopped, it is restarted only when Docker daemon restarts or the container itself is manually restarted.
unless-stopped - Similar to always, except that when the container is stopped (manually or otherwise), it is not restarted even after Docker daemon restarts.


Backup & Restore

Backing up images:

# Save an image locally:
docker save -o fedora-latest.tar fedora:latest

# Load a locally saved image:
docker load --input fedora-latest.tar


Backing up containers. This is problematic because not all settings of a runing container are exported to the image:

# Create a test docker image that runs continuously/doesn't exit, with a bunch of extra features like port mapping and file mapping:
$ cat /tmp/111
$ docker run -dt --name "ubuntu_test" -p 4444:4444 -v /tmp/111:/tmp/222 --restart always ubuntu:21.04 watch -n 2 date # Check the file mapping $ docker exec -it ubuntu_test /bin/bash root@f8a4a63b1875:/# cat /tmp/222 hi root@f8a4a63b1875:/# exit exit # Commit the container as an image: $ docker commit ubuntu_test ubuntu_test:version1 sha256:9d80ce520d2cae10b94d278de685c6cf2c1c6ed0376e3836cf686d77ee4cf69b $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu_test version1 9d80ce520d2c 2 seconds ago 72.4MB # Export the image $ docker save -o ubuntu_test-version1.tar ubuntu_test:version1 # Stop and remove the existing container $ docker stop ubuntu_test ubuntu_test $ docker rm ubuntu_test ubuntu_test # Remove the image $ docker image rm ubuntu_test:version1 Untagged: ubuntu_test:version1 Deleted: sha256:9d80ce520d2cae10b94d278de685c6cf2c1c6ed0376e3836cf686d77ee4cf69b Deleted: sha256:c89e9e0696630d4e7dc0e5eecefd6504a02d735ae51a5c9969816a11aff01ddf # Now re-import the exported image $ docker load --input ubuntu_test-version1.tar e01270f2a79a: Loading layer [==================================================>] 3.584kB/3.584kB Loaded image: ubuntu_test:version1 # The contianer will start without issue: $ docker run -td --rm --name "ubuntu_test" ubuntu_test:version1 # The old entry point "watch -n 2 date" is remembered: $ docker container attach ubuntu_test Every 2.0s: date e01270f2a79a: Thu Feb 10 16:22:34 2022 Thu Feb 10 16:22:34 UTC 2022 # Also the mapped /tmp file is remembered: $ docker exec -it ubuntu_test ls /tmp 222 # But port 4444 is not properly exposed... This is before the backup and restore: $ docker continare ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f8a4a63b1875 ubuntu:21.04 "watch -n 2 date" 8 minutes ago Up 8 minutes>4444/tcp, :::4444->4444/tcp ubuntu_test # This is after the restore: $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d1e30ba7246e ubuntu_test:version1 "watch -n 2 date" 10 seconds ago Up 8 seconds 4444/tcp ubuntu_test # Also the restart always policy is gone...This is before the backup and restore: $ docker container inspect ubuntu_test | grep -A 1 -i restart "RestartPolicy": { "Name": "always", # This is after: $ docker container inspect ubuntu_test | grep -A 1 -i restart "RestartPolicy": { "Name": "no",


Copying to/from containers:

# copy files from docker container to host (based on container hash)
$ docker cp 9874f1193087:/etc/grafana/grafana.ini ./
$ docker cp ./grafana.ini 9874f1193087:/etc/grafana/grafana.ini


Running Commands

# Connect to a running container:
$ docker container attach influxdb

# Start an interactive shell in the container
$ docker exec -it influxdb bash


Container Management

# Show docker space usage
$ docker system df

# Live docker stats
$ docker stats

# SIGHUP to reload config
$ docker kill -s HUP my_container


Creating A New Image

In this example a new Docker image is created which will run GoBGP.


Create a Dockerfile:

$ vi ./Dockerfile# The commands in capital letters are the Docker commands.

# A Dockerfile must begin with a FROM instruction
# FROM provides the user-space environment the application will run in, the actual Kernel is provide by the host machine
FROM ubuntu:20.04

RUN apt-get update && apt-get install -y wget
# iproute2: provides "ip"
# inetutils-ping: provides "ping/ping6"
# net-tools: provides "netstat"
# dnsutils: provides "dig" and "host"
RUN wget && \
tar -zxvf gobgp_2.24.0_linux_amd64.tar.gz && \
mv gobgp* /usr/bin/

RUN mkdir -p /opt/gobgp
WORKDIR /opt/gobgp/
COPY gobgp*.cfg /opt/gobgp/
# ^ COPY from the relative path on the host machine to the relative path in the Docker container.
# WORKDIR set the pwd within the container to /opt/gobgp so the config files in the host machines
# ./ folder will be copied to /opt/gobgp within the container, so we could have used COPY gobgp*.cfg ./

# Expose the following port to to the host machine, by default this is a TCP port
# The following is the same as below: EXPOSE 50051/tcp
# TCP and UDP ports are exposed separately, a 2nd EXPOSE statement would be required to expose UDP
EXPOSE 50051
# EXPOSE 50051/udp

# ENTRYPOINT ["executable", "param1", "param2"]
# or
# ENTRYPOINT command param1 param2
ENTRYPOINT ["gobgpd", "-f", "gobgp1.cfg"]


Build and manage images:

$ sudo docker build -t gobgp-2.24.0 .

# List docker images
$ sudo docker images
gobgp-2.24.0 latest 735449809023 48 minutes ago 149MB
ubuntu 20.04 f63181f19b2f 4 weeks ago 72.9MB
hello-world latest bf756fb1ae65 13 months ago 13.3kB
p4lang/p4app rc-2.0.0 3bea7bbb9ad0 2 years ago 1.13GB

# Delete docker image
$ sudo docker rmi 3bea7bbb9ad0


Running containers based on the newly build image:

# Run a container in an interactive mode and automatically remove it when the container exists
$ sudo docker run -it --rm gobgp-2.24.0

# Or, run in detached (headless/non-interactive) mode
$ sudo docker run -d --rm gobgp-2.24.0

# To expose all ports defined in the Docker file to random ephemeral ports on the host machine, add -P to the docker run command.
# To expose only specific ports, or to control which port numbers on the host machine the container ports are linked to, add the -p option to the docker run command and specify the host IP, host port, and container port:

# Expose container port 6666 to host port 5555 on host IP
$ sudo docker run -d -p gobgp-2.24.0

# Expose container port 6666 to host post 5555 without specifying an IP:
$ sudo docker run -d -p 5555:6666 gobgp-2.24.0

# Expose container port 6666 to host port 6666 on IP
$ sudo docker run -d -p gobgp-2.24.0

# Expose container TCP 6666 to host TCP port 5555 and container UDP port 6666 to host UDP port 5555
$ sudo docker run -d -p 5555:6666/tcp -p 5555:6666/udp gobgp-2.24.0

# In another window, show running containers
$ sudo docker container ls
d4b69d0a30c0 gobgp-2.24.0 "/bin/bash" 3 seconds ago Up 2 seconds kind_lamport

# In another window, show all containers, running and stopped
$ sudo docker container ls -a

# In another window, show live docker resource usage for all running containers
$ sudo docker container stats
a48bb9bdd0aa priceless_proskuriakova 0.00% 1.859MiB / 7.48GiB 0.02% 3.77kB / 0B 0B / 0B 1


Deleting containers and base images:

# To delete a base image, all containers that use that image must be stopped and removed
$ sudo docker container CONTAINER_ID stop
$ sudo docker rm CONTAINER_ID
$ sudo docker container ls -a
$ sudo docker rmi IMAGE_ID


List and delete unused images:

$ docker images -f dangling=true
$ docker image prune


Docker Networking


IPv4 forwarding must be enabled:

sysctl -w net.ipv4.ip_forward=1

If using iptables, "FORWARD" must be allowed at least for the docker bridge interface "docker0".


Enabling IPv6:

# Enable IPv6 globally and provide a default subnet for containers to use in the default "bridge" network.
# The default IPv4 pool is also specified here, which is used in blocks of /24:
# Note: if this file doesn't exist, create it then restart docker:
$ cat /etc/docker/daemon.json
"default-address-pools": [
"ipv6": true,
"fixed-cidr-v6": "2001:db8:1::/64"

# Restart docker
$ sudo systemctl restart docker

# The host machine now has an IP address assigned to it's default docker bridge.
# The host machine always uses ::1
$ ip -6 a show dev docker0
6: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 state DOWN
inet6 2001:db8:1::1/64 scope global
valid_lft forever preferred_lft forever

# After starting a container attached to the default docker network bridge called "bridge", it can be seen that the container has an IPv6 address assigned:
root@52d4e2c26987:/# ip -6 a show dev eth0
51: eth0@if52: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link-netnsid 0
inet6 2001:db8:1::242:ac11:2/64 scope global nodad
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:2/64 scope link
valid_lft forever preferred_lft forever

# The container can ping the host docker bridge network
$ ping6 2001:db8:1::1
PING 2001:db8:1::1 (2001:db8:1::1): 56 data bytes
64 bytes from 2001:db8:1::1: icmp_seq=0 ttl=64 time=0.151 ms
64 bytes from 2001:db8:1::1: icmp_seq=1 ttl=64 time=0.201 ms
^C--- 2001:db8:1::1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss

# For other devices to access the IPv6 addresses of the docker containers, this subnet needs to the routed from the LAN gateway to the docker host's IPv6 address.

# Alternatively one can add "--network host" to a docker run command, to bind a container to the IPv4 and IPv6 addresses of the docker host, then the container has IPs on the local LAN, but the contianer has visibility of the host's network namespace.


Adding a new network bridge:

# List docker networks
$ sudo docker network ls
857a2927ed51 bridge bridge local
fe1a6081b571 host host local
12bdf2463ce4 none null local

# Create a new user-defined network
$ sudo docker network create --driver=bridge --subnet= --ipv6 --subnet=2001:db8:2::/64 dbr0

# Show the detailed configuration of a docket network
$ sudo docker network inspect dbr0

# Connect a running container to this user specified network
$ sudo docker network connect dbr0 52d4e2c26987

# Check from within the container, that it now has an IP address in this bridges subnet:
$ ip -6 a show dev eth1
53: eth1@if54: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link-netnsid 0
inet6 2001:db8:2::2/64 scope global nodad
valid_lft forever preferred_lft forever
inet6 fe80::42:aff:fe00:ff02/64 scope link
valid_lft forever preferred_lft forever

# The container can now ping the IP address of the new docker network:
$ ping6 2001:db8:2::1
PING 2001:db8:2::1 (2001:db8:2::1): 56 data bytes
64 bytes from 2001:db8:2::1: icmp_seq=0 ttl=64 time=0.122 ms
64 bytes from 2001:db8:2::1: icmp_seq=1 ttl=64 time=0.163 ms
^C--- 2001:db8:2::1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.122/0.143/0.163/0.000 ms


Previous page: Raspberry Pi 2 Notes
Next page: dropwatch