Jacob Caban-Tomski
Jacob Caban-Tomski

Reputation: 105

Tagging and pushing Docker image changes digest

Pulling, tagging, and then pushing a Docker image we produce in a Github actions flow is causing a new image with a new digest to be pushed, rather than simply tagging the existing image.

First, we build the image using the newish v2 of the Docker build-push action (https://github.com/docker/build-push-action)

jobs:
  build-push:
    name: Build and push docker image
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      - name: Login to GCR
        uses: docker/login-action@v1
        with:
          registry: gcr.io
          username: _json_key
          password: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
      - id: docker_build
        uses: docker/build-push-action@v2
        with:
          tags: gcr.io/our-project/foo:initial-tag
          push: true
          target: build
          build-args: |
            NPM_TOKEN=${{ secrets.NPM_TOKEN }}

Then, in a separate workflow later we pull that image (gcr.io/our-project/foo:initial-tag) down and add new tags.

jobs:
  tag-image:
    name: Tag image
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Login to GCR
        uses: docker/login-action@v1
        with:
          registry: gcr.io
          username: _json_key
          password: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
      - run: |
          docker pull gcr.io/our-project/foo:initial-tag
          docker tag gcr.io/our-project/foo:initial-tag gcr.io/our-project/foo:new-tag
          docker push gcr.io/our-project/foo:new-tag

After pushing up new-tag, I would expect our registry to contain one image digest with the initial-tag and new-tag on it. Instead, this creates a new image digest with just new-tag on it.

Digest: sha256:abc123
Tags: gcr.io/our-project/foo:initial-tag

Digest: sha256:def456
Tags: gcr.io/our-project/foo:new-tag

In addition, if we now pull and add a tag (say latest) to new-tag, it will NOT create a new image digest

Digest: sha256:abc123
Tags: gcr.io/our-project/foo:initial-tag

Digest: sha256:def456
Tags: gcr.io/our-project/foo:new-tag, gcr.io/our-project/foo:latest

As a workaround, we have found that pushing the image name without tags correctly assigns the tag to the existing digest.

docker pull gcr.io/our-project/foo:initial-tag
docker tag gcr.io/our-project/foo:initial-tag gcr.io/our-project/foo:new-tag
docker push gcr.io/our-project/foo

Upvotes: 7

Views: 5184

Answers (3)

Danny Staple
Danny Staple

Reputation: 7332

If you inspect a docker image, the image id and the repo digests are not the same thing. If I take an image in multiple repositories and run docker inspect I see multiple digests:


    {
        "Id": "sha256:8c2c38aa676e97e57b4c8385bbcdcb240a933fafcc5f6cc508d2a3a005b24cb8",
        "RepoTags": [
            "docker/desktop-vpnkit-controller:v2.0",
            "hubproxy.docker.internal:5000/docker/desktop-vpnkit-controller:v2.0"
        ],
        "RepoDigests": [
            "docker/desktop-vpnkit-controller@sha256:b5bcb3a7172ae44d3a1df2e74a1b4d4e10d5562efe1d3c9197b23b383de70a86",
            "hubproxy.docker.internal:5000/docker/desktop-vpnkit-controller@sha256:b5bcb3a7172ae44d3a1df2e74a1b4d4e10d5562efe1d3c9197b23b383de70a86"
        ],

The ID field will be the same, which means the FS layers will be the same. It is not a different image.

Upvotes: 1

a611155
a611155

Reputation: 33

you can export docker image and push like this. then docker image digest does not change whenever you tag more.

- name: build docker image
  uses: docker/build-push-action@v3
  with:
    context: .
    file: 'Dockerfile'
    load: true
    tags: |
      ${{ steps.tag-container-image.outputs.TAG_A }}
      ${{ steps.tag-container-image.outputs.TAG_B }}
      ${{ steps.tag-container-image.outputs.LATEST }}

- name: push docker image
  run: |
    docker push ${{ steps.tag-container-image.outputs.TAG_A }}
    docker push ${{ steps.tag-container-image.outputs.TAG_B }}
    docker push ${{ steps.tag-container-image.outputs.LATEST }}

Upvotes: 1

csanchez
csanchez

Reputation: 1659

crane cp will copy images efficiently and retaining the digest value

https://github.com/google/go-containerregistry/blob/main/cmd/crane/doc/crane_copy.md

Upvotes: 1

Related Questions