Construction d'images de conteneur multi-architecture avec OpenShift, Buildah et Tekton dans le cloud AWS

En 2022, j’ai écrit un article sur ce sujet intitulé “Build multi-architecture container images with Kubernetes, Buildah, Tekton and Qemu”. L’article relatait la configuration que j’avais mise en place pour mes projets personnels. Il a même un peu débordé de sa vocation initiale puisqu’il a également été utilisé par plusieurs collègues chez Red Hat qui avaient le même besoin. Si la configuration décrite dans ce précédent article est toujours d’actualité, l’approche est un peu datée. Avec la disponibilité grandissante des serveurs ARM dans le Cloud, j’ai revisité le sujet de la construction d’image de conteneurs multi-architecture en utilisant le cloud AWS.

Cas d’usage

Dans cet article, j’explore la construction d’image de conteneurs multi-architecture au travers de trois cas d’usage :

Pour démontrer la faisabilité de la construction d’image de conteneurs multi-architecture, je construis des images de conteneurs pour les architectures x86_64 et arm64. Mais l’approche est généralisable à toute architecture supportée par OpenShift.

Le code illustrant ces trois cas d’usage et leur pipelines Tekton associés sont dans ce dépôt Git.

Vue d’ensemble

Pour mettre en oeuvre ces trois cas d’usage, je vais mettre en place :

Si le précédent article ciblait les plateformes Kubernetes vanilla, dans celui-ci je me concentre sur OpenShift. J’utiliserai également OpenShift Pipelines, la distribution Tekton de Red Hat plutôt que le Tekton upstream.

Dans les pipelines Tekton, j’utilise Buildah pour construire et pousser sur la registry les images de conteneurs.

Vue d'ensemble de la configuration mise en oeuvre.
Vue d’ensemble de la configuration mise en oeuvre.

Déploiement d’OpenShift sur AWS en mode multi-architecture

Procédure d’installation

Dans la suite de cet article, je déploie OpenShift 4.15 sur AWS mais la démarche reste sensiblement la même sur les autres environnements Cloud (Azure, GCP, etc.) Je pars d’un environnement AWS déjà préparé pour OpenShift.

Pour limiter les coûts, je déploie un cluster OpenShift composé du strict minimum :

Dans la documentation OpenShift 4.15, les machines ARM64 testées sont :

Au final, je choisis les types de machine suivants :

La procédure d’installation est la suivante :

Je détaille les points clés de cette installation mais pensez à bien lire la documentation OpenShift 4.15 avant !

Pré-requis

L’installation d’un cluster multi-architecture passe par une version spécifique de la CLI openshift-install.

Télécharger la CLI OpenShift multi architecture.

curl -sfL https://mirror.openshift.com/pub/openshift-v4/multi/clients/ocp/4.15.1/amd64/openshift-install-linux.tar.gz | sudo tar -zx -C /usr/local/bin openshift-install
curl -sfL https://mirror.openshift.com/pub/openshift-v4/multi/clients/ocp/4.15.1/amd64/openshift-client-linux-4.15.1.tar.gz | sudo tar -zx -C /usr/local/bin oc kubectl

Création du Control Plane node

Créer le fichier install-config.yaml. Les zones surlignées sont les points importants du fichier.

Fichier "install-config.yaml"
additionalTrustBundlePolicy: Proxyonly
apiVersion: v1
baseDomain: aws.itix.cloud
compute:
- architecture: amd64
  hyperthreading: Enabled
  name: worker
  platform:
    aws:
      type: m5a.2xlarge
      zones:
      - eu-west-3a
      - eu-west-3b
      - eu-west-3c
  replicas: 0
controlPlane:
  architecture: amd64
  hyperthreading: Enabled
  name: master
  platform:
    aws:
      rootVolume:
        iops: 4000
        size: 500
        type: io1
      type: m5a.2xlarge
      zones:
      - eu-west-3c
  replicas: 1
metadata:
  creationTimestamp: null
  name: build-multiarch
networking:
  clusterNetwork:
  - cidr: 10.128.0.0/14
    hostPrefix: 23
  machineNetwork:
  - cidr: 10.0.0.0/16
  networkType: OVNKubernetes
  serviceNetwork:
  - 172.30.0.0/16
platform:
  aws:
    region: eu-west-3
publish: External
pullSecret: 'REDACTED'
sshKey: |
    REDACTED

