ci: add Dockerfile and Gitea Actions workflow for irtt-server

Introduce a multi-platform build pipeline to automate the publication of a minimal, statically linked irtt-server image to Gitea and GHCR.
This commit is contained in:
Nils Andreas Svee committed 2026-08-25 00:50:04 +07:00
1 parent 95037f7fa0
commit e2b70ac50a
2 files changed
+141

No files matched your search

+99
View File
@@ -0,0 +1,99 @@
name: Publish irtt-server image
on:
push:
tags:
# This repo tags each crate independently (irtt-proto/vX, irtt-client/vX,
# ...); only the app package's tag corresponds to this image.
- "irtt-rs/v*"
workflow_dispatch:
env:
IMAGE_NAME: irtt-server
IMAGE_OWNER: lochnair
GITEA_REGISTRY: git.lochnair.net
GHCR_REGISTRY: ghcr.io
# Pinned so a floating "latest" release doesn't silently change the build.
CRANE_VERSION: v0.20.2
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Determine image tags
id: meta
run: |
if [ "${GITHUB_REF_TYPE}" = "tag" ]; then
version="${GITHUB_REF_NAME#irtt-rs/v}"
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "tags=${version},latest" >> "$GITHUB_OUTPUT"
else
# Manual dispatch off a branch: tag by commit only, never touch
# "latest", so an ad-hoc build can't clobber the last release.
version="sha-$(git rev-parse --short HEAD)"
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "tags=${version}" >> "$GITHUB_OUTPUT"
fi
# Cross-compilation is handled inside the Dockerfile via tonistiigi/xx
# (native builds, no emulation), but buildx still needs a driver that
# can assemble a multi-platform manifest list.
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Gitea Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.GITEA_REGISTRY }}
# The automatic per-job token comes back unauthorized for package
# writes on this instance, so use a PAT (scope: write:package) instead.
# (Secret names can't start with GITEA_/GITHUB_, hence REGISTRY_*.)
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.GHCR_REGISTRY }}
username: ${{ secrets.GHCR_USERNAME }}
password: ${{ secrets.GHCR_TOKEN }}
- name: Build tag list
id: tags
run: |
IFS=',' read -ra tag_list <<< "${{ steps.meta.outputs.tags }}"
gitea_tags=""
for t in "${tag_list[@]}"; do
gitea_tags="${gitea_tags}${GITEA_REGISTRY}/${IMAGE_OWNER}/${IMAGE_NAME}:${t},"
done
echo "gitea=${gitea_tags%,}" >> "$GITHUB_OUTPUT"
# Gitea is the primary publish target: this is the only build. Every
# other registry gets an exact digest copy of this same image (see
# below), never a separate build, so the hash matches everywhere.
- name: Build and push to Gitea
id: build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.tags.outputs.gitea }}
- name: Install crane
run: |
mkdir -p "${HOME}/.local/bin"
curl -sL "https://github.com/google/go-containerregistry/releases/download/${CRANE_VERSION}/go-containerregistry_Linux_x86_64.tar.gz" \
| tar -xz -C "${HOME}/.local/bin" crane
echo "${HOME}/.local/bin" >> "$GITHUB_PATH"
- name: Duplicate image to GHCR (same digest, no rebuild)
run: |
source_ref="${GITEA_REGISTRY}/${IMAGE_OWNER}/${IMAGE_NAME}@${{ steps.build.outputs.digest }}"
IFS=',' read -ra tag_list <<< "${{ steps.meta.outputs.tags }}"
for t in "${tag_list[@]}"; do
crane copy "${source_ref}" "${GHCR_REGISTRY}/${IMAGE_OWNER}/${IMAGE_NAME}:${t}"
done
+42
View File
@@ -0,0 +1,42 @@
# syntax=docker/dockerfile:1
# Builds the irtt-server applet only, statically linked against musl, and
# ships it in a scratch image with no shell or libc.
#
# Cross-compiles for TARGETPLATFORM using tonistiigi/xx: the builder stage
# always runs natively on BUILDPLATFORM (no QEMU emulation) and xx-cargo
# picks the right musl target triple, sysroot, and linker for whatever
# platform buildx asked for.
FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx
FROM --platform=$BUILDPLATFORM rust:1.88-alpine AS builder
COPY --from=xx / /
RUN apk add --no-cache clang lld file
ARG TARGETPLATFORM
RUN xx-apk add --no-cache musl-dev
WORKDIR /build
COPY Cargo.toml Cargo.lock ./
COPY crates ./crates
RUN xx-cargo build \
--release \
--locked \
-p irtt-rs \
--bin irtt-server \
--no-default-features \
--features server \
--target-dir /build/target \
&& xx-verify /build/target/$(xx-cargo --print-target-triple)/release/irtt-server \
&& cp /build/target/$(xx-cargo --print-target-triple)/release/irtt-server /irtt-server
FROM scratch
COPY --from=builder /irtt-server /irtt-server
ENTRYPOINT ["/irtt-server"]