Когда вы работаете в среде с единой архитектурой, довольно легко иметь дело со сборкой образов docker, работающих, например, под одной и той же архитектурой «amd64».
Но что будет, если вы работаете с Macbook Air с чипом M1, который является «arm64», а вам нужно создавать образы для «amd64», или наоборот, вы работаете с машиной «amd64», а вам нужно создавать контейнеры на кластере Raspberry PI или ARM-серверов, которые набирают все большую популярность среди облачных провайдеров.
Сегодняшняя цель — научить вас с моей точки зрения и на английском языке, как генерировать мультиархитектурные или мультиархитектурные докер-образы и публиковать их на Docker Hub.
Прежде всего, необходимо иметь приложение, в моем случае я буду использовать простой Python-файл для получения информации о текущей системе. Для этого мы будем использовать библиотеку платформы
#main.py
import platform
platform_var = platform.uname()
print ("*"*30)
print (f'Machine:t{platform_var.machine}')
print (f'System:tt{platform_var.system}')
print (f'Node:tt{platform_var.node}')
print (f'Release:t{platform_var.release}')
print (f'Version:t{platform_var.version}')
print (f'Processor:t{platform_var.processor}')
print ("*"*30)
Следующим шагом будет создание нашего Dockerfile, как обычно, это начальная версия, позже мы внесем в нее небольшие изменения, чтобы иметь возможность визуализировать архитектуру, на которой мы строим.
FROM python:alpine3.10
WORKDIR /app
COPY . .
CMD [ "python", "main.py" ]
До этого момента мы можем сгенерировать изображение и запустить его.
docker build . -t jevillanueva/multiarch:latest
docker run jevillanueva/multiarch:latest
Где мы имеем результат, подобный этому:
Машина: x86_64
Система: Linux
Узел: 8ca0b41e5372
Выпуск: 4.19.128-microsoft-standard
Версия: #1 SMP Tue Jun 23 12:58:10 UTC 2020
Процессор:
Пока что мы знаем, что это работает. Следующим шагом будет изменение Dockerfile, в котором мы добавим пару вещей, чтобы мы могли визуализировать происходящее.
FROM --platform=$TARGETPLATFORM python:alpine3.10
ARG TARGETPLATFORM
WORKDIR /app
RUN echo "construyendo para $TARGETPLATFORM" > /log
COPY . .
CMD [ "python", "main.py" ]
Мы добавляем опцию платформы и аргумент «TARGETPLATFORM», в данном случае
Существует два способа выполнения многоархивного процесса, первый — самый старый xD, мы опишем его ниже, чтобы понять, как он работает.
МАНИФЕСТ ДОКЕРА
Все образы docker имеют манифест, манифест содержит информацию об образе, его слоях, размере и дайджесте, который является неизменяемым идентификатором для каждого образа. Для нашего многоархитектурного случая это очень важно, так как манифест содержит подробную информацию для образов с одинаковой функциональностью, но для разных операционных систем и архитектур. Вы можете увидеть больше проявлений
Давайте проверим манифест для используемого нами базового образа, который называется «python:alpine3.10».
docker manifest inspect python:alpine3.10
Мы получим результат, подобный этому, который покажет нам размер, его дайджест, платформы, операционную систему и их архитектуру.
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 1368,
"digest": "sha256:655edcda221823fcdb79b61095dd77e6c767bf1543505dcf078f6945497c7fcf",
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 1368,
"digest": "sha256:16779e4847cac747c0496fc56d0daa7c2090ea6cb2e4c9aa455672d6818d7179",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v6"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 1368,
"digest": "sha256:3dee5de82f12477d1f0a8ed0836181064863ba84cd8098b9c62c65f8347c656b",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v7"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 1368,
"digest": "sha256:001faf6c4b5e87a3a4b251e72bb9a9dd1a5ef93083fc3a42d54e8734dc76e1f5",
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 1368,
"digest": "sha256:42829bfc005ccdd282d82da1328c9a2511e20f09439c702311d30627c91c70ca",
"platform": {
"architecture": "386",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 1368,
"digest": "sha256:52e6ffac79478822ea62492d73c7aac3eca9a1cf41e8531899744e8e4958c236",
"platform": {
"architecture": "ppc64le",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 1368,
"digest": "sha256:90f421378ca9b94b071a20e7c4b2df746d9b4bc26dcbd85ea79f0db9322d330f",
"platform": {
"architecture": "s390x",
"os": "linux"
}
}
]
}
До сих пор мы примерно понимали, какую важную роль играет манифест, теперь мы будем использовать его для создания многоархивных образов, так что давайте приступим к работе, мы будем делать это для двух архитектур amd64 и arm64.
Изображения с использованием манифеста
Первое, что необходимо сделать, это создать образы для каждой архитектуры
# AMD64
docker build . -t jevillanueva/multiarch:manifest-amd64 --build-arg TARGETPLATFORM=amd64
docker push jevillanueva/multiarch:manifest-amd64
# ARM64
docker build . -t jevillanueva/multiarch:manifest-arm64 --build-arg TARGETPLATFORM=arm64
docker push jevillanueva/multiarch:manifest-arm64
Теперь мы создали два образа для разных архитектур и опубликовали их в Docker Hub, они выглядят примерно так
Теперь давайте создадим манифест, который будет перечислять эти два изображения с разными тегами в одном блоке.
docker manifest create jevillanueva/multiarch:manifest-latest --amend jevillanueva/multiarch:manifest-amd64 --amend jevillanueva/multiarch:manifest-arm64
И после этого мы публикуем новый манифест
docker manifest push jevillanueva/multiarch:manifest-latest
Как вы можете видеть, теперь в нашем реестре есть новый тег, который относится к двум образам и их соответствующим операционным системам и архитектурам.
Мы можем проверить изображения на основе манифеста из различных экземпляров, чтобы получить результаты архитектуры с помощью python
docker run jevillanueva/multiarch:manifest-latest
Вот результат с моей личной машины amd64 и с машины arm64
Пока это классический и подробный способ понять, почему все так происходит xD Теперь кое-что гораздо быстрее В настоящее время существует новый инструмент, разработанный Docker, который мы можем использовать для таких сценариев, под названием «Buildx».
ДОКЕР BUILDX
Docker buildx — это инструмент, который позволяет нам получить доступ к возможностям инструмента сборки moby buildkit, он позволяет нам поддерживать несколько экземпляров, чтобы мы могли создавать наши образы для разных платформ, мы создаем экземпляр для buildx под названием «mybuild» и используем этот экземпляр.
docker buildx create --name mybuild
docker buildx use mybuild
docker buildx build . --push -t jevillanueva/multiarch:buildx-latest --platform linux/amd64,linux/arm64
После загрузки и компиляции с помощью moby/buildkit мы публикуем образ в хабе docker и получаем результат, аналогичный использованию manifest.
Таким же образом мы переходим к тестированию на разных устройствах с разными архитектурами.
Как вы видите, существует несколько способов сделать это. И, наконец, в качестве дополнения я оставляю модель действий на github для генерации мультиархитектурных образов с использованием qemu для виртуализации архитектур.
Действия на Github
name: Docker Image CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
IMAGE_NAME: ${{ github.repository }}
IMAGE_TAG: ${{ github.sha }}
jobs:
build:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Docker Login
env:
DOCKER_USER: ${{secrets.DOCKER_USER}}
DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}}
run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
-
name: Build and push
uses: docker/build-push-action@v3
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ env.IMAGE_NAME }}:${{env.IMAGE_TAG}},${{ env.IMAGE_NAME }}:latest
Здесь вы найдете репозиторий проекта
Использованные ссылки:
https://docs.docker.com/registry/spec/manifest-v2-2/
https://docs.docker.com/engine/reference/commandline/manifest/
https://docs.docker.com/build/buildx/multiplatform-images/
https://github.com/docker/setup-buildx-action#with-qemu
Вот моя личная домашняя страница jevillanueva.dev