Home > Software design >  Identify FROM line from Docker Image
Identify FROM line from Docker Image

Time:02-17

I have an image from a colleague and the original version of the Dockerfile was lost that was used to create it.

I used alpine/dfimage to rebuild everything in the Dockerfile except the first line (FROM).

According to Artifactory, the digest for the layer is

{
    "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
    "size": 2813316,
    "digest": "sha256:cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08"
}

and the ADD line is:

ADD file:b91adb67b670d3a6ff9463e48b7def903ed516be66fc4282d22c53e41512be49 in /

I'm fairly confident the base image was pulled from a public repo. I've been trying to find a way of searching Docker Hub for images by digest (like I can in Artifactory), but I've yet to identify something. For example, library/apline:3.15.0 has a digest of sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 (different from the repo digest of sha256:c74f1b1166784193ea6c8f9440263b9be6cae07dfe35e32a5df7a31358ac2060 as advertised on Docker Hub).

If I knew the namespace and repo, I could simply specify the digest with docker image pull server/namespace/repo@digest. Unfortunately, the only thing I have is a previous version of the Dockerfile and the namespace and repo referenced there didn't work.

FROM mcr.microsoft.com/dotnet/core/runtime:2.1.11-alpine3.9

In other words, docker image pull mcr.microsoft.com/dotnet/core/runtime@sha256:cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08 did not return success. Nor did docker image pull mcr.microsoft.com/dotnet/runtime@sha256:cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08.

Any help would be greatly appreciated. My only alternative at this point is to reinvent the wheel.

CodePudding user response:

So, I was able to find this, but none of the data I have seem to correlate and I'd welcome a discussion on it if there is, in fact, any correlating data.

The image of interest is alpine:3.11.6 with a digest of sha256:9a839e63dad54c3a6d1834e29692c8492d93f90c59c978c1ed79109ea4fb9a54.

CodePudding user response:

The digest for a layer blob and the digest for the image manifest are two different things, the manifest contains the digests for the layer blobs so that if any layer changes, the digest for the manifest also changes. That's what provides the immutability of images. Inspecting the image you found:

$ regctl manifest get localhost:5000/library/alpine:3.11.6
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.docker.distribution.manifest.v2 json",
  "config": {
    "mediaType": "application/vnd.docker.container.image.v1 json",
    "size": 1507,
    "digest": "sha256:f70734b6a266dcb5f44c383274821207885b549b75c8e119404917a61335981a"
  },
  "layers": [
    {
      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
      "size": 2813316,
      "digest": "sha256:cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08"
    }
  ]
}

You can see your one blob, but to pull the image, you need the manifest digest, and unfortunately there's no way to list all the manifests that point to a specific blob (at least not yet, we may get that as part of OCI reference types, but that's a ways off). However, the manifest itself has a digest that matches what you would see when inspecting the image:

$ regctl manifest get localhost:5000/library/alpine:3.11.6 --format raw-body | sha256sum
39eda93d15866957feaee28f8fc5adb545276a64147445c64992ef69804dbf01  -

$ regctl manifest get localhost:5000/library/alpine:3.11.6 --list --format raw-body | sha256sum
9a839e63dad54c3a6d1834e29692c8492d93f90c59c978c1ed79109ea4fb9a54  -

As for why there are two digests above, the alpine image is a multi-platform image, so there's a digest for the parent manifest list, and then a digest for each image manifest. Here's what the manifest list looks like:

$ regctl manifest get localhost:5000/library/alpine:3.11.6 --list --format raw-body | jq .
{
  "manifests": [
    {
      "digest": "sha256:39eda93d15866957feaee28f8fc5adb545276a64147445c64992ef69804dbf01",
      "mediaType": "application/vnd.docker.distribution.manifest.v2 json",
      "platform": {
        "architecture": "amd64",
        "os": "linux"
      },
      "size": 528
    },
    {
      "digest": "sha256:0ff8a9dffabb5ed8dcba4ee898f62683305b75b4086f433ee722db99138f4f53",
      "mediaType": "application/vnd.docker.distribution.manifest.v2 json",
      "platform": {
        "architecture": "arm",
        "os": "linux",
        "variant": "v6"
      },
      "size": 528
    },
    {
      "digest": "sha256:19c4e520fa84832d6deab48cd911067e6d8b0a9fa73fc054c7b9031f1d89e4cf",
      "mediaType": "application/vnd.docker.distribution.manifest.v2 json",
      "platform": {
        "architecture": "arm",
        "os": "linux",
        "variant": "v7"
      },
      "size": 528
    },
    {
      "digest": "sha256:ad295e950e71627e9d0d14cdc533f4031d42edae31ab57a841c5b9588eacc280",
      "mediaType": "application/vnd.docker.distribution.manifest.v2 json",
      "platform": {
        "architecture": "arm64",
        "os": "linux",
        "variant": "v8"
      },
      "size": 528
    },
    {
      "digest": "sha256:b28e271d721b3f6377cb5bae6cd4506d2736e77ef6f70ed9b0c4716da8bdf17c",
      "mediaType": "application/vnd.docker.distribution.manifest.v2 json",
      "platform": {
        "architecture": "386",
        "os": "linux"
      },
      "size": 528
    },
    {
      "digest": "sha256:e095eb9ac24e21bf2621f4d243274197ef12b91c67cde023092301b2db1e073c",
      "mediaType": "application/vnd.docker.distribution.manifest.v2 json",
      "platform": {
        "architecture": "ppc64le",
        "os": "linux"
      },
      "size": 528
    },
    {
      "digest": "sha256:41ba0806c6113064dd4cff12212eea3088f40ae23f182763ccc07f430b3a52f8",
      "mediaType": "application/vnd.docker.distribution.manifest.v2 json",
      "platform": {
        "architecture": "s390x",
        "os": "linux"
      },
      "size": 528
    }
  ],
  "mediaType": "application/vnd.docker.distribution.manifest.list.v2 json",
  "schemaVersion": 2
}

Once we have the manifest list, either by tag or digest, we can walk the structure to the manifests and contained blobs. But the blobs don't contain digest of the parent (adding it would change the digest of the blob, which changes the digest of the parent, and you get a circular dependency).

One thing that was recently added to the list of OCI standard annotations is org.opencontainers.image.base.digest and org.opencontainers.image.base.tag, which if implemented would allow users of an image to identify their base image by both tag and digest, which can be useful for determining when an image needs to be rebuilt (when the tag no longer refers to the same digest).

  • Related