J’ai choisis de laisser la déclaration des Compute nodes mais avec un replicas à 0 car cela simplifie l’instanciation du Compute node x86_64 par la suite.

Générer les manifests d’installation.

openshift-install create manifests --dir .

Comme la documentation OpenShift 4.15 indique que le Cluster Samples Operator n’est pas compatible multi-architecture, nous devons le désactiver via les cluster capabilities.

Editer le fichier manifests/cvo-overrides.yaml et ajouter la section additionalEnabledCapabilities. Ne faites pas un copier-coller du fichier complet ci-dessous car le clusterID est spécifique à votre installation !

Fichier "manifests/cvo-overrides.yaml"
apiVersion: config.openshift.io/v1
kind: ClusterVersion
metadata:
  namespace: openshift-cluster-version
  name: version
spec:
  channel: stable-4.15
  clusterID: REDACTED
  baselineCapabilitySet: None
  additionalEnabledCapabilities:
  - marketplace
  - MachineAPI
  - Console
  - Insights
  - Storage
  - CSISnapshot
  - NodeTuning
  - ImageRegistry
  - OperatorLifecycleManager
  - Build
  - DeploymentConfig

Démarrer l’installation du cluster sur AWS.

openshift-install create cluster --dir . --log-level=info

Si tout se passe bien, une trentaine de minutes plus tard, vous devriez avoir quelque chose comme ça :

INFO Consuming Common Manifests from target directory 
INFO Consuming Master Machines from target directory 
INFO Consuming Openshift Manifests from target directory 
INFO Consuming Worker Machines from target directory 
INFO Consuming OpenShift Install (Manifests) from target directory 
INFO Credentials loaded from the "default" profile in file "/home/nmasse/.aws/credentials" 
INFO Creating infrastructure resources...         
INFO Waiting up to 20m0s (until 1:15PM CET) for the Kubernetes API at https://api.build-multiarch.aws.itix.cloud:6443... 
INFO API v1.28.6+6216ea1 up                       
INFO Waiting up to 30m0s (until 1:28PM CET) for bootstrapping to complete... 
INFO Destroying the bootstrap resources...        
INFO Waiting up to 40m0s (until 1:52PM CET) for the cluster at https://api.build-multiarch.aws.itix.cloud:6443 to initialize... 
INFO Waiting up to 30m0s (until 1:50PM CET) to ensure each cluster operator has finished progressing... 
INFO All cluster operators have completed progressing 
INFO Checking to see if there is a route at openshift-console/console... 
INFO Install complete!                            
INFO To access the cluster as the system:admin user when using 'oc', run 'export KUBECONFIG=./auth/kubeconfig' 
INFO Access the OpenShift web-console here: https://console-openshift-console.apps.build-multiarch.aws.itix.cloud 
INFO Login to the console with user: "kubeadmin", and password: "REDACTED" 
INFO Time elapsed: 30m21s

Définir la variable KUBECONFIG pour accéder au cluster.

export KUBECONFIG=$PWD/auth/kubeconfig

Ajout du Compute node x86_64

Comme le fichier install-config.yaml contenait la définition des Compute nodes mais avec le replicas à 0, les MachineSet ont bien été générés et sont presque prêt à servir.

$ oc -n openshift-machine-api get MachineSet 
NAME                                      DESIRED   CURRENT   READY   AVAILABLE   AGE
build-multiarch-tw9w9-worker-eu-west-3a   0         0                             67m
build-multiarch-tw9w9-worker-eu-west-3b   0         0                             67m
build-multiarch-tw9w9-worker-eu-west-3c   0         0                             67m

Ajouter aux futurs Compute nodes l’étiquette node-role.kubernetes.io/worker.

for name in $(oc -n openshift-machine-api get MachineSet -o name); do
  oc -n openshift-machine-api patch "$name" --type=json -p '[{"op":"add","path":"/spec/template/spec/metadata/labels","value":{"node-role.kubernetes.io/worker":""}}]'
done

Ajouter un Compute node dans la zone eu-west-3a.

oc -n openshift-machine-api scale machineset build-multiarch-tw9w9-worker-eu-west-3a --replicas=1

Ajout du Compute node arm64

La documentation OpenShift 4.15 recense les vérifications à effectuer avant de pouvoir ajouter au cluster un noeud d’une autre architecture.

