2026-01-24 13:30:26 -08:00
|
|
|
name: 'Build and Push Image'
|
2026-01-24 19:29:01 -08:00
|
|
|
description: 'Build a container image with Docker and push to zot registry via Tailscale sidecar'
|
2026-01-24 13:30:26 -08:00
|
|
|
|
2026-01-24 19:29:01 -08:00
|
|
|
# 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
|
2026-01-24 13:30:26 -08:00
|
|
|
|
|
|
|
|
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'
|
2026-01-24 19:29:01 -08:00
|
|
|
tailscale_authkey:
|
|
|
|
|
description: 'Tailscale OAuth client secret for ci-gateway'
|
|
|
|
|
required: true
|
2026-01-24 13:30:26 -08:00
|
|
|
|
|
|
|
|
runs:
|
|
|
|
|
using: 'composite'
|
|
|
|
|
steps:
|
2026-01-24 19:29:01 -08:00
|
|
|
- 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
|
|
|
|
|
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..."
|
|
|
|
|
|
2026-01-24 13:30:26 -08:00
|
|
|
- name: Build image with Docker
|
|
|
|
|
shell: bash
|
|
|
|
|
run: |
|
|
|
|
|
echo "Building ${{ inputs.image_name }}:${{ inputs.version }}"
|
|
|
|
|
docker build \
|
2026-01-24 19:29:01 -08:00
|
|
|
--tag ${{ inputs.image_name }}:${{ inputs.version }} \
|
|
|
|
|
--tag ${{ inputs.image_name }}:${{ github.sha }} \
|
2026-01-24 13:30:26 -08:00
|
|
|
--file ${{ inputs.context }}/${{ inputs.dockerfile }} \
|
|
|
|
|
${{ inputs.context }}
|
|
|
|
|
|
2026-01-24 19:29:01 -08:00
|
|
|
- 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
|
|
|
|
|
|
|
|
|
|
# Install skopeo in the Tailscale container and push
|
|
|
|
|
docker exec ts-ci-gateway sh -c '
|
|
|
|
|
apk add --no-cache skopeo >/dev/null 2>&1
|
|
|
|
|
|
|
|
|
|
echo "Pushing version tag..."
|
|
|
|
|
skopeo copy \
|
|
|
|
|
--dest-tls-verify=false \
|
|
|
|
|
docker-archive:/tmp/image.tar \
|
|
|
|
|
docker://${{ inputs.registry }}/${{ inputs.image_name }}:${{ inputs.version }}
|
|
|
|
|
|
|
|
|
|
echo "Pushing SHA tag..."
|
|
|
|
|
skopeo copy \
|
|
|
|
|
--dest-tls-verify=false \
|
|
|
|
|
docker-archive:/tmp/image.tar \
|
|
|
|
|
docker://${{ inputs.registry }}/${{ inputs.image_name }}:${{ github.sha }}
|
|
|
|
|
'
|
|
|
|
|
|
|
|
|
|
- name: Cleanup
|
2026-01-24 13:30:26 -08:00
|
|
|
shell: bash
|
2026-01-24 19:29:01 -08:00
|
|
|
if: always()
|
2026-01-24 13:30:26 -08:00
|
|
|
run: |
|
2026-01-24 19:29:01 -08:00
|
|
|
echo "Cleaning up..."
|
|
|
|
|
docker rm -f ts-ci-gateway 2>/dev/null || true
|
|
|
|
|
rm -rf /tmp/ci-images
|
2026-01-24 13:30:26 -08:00
|
|
|
|
|
|
|
|
- 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
|