• Русский
  • Сборка кроссплатформенных образов с помощью Buildah и Merge-Image

    Обзор функции

    В этом руководстве показано, как собирать образы для каждой архитектуры с помощью buildah Task, а затем объединять их в один многоархитектурный образ с помощью merge-image Task.

    Типичный процесс:

    1. Соберите тег образа linux/amd64 (например, :v1.0.0-amd64)
    2. Соберите тег образа linux/arm64 (например, :v1.0.0-arm64)
    3. Объедините исходные теги в один или несколько целевых тегов (например, :v1.0.0, :latest)

    Варианты использования

    • Сборка и публикация многоархитектурных образов из одного репозитория кода.
    • Сохранение результатов сборки для конкретной архитектуры при предоставлении одного унифицированного тега релиза.
    • Переназначение тегов и публикация нескольких целевых тегов за один шаг объединения.

    Предварительные требования

    • Установлен Tekton Pipelines.
    • Установлены git-clone, buildah (0.9) и merge-image (0.1) Tasks.
    • У вас есть возможность отправлять образы в свой registry.
    • Учетные данные для registry подготовлены в виде Secret в Kubernetes.
    • Если вы используете нативные сборки на узлах (как показано в этом руководстве), в кластере должны быть доступны узлы как amd64, так и arm64.
    • Необязательные инструменты для локальной проверки: crane, jq.

    Шаг 1: Подготовьте учетные данные registry

    Создайте общий secret с config.json:

    apiVersion: v1
    kind: Secret
    metadata:
      name: registry-config
    data:
      config.json: <base64-encoded-registry-config-json>

    Шаг 2: Создайте Pipeline и запустите PipelineRun

    Перед использованием обновите следующие значения:

    • URL репозитория Git и revision
    • Исходные теги образов для конкретных архитектур и итоговый целевой тег образа
    • Runtime image для Crane, если нужно заменить значение по умолчанию
    • Имена workspace и secret

    Пример Pipeline:

    apiVersion: tekton.dev/v1
    kind: Pipeline
    metadata:
      name: e2e-multiarch-build
    spec:
      params:
        - name: git-url
          type: string
          description: URL репозитория Git
        - name: git-revision
          type: string
          default: main
        - name: image-amd64
          type: string
          description: ссылка на образ amd64
        - name: image-arm64
          type: string
          description: ссылка на образ arm64
        - name: target-image
          type: string
          description: итоговая ссылка на многоархитектурный образ
        - name: tls-verify
          type: string
          default: "false"
      workspaces:
        - name: shared-workspace
        - name: git-credentials
        - name: registry-credentials
      tasks:
        - name: git-clone
          params:
            - name: url
              value: $(params.git-url)
            - name: revision
              value: $(params.git-revision)
          taskRef:
            resolver: hub
            params:
              - name: kind
                value: task
              - name: catalog
                value: catalog
              - name: name
                value: git-clone
              - name: version
                value: "0.9"
          workspaces:
            - name: output
              workspace: shared-workspace
            - name: basic-auth
              workspace: git-credentials
    
        - name: buildah-amd64
          runAfter:
            - git-clone
          taskRef:
            resolver: hub
            params:
              - name: kind
                value: task
              - name: catalog
                value: catalog
              - name: name
                value: buildah
              - name: version
                value: "0.9"
          params:
            - name: IMAGES
              value:
                - $(params.image-amd64)
            - name: DOCKERFILE
              value: ./Dockerfile
            - name: TLS_VERIFY
              value: $(params.tls-verify)
            - name: FORMAT
              value: docker
          workspaces:
            - name: source
              workspace: shared-workspace
            - name: registryconfig
              workspace: registry-credentials
    
        - name: buildah-arm64
          runAfter:
            - git-clone
          taskRef:
            resolver: hub
            params:
              - name: kind
                value: task
              - name: catalog
                value: catalog
              - name: name
                value: buildah
              - name: version
                value: "0.9"
          params:
            - name: IMAGES
              value:
                - $(params.image-arm64)
            - name: DOCKERFILE
              value: ./Dockerfile
            - name: TLS_VERIFY
              value: $(params.tls-verify)
            - name: FORMAT
              value: docker
          workspaces:
            - name: source
              workspace: shared-workspace
            - name: registryconfig
              workspace: registry-credentials
    
        - name: merge-image
          runAfter:
            - buildah-amd64
            - buildah-arm64
          taskRef:
            resolver: hub
            params:
              - name: kind
                value: task
              - name: catalog
                value: catalog
              - name: name
                value: merge-image
              - name: version
                value: "0.1"
          params:
            - name: craneImage
              value: registry.alauda.cn:60070/devops/tektoncd/hub/crane:latest
            - name: sourceImages
              value:
                - $(params.image-amd64)
                - $(params.image-arm64)
            - name: targetImages
              value:
                - $(params.target-image)
            - name: tlsVerify
              value: $(params.tls-verify)
          workspaces:
            - name: registry-config
              workspace: registry-credentials

    Пример PipelineRun:

    apiVersion: tekton.dev/v1
    kind: PipelineRun
    metadata:
      name: e2e-multiarch-build-run
    spec:
      pipelineRef:
        name: e2e-multiarch-build
      params:
        - name: git-url
          value: https://github.com/your-org/your-app
        - name: git-revision
          value: main
        - name: image-amd64
          value: registry.example.com/team/app:v1.0.0-amd64
        - name: image-arm64
          value: registry.example.com/team/app:v1.0.0-arm64
        - name: target-image
          value: registry.example.com/team/app:v1.0.0
        - name: tls-verify
          value: "false"
      # Расположение узлов настраивается в объекте run.
      taskRunSpecs:
        - pipelineTaskName: buildah-amd64
          podTemplate:
            # Принудительно размещает pod этой задачи на узлах amd64.
            nodeSelector:
              kubernetes.io/arch: amd64
        - pipelineTaskName: buildah-arm64
          podTemplate:
            # Принудительно размещает pod этой задачи на узлах arm64.
            nodeSelector:
              kubernetes.io/arch: arm64
      workspaces:
        - name: shared-workspace
          volumeClaimTemplate:
            spec:
              accessModes:
                - ReadWriteOnce
              resources:
                requests:
                  storage: 1Gi
        - name: git-credentials
          secret:
            secretName: git-credentials
        - name: registry-credentials
          secret:
            # Должно соответствовать Secret, созданному на шаге 1.
            secretName: registry-config

    Ключевые моменты в этом примере:

    • В примере используются ссылки через hub resolver для git-clone, buildah и merge-image, поэтому соответствующие Catalog Tasks должны быть доступны для разрешения в вашем кластере.
    • image-amd64 и image-arm64 заданы как явные параметры Pipeline. Это делает входные данные для объединения однозначными и соответствует тому, как merge-image использует sourceImages.
    • taskRunSpecs + podTemplate.nodeSelector настраиваются в PipelineRun и критически важны, если в кластере используются узлы с разными архитектурами CPU. Они гарантируют, что каждая задача сборки выполняется на узле нужной архитектуры.
    • По умолчанию Tekton использует coschedule: workspaces, который создает Affinity Assistant и пытается разместить TaskRun, использующие один и тот же PVC-backed workspace, на одном узле. Если вы закрепляете buildah-amd64 и buildah-arm64 за разными архитектурами, это поведение по умолчанию конфликтует с nodeSelector на уровне отдельных задач. В таком случае установите spec.pipeline.coschedule: disabled в TektonConfig, чтобы Tekton перестал принудительно размещать TaskRun с общим workspace на одном узле. Operator автоматически распространит эту настройку в ConfigMap feature-flags.
    • Отключение coschedule необходимо для кросс-архитектурного планирования, но само по себе этого недостаточно. Если общий workspace основан на PVC с ReadWriteOnce, Kubernetes все равно не сможет одновременно подключить этот том в режиме read-write к двум разным узлам. Чтобы выполнять параллельные сборки для amd64 и arm64 на разных узлах, используйте workspace backend, который поддерживает совместное использование несколькими узлами, например ReadWriteMany.
    • sourceImages должны указывать на теги для конкретных архитектур, а targetImages — на итоговый многоархитектурный тег или теги, которые вы хотите опубликовать.
    • Workspace registry-credentials переиспользуется и buildah, и merge-image; сопоставление имен workspace (registryconfig против registry-config) зависит от интерфейса задачи и должно соответствовать определению каждой Task.

    Шаг 3: Проверьте платформы объединенного образа

    После успешного завершения PipelineRun вы можете проверить платформы объединенного образа с помощью crane, podman или skopeo:

    С помощью crane:

    crane manifest registry.example.com/team/app:v1.0.0 \
      | jq -r '.manifests[].platform | "\(.os)/\(.architecture)"'

    С помощью podman:

    podman manifest inspect docker://registry.example.com/team/app:v1.0.0 \
      | jq -r '.manifests[].platform | "\(.os)/\(.architecture)"'

    С помощью skopeo:

    skopeo inspect --raw docker://registry.example.com/team/app:v1.0.0 \
      | jq -r '.manifests[].platform | "\(.os)/\(.architecture)"'

    Ожидаемый вывод включает:

    • linux/amd64
    • linux/arm64

    Устранение неполадок

    • Если buildah-amd64 и buildah-arm64 используют один PVC-backed workspace и закреплены за разными архитектурами, проверьте флаг функции Tekton Pipelines coschedule. Установите spec.pipeline.coschedule: disabled в TektonConfig, если нужно, чтобы эти TaskRun планировались на разные узлы; режим по умолчанию workspaces пытается размещать их на одном узле с помощью Affinity Assistant. Точное расположение настройки и поведение см. в Невозможно использовать несколько PVC workspace в Tekton.
    • Даже при coschedule: disabled PVC с ReadWriteOnce все равно нельзя одновременно подключить в режиме read-write с двух разных узлов. Для полноценной параллельной кросс-архитектурной сборки привяжите общий workspace к хранилищу, которое поддерживает ReadWriteMany.
    • Рекомендуется хранить sourceImages и targetImages в одном и том же registry. Ввод из разных registry допускается, но merge-image выводит предупреждения в лог.
    • merge-image допускает объединение между разными repositories. Для исходных или целевых образов из разных registry он продолжает выполнение с предупреждениями в логе, поэтому убедитесь, что учетные данные действительны для каждого задействованного registry.
    • sourceImages и targetImages не должны быть пустыми. Дублирующиеся ссылки на исходные образы или дублирующиеся digest исходных образов пропускаются, и должен остаться как минимум один уникальный исходный образ.
    • Для self-signed registry:
      • buildah: подключайте файлы CA к sslcertdir
      • merge-image: подключайте файлы CA к ca-bundle и при необходимости задавайте caFileName
      • задавайте TLS_VERIFY / tlsVerify в значение false только в доверенных средах
    • Параметры buildah пишутся в верхнем регистре (например, IMAGES, CONTAINERFILE), тогда как merge-image использует lower camel case (например, sourceImages, targetImages).

    Связанные материалы