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.