$ oc adm release info -o jsonpath="{ .metadata.metadata}"
{"release.openshift.io/architecture":"multi","url":"https://access.redhat.com/errata/RHSA-2024:1210"}

$ oc get configmap/coreos-bootimages -n openshift-machine-config-operator -o jsonpath='{.data.stream}' | jq -r '.architectures.aarch64.images.aws.regions."eu-west-3".image'
ami-0eab6a7956a66deda

Ajouter les MachineSet ARM64 au cluster. Ici, l’architecture ARM64 s’appelle “aarch64”.

ARCH="aarch64" # x86_64 or aarch64
AWS_REGION="eu-west-3"
AWS_AZ=("a" "b" "c")
AWS_INSTANCE_TYPE="m6g.2xlarge" # Must match $ARCH!
AMI_ID="$(oc get configmap/coreos-bootimages -n openshift-machine-config-operator -o jsonpath='{.data.stream}' | jq -r ".architectures.$ARCH.images.aws.regions.\"$AWS_REGION\".image")"
INFRASTRUCTURE_NAME="$(oc get -o jsonpath='{.status.infrastructureName}' infrastructure cluster)"

for az in "${AWS_AZ[@]}"; do
  oc apply -f - <<EOF
apiVersion: machine.openshift.io/v1beta1
kind: MachineSet
metadata:
  name: $INFRASTRUCTURE_NAME-$ARCH-worker-$AWS_REGION$az
  namespace: openshift-machine-api
  labels:
    machine.openshift.io/cluster-api-cluster: $INFRASTRUCTURE_NAME
spec:
  replicas: 0
  selector:
    matchLabels:
      machine.openshift.io/cluster-api-cluster: $INFRASTRUCTURE_NAME
      machine.openshift.io/cluster-api-machineset: $INFRASTRUCTURE_NAME-$ARCH-worker-$AWS_REGION$az
  template:
    metadata:
      labels:
        machine.openshift.io/cluster-api-cluster: $INFRASTRUCTURE_NAME
        machine.openshift.io/cluster-api-machine-role: worker
        machine.openshift.io/cluster-api-machine-type: worker
        machine.openshift.io/cluster-api-machineset: $INFRASTRUCTURE_NAME-$ARCH-worker-$AWS_REGION$az
    spec:
      lifecycleHooks: {}
      metadata:
        labels:
          node-role.kubernetes.io/worker: ''
      providerSpec:
        value:
          userDataSecret:
            name: worker-user-data
          placement:
            availabilityZone: $AWS_REGION$az
            region: $AWS_REGION
          credentialsSecret:
            name: aws-cloud-credentials
          instanceType: $AWS_INSTANCE_TYPE
          metadata:
            creationTimestamp: null
          blockDevices:
            - ebs:
                encrypted: true
                iops: 0
                kmsKey:
                  arn: ''
                volumeSize: 120
                volumeType: gp3
          securityGroups:
            - filters:
                - name: 'tag:Name'
                  values:
                    - $INFRASTRUCTURE_NAME-worker-sg
          kind: AWSMachineProviderConfig
          metadataServiceOptions: {}
          tags:
            - name: kubernetes.io/cluster/$INFRASTRUCTURE_NAME
              value: owned
          deviceIndex: 0
          ami:
            id: $AMI_ID
          subnet:
            filters:
              - name: 'tag:Name'
                values:
                  - $INFRASTRUCTURE_NAME-private-$AWS_REGION$az
          apiVersion: machine.openshift.io/v1beta1
          iamInstanceProfile:
            id: $INFRASTRUCTURE_NAME-worker-profile
EOF
done

Ajouter un Compute node arm64 dans la zone eu-west-3b.

oc -n openshift-machine-api scale machineset build-multiarch-tw9w9-aarch64-worker-eu-west-3b --replicas=1

À ce stade, vous devriez avoir trois noeuds dans votre cluster :

Console OpenShift affichant trois noeuds : deux noeuds x86_64 et un arm64.
Console OpenShift affichant trois noeuds : deux noeuds x86_64 et un arm64.

Installation de l’opérateur Tekton

Dans la plateforme OpenShift, l’opérateur Tekton s’appelle OpenShift Pipelines Operator. La documentation explique comment l’installer.

In a nutshell, il suffit de créer la CRD suivante.

apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: openshift-pipelines-operator
  namespace: openshift-operators
