Small secure base images

Prefer Distroless to Alpine https://itnext.io/which-container-images-to-use-distroless-or-alpine-96e3dab43a22

AWESOME list of best practices

https://www.bejarano.io/how-to-write-great-container-images/

Restart policies

  • ”no” is default
  • ”unless-stopped” is preferred
  • behaviour when docker is restarted

https://docs.docker.com/config/containers/start-containers-automatically/

Linting

Hadolit

Docker for local dev environments

https://blog.deref.io/containers-dont-solve-everything/

https://github.com/deref/exo

Build cross-platform

(From https://github.com/teslamotors/fleet-telemetry )

DOCKER_BUILD_KIT=1 DOCKER_CLI_EXPERIMENTAL=enabled docker buildx version
docker buildx create --name go-builder --driver docker-container --driver-opt network=host --buildkitd-flags '--allow-insecure-entitlement network.host' --use
docker buildx inspect --bootstrap
docker buildx build --no-cache --progress=plain --platform linux/amd64 -t <name:tag>(e.x.: fleet-telemetry:local.1.1) -f Dockerfile . --load
container_id=$(docker create fleet-telemetry:local.1.1) docker cp $container_id:/fleet-telemetry /tmp/fleet-telemetry

Rootless docker

https://www.cmtops.dev/posts/rootless-docker-in-multiuser-environment/

https://mohitgoyal.co/2021/04/14/going-rootless-with-docker-and-containers/

Handling signals

Have you ever tried to shut down your Docker image, only for it to take a surprisingly long time to exit?

It turns out that if you don’t configure your Docker image correctly, signals won’t be delivered to your process, and shutdowns will take 10 seconds: first the original signal will be used, then after a timeout SIGKILL will be used, shutting it down with extreme prejudice (the same way kill -9 does).

Because it’s killed with the equivalent of kill -9, any cleanup code you have written for shutdowns won’t run. And while you shouldn’t ever rely on such code, since crashes do happen, it’s often still useful to have the ability to cleanup on shutdown.

So how do you get fast and clean shutdowns in your Docker container? Here is a summary, an excerpt from my Python on Docker Production Handbook:

To get signal delivery working:

Use the [] syntax of ENTRYPOINT and CMD, not the shell syntax. If your entrypoint script is a shell script, make sure it ends by using the shell exec command to run your final program. This will replace the shell process with your program. For example, let’s say you have a Dockerfile that runs a script called entrypoint.sh. The shell script should look like this:

#!/bin/bash
set -euo pipefail
# BAD:
# python myserver.py
# GOOD:
exec python myserver.py

And the Dockerfile:

# BAD:
# ENTRYPOINT ./entrypoint.sh
# GOOD:
ENTRYPOINT ["./entrypoint.sh"]

Additionally, there are two other problems you might encounter:

If you’re using a shell script there’s another failure mode involving pipes: don’t use them on the final command in your entrypoint script. If your program expects a signal other than SIGTERM, use the STOPSIGNAL Dockerfile command. For example, if your program shuts down just fine outside of Docker when you hit Ctrl-C and a KeyboardInterrupt is raised, that means it expects a SIGINT, and you should use STOPSIGNAL INT. References

Why your Dockerized application isn’t receiving signals (hynek.me) STOPSIGNAL reference (docs.docker.com)

Space-saving

Beware: chown / changing file metadata

Running chown on a file makes a copy in that layer

https://blog.vamc19.dev/posts/dockerfile-copy-chmod/