Skip to content

Commit 7aa6ccc

Browse files
phrontizoclaude
andcommitted
Add CI/CD workflow and optimize Docker multi-arch build
Docker: - Replace QEMU emulation with xx cross-compilation for multi-arch builds - Builder runs natively on host arch, cross-compiles via clang+lld - Uses tonistiigi/xx for automatic target sysroot and linker setup - xx-verify validates binary targets correct platform before copy - ~10x faster arm64 builds on amd64 hosts (no QEMU Rust compilation) GitHub Actions (.github/workflows/docker.yml): - Push to master builds and pushes :latest tag to GHCR - Push version tag (v1.2.3) creates :v1.2.3, :v1.2, :v1 tags - Builds linux/amd64 + linux/arm64 in parallel - GitHub Actions cache for Docker layers across builds - Uses built-in GITHUB_TOKEN for GHCR auth (no secrets needed) Cargo.toml: - Add license, description, repository fields for publication Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c052e4d commit 7aa6ccc

3 files changed

Lines changed: 91 additions & 20 deletions

File tree

.github/workflows/docker.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Build and Push Docker Image
2+
3+
on:
4+
push:
5+
branches: [master]
6+
tags: ["v*"]
7+
8+
env:
9+
REGISTRY: ghcr.io
10+
IMAGE_NAME: ${{ github.repository }}
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
packages: write
18+
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- name: Set up QEMU
23+
uses: docker/setup-qemu-action@v3
24+
25+
- name: Set up Docker Buildx
26+
uses: docker/setup-buildx-action@v3
27+
28+
- name: Log in to GitHub Container Registry
29+
uses: docker/login-action@v3
30+
with:
31+
registry: ${{ env.REGISTRY }}
32+
username: ${{ github.actor }}
33+
password: ${{ secrets.GITHUB_TOKEN }}
34+
35+
- name: Extract metadata (tags, labels)
36+
id: meta
37+
uses: docker/metadata-action@v5
38+
with:
39+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
40+
tags: |
41+
# Push to master -> :latest
42+
type=raw,value=latest,enable={{is_default_branch}}
43+
# Tag v1.2.3 -> :v1.2.3, :v1.2, :v1
44+
type=semver,pattern=v{{version}}
45+
type=semver,pattern=v{{major}}.{{minor}}
46+
type=semver,pattern=v{{major}}
47+
48+
- name: Build and push
49+
uses: docker/build-push-action@v6
50+
with:
51+
context: .
52+
platforms: linux/amd64,linux/arm64
53+
push: true
54+
tags: ${{ steps.meta.outputs.tags }}
55+
labels: ${{ steps.meta.outputs.labels }}
56+
cache-from: type=gha
57+
cache-to: type=gha,mode=max

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
name = "squiddish"
33
version = "0.1.0"
44
edition = "2021"
5+
license = "MIT"
6+
description = "High-performance HTTP caching proxy optimized for APT package managers"
7+
repository = "https://github.com/phrontizo/squiddish"
58

69
[dependencies]
710
tokio = { version = "1.42", features = ["full"] }

Dockerfile

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,41 @@
11
# Multi-stage build for Squiddish caching proxy
2-
# Uses musl for static linking to create a minimal scratch-based image
3-
# Supports multi-arch: linux/amd64, linux/arm64
4-
# Uses native compilation on each platform (no cross-compilation)
2+
# Uses cross-compilation via xx (no QEMU emulation) for fast multi-arch builds
3+
# Supports: linux/amd64, linux/arm64
4+
#
5+
# Build: docker buildx build --platform linux/amd64,linux/arm64 -t squiddish .
56

6-
FROM rust:1.85-alpine AS builder
7+
# xx provides cross-compilation helpers (maintained by Docker Inc)
8+
FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.6.1 AS xx
9+
10+
FROM --platform=$BUILDPLATFORM rust:1.85-alpine AS builder
11+
COPY --from=xx / /
712

813
ARG TARGETPLATFORM
914

1015
WORKDIR /build
1116

12-
# Install musl build tools for static linking
13-
RUN apk add --no-cache musl-dev
14-
15-
# Determine the Rust target based on current architecture (not TARGETPLATFORM)
16-
# This works because buildx runs native builds on each platform
17-
RUN case "$(uname -m)" in \
18-
"x86_64") echo "x86_64-unknown-linux-musl" > /tmp/rust-target ;; \
19-
"aarch64") echo "aarch64-unknown-linux-musl" > /tmp/rust-target ;; \
20-
*) echo "Unsupported architecture: $(uname -m)" && exit 1 ;; \
21-
esac && \
22-
export RUST_TARGET=$(cat /tmp/rust-target) && \
23-
rustup target add $RUST_TARGET
24-
25-
# Copy manifests and lock file for reproducible builds
17+
# Install cross-compilation toolchain:
18+
# - clang/lld: natively cross-compile (no QEMU needed)
19+
# - musl-dev: native headers for build scripts
20+
# - xx-apk: installs target-arch musl headers into the correct sysroot
21+
RUN apk add --no-cache clang lld musl-dev && \
22+
xx-apk add --no-cache musl-dev
23+
24+
# Determine Rust target triple and add it
25+
RUN RUST_TARGET="$(xx-info march)-unknown-linux-musl" && \
26+
echo "$RUST_TARGET" > /tmp/rust-target && \
27+
rustup target add "$RUST_TARGET"
28+
29+
# Configure cargo to use xx-clang as the C compiler and linker for both targets.
30+
# Only the matching target's settings are used; the other is ignored.
31+
ENV CC=xx-clang \
32+
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=xx-clang \
33+
CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=xx-clang
34+
35+
# Copy manifests and lock file for reproducible, cacheable dependency builds
2636
COPY Cargo.toml Cargo.lock ./
2737

28-
# Create dummy src files to build dependencies (both lib.rs and main.rs needed)
38+
# Build dependencies only (Docker layer cache — rebuilds only when Cargo.toml/lock change)
2939
RUN export RUST_TARGET=$(cat /tmp/rust-target) && \
3040
mkdir src && \
3141
echo "fn main() {}" > src/main.rs && \
@@ -37,10 +47,11 @@ RUN export RUST_TARGET=$(cat /tmp/rust-target) && \
3747
COPY src ./src
3848
COPY tests ./tests
3949

40-
# Build the actual binary with static linking
50+
# Build the actual binary and verify it targets the correct platform
4151
RUN export RUST_TARGET=$(cat /tmp/rust-target) && \
4252
touch src/main.rs src/lib.rs && \
4353
cargo build --release --target $RUST_TARGET && \
54+
xx-verify target/$RUST_TARGET/release/squiddish && \
4455
cp target/$RUST_TARGET/release/squiddish /build/squiddish
4556

4657
# Runtime stage - from scratch for minimal image

0 commit comments

Comments
 (0)