Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions .github/workflows/publish-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ jobs:
- runner: ubuntu-latest
platform: linux/amd64
arch: amd64
- runner: ubuntu-latest
platform: linux/arm64
arch: arm64
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
Expand Down Expand Up @@ -170,11 +173,13 @@ jobs:
docker buildx imagetools create \
--tag "$tag" \
--annotation "index:org.opencontainers.image.description=${IMAGE_DESCRIPTION}" \
"${src_tag}-amd64"
"${src_tag}-amd64" \
"${src_tag}-arm64"
else
docker buildx imagetools create \
--tag "$tag" \
"${src_tag}-amd64"
"${src_tag}-amd64" \
"${src_tag}-arm64"
fi
done <<< "$tags"

Expand All @@ -192,5 +197,3 @@ jobs:
echo "Signing $tag"
cosign sign --yes "$tag"
done <<< "$tags"


26 changes: 26 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,32 @@ Key recurring tasks (via `config/recurring.yml`):
- Search records denormalized for performance
- Models in `app/models/search/`

## Docker Deployment

### Multi-Architecture Support

Fizzy supports both AMD64 and ARM64 architectures:
- Docker images are built for `linux/amd64` and `linux/arm64`
- Multi-arch manifests are created automatically via GitHub Actions
- Published to GitHub Container Registry (GHCR): `ghcr.io/basecamp/fizzy`

The `@.github/workflows/publish-image.yml` workflow builds both architectures on every push to `main` and on version tags.

### Testing ARM64 Locally

Use the provided test script:
```bash
./test-arm64-build.sh
```

Or manually:
```bash
docker buildx build --platform linux/arm64 --tag fizzy:arm64-test --load .
docker run --rm --platform linux/arm64 -e SECRET_KEY_BASE=test123 -p 80:80 fizzy:arm64-test
```

See `@TESTING_ARM64.md` for detailed testing instructions.

## Tools

### Chrome MCP (Local Dev)
Expand Down
170 changes: 170 additions & 0 deletions TESTING_ARM64.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# Testing ARM64 Docker Builds Locally

This guide shows how to test ARM64 Docker builds locally before pushing changes to GitHub.

## Prerequisites

1. Docker Desktop with Buildx enabled (should be enabled by default on macOS)
2. Verify buildx is available:
```bash
docker buildx version
```

## Step 1: Create a Buildx Builder (if needed)

Create a builder instance that supports multi-platform builds:

```bash
docker buildx create --name multiarch --use
docker buildx inspect --bootstrap
```

## Step 2: Build ARM64 Image Locally

Build the image specifically for ARM64 architecture:

```bash
docker buildx build \
--platform linux/arm64 \
--tag fizzy:arm64-local \
--load \
.
```

The `--load` flag loads the image into your local Docker daemon so you can run it.

**Note**: On Apple Silicon Macs, you can also just use regular `docker build` since you're already on ARM64, but using `buildx` with `--platform` ensures you're testing the exact same build process that GitHub Actions will use.

## Step 3: Verify the Image Architecture

Check that the image was built for ARM64:

```bash
docker inspect fizzy:arm64-local --format '{{.Architecture}}'
```

You should see `arm64`.

## Step 4: Test Running the Image

Test that the ARM64 image runs correctly:

```bash
docker run --rm \
--platform linux/arm64 \
-e SECRET_KEY_BASE=test123456789012345678901234567890123456789012345678901234567890 \
-e DISABLE_SSL=true \
-e BASE_URL=http://localhost \
-p 80:80 \
fizzy:arm64-local
```

If it starts without errors, the ARM64 build is working! Press Ctrl+C to stop it.

## Step 5: Test Multi-Arch Build (Optional)

To fully simulate what GitHub Actions will do, you can build for both architectures and create a manifest:

```bash
# Build and push both architectures to a local registry or just build them
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag fizzy:multiarch-test \
--output type=image,oci-mediatypes=true \
.
```

Or if you want to test the manifest creation process:

