Skip to content
This repository was archived by the owner on Jun 3, 2025. It is now read-only.

Commit 5e7364c

Browse files
committed
Add guide on creating multi-arch manifests
While kaniko itself does not natively support building multi-arch container manifests, it may be used in combination with tools such as manifest-tool to create and merge seperate arch builds into a single manifest. Fixes #1102 Fixes #786
1 parent 971b9f4 commit 5e7364c

2 files changed

Lines changed: 170 additions & 1 deletion

File tree

README.md

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ _If you are interested in contributing to kaniko, see
113113
- [Security](#security)
114114
- [Verifying Signed Kaniko Images](#verifying-signed-kaniko-images)
115115
- [Kaniko Builds - Profiling](#kaniko-builds---profiling)
116+
- [Creating Multi-arch Container Manifests Using Kaniko and Manifest-tool](#creating-multi-arch-container-manifests-using-kaniko-and-manifest-tool)
117+
- [General Workflow](#general-workflow)
118+
- [Limitations and Pitfalls](#limitations-and-pitfalls)
119+
- [Example CI Pipeline (GitLab)](#example-ci-pipeline-gitlab)
120+
- [Building the Separate Container Images](#building-the-separate-container-images)
121+
- [Merging the Container Manifests](#merging-the-container-manifests)
122+
- [On the Note of Adding Versioned Tags](#on-the-note-of-adding-versioned-tags)
116123
- [Comparison with Other Tools](#comparison-with-other-tools)
117124
- [Community](#community-1)
118125
- [Limitations](#limitations)
@@ -1135,6 +1142,163 @@ profiling,
11351142
2. If you are using the kaniko `debug` image, you can copy the file in the
11361143
`pre-stop` container lifecycle hook.
11371144

1145+
## Creating Multi-arch Container Manifests Using Kaniko and Manifest-tool
1146+
1147+
While Kaniko itself currently does not support creating multi-arch manifests
1148+
(contributions welcome), one can use tools such as [manifest-tool](https://github.com/estesp/manifest-tool)
1149+
to stitch multiple separate builds together into a single container manifest.
1150+
1151+
### General Workflow
1152+
1153+
The general workflow for creating multi-arch manifests is as follows:
1154+
1155+
1. Build separate container images using Kaniko on build hosts matching your
1156+
target architecture and tag them with the appropriate ARCH tag.
1157+
2. Push the separate images to your container registry.
1158+
3. Manifest-tool identifies the separate manifests in your container registry,
1159+
according to a given template.
1160+
4. Manifest-tool pushes a combined manifest referencing the separate manifests.
1161+
1162+
![Workflow Multi-arch](docs/images/multi-arch.drawio.svg)
1163+
1164+
### Limitations and Pitfalls
1165+
1166+
The following conditions must be met:
1167+
1168+
1. You need access to build-machines running the desired architectures
1169+
(running Kaniko in an emulator, e.g. QEMU should also be possible but goes
1170+
beyond the scope of this documentation). This is something to keep in mind
1171+
when using SaaS build tools such as github.com or gitlab.com, of which at the
1172+
time of writing neither supports any non-x86_64 SaaS runners ([GitHub](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources),[GitLab](https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html#machine-types-available-for-private-projects-x86-64)),
1173+
so be prepared to bring your own machines ([GitHub](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners),[GitLab](https://docs.gitlab.com/runner/register/).
1174+
2. Kaniko needs to be able to run on the desired architectures. At the time of
1175+
writing, the official Kaniko container supports [linux/amd64, linux/arm64,
1176+
linux/s390x and linux/ppc64le (not on *-debug images)](https://github.com/GoogleContainerTools/kaniko/blob/main/.github/workflows/images.yaml).
1177+
3. The container registry of your choice must be OCIv1 or Docker v2.2
1178+
compatible.
1179+
1180+
### Example CI Pipeline (GitLab)
1181+
1182+
It is up to you to find an automation tool that suits your needs best.
1183+
We recommend using a modern CI/CD system such as GitHub workflows or GitLab CI.
1184+
As we (the authors) happen to use GitLab CI, the following examples are
1185+
tailored to this specific platform but the underlying principles should apply
1186+
anywhere else and the examples are kept simple enough, so that you should be
1187+
able to follow along, even without any previous experiences with this specific
1188+
platform. When in doubt, visit the [gitlab-ci.yml reference page](https://docs.gitlab.com/ee/ci/yaml/index.html)
1189+
for a comprehensive overview of the GitLab CI keywords.
1190+
1191+
#### Building the Separate Container Images
1192+
1193+
gitlab-ci.yml:
1194+
1195+
```yaml
1196+
# define a job for building the containers
1197+
build-container:
1198+
stage: container-build
1199+
# run parallel builds for the desired architectures
1200+
parallel:
1201+
matrix:
1202+
- ARCH: amd64
1203+
- ARCH: arm64
1204+
tags:
1205+
# run each build on a suitable, preconfigured runner (must match the target architecture)
1206+
- runner-${ARCH}
1207+
image:
1208+
name: gcr.io/kaniko-project/executor:debug
1209+
entrypoint: [""]
1210+
script:
1211+
# build the container image for the current arch using kaniko
1212+
- >-
1213+
/kaniko/executor
1214+
--context "${CI_PROJECT_DIR}"
1215+
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
1216+
# push the image to the GitLab container registry, add the current arch as tag.
1217+
--destination "${CI_REGISTRY_IMAGE}:${ARCH}"
1218+
```
1219+
1220+
#### Merging the Container Manifests
1221+
1222+
gitlab-ci.yml:
1223+
1224+
```yaml
1225+
# define a job for creating and pushing a merged manifest
1226+
merge-manifests:
1227+
stage: container-build
1228+
# all containers must be build before merging them
1229+
# alternatively the job may be configured to run in a later stage
1230+
needs:
1231+
- container-build
1232+
artifacts: false
1233+
tags:
1234+
# may run on any architecture supported by manifest-tool image
1235+
- runner-xyz
1236+
image:
1237+
name: mplatform/manifest-tool:alpine
1238+
script:
1239+
- >-
1240+
manifest-tool
1241+
# authorize against your container registry
1242+
--username=${CI_REGISTRY_USER}
1243+
--password=${CI_REGISTRY_PASSWORD}
1244+
push from-args
1245+
# define the architectures you want to merge
1246+
--platforms linux/amd64,linux/arm64
1247+
# "ARCH" will be automatically replaced by manifest-tool
1248+
# with the appropriate arch from the platform definitions
1249+
--template ${CI_REGISTRY_IMAGE}:ARCH
1250+
# The name of the final, combined image which will be pushed to your registry
1251+
--target ${CI_REGISTRY_IMAGE}
1252+
```
1253+
1254+
#### On the Note of Adding Versioned Tags
1255+
1256+
For simplicity's sake we deliberately refrained from using versioned
1257+
tagged images (all builds will be tagged as "latest") in the
1258+
previous examples, as we feel like this adds to much platform and workflow
1259+
specific code.
1260+
1261+
Nethertheless, for anyone interested in how we handle (dynamic) versioning in
1262+
GitLab, here is a short rundown:
1263+
1264+
- If you are only interested in building tagged releases, you can simply
1265+
use the [GitLab predefined](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html) `CI_COMMIT_TAG` variable when running a tag pipeline.
1266+
- When you (like us) want to additionally build container images outside of
1267+
releases, things get a bit messier. In our case, we added a additional job
1268+
which runs before the build and merge jobs (don't forget to extend the `needs`
1269+
section of the build and merge jobs accordingly), which will set the tag to
1270+
`latest` when running on the default branch, to the commit hash when run on
1271+
other branches and to the release tag when run on a tag pipeline.
1272+
1273+
gitlab-ci.yml:
1274+
1275+
```yaml
1276+
container-get-tag:
1277+
stage: pre-container-build-stage
1278+
tags:
1279+
- runner-xyz
1280+
image: busybox
1281+
script:
1282+
# All other branches are tagged with the currently built commit SHA hash
1283+
- |
1284+
# If pipeline runs on the default branch: Set tag to "latest"
1285+
if test "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH"; then
1286+
tag="latest"
1287+
# If pipeline is a tag pipeline, set tag to the git commit tag
1288+
elif test -n "$CI_COMMIT_TAG"; then
1289+
tag="$CI_COMMIT_TAG"
1290+
# Else set the tag to the git commit sha
1291+
else
1292+
tag="$CI_COMMIT_SHA"
1293+
fi
1294+
- echo "tag=$tag" > build.env
1295+
# parse tag to the build and merge jobs.
1296+
# See: https://docs.gitlab.com/ee/ci/variables/#pass-an-environment-variable-to-another-job
1297+
artifacts:
1298+
reports:
1299+
dotenv: build.env
1300+
```
1301+
11381302
## Comparison with Other Tools
11391303

11401304
Similar tools include:
@@ -1152,7 +1316,8 @@ All of these tools build container images with different approaches.
11521316
BuildKit (and `img`) can perform as a non-root user from within a container but
11531317
requires seccomp and AppArmor to be disabled to create nested containers.
11541318
`kaniko` does not actually create nested containers, so it does not require
1155-
seccomp and AppArmor to be disabled.
1319+
seccomp and AppArmor to be disabled. BuildKit supports "cross-building"
1320+
multi-arch containers by leveraging QEMU.
11561321

11571322
`orca-build` depends on `runc` to build images from Dockerfiles, which can not
11581323
run inside a container (for similar reasons to `img` above). `kaniko` doesn't

0 commit comments

Comments
 (0)