How to use docker buildx imagetools create command to combine and tag images

DockerDockerBeginner
Practice Now

Introduction

In this lab, you will learn how to effectively use the docker buildx imagetools create command to combine and tag Docker images. This hands-on experience will guide you through the process of creating a new image by merging content from multiple source images, a common practice in building complex applications.

You will then explore how to tag the newly created image, preview the final image structure without pushing using the --dry-run flag, and add valuable annotations to the image index for better organization and metadata management. By the end of this lab, you will have a solid understanding of how to leverage docker buildx imagetools create for advanced image manipulation and management.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("Docker")) -.-> docker/ImageOperationsGroup(["Image Operations"]) docker(("Docker")) -.-> docker/DockerfileGroup(["Dockerfile"]) docker(("Docker")) -.-> docker/ContainerOperationsGroup(["Container Operations"]) docker/ContainerOperationsGroup -.-> docker/inspect("Inspect Container") docker/ContainerOperationsGroup -.-> docker/create("Create Container") docker/ImageOperationsGroup -.-> docker/pull("Pull Image from Repository") docker/ImageOperationsGroup -.-> docker/tag("Tag an Image") docker/ImageOperationsGroup -.-> docker/images("List Images") docker/DockerfileGroup -.-> docker/build("Build Image from Dockerfile") subgraph Lab Skills docker/inspect -.-> lab-555057{{"How to use docker buildx imagetools create command to combine and tag images"}} docker/create -.-> lab-555057{{"How to use docker buildx imagetools create command to combine and tag images"}} docker/pull -.-> lab-555057{{"How to use docker buildx imagetools create command to combine and tag images"}} docker/tag -.-> lab-555057{{"How to use docker buildx imagetools create command to combine and tag images"}} docker/images -.-> lab-555057{{"How to use docker buildx imagetools create command to combine and tag images"}} docker/build -.-> lab-555057{{"How to use docker buildx imagetools create command to combine and tag images"}} end

Create a new image from multiple source images

In this step, we will learn how to create a new Docker image by combining content from multiple source images. This is a common scenario when you need to build an image that includes components from different base images or pre-built images.

First, let's pull the necessary source images. We will use the ubuntu and alpine images as examples.

docker pull ubuntu:latest
docker pull alpine:latest

You should see output indicating that the images are being pulled.

latest: Pulling from library/ubuntu
...
Status: Downloaded newer image for ubuntu:latest
latest: Pulling from library/alpine
...
Status: Downloaded newer image for alpine:latest

Now, we will create a new image using a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Create a new file named Dockerfile in your ~/project directory.

nano ~/project/Dockerfile

Add the following content to the Dockerfile:

FROM ubuntu:latest AS base
FROM alpine:latest AS alpine_base

COPY --from=alpine_base /etc/alpine-release /app/alpine-release
COPY --from=base /etc/os-release /app/ubuntu-release

WORKDIR /app

CMD ["ls", "-l"]

Let's break down this Dockerfile:

  • FROM ubuntu:latest AS base: This line sets the base image for the first stage of our build to ubuntu:latest and names this stage base.
  • FROM alpine:latest AS alpine_base: This line starts a new build stage using alpine:latest as the base image and names this stage alpine_base. This is a multi-stage build, allowing us to copy files between stages.
  • COPY --from=alpine_base /etc/alpine-release /app/alpine-release: This command copies the file /etc/alpine-release from the alpine_base stage to the /app/alpine-release directory in the current stage.
  • COPY --from=base /etc/os-release /app/ubuntu-release: This command copies the file /etc/os-release from the base stage to the /app/ubuntu-release directory in the current stage.
  • WORKDIR /app: This sets the working directory for subsequent instructions to /app.
  • CMD ["ls", "-l"]: This specifies the default command to run when a container is started from this image. It will list the contents of the /app directory.

Save the Dockerfile by pressing Ctrl + X, then Y, and Enter.

Now, build the image using the docker build command. The . at the end of the command specifies the build context, which is the current directory (~/project).

docker build -t my-multi-stage-image:latest ~/project

You should see output indicating the build process, including the different stages being executed.

[+] Building
...
Successfully built <image_id>
Successfully tagged my-multi-stage-image:latest

After the build is complete, you can verify that the image was created by listing your local images.

docker images my-multi-stage-image

You should see your newly created image in the list.

REPOSITORY             TAG       IMAGE ID       CREATED         SIZE
my-multi-stage-image   latest    <image_id>     About a minute ago   ...MB

Finally, let's run a container from this image to see the copied files.

docker run --rm my-multi-stage-image:latest

The --rm flag automatically removes the container when it exits. The output should show the files copied from the ubuntu and alpine images.

total 8
-rw-r--r-- 1 root root 25 Aug 24 10:00 alpine-release
-rw-r--r-- 1 root root 281 Aug 24 10:00 ubuntu-release

This confirms that we successfully created an image by combining content from multiple source images using a multi-stage build.

Tag the newly created image

In this step, we will learn how to add additional tags to the Docker image we created in the previous step. Tagging an image is useful for versioning, identifying different builds, or associating an image with a specific repository.