spec:
  channel: latest
  name: openshift-pipelines-operator-rh
  source: redhat-operators
  sourceNamespace: openshift-marketplace

Choix d’une technologie de stockage persistant

Les pipelines Tekton qui construisent les images de conteneur ont besoin de stocker des données qui sont utilisées par plusieurs tâches.

Par exemple, une tâche construit l’image x86_64 pendant que en parallèle une tâche construit l’image arm64 et une dernière tâche assemble ces deux images sous la forme d’un manifeste qui sera poussé sur la registry quay.io.

J’avais le choix entre plusieurs technologies de stockage, chacune avec ses avantages et ses inconvénients. J’ai fait le choix d’utiliser AWS EFS mais d’autres technologies auraient été possibles.

J’ai choisi AWS EFS comme stockage persistant pour les pipelines Tekton mais il n’a pas que des avantages. En particulier, l’utilisation d’AWS EFS depuis Kubernetes peut générer des problème de droits d’accès avec les UIDs aléatoires (SCC restricted) ou arbitraires (SCC anyuid).

L’article How to Solve AWS EFS “Operation Not Permitted” Errors in EKS est un bon résumé du problème.

Initialement, j’ai tenté très naïvement de mettre le répertoire de travail de Buildah (/var/lib/containers) sur un volume AWS EFS. Avec cette configuration, j’ai constaté des lenteurs et les problèmes de droits d’accès mentionnés ci-dessus.

Pour utiliser AWS EFS avec les Pipelines Tekton, j’ai choisi d’aller au plus simple. Plutôt que de mettre le répertoire de travail de Buildah sur un volume AWS EFS, j’ai choisi de recopier manuellement l’image construite par Buildah sur le volume EFS.

Stockage AWS EFS

La documentation OpenShift 4.15 décrit l’installation de l’AWS EFS CSI Driver Operator.

Installer l’AWS EFS CSI Driver Operator.

apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: aws-efs-csi-driver-operator
  namespace: openshift-cluster-csi-drivers
spec:
  channel: stable
  installPlanApproval: Automatic
  name: aws-efs-csi-driver-operator
  source: redhat-operators
  sourceNamespace: openshift-marketplace

Installer le driver AWS EFS CSI.

apiVersion: operator.openshift.io/v1
kind: ClusterCSIDriver
metadata:
    name: efs.csi.aws.com
spec:
  managementState: Managed

Créer un volume EFS en suivant les étapes décrites dans la documentation AWS.

Console AWS montrant un volume EFS.
Console AWS montrant un volume EFS.

Créer la StorageClass associée au volume EFS. Le champ fileSystemId correspond à la deuxième colonne de la capture d’écran ci-dessus. Les champs uid et gid à 0 permettent d’être certain que les Pods qui s’exécutent en root ne verront pas d’incohérences entre leur uid (0) et celui du volume EFS (0 aussi).

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: efs-csi
provisioner: efs.csi.aws.com
parameters:
  provisioningMode: efs-ap
  fileSystemId: fs-0ba31e44186d037e9
  directoryPerms: "700"
  basePath: "/pv"
  uid: "0"
  gid: "0"

En suivant la documentation OpenShift 4.15, modifier le Security Group EFS pour autoriser les noeuds OpenShift à accéder au stockage via le protocole NFS.

Console AWS montrant la configuration du Security Group EFS.
Console AWS montrant la configuration du Security Group EFS.

À ce stade, le service AWS EFS est accessible depuis le cluster OpenShift mais il n’est pas encore utilisable par les pipelines Tekton. En effet, l’affinity-assistant de Tekton interdit à un volume persistant RWX d’être monté à deux endroits en même temps (erreur “more than one PersistentVolumeClaim is bound”).

Désactiver l’affinity-assistant dans la configuration Tekton.

oc patch configmap/feature-flags -n openshift-pipelines --type=merge -p '{"data":{"disable-affinity-assistant":"true"}}'

Pipelines Tekton multi-architecture

Dans cette section, je donne brièvement les instructions nécessaire au déploiement des pipelines d’exemple et ensuite je détaille les spécificités de chaque pipeline.

Créer un projet OpenShift.

oc new-project build-multiarch

Créer le Secret contenant votre login et mot de passe quay.io.

oc create secret docker-registry quay-authentication --docker-email=nmasse@redhat.com --docker-username=nmasse --docker-password=REDACTED --docker-server=quay.io
oc annotate secret/quay-authentication tekton.dev/docker-0=https://quay.io