```bash
# Build and push AMD64 (requires a registry, or use local)
docker buildx build --platform linux/amd64 --tag localhost:5000/fizzy:amd64-test --push .

# Build and push ARM64
docker buildx build --platform linux/arm64 --tag localhost:5000/fizzy:arm64-test --push .

# Create multi-arch manifest
docker buildx imagetools create --tag localhost:5000/fizzy:multiarch-test \
localhost:5000/fizzy:amd64-test \
localhost:5000/fizzy:arm64-test
```

## Step 6: Verify Dockerfile Compatibility

The Dockerfile should work for both architectures. Key things to verify:

1. **Base image**: `ruby:3.4.7-slim` supports both architectures ✅
2. **Architecture detection**: Line 20 uses `$(uname -m)` which works for both ✅
3. **Package names**: All packages (`libjemalloc2`, `libvips`, etc.) are available for both architectures ✅

You can verify package availability by checking:
```bash
docker run --rm --platform linux/arm64 ruby:3.4.7-slim bash -c "apt-get update -qq && apt-cache search libjemalloc2"
```

## What You Can Verify Locally

✅ ARM64 image builds successfully
✅ ARM64 image runs without errors
✅ Dockerfile syntax is correct
✅ All dependencies are available for ARM64

## What Requires GitHub Actions

❌ Multi-arch manifest creation (requires both architectures built)
❌ Pushing to GHCR
❌ Final verification that `ghcr.io/basecamp/fizzy:main` works on ARM64

## Quick Test Script

Save this as `test-arm64-build.sh`:

```bash
#!/bin/bash
set -e

echo "Building ARM64 image..."
docker buildx build \
--platform linux/arm64 \
--tag fizzy:arm64-test \
--load \
.

echo "Verifying architecture..."
ARCH=$(docker inspect fizzy:arm64-test --format '{{.Architecture}}')
if [ "$ARCH" = "arm64" ]; then
echo "✅ Image is ARM64"
else
echo "❌ Image architecture is '$ARCH', expected 'arm64'"
exit 1
fi

echo "Testing image startup..."
docker run --rm -d \
--name fizzy-arm64-test \
--platform linux/arm64 \
-e SECRET_KEY_BASE=test123456789012345678901234567890123456789012345678901234567890 \
-e DISABLE_SSL=true \
-e BASE_URL=http://localhost \
-p 8080:80 \
fizzy:arm64-test

sleep 5

if docker ps | grep -q fizzy-arm64-test; then
echo "✅ Container started successfully"
docker stop fizzy-arm64-test > /dev/null
echo "✅ ARM64 build test passed!"
else
echo "❌ Container failed to start"
docker logs fizzy-arm64-test
docker rm -f fizzy-arm64-test > /dev/null 2>&1
exit 1
fi
```

Make it executable and run:
```bash
chmod +x test-arm64-build.sh
./test-arm64-build.sh
```
44 changes: 44 additions & 0 deletions test-arm64-build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/bash
set -e

echo "🔨 Building ARM64 image..."
docker buildx build \
--platform linux/arm64 \
--tag fizzy:arm64-test \
--load \
.

echo "🔍 Verifying architecture..."
ARCH=$(docker inspect fizzy:arm64-test 2>/dev/null --format '{{.Architecture}}')
if [ "$ARCH" = "arm64" ]; then
echo "✅ Image is ARM64"
else
echo "❌ Image architecture is '$ARCH', expected 'arm64'"
exit 1
fi

echo "🚀 Testing container startup..."
docker run --rm -d \
--name fizzy-arm64-test \
--platform linux/arm64 \
-e SECRET_KEY_BASE=test123456789012345678901234567890123456789012345678901234567890 \
-e DISABLE_SSL=true \
-e BASE_URL=http://localhost \
-p 8080:80 \
fizzy:arm64-test > /dev/null

sleep 5

if docker ps | grep -q fizzy-arm64-test; then
echo "✅ Container started successfully"
docker stop fizzy-arm64-test > /dev/null
echo ""
echo "✅ ARM64 build test passed! The Dockerfile works for ARM64."
echo " You can now confidently propose the workflow changes."
else
echo "❌ Container failed to start"
echo "📋 Container logs:"
docker logs fizzy-arm64-test
docker rm -f fizzy-arm64-test > /dev/null 2>&1
exit 1
fi