1. Introduction

Docker is a popular deployment tool that enables us to package and run apps. Due to the high adoption, a need often arises to extend functionality based on different requirements. Thus, to achieve this, some deployments make use of docker plugins.

For example, if we want to persist data across different hosts, we use a volumes plugin. Another commonly used plugin is Docker buildx. It extends the building ability of images by using the BuildKit builder. Hence, with the plugin, we can build images for different platforms and architectures. Furthermore, it supports parallel multi-stage makes with custom contexts.

In this tutorial, we’ll look at an introduction to Docker buildx.

2. Installing buildx

First and foremost, for buildx to run, we need to have Docker installed. Docker buildx support is available from Docker engine 19.00 onwards.

2.1. Docker Version Check

Let’s first start by checking our Docker version:

$ docker --version
Docker version 19.03.8, build afacb8b

In this case, we have support for buildx.

2.2. Enable Experimental Features

Next, we enable the Docker experimental feature by setting the environment variable:

$ export DOCKER_CLI_EXPERIMENTAL=enabled

To ensure our setting remains after the session, We add the variable to $HOME/.bashrc for Bash.

2.3. Verify buildx

With that in place, we should now have access to buildx:

$ docker buildx

Usage:  docker buildx COMMAND

Build with BuildKit

Management Commands:
  imagetools  Commands to work on images in registry

Commands:
  bake        Build from a file
  build       Start a build
  create      Create a new builder instance
  inspect     Inspect current builder instance
  ls          List builder instances
  rm          Remove a builder instance
  stop        Stop builder instance
  use         Set the current builder instance
  version     Show buildx version information

Run 'docker buildx COMMAND --help' for more information on a command.

The output shows common subcommands and the syntax for each.

2.4. Troubleshooting

Sometimes, despite everything being in place, we might get an error when running the buildx subcommand of docker:

$ docker buildx build .
docker: 'buildx' is not a docker command.
See 'docker --help'

This can happen even if we seem to have a version of Docker after 19. Often, the reason for that is the use of the docker.io package.

Regardless, one main way to correct this is to install the docker-buildx package. For example, let’s use APT:

$ apt install docker-buildx

Alternatively, if we use the official Docker repositories, we install the docker-buildx-plugin package:

$ apt install docker-buildx-plugin

Usually, the latter is a better approach, since it’s officially supported.

To find out which package is available, if any, we can also use the local package manager:

$ apt list --installed | grep buildx

If all else fails, we can also reboot the Docker host as a potential fix.

3. Building With buildx

buildx performs all the Docker build capabilities. Therefore, we can execute them similarly to build. For instance, specifying the target platform, build caching, and output configs. Beyond that, buildx provides extra features.

Primarily, buildx provides the ability to build images for multiple platforms simultaneously. In addition, we can use it for multi-stage builds within a single dockerfile for smaller images. Finally, buildx has the ability to customize inputs, arguments, or variables during the build process.

Let’s dive into an example by creating an instance:

$ docker buildx create --name ourbuilder
ourbuilder

This creates a build instance called ourbuilder.

Next, we’ll set it as the active directory:

$ docker buildx use ourbuilder

After that, let’s create a dockerfile to run a simple node application:

# Base image
FROM node:14-alpine

# Set working directory
WORKDIR /app

# Copy application files
COPY . .

# Install dependencies
RUN npm install --production

# Expose the port
EXPOSE 3000

# Start the application
CMD ["node", "app.js"]

Here, we use the node.js base image and set the working directory to /app. Then, we copy app files to the container. Lastly, we install all dependencies, expose port 3000, and start the app:

$ docker buildx build --platform linux/amd64,linux/arm64 -t ourapp:latest .
time="2023-06-01T07:13:20+03:00" level=warning msg="No output specified for docker-container driver.
  Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load"
#1 [internal] booting buildkit
#1 pulling image moby/buildkit:buildx-stable-1
#1 pulling image moby/buildkit:buildx-stable-1 73.2s done
#1 creating container buildx_buildkit_ourbuilder0
#1 creating container buildx_buildkit_ourbuilder0 2.1s done
#1 DONE 75.4s

#3 [internal] load .dockerignore
#3 transferring context: 0.0s
#3 transferring context: 2B 0.1s done
#3 DONE 0.3s

#2 [internal] load build definition from Dockerfile
#2 transferring dockerfile: 294B 0.0s done
#2 DONE 0.4s

#4 [linux/amd64 internal] load metadata for docker.io/library/node:14-alpin...
#4 DONE 4.7s
.... truncated ..... 

We specify the target platforms using the –platform flag. In this case, we target the x86 (Linux/amd64) and ARM (Linux/arm64) architectures. Further, we provide the tag -t ourapp:latest, so the image includes the name ourapp and the latest tag. The period specifies the build context, which is the current directory.

Docker buildx automatically handles multi-platform builds and generates separate images for each targeted architecture.

4. Conclusion

In this tutorial, we explored Docker buildx, a tool that extends the building and managing abilities of Docker images. It simplifies the process by supporting parallelized builds, custom-build contexts, and multi-stage builds.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.