Everyday Hacks for Docker

Everyday Hacks for Docker

6 min read

In this post, I’ve decided to share with you some useful commands and tools I frequently use when working with awesome Docker technology. There is no particular order or “coolness level” for every “hack.” I will simply present the use case and how the specific command or tool has helped me with my work. Read these great hacks and make sure to check out the great hack of all – Codefresh –  the best CI for Docker out there.

Docker Hacks

Cleaning Up

After working with Docker for some time, you start accumulating development junk: unused volumes, networks, exited containers and unused images.

One Command to “Rule Them All”

$ docker system prune

prune is a very useful command (also works for volume and network sub-commands), but it is only available for Docker 1.13. So if you’re using older Docker versions, the following commands can help you to replace the prune command.

Remove Dangling Volumes

dangling volumes are volumes not in use by any container. To remove them, combine two commands: first, list volume IDs for dangling volumes and then remove them.

$ docker volume rm $(docker volume ls -q -f "dangling=true")

Remove Exited Containers

The same principle works here too. First, list the containers (only IDs) you want to remove (with filter) and then remove them (consider rm -f to force remove).

$ docker rm $(docker ps -q -f "status=exited")

Remove Dangling Images

dangling images are untagged images, that are the leaves of the images tree (not intermediary layers).

docker rmi $(docker images -q -f "dangling=true")

Autoremove Interactive Containers

When you run a new interactive container and want to avoid typing rm command after it exits, use --rm option. Then when you exit from the created container, it will be automatically destroyed.

$ docker run -it --rm alpine sh

Inspect Docker Resources

jqjq is a lightweight and flexible command-line JSON processor. It is like sed for JSON data. You can use it to slice and filter, and map and transform structured data with the same ease that sed, awk, grep and friends let you play with text.

docker info and docker inspect commands can produce output in JSON format. Combine these commands with jq processor.

Pretty JSON and jq Processing

# show whole Docker info
$ docker info --format "{{json .}}" | jq .

# show Plugins only
$ docker info --format "{{json .Plugins}}" | jq .

# list IP addresses for all containers connected to 'bridge' network
$ docker network inspect bridge -f '{{json .Containers}}' | jq '.[] | {cont: .Name, ip: .IPv4Address}'

Watching Containers Lifecycle

Sometimes you want to see containers being activated and exited when you run certain docker commands or try different restart policies. Thewatch command combined with docker ps can be pretty useful here. I found that the docker stats command (even with --format option) is not useful for this because it doesn’t allow you to see the same information as you can with the docker ps command.

Display a Table with ‘ID Image Status’ for Active Containers and Refresh it Every 2 Seconds

$ watch -n 2 'docker ps --format "table {{.ID}}t {{.Image}}t {{.Status}}"'

Enter into Host/Container Namespace

Sometimes you want to connect to the Docker host. The ssh command is the default option, but this option may not be available, due to security settings, firewall rules or other undocumented issues (just try googling “how to ssh into Docker for Mac VM” to see what I mean).

nsenter, by Jérôme Petazzoni, is a small and very useful tool for this use cases. The nsenter command allows you to enter into namespaces. I like to use the minimalistic (580 kB) walkerlee/nsenter Docker image.

Enter into Docker Host

You can use --pid=host to enter into Docker host namespaces.

# get a shell into Docker host
$ docker run --rm -it --privileged --pid=host walkerlee/nsenter -t 1 -m -u -i -n sh

Enter into ANY Container

It’s also possible to enter into any container with nsenter and --pid=container:[id OR name]. But in most cases, it’s better to use the standard docker exec command. The main difference is that nsenter doesn’t enter the cgroups, and therefore evades resource limitations (which can be useful for debugging).

# get a shell into 'redis' container namespace
$ docker run --rm -it --privileged --pid=container:redis walkerlee/nsenter -t 1 -m -u -i -n sh

Heredoc Docker Container

Sometimes you want to get some tool as a Docker image, but you do not want to search for a suitable image or to create a new Dockerfile (no need to keep it for future use, for example). Sometimes storing Docker image definition in a file looks like an overkill – you need to decide how you edit, store and share this Dockerfile. Sometimes it’s better to have a single line command, that you can copy, share, embed into a shell script or create special command alias.
So, when you want to create a new ad-hoc container with a single command, try a Heredoc approach.

Create Alpine Based Container with ‘htop’ Tool

$ docker build -t htop - << EOF
FROM alpine
RUN apk --no-cache add htop
EOF

Docker Command Completion

The Docker CLI syntax is very rich and constantly growing: adding new commands and new options. It’s hard to remember every possible command and option, so having a nice command completion for a terminal is a must have.

The command completion is a kind of terminal plugin, that lets you auto-complete or auto-suggest what to type in next by hitting the tab key. Docker command completion works for commands and options. The Docker team prepared command completion for the docker, docker-machine and docker-compose commands, for both Bash and Zsh  shell.

If you are using Mac and Homebrew, then installing the Docker commands completion is pretty straight forward.

# Tap homebrew/completion to gain access to these
$ brew tap homebrew/completions

# Install completions for docker suite
$ brew install docker-completion
$ brew install docker-compose-completion
$ brew install docker-machine-completion

If you’re not using Mac, read the official Docker documentation for install instructions: docker engine, docker-compose and docker-machine.

Start Containers Automatically

When running a process inside a Docker container,  a failure may occur due to multiple reasons. In some cases, you can fix it by re-running the failed container. If you are using a Docker orchestration engine, like Swarm or Kubernetes, the failed service will be restarted automatically.
If not, then you might want to restart the container based on the exit code of the container’s main process, or always restart (regardless the exit code). Docker 1.12 introduced the docker run command: restart for this use case.

Restart Always

Restart the redis container with a restart policy of always so that if the container exits, Docker will restart it.

$ docker run --restart=always redis

Restart Container on Failure

Restart the redis container with a restart policy of on-failure and a maximum restart count of 10.

$ docker run --restart=on-failure:10 redis

Network Tricks

There are times when you might want to create a new container and connect it to an existing network stack. This might be the Docker host network or another container’s network. This is helpful when debugging and auditing network issues.
The docker run --network/net option allows you to do this.

Use the Docker Host Network Stack

$ docker run --net=host ...

The new container will attach to the same network interfaces as the Docker host.

Use Another Container’s Network Stack

$ docker run --net=container:<name|id> ...

The new container will attach to the same network interfaces as the other container. The target container can be specified by id or name.

Attachable Overlay Network

Using Docker Engine running in swarm mode, you can create a multi-host overlay network on a manager node. When you create a new swarm service, you can attach it to the previously created overlay network.

Sometimes you need to attach a new Docker container (filled with different networking tools), to an existing overlay network, in order to inspect the network configuration or debug network issues.  You can use the docker run command for this, eliminating the need to create a completely new “debug service”.

Docker 1.13 brings a new option to the docker network create command: attachable. The attachable option enables manual container attachment.

# create an attachable overlay network
$ docker network create --driver overlay --attachable mynet
# create net-tools container and attach it to mynet overlay network
$ docker run -it --rm --net=mynet net-tools sh

 


I hope you find this post useful. If you have more tricks on your own, please leave them in the comments box!

Pssst, secret last hack, check out Codefresh for Docker native CI/CD, it’s designed specifically for Docker and can handle the entire container driven lifecycle.

 

Ready to Get Started?
  • safer deployments
  • More frequent deployments
  • resilient deployments