Build musl and glibc for amd64 and arm64 through one native package path. Reuse musl outputs for OCI images and OpenWrt installers, and export binaries inside a rootless unshare session. Restore the executable dependency graph into a shared persistent NuGet cache, build managed dependencies once, and run isolated native publishes in parallel. Clean temporary outputs and expired image layers under store locks, retire inactive legacy stores after seven days, and retain two toolchain exports. Add regression coverage for staging, extraction, packaging and cleanup boundaries.
131 lines
5.1 KiB
Bash
131 lines
5.1 KiB
Bash
#!/usr/bin/env bash
|
|
# Publish musl OCI images for the Linux Agent on amd64 and arm64.
|
|
set -euo pipefail
|
|
|
|
tag="${CI_COMMIT_TAG:-}"
|
|
channel=release
|
|
namespace=moshiro
|
|
if [[ -z "$tag" ]]; then
|
|
[[ "${CI_PIPELINE_EVENT:-}" == push && "${CI_COMMIT_BRANCH:-}" == main && "${CI_COMMIT_MESSAGE:-}" == *'[CI]'* ]] || exit 2
|
|
channel=dev
|
|
namespace=moshiro-dev
|
|
else
|
|
[[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]] || exit 2
|
|
fi
|
|
[[ -n "${GITEA_TOKEN:-}" ]] || { echo "GITEA_TOKEN is required" >&2; exit 2; }
|
|
[[ -n "${ZOT_USERNAME:-}" && -n "${ZOT_SECRET:-}" ]] || {
|
|
echo "Zot credentials are required" >&2
|
|
exit 2
|
|
}
|
|
|
|
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
# Native packages and OCI tags use the same deterministic CI version.
|
|
source "$root/ci/version.sh"
|
|
version="$MOSHIRO_VERSION"
|
|
tag="$MOSHIRO_TAG"
|
|
|
|
gitea_base="${GITEA_BASE:-http://127.0.0.1:3100}"
|
|
gitea_base="${gitea_base%/}"
|
|
gitea_host="${gitea_base#https://}"
|
|
gitea_host="${gitea_host#http://}"
|
|
gitea_host="${gitea_host%%/*}"
|
|
gitea_host="${gitea_host%%:*}"
|
|
registry="${ZOT_REGISTRY:-registry.oeo.one}"
|
|
image_root="$registry/$namespace"
|
|
work="$root/.release/node-images/$channel"
|
|
netrc="$work/netrc"
|
|
buildah_home="/home/justme/woodpecker/buildah-home/node-images-$channel"
|
|
mkdir -p "$buildah_home"
|
|
exec 9> "$buildah_home/.lock"
|
|
flock -w 1800 9
|
|
source "$root/ci/buildah-env.sh"
|
|
moshiro_setup_buildah "$buildah_home"
|
|
mkdir -p "$work"
|
|
chmod 700 "$work"
|
|
printf 'machine %s login justme password %s\n' "$gitea_host" "$GITEA_TOKEN" > "$netrc"
|
|
chmod 600 "$netrc"
|
|
export REGISTRY_AUTH_FILE="$work/zot-auth.json"
|
|
trap 'rm -rf "$work"' EXIT
|
|
|
|
logged_in=false
|
|
for attempt in 1 2 3 4; do
|
|
if buildah login --tls-verify=true --username "$ZOT_USERNAME" --password-stdin "$registry" <<< "$ZOT_SECRET" >/dev/null; then
|
|
logged_in=true
|
|
break
|
|
fi
|
|
if [[ "$attempt" -lt 4 ]]; then
|
|
echo "Zot login attempt $attempt failed; retrying in 3 seconds" >&2
|
|
sleep 3
|
|
fi
|
|
done
|
|
[[ "$logged_in" == true ]] || { echo "could not authenticate to Zot after 4 attempts" >&2; exit 1; }
|
|
|
|
build_arch_image() {
|
|
local component="$1" arch="$2" suffix="$3"
|
|
local filename="moshiro-$component-v$version-linux-$suffix.tar.gz"
|
|
local context="$work/$component-$arch"
|
|
local archive="$work/$filename"
|
|
local containerfile="$root/packaging/container/${component^}.Containerfile"
|
|
local image="$image_root/moshiro-$component"
|
|
local local_image="localhost/moshiro-$component:ci-$channel-$arch"
|
|
|
|
curl --fail-with-body --silent --show-error --retry 3 --netrc-file "$netrc" \
|
|
"$gitea_base/api/packages/justme/generic/moshiro-node/$version/$filename" -o "$archive"
|
|
mkdir -p "$context/app" "$context/config"
|
|
tar -xzf "$archive" -C "$work"
|
|
install -m 0755 "$work/fleet-enroll" "$context/app/fleet-enroll"
|
|
install -m 0755 "$work/moshiro-$component" "$context/app/moshiro-$component"
|
|
: > "$context/config/.keep"
|
|
install -m 0755 "$root/packaging/container/entrypoint.sh" "$context/entrypoint.sh"
|
|
|
|
buildah bud --tls-verify=true --arch "$arch" \
|
|
--build-arg "APP_VERSION=$version" \
|
|
-f "$containerfile" -t "$local_image" "$context" >/dev/null
|
|
|
|
local pushed=false
|
|
for attempt in 1 2 3; do
|
|
if buildah push --tls-verify=true "$local_image" "docker://$image:$version-$arch" >/dev/null; then
|
|
pushed=true
|
|
break
|
|
fi
|
|
if [[ "$attempt" -lt 3 ]]; then
|
|
echo "Zot push for $component/$arch attempt $attempt failed; retrying in 5 seconds" >&2
|
|
sleep 5
|
|
fi
|
|
done
|
|
[[ "$pushed" == true ]] || { echo "could not push $component/$arch image after 3 attempts" >&2; return 1; }
|
|
echo "pushed Zot image $image:$version-$arch"
|
|
}
|
|
|
|
publish_index() {
|
|
local component="$1" image="$image_root/moshiro-$component"
|
|
local manifest="localhost/moshiro-$component:$version-multiarch"
|
|
buildah manifest rm "$manifest" >/dev/null 2>&1 || true
|
|
buildah manifest create "$manifest" >/dev/null
|
|
buildah manifest add "$manifest" "docker://$image:$version-amd64" >/dev/null
|
|
buildah manifest add "$manifest" "docker://$image:$version-arm64" >/dev/null
|
|
buildah manifest push --all --format oci --digestfile "$work/$component.digest" "$manifest" "docker://$image:$version" >/dev/null
|
|
if [[ "$channel" == dev || "$version" != *-* ]]; then
|
|
buildah manifest push --all --format oci "$manifest" "docker://$image:latest" >/dev/null
|
|
fi
|
|
buildah manifest rm "$manifest" >/dev/null
|
|
echo "published multi-architecture index $image:$version"
|
|
if [[ "$channel" == dev || "$version" != *-* ]]; then
|
|
echo "published multi-architecture index $image:latest"
|
|
fi
|
|
}
|
|
|
|
for component in agent; do
|
|
build_arch_image "$component" amd64 musl-amd64
|
|
build_arch_image "$component" arm64 musl-arm64
|
|
publish_index "$component"
|
|
# 发布清单:给多架构镜像的 digest 签名(私钥只在 CI 密钥里),放进镜像仓库(<仓库>-manifest:release),面板在线时再登记一份加速。
|
|
# 没有配置签名密钥(例如 fork)就只发镜像、不发清单。
|
|
if [[ -n "${RELEASE_SIGNING_KEY:-}" ]]; then
|
|
digest="$(cat "$work/$component.digest")"
|
|
bash "$root/ci/publish-release-offer.sh" "$component" "$image_root/moshiro-$component" "$digest" "$tag" "$channel" "$work/$component-release"
|
|
fi
|
|
done
|
|
|
|
bash "$root/ci/cleanup-build-cache.sh"
|