In this blog, I will be discussing how to build a multi-arch image for any desired docker architecture to run litmus chore components. For those who are new to litmus and wanted to explore more about chaos engineering, I would recommend to check out litmus blog. Now coming back to the topic we will be using docker buildx for building the images in the following sections.
Pre-requisites:
Docker(version 19.03)
Understanding Multiarch Builds
Docker introduced the principle of multi-arch builds to support the "Build once, deploy anywhere" concept which helps to use ARM targets and reduce your bills such as AWS A1 and Raspberry Pis instances. But how do we produce them? and How do they work?
A multi-arch Docker image supports a different architecture behind the same imagetag. Let's compare the manifest of the multi-arch image with the image having a single arch.
Enable docker CLI if not already enabled using the following steps:
export DOCKER_CLI_EXPERIMENTAL=enabled
Add "experimental": "enabled", to ~/.docker/config.json (default location) at the beginning of the file and not at the end.
We can observe that the manifest for the multi-arch image is a simple list of manifests prepared for each platform while an image with a single arch will have only one platform in its manifest.
Build Multi-arch image for Litmus Components
For building a multi-arch image for litmus core components just follow the following simple steps:
Setup buildx
Build go binary for different architectures.
Prepare Dockerfile for Multiarch.
Build and push the multi-arch image.
Build using Buildx instance
Introduction:
Docker Buildx is a CLI plugin that extends the docker command with the full support of the features provided by Moby BuildKit builder toolkit. It has new features like creating scoped builder instances and building against multiple nodes concurrently.
Setup:
The Docker Buildx is included in Docker 19.03 to install it run the following commands:
Now the buildx is setup in your system. Buildx allows you to create new instances of isolated builders. You can use this to get a scoped environment for your CI builds that does not change the state of the shared daemon, or for isolating builds for different projects. You can create a new instance for a set of remote nodes, forming a build farm, and quickly switch between them.
Setup Builder instance
1. Using the QEMU emulation support in the kernel
sudo apt-get install qemu-user-static -y
docker run --rm--privileged multiarch/qemu-user-static --reset-pyes i
We know that all the litmus core components (chaos experiment, operator, and runner) are written in Golang and we are building the go binaries and using them in the image.
Note: You can build the go binaries and copy them in Dockerfile or we can build the binary in the Dockerfile itself and use them.
In this example, I'll be following the first way that is building binary and copying them in the Dockerfile.
The main key point here is to build different binaries with Go ENVs set to desired values like GOARCH=amd64 &GOOS=linux for which we have to build the image.
git clone https://github.com/litmuschaos/chaos-operator.git
cd chaos-operator
vi build/go-multiarch-build.sh
The following script will help to do that:
#!/usr/bin/env bashpackage=$1if[[-z"$package"]];then
echo"usage: $0 <package-name>"exit 1
fi
package_split=(${package//\// })package_name=${package_split[-1]}# add the arch for which we want to build the imageplatforms=("linux/amd64""linux/arm64")for platform in"${platforms[@]}"do
platform_split=(${platform//\// })GOOS=${platform_split[0]}GOARCH=${platform_split[1]}output_name=build/_output/bin/chaos-operator$GOARCH# The script executes for the argument passed (in package variable)# here the arg will be "github.com/litmuschaos/chaos-operator/cmd/manager" for creating binaryenv GOOS=$GOOSGOARCH=$GOARCH go build -o$output_name$packageif[$?-ne 0 ];then
echo'An error has occurred! Aborting the script execution...'exit 1
fi
done
In the above script, we are creating the binary of github.com/litmuschaos/chaos-operator/cmd/manage with GOARCH & GOOS set in the platforms. This will create binaries as follow:
$ ls build/_output/bin/
chaos-operatoramd64* chaos-operatorarm64*
Prepare Dockerfile for Multiarch
Prepare a Dockerfile that should work for all the different architectures. Make sure that: 1. The base image should be multi-arch: Use the base image which is having multiarch support.
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3
Which supports both ARM64 and AMD64 arch.
2. Use TARGETARCH variable for using binary in Dockerfile: All binaries used should support multi-arch builds and are built accordingly. The Docker predefines a set of ARG variables according to the --platform we pass in buildx. This is only available when using the BuildKit backend. Here the TARGETARCH is the architecture component of TARGETPLATFORM. Check out more platform env here.
This will copy the binaries created in the previous step while building the image.
Build and push the multi-arch image
BuildKit is designed to work well for building for multiple platforms and not only for the architecture and operating system that the user invoking the build happens to run. When you invoke a build, you can set the --platform flag to specify the target platform for the build output, (for example, linux/amd64, linux/arm64, darwin/amd64).
A sample command to build and push the multiarch image with the Dockerfile created in the previous stage.
We have successfully built and pushed the multiarch images on Dockerhub. The images will look like:
Troubleshooting
1. standard_init_linux.go:211: exec user process caused "exec format error":
There could be multiple reasons for this. Try to check out the base image you're using is supporting all the platforms for which you're building the images.
Make sure while building and copying the binary in Dockerfile that the arch and os should be same. Like you're building the binary with linux/amd64 and you're trying to run it on linux/arm64.
2. rpc error: code = Unknown desc = failed to load LLB: runtime execution on platform linux/arm/v7 not supported:
This means the platform you're looking for is not available. You can verify the available platforms using docker buildx inspect <builder-name>.Now you can run the following commands to resolve the above error.
sudo apt-get install qemu-user-static -y
docker run --rm--privileged multiarch/qemu-user-static --reset-pyes i
docker buildx rm multibuilder
docker buildx create --name multibuilder
docker buildx ls
docker buildx inspect multibuilder
docker buildx inspect multibuilder --bootstrap
docker buildx use multibuilder
docker ps -a
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t <ORG_NAME>/<IMAGE_NAME>:<IMAGE_TAG> --push.
Conclusion
In this blog, we learn how to build and push an image that can be used at different docker architecture with the same image tag on it. This can be done using a powerful docker buildx feature which helps to build image with a single command. We can create images that can run on any desired platform using buildx and can be used to reduce your bills using ARM targets Raspberry Pis instance. So have ever tried building multiarch images? How useful it could be? Please leave your thoughts in the comment box.
🚀 Special Thanks 🙌
Thanks to Michael Fornaro for helping in suggesting, reviewing & adopting the multiarch support for Litmus Chore Components.
Are you an SRE or a Kubernetes enthusiast? Does Chaos Engineering excite you?
Join Our Community On Slack For Detailed Discussion, Feedback & Regular Updates On Chaos Engineering For Kubernetes: https://kubernetes.slack.com/messages/CNXNB0ZTN
(#litmus channel on the Kubernetes workspace)
Check out the Litmus Chaos GitHub repo and do share your feedback: https://github.com/litmuschaos/litmus
Submit a pull request if you identify any necessary changes.
Litmus helps SREs and developers practice chaos engineering in a Cloud-native way. Chaos experiments are published at the ChaosHub (https://hub.litmuschaos.io). Community notes is at https://hackmd.io/a4Zu_sH4TZGeih-xCimi3Q
LitmusChaos is an open source Chaos Engineering platform that enables teams to identify weaknesses & potential outages in infrastructures by
inducing chaos tests in a controlled way. Developers & SREs can practice Chaos Engineering with LitmusChaos as it is easy to use, based on modern
Chaos Engineering principles & community collaborated. It is 100% open source & a CNCF project.
LitmusChaos takes a cloud-native approach to create, manage and monitor chaos. The platform itself runs as a set of microservices and uses Kubernetes
custom resources (CRs) to define the chaos intent, as well as the steady state hypothesis.
At a high-level, Litmus comprises of:
Chaos Control Plane: A centralized chaos management tool called chaos-center, which helps construct, schedule and visualize Litmus chaos workflows