From 1cfeaf556e77e5e5ca25f68f5b03d9f7745149c7 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Sat, 26 Jul 2025 16:22:38 -0500 Subject: [PATCH] Simplify Dockerfile for much faster builds - Remove BuildKit advanced features that were slowing builds - Remove multi-platform builds (only build for amd64) - Remove security scanning stage - Remove complex caching mounts - Simplify to basic 2-stage build - Use registry cache instead of GitHub Actions cache This should reduce build time from 10+ minutes to 2-3 minutes. Co-Authored-By: Claude --- .github/workflows/deploy.yml | 13 +--- Dockerfile | 147 ++++++++--------------------------- 2 files changed, 33 insertions(+), 127 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c97e766..a276062 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -43,13 +43,6 @@ jobs: type=sha,prefix={{branch}}- type=raw,value=latest,enable={{is_default_branch}} - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - with: - driver-opts: | - network=host - image=moby/buildkit:latest - - name: Build and push Docker image uses: docker/build-push-action@v5 with: @@ -57,10 +50,8 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - platforms: linux/amd64,linux/arm64 - provenance: false + cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache + cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max deploy: needs: build-and-push diff --git a/Dockerfile b/Dockerfile index 01783af..37c4607 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,150 +1,65 @@ -# syntax=docker/dockerfile:1.4 - # Build arguments ARG ELIXIR_VERSION=1.18.4 ARG OTP_VERSION=27.2.4 ARG DEBIAN_VERSION=bullseye-20250520-slim -ARG APP_NAME=aprs ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}" ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}" -# Platform args for multi-platform builds -ARG TARGETPLATFORM -ARG BUILDPLATFORM - -# Stage 1: Dependencies only (cached layer) -FROM ${BUILDER_IMAGE} AS deps +# Build stage +FROM ${BUILDER_IMAGE} AS builder # Install build dependencies -ENV DEBIAN_FRONTEND=noninteractive -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt,sharing=locked \ - apt-get update -y && apt-get install -y --no-install-recommends \ - gcc \ - g++ \ - make \ - git +RUN apt-get update -y && \ + apt-get install -y --no-install-recommends gcc g++ make git && \ + apt-get clean && rm -rf /var/lib/apt/lists/* WORKDIR /app -# Install Hex and Rebar with cache mount -RUN --mount=type=cache,target=/root/.cache/rebar3,sharing=locked \ - --mount=type=cache,target=/root/.hex,sharing=locked \ - mix local.hex --force && \ +# Install hex + rebar +RUN mix local.hex --force && \ mix local.rebar --force && \ mix archive.install hex mix_gleam 0.6.2 --force ENV MIX_ENV=prod -# Copy only files needed for dependencies +# Install mix dependencies COPY mix.exs mix.lock ./ COPY vendor vendor +RUN mix deps.get --only $MIX_ENV && \ + mix deps.compile -# Get and compile dependencies with cache mount -RUN --mount=type=cache,target=/app/deps,sharing=locked \ - --mount=type=cache,target=/app/_build,sharing=locked \ - mix deps.get --only $MIX_ENV && \ - mix deps.compile && \ - cd vendor/aprs && \ - mix compile && \ - cd ../.. && \ - # Copy compiled deps to a location that persists - cp -r deps /app/deps_compiled && \ - cp -r _build /app/_build_compiled - -# Stage 2: Build application -FROM deps AS builder - -# Copy pre-compiled dependencies -RUN cp -r /app/deps_compiled deps && \ - cp -r /app/_build_compiled _build - -# Copy application code (ordered by change frequency) -COPY rel rel +# Copy and compile application COPY config config -COPY priv priv -COPY assets assets COPY lib lib +COPY assets assets +COPY priv priv +COPY rel rel -# Build everything in one RUN with proper error handling -RUN --mount=type=cache,target=/root/.cache,sharing=locked </dev/null)" ]; then - cp priv/gleam/*.beam _build/prod/lib/aprsme/ebin/ - fi - - # Compile and build release - mix compile - mix assets.deploy - mix release --path /app/release -EOF +# Build application +RUN cd vendor/aprs && mix compile && cd ../.. && \ + mkdir -p _build/prod/lib/aprs/ebin && \ + cp -r vendor/aprs/_build/prod/lib/aprs/ebin/* _build/prod/lib/aprs/ebin/ && \ + mix compile && \ + mix assets.deploy && \ + mix release -# Stage 3: Security scan (optional, can be commented out for faster builds) -FROM aquasec/trivy:latest AS security-scan -COPY --from=builder /app/release /scan -RUN trivy filesystem --exit-code 0 --no-progress --security-checks vuln /scan +# Runtime stage +FROM ${RUNNER_IMAGE} -# Stage 4: Create minimal runtime image -FROM ${RUNNER_IMAGE} AS runtime - -# Create user first to avoid running as root -RUN useradd -r -u 1001 -g root -s /bin/false elixir - -# Install only essential runtime dependencies in one layer -RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ - --mount=type=cache,target=/var/lib/apt,sharing=locked < /app/deployed_at.txt -# Use exec form to ensure proper signal handling -ENTRYPOINT ["/app/bin/server"] - -# Add metadata labels -LABEL maintainer="aprs.me" \ - security.scan="true" \ - security.user="non-root" \ - org.opencontainers.image.title="APRS.me" \ - org.opencontainers.image.description="Real-time APRS packet tracker" \ - org.opencontainers.image.vendor="aprs.me" \ - org.opencontainers.image.source="https://github.com/aprsme/aprs.me" \ No newline at end of file +CMD ["/app/bin/server"] \ No newline at end of file