feat(docker): Refactored the Docker build and release process and added support for image signing.

This commit is contained in:
Gouryella
2025-12-07 11:21:21 +08:00
parent 0fee9569d2
commit faa53400f5
2 changed files with 70 additions and 165 deletions

View File

@@ -1,176 +1,66 @@
name: Docker
on:
# Trigger when a release is published (after assets are uploaded)
release:
types: [published]
# Optional manual trigger
workflow_dispatch:
inputs:
version:
description: 'Release tag to use (e.g., v1.0.0 or latest)'
required: false
default: 'latest'
push:
tags: [ "v*.*.*" ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
permissions:
contents: read
packages: write
VERSION: ${{ github.ref_name }}
jobs:
build-and-push:
name: Build and Push Docker Image
build:
runs-on: ubuntu-latest
# For release event, only build for tags like v1.2.3
if: |
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'release' && startsWith(github.event.release.tag_name, 'v'))
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Install cosign
if: github.event_name != 'pull_request'
uses: sigstore/cosign-installer@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
- name: Log into registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Resolve VERSION:
# - release event: use release tag_name (e.g., v0.3.0)
# - workflow_dispatch: use input version (default: latest)
- name: Get version
id: version
run: |
if [ "${{ github.event_name }}" = "release" ]; then
v="${{ github.event.release.tag_name }}"
else
v="${{ github.event.inputs.version }}"
if [ -z "$v" ]; then
v="latest"
fi
fi
echo "VERSION=$v" >> "$GITHUB_OUTPUT"
echo "Resolved VERSION=$v"
# Ensure release assets exist before building
- name: Check release assets
id: check_assets
run: |
VERSION="${{ steps.version.outputs.VERSION }}"
REPO="${{ github.repository }}"
echo "Checking assets for $REPO, VERSION=$VERSION"
# For 'latest', we can only reliably ask the latest release API,
# the asset names are still versioned (drip-vX.Y.Z-linux-arch).
if [ "$VERSION" = "latest" ]; then
API_URL="https://api.github.com/repos/${REPO}/releases/latest"
echo "Using latest release API: $API_URL"
json=$(curl -fsSL "$API_URL")
# Check that assets for both amd64 and arm64 exist
echo "$json" | grep -q 'drip-.*linux-amd64' || missing_amd64=1
echo "$json" | grep -q 'drip-.*linux-arm64' || missing_arm64=1
if [ "${missing_amd64:-0}" -eq 0 ] && [ "${missing_arm64:-0}" -eq 0 ]; then
echo "assets_ready=true" >> "$GITHUB_OUTPUT"
echo "Assets found for both linux-amd64 and linux-arm64 (latest)."
else
echo "assets_ready=false" >> "$GITHUB_OUTPUT"
echo "Required assets for latest release are missing; build will be skipped."
fi
exit 0
fi
# For a specific version tag (e.g., v0.3.0) check direct download URLs
archs="amd64 arm64"
missing=0
for arch in $archs; do
url="https://github.com/${REPO}/releases/download/${VERSION}/drip-${VERSION}-linux-${arch}"
status=$(curl -o /dev/null -w "%{http_code}" -sL "$url")
echo "[$arch] HTTP $status -> $url"
if [ "$status" != "200" ]; then
missing=1
fi
done
if [ "$missing" -eq 0 ]; then
echo "assets_ready=true" >> "$GITHUB_OUTPUT"
echo "All required assets exist. Proceeding with build."
else
echo "assets_ready=false" >> "$GITHUB_OUTPUT"
echo "Required assets are missing; build will be skipped."
fi
- name: Skip build (assets not ready)
if: steps.check_assets.outputs.assets_ready != 'true'
run: |
echo "Release assets are not ready. Docker image build is skipped."
echo "You must upload all required release files (drip-<version>-linux-amd64/arm64) first."
- name: Extract metadata (tags & labels)
- name: Extract Docker metadata
id: meta
if: steps.check_assets.outputs.assets_ready == 'true'
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
# Main tag, e.g. v0.3.0 or latest
type=raw,value=${{ steps.version.outputs.VERSION }}
# Also tag 'latest' for convenience when using a specific version
type=raw,value=latest,enable=${{ steps.version.outputs.VERSION != 'latest' }}
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push
if: steps.check_assets.outputs.assets_ready == 'true'
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v5
with:
context: .
file: deployments/Dockerfile.release
platforms: linux/amd64,linux/arm64
push: true
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VERSION=${{ steps.version.outputs.VERSION }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64
build-args: |
VERSION=${{ env.VERSION }}
provenance: false
- name: Generate deployment summary
if: steps.check_assets.outputs.assets_ready == 'true'
run: |
echo "## 🐳 Docker Image Published" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "**Version (GitHub Release tag or 'latest'):** \`${{ steps.version.outputs.VERSION }}\`" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "### Pull from GHCR" >> "$GITHUB_STEP_SUMMARY"
echo "\`\`\`bash" >> "$GITHUB_STEP_SUMMARY"
echo "docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}" >> "$GITHUB_STEP_SUMMARY"
echo "\`\`\`" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "### Quick start" >> "$GITHUB_STEP_SUMMARY"
echo "\`\`\`bash" >> "$GITHUB_STEP_SUMMARY"
echo "docker run -d \\\\" >> "$GITHUB_STEP_SUMMARY"
echo " --name drip-server \\\\" >> "$GITHUB_STEP_SUMMARY"
echo " -p 443:443 \\\\" >> "$GITHUB_STEP_SUMMARY"
echo " -v /path/to/certs:/app/data/certs:ro \\\\" >> "$GITHUB_STEP_SUMMARY"
echo " ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} \\\\" >> "$GITHUB_STEP_SUMMARY"
echo " server --domain your.domain.com --port 443 \\\\" >> "$GITHUB_STEP_SUMMARY"
echo " --tls-cert /app/data/certs/fullchain.pem \\\\" >> "$GITHUB_STEP_SUMMARY"
echo " --tls-key /app/data/certs/privkey.pem" >> "$GITHUB_STEP_SUMMARY"
echo "\`\`\`" >> "$GITHUB_STEP_SUMMARY"
- name: Sign the published Docker image
if: github.event_name != 'pull_request'
env:
TAGS: ${{ steps.meta.outputs.tags }}
DIGEST: ${{ steps.build-and-push.outputs.digest }}
run: echo "${TAGS}" | tr ',' '\n' | xargs -I {} cosign sign --yes {}@${DIGEST}

View File

@@ -1,37 +1,52 @@
# Dockerfile for deploying drip-server from GitHub Release
# Usage:
# docker build -f deployments/Dockerfile.release -t drip-server .
# docker build -f deployments/Dockerfile.release --build-arg VERSION=v1.0.0 -t drip-server:v1.0.0 .
# =========================
# Builder stage (Alpine)
# =========================
FROM golang:1.25-alpine AS builder
FROM alpine:latest
RUN apk add --no-cache ca-certificates tzdata
# VERSION is passed from GitHub Actions (release tag or "latest")
ARG VERSION=latest
# TARGETARCH is automatically set by Docker Buildx (amd64, arm64, etc.)
ARG TARGETARCH=amd64
# All project files under /app
WORKDIR /app
ADD . .
RUN apk add --no-cache ca-certificates tzdata curl && update-ca-certificates
# Git tag/version passed from build args, e.g. v1.0.0
ARG VERSION=dev
RUN addgroup -S drip && adduser -S -G drip drip
# Buildx injects these automatically for multi-arch builds
ARG TARGETOS
ARG TARGETARCH
# Adjust this to your real main package directory
# e.g. /app/cmd/drip-server if different
WORKDIR /app/cmd/drip
# main.version should match the version variable in your Go code
RUN env CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH:-amd64} \
go build -v -trimpath \
-ldflags "-s -w -X main.version=${VERSION}" \
-o /app/bin/drip
# =========================
# Runtime stage (Alpine)
# =========================
FROM alpine:3.22
RUN apk add --no-cache ca-certificates tzdata curl && \
update-ca-certificates
# Everything lives under /app in runtime image
WORKDIR /app
# Download binary from GitHub Releases
RUN set -ex; \
# Resolve "latest" to an actual tag
if [ "$VERSION" = "latest" ]; then \
VERSION=$(curl -sL https://api.github.com/repos/Gouryella/drip/releases/latest \
| grep '"tag_name"' | cut -d'"' -f4); \
fi; \
echo "Resolved VERSION=${VERSION}"; \
echo "Downloading drip ${VERSION} for linux-${TARGETARCH}"; \
curl -fsSL "https://github.com/Gouryella/drip/releases/download/${VERSION}/drip-${VERSION}-linux-${TARGETARCH}" -o /app/drip; \
chmod +x /app/drip; \
/app/drip version --short
# Optional but nice to have: certs + timezone data
COPY --from=builder /etc/ssl/certs /etc/ssl/certs
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
RUN mkdir -p /app/data/certs && \
# Copy the built binary into /app
COPY --from=builder /app/bin/drip /app/drip
# Non-root user
RUN addgroup -S drip && adduser -S -G drip drip && \
chown -R drip:drip /app
USER drip
EXPOSE 80 443 8080 20000-20100