In the previous step, we built an image and automatically tagged it as my-multi-stage-image:latest. Now, let's add another tag to this image, for example, my-multi-stage-image:v1.0.

The docker tag command is used to create a tag TARGET_IMAGE that refers to SOURCE_IMAGE. The syntax is docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG].

First, let's list the existing images to confirm the image ID of my-multi-stage-image:latest.

docker images my-multi-stage-image

You will see output similar to this, where <image_id> is the unique identifier for your image:

REPOSITORY             TAG       IMAGE ID       CREATED         SIZE
my-multi-stage-image   latest    <image_id>     ...             ...MB

Now, use the docker tag command to add the v1.0 tag to this image. You can use either the image name and tag (my-multi-stage-image:latest) or the image ID (<image_id>) as the source. Using the name and tag is generally easier.

docker tag my-multi-stage-image:latest my-multi-stage-image:v1.0

This command creates a new tag v1.0 that points to the same image ID as my-multi-stage-image:latest. There will be no output if the command is successful.

To verify that the new tag has been added, list the images again.

docker images my-multi-stage-image

You should now see both tags associated with the same image ID:

REPOSITORY             TAG       IMAGE ID       CREATED         SIZE
my-multi-stage-image   latest    <image_id>     ...             ...MB
my-multi-stage-image   v1.0      <image_id>     ...             ...MB

You have successfully added a new tag to your Docker image. This allows you to refer to the same image using different names or versions.

Show the final image without pushing using --dry-run

In this step, we will explore how to view the details of the final image that would be pushed to a registry without actually performing the push operation. This is useful for inspecting the image manifest and configuration before sharing it.

The docker manifest command allows you to inspect and manage image manifests. An image manifest is a JSON document that describes the image, including its layers, configuration, and potentially references to other platform-specific images in a manifest list.

To show the manifest of our my-multi-stage-image:latest image without pushing, we can use the docker manifest inspect command with the --dry-run flag.

docker manifest inspect --dry-run my-multi-stage-image:latest

This command will output the image manifest in JSON format to your terminal. The --dry-run flag prevents the command from attempting to contact a registry or push any data.

The output will be a detailed JSON structure describing the image. It will include information like the image's configuration, the layers it consists of (represented by their digests), and other metadata.

{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   "config": {
      "mediaType": "application/vnd.docker.container.image.v1+json",
      "size": ...,
      "digest": "sha256:..."
   },
   "layers": [
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": ...,
         "digest": "sha256:..."
      },
      ...
   ]
}

You can examine this output to understand the structure and content of your image as it would be represented in a registry. This is particularly helpful for debugging or verifying the image's composition.

Note that the exact content of the JSON output will vary depending on the image's layers and configuration.

Add annotations to the created image index

In this step, we will learn how to add annotations to an image index (also known as a manifest list). An image index is used to reference multiple image manifests, typically for different architectures or operating systems. Adding annotations to the index provides metadata about the entire set of images.

While our current my-multi-stage-image is a single-architecture image, we can still demonstrate the concept of adding annotations to its manifest, which acts as a simple index in this case.

The docker manifest annotate command is used to add or update annotations for a specific image within a manifest list. The syntax is docker manifest annotate MANIFEST_LIST IMAGE --annotation KEY=VALUE.

First, let's create a manifest list for our image. Since we only have one image, the manifest list will simply reference our existing image. We'll use the docker manifest create command.

docker manifest create my-multi-stage-image:annotated my-multi-stage-image:latest

This command creates a new manifest list named my-multi-stage-image:annotated that includes a reference to my-multi-stage-image:latest. There will be no output if successful.

Now, we can use the docker manifest annotate command to add an annotation to the entry for my-multi-stage-image:latest within the my-multi-stage-image:annotated manifest list. Let's add an annotation indicating the operating system.

docker manifest annotate my-multi-stage-image:annotated my-multi-stage-image:latest --annotation "os=linux"

This command adds the annotation os=linux to the manifest entry for my-multi-stage-image:latest within the my-multi-stage-image:annotated list. Again, there is no output on success.

To verify that the annotation has been added, we can inspect the manifest list using docker manifest inspect.

docker manifest inspect my-multi-stage-image:annotated

The output will be a JSON structure representing the manifest list. You should see the annotation you added within the entry for my-multi-stage-image:latest. Look for the "annotations" field within the "manifests" array.

{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": ...,
         "digest": "sha256:...",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         },
         "annotations": {
            "os": "linux"
         }
      }
   ]
}

You have successfully added an annotation to the image index. Annotations provide valuable metadata that can be used by registries and clients to understand more about the images they are dealing with.

Summary

In this lab, we learned how to use the docker buildx imagetools create command to combine and tag images. We started by creating a new image from multiple source images using a multi-stage Dockerfile, demonstrating how to copy files between different base images.

Following the image creation, we explored how to tag the newly created image and used the --dry-run flag to preview the final image without pushing it. Finally, we learned how to add annotations to the created image index, providing additional metadata for the combined image.