Docker Image Maintainer Best Practices
Docker Image Maintainer Best Practices
Introduction
Docker leverages container advantages, like isolation, security and fast startup coupled with image
packaging advantages like versioning, rapid deployment and consistency. But just like other packaging systems, e.g. Linux software packages like RPM or DPKG and Java Enterprise Archives, you need to apply standards to your Docker image building and maintainance process. This post documents the best practises I use in my Docker projects.
Guidelines for developing Docker images
- Every Docker image should have a maintainer (either a team or an individual). The maintainer should perform the following tasks.
- Adding new features to the image.
- Fixing bugs.
- Life Cycle Management (LCM): Keep track of up stream fixes and new versions of the software that you use in your containers. This is very important to ensure you're running up to date software in your containers. Outdated software might contain security holes, that are exploitable by malicious users.
- Every Docker image should serve one clear purpose. This adheres to classic Unix Philosophy : Do one thing and do it well.
- Create so called Side Kick images to perform utility task such as generating configuration files. This way you can keep your main images lean
- Always add a README to your project that documents the image and its parameters
- Carefully choose your base images, i.e. the images that you build your own images on, e.g. the Alpine or Debian Linux distributions. Limiting the number of base images makes your LCM easier (at the cost of flexibility ofcourse). It's much easier to just track one base distribution security list than ten. So standardize on a limited set of Linux distribution base images for your projects. Either Debian, Alpine, Ubuntu, CentOS etc. but don't use all of them. If an official image is based on another Linux distribution you should check if they regularly release security updates or considering porting it to the base images that you decided to support. But usually official images are available based on multiple distributions already ie.g. the OpenJDK image is available based on both Debian and Alpine.
- Keep your images minimal, only install the software needed and alway perform a clean operation on the package manager command (e.g. apt-get clean).
Technical Guidelines
- Every Docker Image should contain a health check.
The HEALTCHECK command in the Dockerfile should contain a CMD that runs at an interval to check the health of the container. This should be a simple check to verify the basic health of the container.
For example, the following healthcheck could be used in a LDAP container to ensure the LDAP daemon is still available:
HEALTHCHECK --interval=5m --retries=1 --timeout=1m CMD ldapsearch -Y EXTERNAL -H ldapi:/// -b dc=superclass,dc=nl -s base|grep -q "numEntries: 1"||exit 1
- Enable your containers to run non-root
While Docker containers are more protected than regular processes, as ports have to be explicitly exposed, it's always better to run your software non-root. You can use the USER instruction in your Dockerfile, but some applications (e.g. most daemons) have the ability to drop root-privileges themselves. - Prepare to synchronise your container and host user-ids (UID).
Containers use their own UID/GIDs that are unrelated to the hosti UID/GIDs. So if you use a UID of 1000 in your container this will most likely map to a different name users on the host (if at all). Only UID 0 will alway map to the root user (but see the previous bullet). Especially if you're containers are writing to host fileystems it's important that your containers have the possibility to change the UIDs used in the container to the ones used on the host system. To do this use an ENRTYPOINT script that is able to change the UID/GID in container password file based on environment variables so they match with the ones available on the host.