Cloner le dépôt Git tekton-pipeline-multiarch.

git clone https://github.com/nmasse-itix/tekton-pipeline-multiarch
cd tekton-pipeline-multiarch

Déployer les pipelines Tekton.

oc apply -k tekton/
for yaml in examples/*/tekton/pipeline.yaml; do oc apply -f $yaml; done

Démarrer les pipelines Tekton.

for yaml in examples/*/tekton/pipelinerun.yaml; do oc create -f $yaml; done

Tâches tekton

La tâche buildah-build construit une image de conteneur en utilisant la commande buildah. Les spécificités de cette tâche sont liées au pré-requis nécessaire à l’exécution de buildah en conteneur.

Fichier "tekton/task-buildah-build.yaml"
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: buildah-build
spec:
  params:
  - name: context-dir
    type: string
    default: .
  - name: containerfile-path
    type: string
    default: Containerfile
  workspaces:
  - name: source-workspace
    description: Workspace containing source code
  - name: oci-images
    mountPath: /srv/oci-images
  volumes:
  - name: container-storage
    emptyDir: {}
  steps:
  - name: build
    image: registry.redhat.io/rhel8/buildah:8.9
    env:
    - name: STORAGE_DRIVER
      value: vfs
    script: |
      #!/bin/bash
      set -Eeuo pipefail
      buildah bud -t localhost/image:$(uname -m) -f $(workspaces.source-workspace.path)/$(params.containerfile-path) $(workspaces.source-workspace.path)/$(params.context-dir)
      buildah push localhost/image:$(uname -m) oci-archive:/srv/oci-images/$(uname -m).tar      
    securityContext:
      capabilities:
        add:
          - SETFCAP
    volumeMounts:
    - name: container-storage
      mountPath: /var/lib/containers

Le script exécuté par cette tâche est concis (seulement deux étapes) :

La tâche buildah-push récupère depuis le volume AWS EFS les images générées par les multiples instances de buildah-build, les assemble sous la forme d’un manifeste multi-architecture et pousse le tout sur la registry.

Les spécificités de cette tâche sont majoritairement les mêmes que pour buildah-build. Seul un workspace additionnel nommé “dockerconfig” a été ajouté pour passer les credentials d’accès à la registry.

Mais attardons nous sur son script.

#!/bin/bash
set -Eeuo pipefail

# Handle registry credentials
if [[ "$(workspaces.dockerconfig.bound)" == "true" ]]; then
  if test -f "$(workspaces.dockerconfig.path)/config.json"; then
    export DOCKER_CONFIG="$(workspaces.dockerconfig.path)"
  elif test -f "$(workspaces.dockerconfig.path)/.dockerconfigjson"; then
    cp "$(workspaces.dockerconfig.path)/.dockerconfigjson" "$HOME/.docker/config.json"
    export DOCKER_CONFIG="$HOME/.docker"
  else
    echo "neither 'config.json' nor '.dockerconfigjson' found at workspace root"
    exit 1
  fi
fi

declare -a iids=()
for arch; do
  echo "Loading image for architecture $arch..."
  iid=$(buildah pull oci-archive:/srv/oci-images/$arch.tar)
  iids+=("$iid")
done
buildah manifest create localhost/multi-arch-image "${iids[@]}"
buildah manifest push --all localhost/multi-arch-image docker://$(params.image-name)

La première partie du script positionne la variable DOCKER_CONFIG qui sera utilisée par la commande buildah push pour s’authentifier sur la registry.

La seconde partie récupère les images des différentes architectures (commande buildah pull) et stocke leur Image ID dans une liste.

La commande buildah manifest create crée un manifeste multi-architecture avec la liste de toutes les images chargées précédemment.

Enfin, la commande buildah manifest push envoie le manifeste et les images sur la registry.

Pipeline “Containerfile”

Le premier cas d’usage présenté au début de cet article porte sur l’utilisation d’un Dockerfile / Containerfile pour construire une image de conteneur :

Construction d’une image depuis un Dockerfile / Containerfile. Une image de base multi-architecture est disponible dans une registry et le Dockerfile / Containerfile vient appliquer une série de modifications à cette image. L’image résultante est également multi-architecture.

Le pipeline correspondant récupère le code source, exécute un buildah build pour chaque architecture (x86_64 et arm64) et pousse le manifeste sur la registry.

