← К программе курса

Модуль 16 / 18

CI/CD: buildx, multi-platform и immutable delivery

DOCKER

Содержание
01

1. Цели и результат CI/CD

После модуля вы сможете построить pipeline, который один раз собирает multi-platform image, проверяет его и продвигает один digest между окружениями.

  • commit запускает сборку
  • gates предшествуют публикации
  • release задаётся digest
  • promotion не пересобирает artifact
02

2. Теория: стадии pipeline

Pipeline разделяет lint и unit tests, проверку Dockerfile, build, integration tests, supply-chain gates, push и deployment. Ранний дешёвый отказ должен останавливать следующие стадии.

Runner входит в trusted computing base. Его image, Docker/Buildx versions, permissions и network access фиксируют. Общий долгоживущий daemon повышает риск утечки cache, credentials и privileged control.

03

3. Теория: Buildx и BuildKit

Buildx управляет builders, BuildKit выполняет build graph. docker-container driver даёт изолированный builder и поддерживает OCI, registry и cache exporters, но результат не загружается автоматически в классический image store.

Builder создают детерминированно, bootstrap проверяют до build, metadata и build record сохраняют как evidence.

04

4. Теория: multi-platform images

Multi-platform image — OCI index с manifest для каждой OS/architecture. Один digest index описывает весь набор, а registry выбирает подходящий manifest клиенту.

Стратегии: QEMU emulation, native nodes и cross-compilation. При cross-compilation build stage закрепляют за BUILDPLATFORM, компилятору передают TARGETOS, TARGETARCH и TARGETVARIANT.

05

5. Теория: cache и воспроизводимость

Для ephemeral runners используют registry или CI cache exporter. Cache лишь ускоряет build: scope учитывает platform, toolchain и lockfiles.

Base images и зависимости закрепляют digest/lockfile; secrets передают secret или SSH mounts, не ARG. SOURCE_DATE_EPOCH помогает, но одинаковый source не гарантирует digest при других inputs или builder.

06

6. Теория: immutable delivery

Tag удобен, но изменяем. После push pipeline получает digest из metadata или registry, проверяет repository@digest и передаёт его deployment-системе.

Promotion переносит проверенный manifest без rebuild. Production rebuild создаёт новый, ещё не проверенный artifact. Environment configuration хранится отдельно от image.

07

7. Методические указания

  • Закрепляйте версии CI actions и builder
  • Минимальные job permissions
  • Не выдавайте secrets untrusted PR
  • Tests до push
  • SBOM, provenance, scan и signature
  • Разные build/deploy identities
  • Deployment concurrency control
  • Сохраняйте digest и evidence
  • Rollback на прежний digest
08

8. Лабораторная работа: multi-platform artifact

Создайте isolated builder и native build stage для двух TARGETPLATFORM.

terminal
rm -rf /tmp/docker-m16
mkdir -p /tmp/docker-m16/context /tmp/docker-m16/unpacked
cat > /tmp/docker-m16/context/Dockerfile <<'EOF'
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM alpine:3.21 AS build
ARG BUILDPLATFORM
ARG TARGETPLATFORM
RUN printf 'built_on=%s\ntarget=%s\n' "$BUILDPLATFORM" "$TARGETPLATFORM" > /artifact.txt
FROM alpine:3.21
COPY --from=build /artifact.txt /artifact.txt
CMD ["cat", "/artifact.txt"]
EOF
docker buildx rm docker-m16 2>/dev/null || true
docker buildx create --name docker-m16 --driver docker-container --use --bootstrap
docker buildx inspect --bootstrap

Экспортируйте amd64 и arm64 в OCI archive. Provenance здесь отключён лишь для исследования index; в production включите его.

terminal
docker buildx build --builder docker-m16 \
  --platform linux/amd64,linux/arm64 --provenance=false \
  --metadata-file /tmp/docker-m16/metadata.json \
  --output type=oci,dest=/tmp/docker-m16/image.oci.tar \
  /tmp/docker-m16/context
tar -xf /tmp/docker-m16/image.oci.tar -C /tmp/docker-m16/unpacked
jq . /tmp/docker-m16/metadata.json

Разрешите корневой digest и проверьте content-addressed manifests.

terminal
index_digest=$(jq -r '."containerimage.digest"' /tmp/docker-m16/metadata.json)
index_file="/tmp/docker-m16/unpacked/blobs/sha256/${index_digest#sha256:}"
test -f "$index_file"
jq -r '.manifests[].platform | "\(.os)/\(.architecture)"' "$index_file" | sort
actual="sha256:$(sha256sum "$index_file" | awk '{print $1}')"
test "$actual" = "$index_digest"
for digest in $(jq -r '.manifests[].digest' "$index_file"); do
  blob="/tmp/docker-m16/unpacked/blobs/sha256/${digest#sha256:}"
  test "sha256:$(sha256sum "$blob" | awk '{print $1}')" = "$digest"
  printf 'verified_manifest=%s\n' "$digest"
done
terminal
test "$(jq -r '.manifests | length' "$index_file")" -eq 2
test "$(jq -r '[.manifests[].platform | select(.os=="linux" and (.architecture=="amd64" or .architecture=="arm64"))] | length' "$index_file")" -eq 2
printf 'release_candidate=%s\n' "$index_digest"

Критерий: ровно две платформы, index и оба manifests прошли checksum.

09

9. Диагностика CI и release

Проверяйте цепочку checkout → bootstrap → dependencies → platform execution → cache → exporter → registry auth → policy → deploy.

terminal
docker buildx ls
docker buildx inspect docker-m16 --bootstrap
docker logs buildx_buildkit_docker-m160 --tail 100
jq . /tmp/docker-m16/metadata.json
tar -tf /tmp/docker-m16/image.oci.tar | sed -n '1,40p'
docker system df
df -h /var/lib/docker
  • exec format error — нет emulator
  • no match for platform — нет base manifest
  • failed to solve — найдите BuildKit vertex
  • cache miss — scope/inputs
  • denied — identity/scope
  • digest изменился — изменились inputs, builder или был rebuild
10

10. Контроль и cleanup

  • Buildx или BuildKit?
  • Почему результат является index?
  • Когда emulation, native или cross-build?
  • Почему --load не для обычного multi-platform output?
  • Почему tag недостаточен?
  • Почему нельзя rebuild после tests?
  • Какие evidence нужны?
terminal
docker buildx rm docker-m16
rm -rf /tmp/docker-m16
docker ps -a --filter name=buildx_buildkit_docker-m16

Модуль освоен, если один index digest проходит build → verify → promote → deploy без пересборки.