-
Best practices
Keeping container images small
It is important to keep container images small. Smaller images download faster, which reduces startup time for Pods in Kubernetes and improves the responsiveness of scaling operations. They also use less storage in registries and on cluster nodes, which matters in multi-tenant environments like Rahti. Moreover, a smaller image contains fewer packages and files, which reduces the potential attack surface and lowers the chance of including outdated or vulnerable components. This makes maintenance easier and improves overall security. Because smaller images contain only what the application actually needs, they are more predictable, easier to debug, and simpler to reproduce across environments. Rahti's registry has an image size limit of 5 GiB.
Use a minimal base image
Start with the smallest image that still provides what you need. Images like Alpine, UBI-minimal, or Distroless include only essential components, which significantly reduces the size of the final image and lowers the attack surface. Example:
Use multi-stage builds
Build your application in one stage that contains compilers and build tools, and copy only the final binary or required output into a much smaller runtime stage. This prevents large toolchains from ending up in the final image. Example:
FROM golang:1.21 AS builder
WORKDIR /app
COPY ../../images .
RUN go build -o app
FROM alpine:3.19
COPY --from=builder /app/app /usr/local/bin/app
CMD ["app"]
Use a .dockerignore file
The .dockerignore file allows you to exclude files like source control metadata, documentation, artifacts, and other
unnecessary files reduces the build context and keeps them out of your image. This speeds up builds and avoids adding
unwanted content. Example:
Install only what the application needs
Adding tools, debuggers, shells, or libraries “just in case” increases the image size and security risk. Stick to the minimal set of dependencies your application actually needs. Example:
Bad (bloated image):
Better:
Combine related commands into fewer layers.
Every RUN instruction creates a new layer. If you install packages in one layer and clean them in another, the unwanted content remains in earlier layers. Package managers leave behind metadata, caches, and temporary files. Cleaning these in the same layer where they're created prevents them from being stored permanently in the image. Combining commands prevents this. Example:
Bad (bloated image):
Better (all in one layer):
Keep data out of the image
Images should only contain the application's runtime. This means that the data needed to run the application should not be added to the image. In this way, not only the image is smaller, but we avoid a rebuild when the data changes. The data can be stored in an external volume that will be attached to the Pod upon startup, or it can be stored in a remote object storage like Allas and downloaded during the startup or on demand when needed.