Skip to content

fix(ci): build and publish images for linux/arm64 - #28

Merged
fey merged 3 commits into
mainfrom
content-326-multiarch-images
Aug 20, 2026
Merged

fix(ci): build and publish images for linux/arm64#28
fey merged 3 commits into
mainfrom
content-326-multiarch-images

Conversation

@fey

@fey fey commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Тикет: CONTENT-326, выделен из CONTENT-324 — актуализации курса «Docker».

Проблема

Опубликованный манифест содержит только linux/amd64:

docker buildx imagetools inspect hexletcomponents/devops-example-app:latest

Name:      docker.io/hexletcomponents/devops-example-app:latest
  Platform:  linux/amd64
  Platform:  unknown/unknown

linux/arm64 нет. На Apple Silicon образ идёт через эмуляцию, Docker печатает предупреждение о несовпадении платформы, а при отключённой Rosetta запуск падает. Образ используется в уроках 300 и 600 курса docker_basics_course — это первое, что студент вообще запускает в курсе, и проходят курс в основном на macOS.

Причина не в отсутствии настройки

Настройка под мультиарх в репозитории уже была, ей просто никто не пользовался.

В main.yml стоят setup-qemu-action и setup-buildx-action, но у шагов публикации не задан platforms. Без него build-push-action собирает только под архитектуру раннера, то есть ubuntu-latest → amd64. QEMU и buildx стоят рядом и не используются.

Мультиарх-команда в репозитории тоже есть — цель docker-push в Makefile:

docker-push:
	docker buildx build --platform linux/amd64,linux/arm64 -t hexletcomponents/devops-example-app --push .

Но CI её не вызывает: публикация идёт через build-push-action. По отношению к опубликованному образу эта цель мертва, она осталась для ручного пуша.

Что изменено

1. main.ymlplatforms обоим шагам публикации, приложению и caddy.

Шаг «Build and export to Docker» намеренно не тронут: у него load: true, а load с несколькими платформами не работает. Он нужен только чтобы прогнать make compose-test-ci и make compose-lint-ci перед публикацией, и остаётся однoплатформенным.

2. release.ymlimagetools create вместо pull/tag/push.

Это вторая, менее заметная половина проблемы. Версионный тег собирался так:

- run: docker pull ${APP_IMAGE_NAME}:latest
- run: docker tag  ${APP_IMAGE_NAME}:latest ${APP_IMAGE_NAME}:${{ github.ref_name }}
- run: docker push ${APP_IMAGE_NAME}:${{ github.ref_name }}

docker pull забирает образ только под платформу раннера, поэтому re-tag и push публикуют однoархитектурный образ. То есть даже с починенным main.yml теги v* остались бы amd64-only: этот паттерн схлопывает мультиарх-манифест.

docker buildx imagetools create работает с манифестом в реестре, а не со скачанным образом, поэтому переносит все платформы.

Проверено

  • оба Dockerfile архитектурно нейтральны: node:26-slim и caddy мультиарховые, пиновок под amd64 или имён артефактов вида x86_64 нет. У caddy-образа вообще только COPY
  • YAML обоих workflow валиден (yq)
  • сборка под arm64 локально не проверялась, и это стоит сказать прямо: на машине не зарегистрирован binfmt для arm64, а регистрировать его — правка хостовой системы. На раннере эмуляцию поднимает setup-qemu-action, который в workflow уже есть. Фактическую проверку даст этот CI-прогон

Приёмка

После мержа и прогона main:

docker buildx imagetools inspect hexletcomponents/devops-example-app:latest

должен показать и linux/amd64, и linux/arm64. То же для hexletcomponents/devops-example-caddy.

Смежное, за пределами этого PR

За время, пока курс не трогали, образ уже пересобирали: CMD стал bin/start.sh, флаг Fastify -P стал -o, поменялся формат лога. Выводы уроков 300 и 600 под это подтянуты в CONTENT-324. Если после мержа образ соберётся заново и что-то из этого изменится — стоит сверить уроки ещё раз.

fey and others added 3 commits August 20, 2026 23:01
Опубликованный манифест hexletcomponents/devops-example-app содержал только
linux/amd64. На Apple Silicon образ идёт через эмуляцию и Docker печатает
предупреждение о несовпадении платформы, а при отключённой Rosetta запуск
падает. Образ используется в уроках 300 и 600 курса docker_basics_course, и это
первое, что студент вообще запускает.

Причина была не в отсутствии настройки, а в том, что CI не пользовался тем, что
уже настроено. В main.yml стоят setup-qemu-action и setup-buildx-action, но у
шагов публикации не задан platforms, поэтому build-push-action собирал только
под архитектуру раннера, то есть amd64. Мультиарх-команда в репозитории была —
цель docker-push в Makefile, — но CI её не вызывает.

Добавлен platforms: linux/amd64,linux/arm64 обоим шагам публикации, приложению
и caddy. Шаг «Build and export to Docker» не тронут: у него load: true, а он с
несколькими платформами не работает и нужен только для прогона тестов.

Отдельно release.yml. Он собирал версионный тег через pull, tag и push, а этот
паттерн схлопывает мультиарх: pull забирает образ только под платформу раннера.
То есть даже с починенным main.yml теги v* остались бы однoархитектурными.
Заменено на docker buildx imagetools create, который работает с манифестом в
реестре, а не со скачанным образом.

Оба Dockerfile архитектурно нейтральны: node:26-slim и caddy мультиарховые,
пиновок под amd64 нет. Сборка под arm64 локально не проверялась — на машине не
зарегистрирован binfmt, эмуляцию на раннере поднимает setup-qemu-action.
imagetools-команды влезают в одну строку, комментарий сокращён до причины.
Закомментированные uses в release.yml удалены: checkout, qemu и buildx этой
джобе не нужны, а рядом с новой правкой они читаются как незаконченный шаг.

Цель docker-push в Makefile мертва: публикацию делает CI, и после правки он
собирает обе платформы сам. Комментарий про запуск x86-образа на ARM снят
вместе с ней — образ мультиарховый.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
У события create фильтр tags игнорируется: воркфлоу срабатывал и на создание
ветки, а github.ref_name тогда равен её имени. Так на Docker Hub попали теги
content-326-multiarch-images, remove-biome, fix-main-ci и fix-stop-server —
у обоих образов. У push фильтр по тегам работает.

Мусорные теги удаляются в Docker Hub руками, воркфлоу их не трогает.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@fey
fey merged commit 5394e26 into main Aug 20, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant