Docker is a very versatile tool, which boosts development and speeds up deployment. In this post, I am going to show 10 awesome tricks for Docker professionals (a.k.a. Dockeressionals). Complementing code snippets can be found on Github. Each directory includes an executable file run.sh, which makes each example executable with little effort.
Let’s get started….Dockerioo.
1. Conditional dependency based on healthcheck
In certain cases, it is necessary to define the order in which specific services are started (e.g. applications should start after the database has booted successfully). Therefore, Docker introduced health checks for containers, which can be used to constrain the startup order of the services. In the example below the service, pgweb depends on a healthy db service. Unfortunately, this feature was removed in version 3 of Docker Compose.
2. Multi-stage builds
Building applications inside Dockerfiles result in large image sizes (e.g. due to build dependencies) and should be avoided unless multi-staged builds are used. It is possible to build applications in a dedicated stage, whereas only the build artefacts are copied to the final Docker image. The example below builds a Java-based application and copies the resulting Jar-file to the final image. All maven dependencies fetched during the build are omitted. More information can be found in the official documentation.
3. Network Security
Docker Compose provides functionalities for defining networks between individual services, whereas containers are only allowed to talk to services within the same network. The example below shows three services and two networks (i.e. db-backend and frontend). It prohibits communication between services maildev and db. Only pgweb and db are allowed to talk to each other since they are part of the same network. The results can be checked via accessing http://localhost:8081 after run.sh has been executed.
4. Database Initialisation
Sometimes it is handy to start with an initialised database (e.g. inserting dumped database exports). The official PostgreSQL image from Docker supports this feature. Simply copy your SQL or shell scripts to /docker-entrypoint-initdb.d/ (see code snippet below). More information can be found in the official documentation.
5. Adapting ps Output
The output of docker ps can be too verbose sometimes, which results in unreadable output in the terminal. Fortunately, it is possible to define which columns should be included in the output (see command below). It is even possible to edit the default format for the output. Further information can be found here.
A very handy but dangerous way to use Docker inside Docker containers is linking docker.sock from the host via volumes (see code below). This way the Docker installation of the host can be used inside the container. A scenario for this setup might be a CI framework (e.g. Jenkins) inside a Docker container, which should be able to build and push Docker images. More information can be found here.
A very useful feature for building reusable base images came with Docker version 0.8. The ONBUILD command allows defining commands, which are executed once child images are built. An example can be found in the official base images for Python (see code below).
8. Execute Applications as non-root User
A lot of containerised applications are executed with the root user. This might not always be necessary and exposes possible security-relevant attack surfaces. In the example below an NGINX web server is configured so it can be executed without superuser rights. More information can be found here.
9. Installation of updated Packages
This one might be a minor issue, but it happened to me more than once. If the command "RUN apt-get update" is stated in a dedicated line, it will be cached and not executed in subsequent builds. Therefore, an installation of outdated packages may occur. The code snippet below updates packages and installs curl in a single RUN command.
10. Endless BusyBox
In certain cases, it is necessary to just start a container without a specific task (i.e. an endless loop in the code snippet below). Once it is running you can connect to it via docker exec and perform necessary debugging inside the Docker environment (e.g. inside a certain network).
That's it. I hope these 10 commands help you in your daily work with Docker. They have definitely helped me a lot. Stay tuned for further blog posts.