Docker tips

Posted on 2015-05-24 in Trucs et astuces

For my tips about docker compose, go here.

Create an image

docker build -t <name> .

Save and import

docker save <image> > file
docker load < <image>

Run

docker run --name aot -d -p 8080:8080 --link redis:redis aot

Volumes

docker run -it --rm -v $(pwd)/test:/root busybox /bin/sh

If SELinux is enabled, use: Z (capital z, recommended, better matches the context of the container, eg system_u:object_r:container_file_t:s0:c667,c788 with the c667,c788 part changing for each container) or z (lower caps z to have a context appliable to all containers, eg system_u:object_r:container_file_t:s0):

docker run -it --rm -v $(pwd)/test:/root:Z busybox /bin/sh

If you cannot run with Z, run chcon -R system_u:object_r:container_file_t:s0 FOLDER. If you must use a different context on your system, start a container with a volume mounted with z (lower caps z indented) and run ls -dZ FOLDER to get the proper context.

See https://blog.voina.org/docker-selinux/, http://www.projectatomic.io/blog/2015/06/using-volumes-with-docker-can-cause-problems-with-selinux/ and https://opensource.com/business/14/9/security-for-docker

You can also use multiple mount options by separating them with a comma. For instance to mount a read only file with SELinux support, you can do this:

docker run -it --rm -v $(pwd)/test/README.rst:/root/README.rst:ro,Z busybox /bin/sh

Networking

If you have SELinux enabled and use user namespaces, you will hit two SELinux errors related to ip tables:

avc:  denied  { net_admin } for  pid=7464 comm="iptables" capability=12  scontext=system_u:system_r:iptables_t:s0 tcontext=system_u:system_r:iptables_t:s0 tclass=cap_userns permissive=1
avc:  denied  { net_raw } for  pid=8158 comm="iptables" capability=13  scontext=system_u:system_r:iptables_t:s0 tcontext=system_u:system_r:iptables_t:s0 tclass=cap_userns permissive=0

To allow these actions in SELinux, run as root (the plain text description of the rule is avaiable in dk-userns-iptables.te):

ausearch -c 'iptables' --raw | audit2allow -M dk-userns-iptables
semodule -X 300 -i dk-userns-iptables.pp

Attach to a running container

If you are running docker 1.3 or above, you should use: docker exec -it CONTAINER COMMAND to run COMMAND within the container. You can easily create a function to ease the thing and run bash by default:

dk-enter() {
    docker exec -it "$1" "${2:-/bin/bash}"
}

You can easily open a shell in a running docker container with the following commands:

  1. Get the container pid: docker inspect -f {{.State.Pid}} <container-id>
  2. Connect: nsenter --target <pid> --mount --uts --ipc --net --pid

Use customs DNS

During development you may need to use custom domains to reach your site. Since these domains aren't real and must point to your machine, you need to use a custom DNS resolver. I'll detail here, how to acheive this with dnsmaq and Network Manager.

First, you need to install dnsmaq. It should be in the repositories of your distribution.

Then you need to map your domains to the proper ip addresses. To do that, create as root /etc/NetworkManager/dnsmasq.d/mapping.conf and add something like this to map the domain to the ip:

address=/dev.here/127.0.0.1

Now, as described here you need to configure Network Manager to listen to the docker bridge, so the DNS requests from your containers are correctly passed to dnsmasq. To do so, create /etc/NetworkManager/dnsmasq.d/docker-bridge.conf with this content (if you use another ip than the default one, you will have to adapt this):

listen-address=172.17.0.1

Restart Network Manager for the changes to be taken into account: systemctl restart NetworkManager.

Then, as described here, we need to configure the docker daemon to use our DNS. To to that, create /etc/docker/daemon.json with this content (or add the dns entry if the file already exists):

{
  "dns": [
    "172.17.0.1"
  ]
}

Restart docker for the changes to be taken into account: systemctl restart docker.

Finally, you need to allow DNS requests in your firewall (the commands below are for firewalld, default firewall on Fedora):

  1. Allow permanently the DNS service in the firewall (remove --permanent and don't run the second command to make this temporary): firewall-cmd --add-service=dns --permanent
  2. Reload the configuration: firewall-cmd --reload

Usage with sudo

If you want your users to use the docker command but want to prevent some options, you should rely on sudo to allow your users to run sudo docker SOMETING. You can then configure sudo to prevent some action. Here is an example that allows user jenselme to run sudo docker without a password without allowing the --privileged option nor to disable namespaces:

jenselme ALL=(root) NOPASSWD: /usr/bin/docker,
    ! /usr/bin/docker *--privileged*,
    ! /usr/bin/docker *=host*