Console OpenShift montrant l'exécution du pipeline Tekton multi-architecture (Containerfile construisant une image de conteneur de l'utilitaire `htop`).
Console OpenShift montrant l’exécution du pipeline Tekton multi-architecture (Containerfile construisant une image de conteneur de l’utilitaire htop).

L’image résultante sur la registry quay.io montre bien un manifeste contenant deux images : une pour x86_64 et une pour arm64.

Console Quay montrant une image multi-architecture de l'utilitaire `htop`).
Console Quay montrant une image multi-architecture de l’utilitaire htop).

Pipeline “NodeJS”

Le pipeline NodeJS est sensiblement différent dans le sens où le dépôt Git est récupéré deux fois : une fois pour chaque architecture.

La raison est que la commande npm install va télécharger les dépendances de l’application et certaines de ces dépendances peuvent embarquer du code natif (c’est le cas de certaines bibliothèques bas niveau). Il faut donc un workspace séparé pour chaque architecture.

Console OpenShift montrant l'exécution du pipeline Tekton multi-architecture construisant une application NodeJS.
Console OpenShift montrant l’exécution du pipeline Tekton multi-architecture construisant une application NodeJS.

Pipeline “Quarkus”

Le pipeline Quarkus est encore différent du pipeline NodeJS dans le sens où l’application Quarkus est compilée en mode JVM et donc la compilation n’a lieu qu’une seule fois. Le bytecode contenu dans les fichiers Jar pouvant tourner de manière indifférenciée sur n’importe quelle architecture, il n’y a qu’un workspace Git partagé entre toutes les architectures.

Console OpenShift montrant l'exécution du pipeline Tekton multi-architecture construisant une application Quarkus.
Console OpenShift montrant l’exécution du pipeline Tekton multi-architecture construisant une application Quarkus.

Lier une tâche à une architecture

Jusqu’à présent l’article ne dit pas comment Tekton s’organise pour exécuter la tâche de construction de l’image x86_64 sur un noeud x86_64, l’image arm64 sur un noeud arm64, etc.

Il n’y a pas de magie ! Tout se passe dans le PipelineRun !

Fichier "examples/htop/tekton/pipelinerun.yaml"
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  generateName: htop-
spec:
  pipelineRef:
    name: htop
  params:
  - name: git-url
    value: https://github.com/nmasse-itix/tekton-pipeline-multiarch.git
  - name: image-name
    value: quay.io/nmasse_itix/htop-multiarch
  - name: context-dir
    value: examples/htop/src
  - name: containerfile-path
    value: "examples/htop/src/Containerfile"
  workspaces:
  - name: oci-images
    volumeClaimTemplate:
      spec:
        storageClassName: efs-csi
        accessModes:
        - ReadWriteMany
        resources:
          requests:
            storage: 10Gi
  - name: source-workspace
    volumeClaimTemplate:
      spec:
        storageClassName: efs-csi
        accessModes:
        - ReadWriteMany
        resources:
          requests:
            storage: 1Gi
  - name: registry-token
    secret:
      secretName: quay-authentication
  taskRunTemplate:
    serviceAccountName: buildbot
  taskRunSpecs:
  - pipelineTaskName: build-x86-64
    podTemplate:
      nodeSelector:
        beta.kubernetes.io/arch: amd64
  - pipelineTaskName: build-aarch64
    podTemplate:
      nodeSelector:
        beta.kubernetes.io/arch: arm64

Le champ taskRunSpecs permet d’ajouter des contraintes d’exécution à une ou plusieurs tâches du pipeline.

Dans l’exemple ci-dessus, le PipelineRun contraint l’exécution de la tâche build-x86-64 sur un noeud ayant l’étiquette beta.kubernetes.io/arch=amd64 et la tâche build-aarch64 sur un noeud ayant l’étiquette beta.kubernetes.io/arch=arm64.

Conclusion

Dans cet article, nous avons passé en revue la configuration nécessaire à la construction d’images multi-architecture dans un environnement OpenShift dans le Cloud AWS. Trois cas d’usage ont été implémentés : construction d’une image à partir d’un Dockerfile / Containerfile, construction d’une application NodeJS et enfin construction d’une application Quarkus.

Le code source et les manifestes sont présents dans le dépôt Git pour qui veut reproduire l’expérience.