How to Use Container Image Digests to Improve Reproducibility

Video demonstration of using digests with Chainguard Images

Tools used in this video

Commands used

docker pull cgr.dev/chainguard/node
docker manifest inspect cgr.dev/chainguard/node@sha256:ede7ef4ca485553f5313f7a02ad3537db1fe337079fc7cfb879f44cf709326db
crane digest --full-ref cgr.dev/chainguard/node
docker pull cgr.dev/chainguard/node:latest@sha256:ede7ef4ca485553f5313f7a02ad3537db1fe337079fc7cfb879f44cf709326db

Dockerfile

FROM cgr.dev/chainguard/go:latest@sha256:7e60584b9ae1eec6ddc6bc72161f4712bcca066d5b1f511d740bcc0f65b05949 AS build 

WORKDIR /src
RUN CGO_ENABLED=0 go build -o /bin/server ./src


FROM cgr.dev/chainguard/static AS prod

COPY --from=build /bin/server /bin/
EXPOSE 8000
ENTRYPOINT [ "/bin/server" ]

Transcript

0:05 You might have heard the advice to pin to a digest when using container images.

0:10 But what does this mean?

0:11 Why is it useful and how can you do it?

0:15 So a digest is a content based hash of a unique container image.

0:19 No two container images can have the same digest.

0:23 If you pull an image by the digest, you are guaranteed to get exactly the same image each time.

0:30 And this contrasts with tags like latest or 3.0 which are continually updated and changed.

0:37 So you run pull twice, you might well get a different image.

0:41 And this has implications for reproducibility.

0:46 If images are changing how can I be sure if it works for me it will work for anybody else or myself in the future?

0:52 So what’s the easiest way to get the digest of an image?

0:56 You can run Docker pull and grab it directly from there, for example.

1:02 And you can see the digest right here, but do note that this digest will refer to the index of the image which will list different images for different platforms.

1:15 And most likely this is what you want.

1:18 But we can see what I mean by using the Docker manifest inspect tool.

1:28 And we’ll use this digest and we’ll pipe it through jq.

1:40 And so note that this is the index of the image and it actually lists two more digests that point to actual platform specific images.

1:48 In this case, the arm64 image and the amd64 image.

1:54 If you wanted the image for a specific platform, you could use the address listed here, but not that that might break for some people.

2:02 So make sure you know what you’re doing before using that.

2:06 And I should also mention the crane tool which is a little bit easier to use in scripts as you don’t have to parse the output. If I can spell.

2:16 There we go.

2:18 So here I’ve run crane digest.

2:20 I’ve asked for the full reference which makes it output the beginning part again.

2:24 So we got the digest for the node image as a single line in output.

2:29 And you can also pass a `–platform`` argument which will return the digest for specific platform.

2:38 So I could ask for the arm64 platform and get this digest back.

2:42 OK.

2:43 So now that we have the digest, how can we use it?

2:46 Well, the most obvious way is to just do a Docker pull.

2:53 So here we’ve done a docker pull on node:latest, using this above digest and that works.

3:01 We get back exactly the same image.

3:03 One of the interesting things there and you might have noticed as I went backwards from history is that we can change this tag here.

3:10 It doesn’t, and it turns out Docker or Docker Hub and registries don’t actually care what this tag is when you specify an digest - that part gets ignored.

3:21 So we can put anything at all there and you can use it for metadata.

3:26 But where you’re most likely to use a digest is in the configuration file like a Dockerfile, a compose file or Kubernetes yaml file.

3:35 So I have an example here using the Dockerfile here.

3:39 We’ve pinned the version of the Go compiler.

3:43 And what that means is every time I run the docker build, I’ll be using exactly the same Go compiler.

3:50 So I’m absolutely sure that nothing’s changed in the Go compiler that might cause this build to fail.

3:56 And by using digest in Dockerfiles, we make the whole process much more reproducible; things won’t break because the underlying image has changed in this case.

4:08 And that’s really about it.

4:09 We’ve looked at what our digest is, how you can get it and how you can use it to improve reproducibility.

Last updated: 2023-08-10 15:21