blumeops/.forgejo/actions/build-push-image/action.yaml
Erich Blume ed8fbdc7ea
Some checks failed
Build Container / build (push) Failing after 12s
Force HTTPS by specifying port 443 in skopeo destination URL
2026-01-24 20:12:54 -08:00

164 lines
5.7 KiB
YAML

name: 'Build and Push Image'
description: 'Build a container image with Docker and push to zot registry via Tailscale sidecar'
# Uses a Tailscale sidecar container to push images to the registry.
# This works around Docker Desktop's VM not having access to the tailnet.
#
# Flow:
# 1. Start Tailscale sidecar container (joins tailnet)
# 2. Build image with docker build
# 3. Save image to OCI tarball
# 4. Push tarball to registry using skopeo (via Tailscale network)
# 5. Cleanup sidecar
inputs:
context:
description: 'Build context path'
required: true
dockerfile:
description: 'Dockerfile path (relative to context)'
required: false
default: 'Dockerfile'
image_name:
description: 'Image name (without registry, e.g. blumeops/devpi)'
required: true
version:
description: 'Version tag (e.g. v1.0.0)'
required: true
registry:
description: 'Registry URL'
required: false
default: 'registry.tail8d86e.ts.net'
tailscale_authkey:
description: 'Tailscale OAuth client secret for ci-gateway'
required: true
runs:
using: 'composite'
steps:
- name: Start Tailscale sidecar
shell: bash
run: |
echo "Starting Tailscale sidecar..."
# Clean up any existing sidecar
docker rm -f ts-ci-gateway 2>/dev/null || true
# Start Tailscale container
docker run -d \
--name ts-ci-gateway \
--hostname ci-gateway \
-e TS_AUTHKEY="${{ inputs.tailscale_authkey }}" \
-e TS_EXTRA_ARGS="--advertise-tags=tag:ci-gateway" \
-e TS_ACCEPT_DNS=true \
-e TS_USERSPACE=true \
tailscale/tailscale:latest
# Wait for Tailscale to connect
echo "Waiting for Tailscale to connect..."
for i in {1..30}; do
# Check if container is still running
if ! docker ps -q -f name=ts-ci-gateway | grep -q .; then
echo "ERROR: Tailscale container exited unexpectedly!"
echo "Container logs:"
docker logs ts-ci-gateway 2>&1 || true
exit 1
fi
if docker exec ts-ci-gateway tailscale status >/dev/null 2>&1; then
echo "Tailscale connected!"
docker exec ts-ci-gateway tailscale status
break
fi
echo " Attempt $i/30..."
sleep 2
done
# Verify DNS resolution
echo "Testing DNS resolution..."
docker exec ts-ci-gateway nslookup ${{ inputs.registry }} || echo "DNS test failed, continuing anyway..."
- name: Build image with Docker
shell: bash
run: |
echo "Building ${{ inputs.image_name }}:${{ inputs.version }}"
docker build \
--tag ${{ inputs.image_name }}:${{ inputs.version }} \
--tag ${{ inputs.image_name }}:${{ github.sha }} \
--file ${{ inputs.context }}/${{ inputs.dockerfile }} \
${{ inputs.context }}
- name: Save image to tarball
shell: bash
run: |
echo "Saving image to tarball..."
mkdir -p /tmp/ci-images
docker save ${{ inputs.image_name }}:${{ inputs.version }} -o /tmp/ci-images/image.tar
ls -lh /tmp/ci-images/image.tar
- name: Push to registry via Tailscale
shell: bash
run: |
echo "Pushing ${{ inputs.image_name }}:${{ inputs.version }} via Tailscale sidecar..."
# Copy tarball into the Tailscale container
docker cp /tmp/ci-images/image.tar ts-ci-gateway:/tmp/image.tar
# Get indri's Tailscale IP from tailscale status (registry runs on indri)
echo "Getting indri's Tailscale IP..."
echo "Tailscale status:"
docker exec ts-ci-gateway tailscale status || true
INDRI_IP=$(docker exec ts-ci-gateway tailscale status 2>/dev/null | grep -E '\bindri\b' | awk '{print $1}')
if [ -z "$INDRI_IP" ]; then
echo "ERROR: Could not get indri's Tailscale IP from tailscale status"
exit 1
fi
echo "Indri Tailscale IP: $INDRI_IP"
# Install skopeo and push
docker exec ts-ci-gateway sh -c "
apk add --no-cache skopeo >/dev/null 2>&1
# Add registry hostname pointing to indri's Tailscale IP
echo '$INDRI_IP ${{ inputs.registry }}' >> /etc/hosts
echo 'Added /etc/hosts entry: $INDRI_IP ${{ inputs.registry }}'
# Configure skopeo to use HTTPS for our registry (skip cert verification)
mkdir -p /etc/containers
echo '[[registry]]' > /etc/containers/registries.conf
echo 'location = \"${{ inputs.registry }}\"' >> /etc/containers/registries.conf
echo 'insecure = true' >> /etc/containers/registries.conf
cat /etc/containers/registries.conf
echo 'Pushing version tag...'
skopeo copy \
--dest-tls-verify=false \
docker-archive:/tmp/image.tar \
docker://${{ inputs.registry }}:443/${{ inputs.image_name }}:${{ inputs.version }}
echo 'Pushing SHA tag...'
skopeo copy \
--dest-tls-verify=false \
docker-archive:/tmp/image.tar \
docker://${{ inputs.registry }}:443/${{ inputs.image_name }}:${{ github.sha }}
"
- name: Cleanup
shell: bash
if: always()
run: |
echo "Cleaning up..."
docker rm -f ts-ci-gateway 2>/dev/null || true
rm -rf /tmp/ci-images
- name: Summary
shell: bash
run: |
echo "Built and pushed:"
echo " ${{ inputs.registry }}/${{ inputs.image_name }}:${{ inputs.version }}"
echo " ${{ inputs.registry }}/${{ inputs.image_name }}:${{ github.sha }}"
echo ""
echo "Registry tags:"
curl -sf "https://${{ inputs.registry }}/v2/${{ inputs.image_name }}/tags/list" | jq -r '.tags[]' | sort -V | tail -10 || true