Initial commit: multi-version .NET Docker images with apko base
- apko configs for runtime (ICU), runtime-invariant (no ICU), and SDK variants - Build workflow with dynamic matrix from .NET release metadata (EOL-aware) - Daily update-check workflow to detect new .NET versions - Docker Scout PR analysis workflow - LTS/STS floating tags, multi-arch (amd64 + arm64) - Makefile for local builds and version discovery Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
commit
0b301121ad
245
.gitea/workflows/build.yaml
Normal file
245
.gitea/workflows/build.yaml
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
name: Build and Push .NET Images
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
# Weekly rebuild for CVE patches (Sunday 6am UTC)
|
||||||
|
- cron: "0 6 * * 0"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
DOCKER_IMAGE: docker.io/svrnty/dotnet
|
||||||
|
RELEASES_INDEX_URL: https://dotnetcli.azureedge.net/dotnet/release-metadata/releases-index.json
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
discover:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
matrix: ${{ steps.discover.outputs.matrix }}
|
||||||
|
lts_major: ${{ steps.discover.outputs.lts_major }}
|
||||||
|
sts_major: ${{ steps.discover.outputs.sts_major }}
|
||||||
|
steps:
|
||||||
|
- name: Discover supported .NET versions
|
||||||
|
id: discover
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
RELEASES=$(curl -fsSL "$RELEASES_INDEX_URL")
|
||||||
|
|
||||||
|
# Filter active/go-live versions (excludes EOL automatically)
|
||||||
|
SUPPORTED=$(echo "$RELEASES" | jq -c '[.["releases-index"][] | select(.["support-phase"] == "active" or .["support-phase"] == "go-live")]')
|
||||||
|
|
||||||
|
# Build matrix JSON
|
||||||
|
MATRIX=$(echo "$SUPPORTED" | jq -c '{include: [.[] | {
|
||||||
|
major: (.["channel-version"] | split(".")[0]),
|
||||||
|
runtime: .["latest-runtime"],
|
||||||
|
sdk: .["latest-sdk"],
|
||||||
|
type: .["release-type"]
|
||||||
|
}]}')
|
||||||
|
|
||||||
|
# Find highest LTS and STS majors
|
||||||
|
LTS_MAJOR=$(echo "$SUPPORTED" | jq -r '[.[] | select(.["release-type"] == "lts")] | sort_by(.["channel-version"] | split(".") | map(tonumber)) | last | .["channel-version"] | split(".")[0]')
|
||||||
|
STS_MAJOR=$(echo "$SUPPORTED" | jq -r '[.[] | select(.["release-type"] == "sts")] | sort_by(.["channel-version"] | split(".") | map(tonumber)) | last | .["channel-version"] | split(".")[0] // ""')
|
||||||
|
|
||||||
|
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
|
||||||
|
echo "lts_major=$LTS_MAJOR" >> $GITHUB_OUTPUT
|
||||||
|
echo "sts_major=$STS_MAJOR" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
echo "Matrix: $MATRIX"
|
||||||
|
echo "LTS major: $LTS_MAJOR"
|
||||||
|
echo "STS major: $STS_MAJOR"
|
||||||
|
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: discover
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix: ${{ fromJson(needs.discover.outputs.matrix) }}
|
||||||
|
env:
|
||||||
|
LTS_MAJOR: ${{ needs.discover.outputs.lts_major }}
|
||||||
|
STS_MAJOR: ${{ needs.discover.outputs.sts_major }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
with:
|
||||||
|
platforms: arm64
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Log in to DockerHub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build apko base images
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
for VARIANT in runtime runtime-invariant sdk; do
|
||||||
|
for ARCH in x86_64 aarch64; do
|
||||||
|
echo "::group::Building apko base: $VARIANT ($ARCH)"
|
||||||
|
mkdir -p ${{ github.workspace }}/build-${ARCH}/${VARIANT}
|
||||||
|
docker run --rm \
|
||||||
|
-v ${{ github.workspace }}/apko:/work:ro \
|
||||||
|
-v ${{ github.workspace }}/build-${ARCH}/${VARIANT}:/output \
|
||||||
|
cgr.dev/chainguard/apko build \
|
||||||
|
--arch $ARCH /work/${VARIANT}.yaml ${VARIANT}:latest /output/rootfs.tar.gz
|
||||||
|
echo "::endgroup::"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Download .NET binaries
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
RUNTIME_VERSION="${{ matrix.runtime }}"
|
||||||
|
SDK_VERSION="${{ matrix.sdk }}"
|
||||||
|
|
||||||
|
for ARCH in x86_64 aarch64; do
|
||||||
|
if [ "$ARCH" = "x86_64" ]; then
|
||||||
|
DOTNET_ARCH="x64"
|
||||||
|
PLATFORM_ARCH="amd64"
|
||||||
|
else
|
||||||
|
DOTNET_ARCH="arm64"
|
||||||
|
PLATFORM_ARCH="arm64"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Download ASP.NET Core runtime (for runtime and runtime-invariant)
|
||||||
|
echo "::group::Downloading ASP.NET Core runtime $RUNTIME_VERSION ($DOTNET_ARCH)"
|
||||||
|
mkdir -p dotnet-${PLATFORM_ARCH}/runtime
|
||||||
|
curl -fsSL "https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/${RUNTIME_VERSION}/aspnetcore-runtime-${RUNTIME_VERSION}-linux-${DOTNET_ARCH}.tar.gz" \
|
||||||
|
-o /tmp/aspnet-runtime-${PLATFORM_ARCH}.tar.gz
|
||||||
|
tar xf /tmp/aspnet-runtime-${PLATFORM_ARCH}.tar.gz -C dotnet-${PLATFORM_ARCH}/runtime
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
# Download .NET SDK
|
||||||
|
echo "::group::Downloading .NET SDK $SDK_VERSION ($DOTNET_ARCH)"
|
||||||
|
mkdir -p dotnet-${PLATFORM_ARCH}/sdk
|
||||||
|
curl -fsSL "https://dotnetcli.azureedge.net/dotnet/Sdk/${SDK_VERSION}/dotnet-sdk-${SDK_VERSION}-linux-${DOTNET_ARCH}.tar.gz" \
|
||||||
|
-o /tmp/dotnet-sdk-${PLATFORM_ARCH}.tar.gz
|
||||||
|
tar xf /tmp/dotnet-sdk-${PLATFORM_ARCH}.tar.gz -C dotnet-${PLATFORM_ARCH}/sdk
|
||||||
|
echo "::endgroup::"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Build and push runtime image
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
MAJOR="${{ matrix.major }}"
|
||||||
|
VERSION="${{ matrix.runtime }}"
|
||||||
|
VARIANT="runtime"
|
||||||
|
|
||||||
|
# Prepare build context
|
||||||
|
mkdir -p context-runtime
|
||||||
|
for ARCH in amd64 arm64; do
|
||||||
|
APKO_ARCH=$([[ "$ARCH" == "amd64" ]] && echo "x86_64" || echo "aarch64")
|
||||||
|
mkdir -p context-runtime/build-${ARCH}/runtime
|
||||||
|
cp build-${APKO_ARCH}/${VARIANT}/rootfs.tar.gz context-runtime/build-${ARCH}/runtime/
|
||||||
|
mkdir -p context-runtime/dotnet-${ARCH}
|
||||||
|
cp -r dotnet-${ARCH}/runtime context-runtime/dotnet-${ARCH}/
|
||||||
|
done
|
||||||
|
cp dockerfiles/runtime.Dockerfile context-runtime/Dockerfile
|
||||||
|
|
||||||
|
# Determine tags
|
||||||
|
TAGS="-t $DOCKER_IMAGE:${VARIANT}-${MAJOR} -t $DOCKER_IMAGE:${VARIANT}-${VERSION}"
|
||||||
|
if [ "$MAJOR" = "$LTS_MAJOR" ]; then
|
||||||
|
TAGS="$TAGS -t $DOCKER_IMAGE:${VARIANT}-lts"
|
||||||
|
fi
|
||||||
|
if [ "$MAJOR" = "$STS_MAJOR" ]; then
|
||||||
|
TAGS="$TAGS -t $DOCKER_IMAGE:${VARIANT}-sts"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Building $VARIANT with tags: $TAGS"
|
||||||
|
docker buildx build --platform linux/amd64,linux/arm64 --push \
|
||||||
|
--sbom=true --provenance=mode=max \
|
||||||
|
$TAGS \
|
||||||
|
context-runtime/
|
||||||
|
|
||||||
|
- name: Build and push runtime-invariant image
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
MAJOR="${{ matrix.major }}"
|
||||||
|
VERSION="${{ matrix.runtime }}"
|
||||||
|
VARIANT="runtime-invariant"
|
||||||
|
|
||||||
|
mkdir -p context-runtime-invariant
|
||||||
|
for ARCH in amd64 arm64; do
|
||||||
|
APKO_ARCH=$([[ "$ARCH" == "amd64" ]] && echo "x86_64" || echo "aarch64")
|
||||||
|
mkdir -p context-runtime-invariant/build-${ARCH}/runtime-invariant
|
||||||
|
cp build-${APKO_ARCH}/${VARIANT}/rootfs.tar.gz context-runtime-invariant/build-${ARCH}/runtime-invariant/
|
||||||
|
mkdir -p context-runtime-invariant/dotnet-${ARCH}
|
||||||
|
cp -r dotnet-${ARCH}/runtime context-runtime-invariant/dotnet-${ARCH}/
|
||||||
|
done
|
||||||
|
cp dockerfiles/runtime-invariant.Dockerfile context-runtime-invariant/Dockerfile
|
||||||
|
|
||||||
|
TAGS="-t $DOCKER_IMAGE:${VARIANT}-${MAJOR} -t $DOCKER_IMAGE:${VARIANT}-${VERSION}"
|
||||||
|
if [ "$MAJOR" = "$LTS_MAJOR" ]; then
|
||||||
|
TAGS="$TAGS -t $DOCKER_IMAGE:${VARIANT}-lts"
|
||||||
|
fi
|
||||||
|
if [ "$MAJOR" = "$STS_MAJOR" ]; then
|
||||||
|
TAGS="$TAGS -t $DOCKER_IMAGE:${VARIANT}-sts"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Building $VARIANT with tags: $TAGS"
|
||||||
|
docker buildx build --platform linux/amd64,linux/arm64 --push \
|
||||||
|
--sbom=true --provenance=mode=max \
|
||||||
|
$TAGS \
|
||||||
|
context-runtime-invariant/
|
||||||
|
|
||||||
|
- name: Build and push SDK image
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
MAJOR="${{ matrix.major }}"
|
||||||
|
VERSION="${{ matrix.sdk }}"
|
||||||
|
VARIANT="sdk"
|
||||||
|
|
||||||
|
mkdir -p context-sdk
|
||||||
|
for ARCH in amd64 arm64; do
|
||||||
|
APKO_ARCH=$([[ "$ARCH" == "amd64" ]] && echo "x86_64" || echo "aarch64")
|
||||||
|
mkdir -p context-sdk/build-${ARCH}/sdk
|
||||||
|
cp build-${APKO_ARCH}/${VARIANT}/rootfs.tar.gz context-sdk/build-${ARCH}/sdk/
|
||||||
|
mkdir -p context-sdk/dotnet-${ARCH}
|
||||||
|
cp -r dotnet-${ARCH}/sdk context-sdk/dotnet-${ARCH}/
|
||||||
|
done
|
||||||
|
cp dockerfiles/sdk.Dockerfile context-sdk/Dockerfile
|
||||||
|
|
||||||
|
TAGS="-t $DOCKER_IMAGE:${VARIANT}-${MAJOR} -t $DOCKER_IMAGE:${VARIANT}-${VERSION}"
|
||||||
|
if [ "$MAJOR" = "$LTS_MAJOR" ]; then
|
||||||
|
TAGS="$TAGS -t $DOCKER_IMAGE:${VARIANT}-lts"
|
||||||
|
fi
|
||||||
|
if [ "$MAJOR" = "$STS_MAJOR" ]; then
|
||||||
|
TAGS="$TAGS -t $DOCKER_IMAGE:${VARIANT}-sts"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Building $VARIANT with tags: $TAGS"
|
||||||
|
docker buildx build --platform linux/amd64,linux/arm64 --push \
|
||||||
|
--sbom=true --provenance=mode=max \
|
||||||
|
$TAGS \
|
||||||
|
context-sdk/
|
||||||
|
|
||||||
|
- name: Install Docker Scout
|
||||||
|
run: |
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh -o install-scout.sh
|
||||||
|
sh install-scout.sh
|
||||||
|
|
||||||
|
- name: Docker Scout CVE Scan
|
||||||
|
run: |
|
||||||
|
MAJOR="${{ matrix.major }}"
|
||||||
|
for VARIANT in runtime runtime-invariant sdk; do
|
||||||
|
echo "::group::Scout scan: ${VARIANT}-${MAJOR}"
|
||||||
|
docker scout cves ${{ env.DOCKER_IMAGE }}:${VARIANT}-${MAJOR} --only-severity critical,high || true
|
||||||
|
echo "::endgroup::"
|
||||||
|
done
|
||||||
115
.gitea/workflows/scout.yaml
Normal file
115
.gitea/workflows/scout.yaml
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
name: Docker Scout Analysis
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: ["**"]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
DOCKER_IMAGE: docker.io/svrnty/dotnet
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-image:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
image_exists: ${{ steps.check.outputs.exists }}
|
||||||
|
steps:
|
||||||
|
- name: Log in to DockerHub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Check if latest runtime-lts image exists
|
||||||
|
id: check
|
||||||
|
run: |
|
||||||
|
if docker manifest inspect ${{ env.DOCKER_IMAGE }}:runtime-lts > /dev/null 2>&1; then
|
||||||
|
echo "exists=true" >> $GITHUB_OUTPUT
|
||||||
|
echo "Latest runtime-lts image found, Scout compare will run"
|
||||||
|
else
|
||||||
|
echo "exists=false" >> $GITHUB_OUTPUT
|
||||||
|
echo "No runtime-lts image found, skipping Scout compare"
|
||||||
|
fi
|
||||||
|
|
||||||
|
scout:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: check-image
|
||||||
|
if: needs.check-image.outputs.image_exists == 'true'
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: [amd64, arm64]
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
if: matrix.arch == 'arm64'
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
with:
|
||||||
|
platforms: arm64
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Log in to DockerHub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Discover latest LTS version
|
||||||
|
id: discover
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
RELEASES=$(curl -fsSL https://dotnetcli.azureedge.net/dotnet/release-metadata/releases-index.json)
|
||||||
|
SUPPORTED=$(echo "$RELEASES" | jq -c '[.["releases-index"][] | select(.["support-phase"] == "active" or .["support-phase"] == "go-live")]')
|
||||||
|
|
||||||
|
# Find highest LTS major
|
||||||
|
LTS_MAJOR=$(echo "$SUPPORTED" | jq -r '[.[] | select(.["release-type"] == "lts")] | sort_by(.["channel-version"] | split(".") | map(tonumber)) | last | .["channel-version"] | split(".")[0]')
|
||||||
|
LTS_RUNTIME=$(echo "$SUPPORTED" | jq -r --arg ch "${LTS_MAJOR}.0" '.[] | select(.["channel-version"] == $ch) | .["latest-runtime"]')
|
||||||
|
|
||||||
|
echo "lts_major=$LTS_MAJOR" >> $GITHUB_OUTPUT
|
||||||
|
echo "lts_runtime=$LTS_RUNTIME" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Build test image (${{ matrix.arch }})
|
||||||
|
run: |
|
||||||
|
# Build apko base
|
||||||
|
docker run --rm -v ${{ github.workspace }}/apko:/work cgr.dev/chainguard/apko build \
|
||||||
|
--arch ${{ matrix.arch == 'amd64' && 'x86_64' || 'aarch64' }} \
|
||||||
|
/work/runtime.yaml runtime:latest /tmp/rootfs.tar.gz
|
||||||
|
|
||||||
|
# Download .NET runtime
|
||||||
|
DOTNET_ARCH=${{ matrix.arch == 'amd64' && 'x64' || 'arm64' }}
|
||||||
|
RUNTIME_VERSION=${{ steps.discover.outputs.lts_runtime }}
|
||||||
|
curl -fsSL "https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/${RUNTIME_VERSION}/aspnetcore-runtime-${RUNTIME_VERSION}-linux-${DOTNET_ARCH}.tar.gz" \
|
||||||
|
-o /tmp/dotnet.tar.gz
|
||||||
|
mkdir -p /tmp/dotnet
|
||||||
|
tar xf /tmp/dotnet.tar.gz -C /tmp/dotnet
|
||||||
|
|
||||||
|
# Build image
|
||||||
|
cat > /tmp/Dockerfile <<'DOCKERFILE'
|
||||||
|
FROM scratch
|
||||||
|
ADD rootfs.tar.gz /
|
||||||
|
COPY dotnet/ /usr/share/dotnet/
|
||||||
|
ENV DOTNET_ROOT=/usr/share/dotnet
|
||||||
|
ENV PATH="/usr/share/dotnet:${PATH}"
|
||||||
|
WORKDIR /app
|
||||||
|
USER 65532
|
||||||
|
DOCKERFILE
|
||||||
|
|
||||||
|
docker build -t ${{ env.DOCKER_IMAGE }}:pr-${{ github.event.pull_request.number }}-${{ matrix.arch }} /tmp/
|
||||||
|
|
||||||
|
- name: Install Docker Scout
|
||||||
|
run: |
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh -o install-scout.sh
|
||||||
|
sh install-scout.sh
|
||||||
|
|
||||||
|
- name: Docker Scout Compare (${{ matrix.arch }})
|
||||||
|
run: |
|
||||||
|
docker scout compare \
|
||||||
|
${{ env.DOCKER_IMAGE }}:pr-${{ github.event.pull_request.number }}-${{ matrix.arch }} \
|
||||||
|
--to ${{ env.DOCKER_IMAGE }}:runtime-lts \
|
||||||
|
--ignore-unchanged --only-severity critical,high
|
||||||
74
.gitea/workflows/update-check.yaml
Normal file
74
.gitea/workflows/update-check.yaml
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
name: Daily .NET Version Check
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 8 * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
DOCKER_IMAGE: docker.io/svrnty/dotnet
|
||||||
|
RELEASES_INDEX_URL: https://dotnetcli.azureedge.net/dotnet/release-metadata/releases-index.json
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-versions:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Log in to DockerHub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_SVRNTY_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_SVRNTY_ACCESS_TOKEN }}
|
||||||
|
|
||||||
|
- name: Check for new .NET versions
|
||||||
|
id: check
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Fetch release metadata
|
||||||
|
RELEASES=$(curl -fsSL "$RELEASES_INDEX_URL")
|
||||||
|
|
||||||
|
# Filter active/go-live versions (excludes EOL automatically)
|
||||||
|
SUPPORTED=$(echo "$RELEASES" | jq -c '[.["releases-index"][] | select(.["support-phase"] == "active" or .["support-phase"] == "go-live")]')
|
||||||
|
|
||||||
|
NEEDS_BUILD=false
|
||||||
|
|
||||||
|
echo "$SUPPORTED" | jq -r '.[] | "\(.["channel-version"]) \(.["latest-runtime"]) \(.["latest-sdk"]) \(.["release-type"])"' | \
|
||||||
|
while read -r CHANNEL RUNTIME SDK TYPE; do
|
||||||
|
MAJOR=$(echo "$CHANNEL" | cut -d. -f1)
|
||||||
|
echo "Checking .NET $MAJOR: runtime=$RUNTIME sdk=$SDK type=$TYPE"
|
||||||
|
|
||||||
|
# Check if runtime image for this exact version exists
|
||||||
|
if docker manifest inspect "$DOCKER_IMAGE:runtime-$RUNTIME" > /dev/null 2>&1; then
|
||||||
|
echo " Image runtime-$RUNTIME already exists, skipping"
|
||||||
|
else
|
||||||
|
echo " New version detected: runtime-$RUNTIME"
|
||||||
|
NEEDS_BUILD=true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Re-check outside the pipe (subshell issue)
|
||||||
|
NEEDS_BUILD=false
|
||||||
|
while read -r CHANNEL RUNTIME SDK TYPE; do
|
||||||
|
MAJOR=$(echo "$CHANNEL" | cut -d. -f1)
|
||||||
|
if ! docker manifest inspect "$DOCKER_IMAGE:runtime-$RUNTIME" > /dev/null 2>&1; then
|
||||||
|
NEEDS_BUILD=true
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done < <(echo "$SUPPORTED" | jq -r '.[] | "\(.["channel-version"]) \(.["latest-runtime"]) \(.["latest-sdk"]) \(.["release-type"])"')
|
||||||
|
|
||||||
|
echo "needs_build=$NEEDS_BUILD" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Trigger build workflow
|
||||||
|
if: steps.check.outputs.needs_build == 'true'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
await github.rest.actions.createWorkflowDispatch({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
workflow_id: 'build.yaml',
|
||||||
|
ref: context.ref
|
||||||
|
})
|
||||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
build-*/
|
||||||
|
dotnet-*/
|
||||||
|
context-*/
|
||||||
|
*.tar.gz
|
||||||
|
.env
|
||||||
55
Makefile
Normal file
55
Makefile
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
DOCKER_IMAGE := svrnty/dotnet
|
||||||
|
VARIANTS := runtime runtime-invariant sdk
|
||||||
|
|
||||||
|
# Default: show help
|
||||||
|
.PHONY: help
|
||||||
|
help:
|
||||||
|
@echo "Usage:"
|
||||||
|
@echo " make discover - Query .NET release metadata and show supported versions"
|
||||||
|
@echo " make build-apko - Build all apko base images locally"
|
||||||
|
@echo " make build MAJOR=10 - Build all variants for a specific .NET major version"
|
||||||
|
@echo " make clean - Remove build artifacts"
|
||||||
|
|
||||||
|
# Discover supported .NET versions from release metadata
|
||||||
|
.PHONY: discover
|
||||||
|
discover:
|
||||||
|
@echo "Fetching .NET release metadata..."
|
||||||
|
@curl -fsSL https://dotnetcli.azureedge.net/dotnet/release-metadata/releases-index.json | \
|
||||||
|
jq -r '.["releases-index"][] | select(.["support-phase"] == "active" or .["support-phase"] == "go-live") | "\(.["channel-version"])\t\(.["latest-runtime"])\t\(.["latest-sdk"])\t\(.["release-type"])\t\(.["support-phase"])"' | \
|
||||||
|
column -t -s$$'\t' -N "CHANNEL,RUNTIME,SDK,TYPE,PHASE"
|
||||||
|
|
||||||
|
# Build apko base images for a specific variant (local only)
|
||||||
|
.PHONY: build-apko
|
||||||
|
build-apko:
|
||||||
|
@for variant in $(VARIANTS); do \
|
||||||
|
echo "Building apko base: $$variant"; \
|
||||||
|
for arch in x86_64 aarch64; do \
|
||||||
|
docker run --rm -v $(PWD)/apko:/work cgr.dev/chainguard/apko build \
|
||||||
|
--arch $$arch /work/$$variant.yaml $$variant:latest build-$$arch/$$variant.tar.gz || exit 1; \
|
||||||
|
done; \
|
||||||
|
done
|
||||||
|
|
||||||
|
# Build all variants for a .NET major version
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
ifndef MAJOR
|
||||||
|
$(error MAJOR is required, e.g. make build MAJOR=10)
|
||||||
|
endif
|
||||||
|
@echo "Building .NET $(MAJOR) images..."
|
||||||
|
@$(MAKE) build-variant VARIANT=runtime MAJOR=$(MAJOR)
|
||||||
|
@$(MAKE) build-variant VARIANT=runtime-invariant MAJOR=$(MAJOR)
|
||||||
|
@$(MAKE) build-variant VARIANT=sdk MAJOR=$(MAJOR)
|
||||||
|
|
||||||
|
# Build a single variant (internal target)
|
||||||
|
.PHONY: build-variant
|
||||||
|
build-variant:
|
||||||
|
@echo "Building $(VARIANT)-$(MAJOR)..."
|
||||||
|
@for arch in x86_64 aarch64; do \
|
||||||
|
docker run --rm -v $(PWD)/apko:/work cgr.dev/chainguard/apko build \
|
||||||
|
--arch $$arch /work/$(VARIANT).yaml $(VARIANT):latest build-$$arch/rootfs.tar.gz || exit 1; \
|
||||||
|
done
|
||||||
|
|
||||||
|
# Clean build artifacts
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -rf build-* dotnet-*
|
||||||
30
apko/runtime-invariant.yaml
Normal file
30
apko/runtime-invariant.yaml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
contents:
|
||||||
|
repositories:
|
||||||
|
- https://packages.wolfi.dev/os
|
||||||
|
keyring:
|
||||||
|
- https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
|
||||||
|
packages:
|
||||||
|
- wolfi-baselayout
|
||||||
|
- glibc
|
||||||
|
- libstdc++
|
||||||
|
- ca-certificates-bundle
|
||||||
|
- libssl3
|
||||||
|
- zlib
|
||||||
|
|
||||||
|
accounts:
|
||||||
|
groups:
|
||||||
|
- groupname: nonroot
|
||||||
|
gid: 65532
|
||||||
|
users:
|
||||||
|
- username: nonroot
|
||||||
|
uid: 65532
|
||||||
|
gid: 65532
|
||||||
|
run-as: 65532
|
||||||
|
|
||||||
|
archs:
|
||||||
|
- x86_64
|
||||||
|
- aarch64
|
||||||
|
|
||||||
|
environment:
|
||||||
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
|
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: "true"
|
||||||
32
apko/runtime.yaml
Normal file
32
apko/runtime.yaml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
contents:
|
||||||
|
repositories:
|
||||||
|
- https://packages.wolfi.dev/os
|
||||||
|
keyring:
|
||||||
|
- https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
|
||||||
|
packages:
|
||||||
|
- wolfi-baselayout
|
||||||
|
- glibc
|
||||||
|
- libstdc++
|
||||||
|
- ca-certificates-bundle
|
||||||
|
- libssl3
|
||||||
|
- zlib
|
||||||
|
- icu
|
||||||
|
- tzdata
|
||||||
|
|
||||||
|
accounts:
|
||||||
|
groups:
|
||||||
|
- groupname: nonroot
|
||||||
|
gid: 65532
|
||||||
|
users:
|
||||||
|
- username: nonroot
|
||||||
|
uid: 65532
|
||||||
|
gid: 65532
|
||||||
|
run-as: 65532
|
||||||
|
|
||||||
|
archs:
|
||||||
|
- x86_64
|
||||||
|
- aarch64
|
||||||
|
|
||||||
|
environment:
|
||||||
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
|
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: "false"
|
||||||
36
apko/sdk.yaml
Normal file
36
apko/sdk.yaml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
contents:
|
||||||
|
repositories:
|
||||||
|
- https://packages.wolfi.dev/os
|
||||||
|
keyring:
|
||||||
|
- https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
|
||||||
|
packages:
|
||||||
|
- wolfi-baselayout
|
||||||
|
- glibc
|
||||||
|
- libstdc++
|
||||||
|
- ca-certificates-bundle
|
||||||
|
- libssl3
|
||||||
|
- zlib
|
||||||
|
- icu
|
||||||
|
- tzdata
|
||||||
|
- bash
|
||||||
|
- git
|
||||||
|
- curl
|
||||||
|
- coreutils
|
||||||
|
|
||||||
|
accounts:
|
||||||
|
groups:
|
||||||
|
- groupname: nonroot
|
||||||
|
gid: 65532
|
||||||
|
users:
|
||||||
|
- username: nonroot
|
||||||
|
uid: 65532
|
||||||
|
gid: 65532
|
||||||
|
run-as: 0
|
||||||
|
|
||||||
|
archs:
|
||||||
|
- x86_64
|
||||||
|
- aarch64
|
||||||
|
|
||||||
|
environment:
|
||||||
|
DOTNET_RUNNING_IN_CONTAINER: "true"
|
||||||
|
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: "false"
|
||||||
10
dockerfiles/runtime-invariant.Dockerfile
Normal file
10
dockerfiles/runtime-invariant.Dockerfile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
FROM scratch
|
||||||
|
ARG TARGETARCH
|
||||||
|
ADD build-${TARGETARCH}/runtime-invariant/rootfs.tar.gz /
|
||||||
|
COPY dotnet-${TARGETARCH}/runtime/ /usr/share/dotnet/
|
||||||
|
ENV DOTNET_ROOT=/usr/share/dotnet
|
||||||
|
ENV PATH="/usr/share/dotnet:${PATH}"
|
||||||
|
ENV DOTNET_RUNNING_IN_CONTAINER=true
|
||||||
|
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true
|
||||||
|
WORKDIR /app
|
||||||
|
USER 65532
|
||||||
10
dockerfiles/runtime.Dockerfile
Normal file
10
dockerfiles/runtime.Dockerfile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
FROM scratch
|
||||||
|
ARG TARGETARCH
|
||||||
|
ADD build-${TARGETARCH}/runtime/rootfs.tar.gz /
|
||||||
|
COPY dotnet-${TARGETARCH}/runtime/ /usr/share/dotnet/
|
||||||
|
ENV DOTNET_ROOT=/usr/share/dotnet
|
||||||
|
ENV PATH="/usr/share/dotnet:${PATH}"
|
||||||
|
ENV DOTNET_RUNNING_IN_CONTAINER=true
|
||||||
|
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
|
||||||
|
WORKDIR /app
|
||||||
|
USER 65532
|
||||||
10
dockerfiles/sdk.Dockerfile
Normal file
10
dockerfiles/sdk.Dockerfile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
FROM scratch
|
||||||
|
ARG TARGETARCH
|
||||||
|
ADD build-${TARGETARCH}/sdk/rootfs.tar.gz /
|
||||||
|
COPY dotnet-${TARGETARCH}/sdk/ /usr/share/dotnet/
|
||||||
|
ENV DOTNET_ROOT=/usr/share/dotnet
|
||||||
|
ENV PATH="/usr/share/dotnet:${PATH}"
|
||||||
|
ENV DOTNET_RUNNING_IN_CONTAINER=true
|
||||||
|
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
|
||||||
|
WORKDIR /app
|
||||||
|
USER 0
|
||||||
Loading…
Reference in New Issue
Block a user