kbld - digest reference to container image

Let’s imagine the situation when the deployment Kubernetes manifest is referencing the latest image tag of third-party software like this:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

Then you made a static analysis of that manifest and in the result you get:

$ datree test deployment.yaml
...
❌  Ensure each container image has a pinned (tag) version  [1 occurrence]
    - metadata.name: nginx-deployment (kind: Deployment)
      > key: spec.template.spec.containers.0.image (line: 17:16)

💡  Incorrect value for key `image` - specify an image version to avoid unpleasant "version surprises" in the future
...

It’s undoubtedly a valid point, but as I mentioned before I cannot change the image build process and get the “right” tags. How can we avoid this unpleasant version surprise?

A long long time ago docker decide to abandon its own mechanism of image IDs by migrating it to a secure SHA256 checksum. It brings some benefits because each image layer get its own unique SHA256 checksum (the same like commit id in git) and can be shared between completely different images. The image tag becomes some kind of pointer pointing to the selected SHA256 checksum. So there is a question of what is happening when we change pointer latest to a different checksum, does the previous checksum will be removed aka can I reuse it ?

Now to the play comes tools kbld, it’s a part of a bigger project called carvel which again it’s a part of VMware Tanzu - a modern application approach including the platform Kubernetes and tools above it. kbld is responsible for building images using different building platforms (docker, ko, bazel) and resolving image digest from the tag. The second feature is what are we looking for, we want to stick our deployment with the exact image version:

$ kbld -f /tmp/pod.yaml
resolve | final: nginx:latest -> index.docker.io/library/nginx@sha256:2f770d2fe27bc85f68fd7fe6a63900ef7076bc703022fe81b980377fe3d27b70
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    kbld.k14s.io/images: |
      - origins:
        - resolved:
            tag: latest
            url: nginx:latest
        url: index.docker.io/library/nginx@sha256:2f770d2fe27bc85f68fd7fe6a63900ef7076bc703022fe81b980377fe3d27b70
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: index.docker.io/library/nginx@sha256:2f770d2fe27bc85f68fd7fe6a63900ef7076bc703022fe81b980377fe3d27b70
        name: nginx
        ports:
        - containerPort: 80

Succeeded

Every time you run your app you will get the same version of it. AFAIK docker hub is not doing garbage collection so each image digest should be kept. A similar approach is taken in ArgoCD when you decide to combine it with Image Updater it’s called the digest update strategy.

comments powered by Disqus

powered by Hugo and Noteworthy theme