diff --git a/.github/workflows/docker-publish-arm.yaml b/.github/workflows/docker-publish-arm.yaml deleted file mode 100644 index 0147fa1c..00000000 --- a/.github/workflows/docker-publish-arm.yaml +++ /dev/null @@ -1,105 +0,0 @@ -name: Docker publish ARM - -on: - schedule: - - cron: '00 0 * * *' - push: - branches: [ "main" ] - paths: - - 'backend/**' - - 'frontend/**' - - 'Dockerfile' - - 'Dockerfile.rootless' - - '.dockerignore' - - '.github/workflows' - # Publish semver tags as releases. - tags: [ 'v*.*.*' ] - pull_request: - branches: [ "main" ] - paths: - - 'backend/**' - - 'frontend/**' - - 'Dockerfile' - - 'Dockerfile.rootless' - - '.dockerignore' - - '.github/workflows' - -env: - # Use docker.io for Docker Hub if empty - REGISTRY: ghcr.io - # github.repository as / - IMAGE_NAME: ${{ github.repository }} - -jobs: - build: - - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - attestations: write - id-token: write - - steps: - # Step 1: Checkout repository - - name: Checkout repository - uses: actions/checkout@v4 - - # Step 2: Set up Buildx without specifying driver - # Let it use default settings to avoid the 'no remote endpoint' issue - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.0.0 - with: - install: true # Ensure Buildx is installed and set up properly - use: true # Use Buildx instance directly for this job - - # Step 3: Login against Docker registry except on PR - - name: Log into registry ${{ env.REGISTRY }} - if: github.event_name != 'pull_request' - uses: docker/login-action@v3.0.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - # Step 4: Extract metadata for Docker images - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@v5.0.0 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - type=schedule,pattern=nightly - flavor: | - suffix=-arm,onlatest=true - - # Step 5: Build and push the Docker image - - name: Build and push Docker image - id: build-and-push - uses: docker/build-push-action@v5.0.0 - with: - context: . - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - platforms: linux/arm64,linux/arm/v7 - cache-from: type=gha - cache-to: type=gha,mode=max - build-args: | - VERSION=${{ github.ref_name }} - COMMIT=${{ github.sha }} - - # Step 6: Attest built image to prove build provenance - - name: Attest - uses: actions/attest-build-provenance@v1 - id: attest - if: ${{ github.event_name != 'pull_request' }} - with: - subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - subject-digest: ${{ steps.build-and-push.outputs.digest }} - push-to-registry: true diff --git a/.github/workflows/docker-publish-rootless-arm.yaml b/.github/workflows/docker-publish-rootless-arm.yaml deleted file mode 100644 index c40cd55b..00000000 --- a/.github/workflows/docker-publish-rootless-arm.yaml +++ /dev/null @@ -1,104 +0,0 @@ -name: Docker publish rootless ARM - -on: - schedule: - - cron: '00 0 * * *' - push: - branches: [ "main" ] - paths: - - 'backend/**' - - 'frontend/**' - - 'Dockerfile' - - 'Dockerfile.rootless' - - '.dockerignore' - - '.github/workflows' - # Publish semver tags as releases. - tags: [ 'v*.*.*' ] - pull_request: - branches: [ "main" ] - paths: - - 'backend/**' - - 'frontend/**' - - 'Dockerfile' - - 'Dockerfile.rootless' - - '.dockerignore' - - '.github/workflows' - -env: - # Use docker.io for Docker Hub if empty - REGISTRY: ghcr.io - # github.repository as / - IMAGE_NAME: ${{ github.repository }} - -jobs: - build-rootless: - - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - attestations: write - id-token: write - - steps: - # Step 1: Checkout repository - - name: Checkout repository - uses: actions/checkout@v4 - - # Step 2: Set up Buildx without specifying driver - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.0.0 - with: - install: true # Ensure Buildx is installed and set up properly - use: true # Use Buildx instance directly for this job - - # Step 3: Login to Docker registry except on PR - - name: Log into registry ${{ env.REGISTRY }} - if: github.event_name != 'pull_request' - uses: docker/login-action@v3.0.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - # Step 4: Extract metadata for Docker images - - name: Extract Docker metadata - id: metadata - uses: docker/metadata-action@v5.0.0 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - type=schedule,pattern=nightly - flavor: | - suffix=-rootless-arm,onlatest=true - - # Step 5: Build and push the Docker image - - name: Build and push Docker image - id: build-and-push - uses: docker/build-push-action@v5.0.0 - with: - context: . - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.metadata.outputs.tags }} - labels: ${{ steps.metadata.outputs.labels }} - platforms: linux/arm64,linux/arm/v7 - cache-from: type=gha - cache-to: type=gha,mode=max - build-args: | - VERSION=${{ github.ref_name }} - COMMIT=${{ github.sha }} - - # Step 6: Attest built image to prove build provenance - - name: Attest - uses: actions/attest-build-provenance@v1 - id: attest - if: ${{ github.event_name != 'pull_request' }} - with: - subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - subject-digest: ${{ steps.build-and-push.outputs.digest }} - push-to-registry: true diff --git a/.github/workflows/docker-publish-rootless.yaml b/.github/workflows/docker-publish-rootless.yaml index f5d022c6..e06ae05e 100644 --- a/.github/workflows/docker-publish-rootless.yaml +++ b/.github/workflows/docker-publish-rootless.yaml @@ -11,8 +11,7 @@ on: - 'Dockerfile' - 'Dockerfile.rootless' - '.dockerignore' - - '.github/workflows' - # Publish semver tags as releases. + - '.github/workflows/**' tags: [ 'v*.*.*' ] pull_request: branches: [ "main" ] @@ -22,55 +21,141 @@ on: - 'Dockerfile' - 'Dockerfile.rootless' - '.dockerignore' - - '.github/workflows' - + - '.github/workflows/**' env: - # Use docker.io for Docker Hub if empty - REGISTRY: ghcr.io - # github.repository as / - IMAGE_NAME: ${{ github.repository }} - + DOCKERHUB_REPO: sysadminsmedia/homebox + GHCR_REPO: ghcr.io/sysadminsmedia/homebox jobs: - build-rootless: - + build: runs-on: ubuntu-latest permissions: - contents: read - packages: write - # This is used to complete the identity challenge - # with sigstore/fulcio when running outside of PRs. - attestations: write - id-token: write + contents: read # Allows access to repository contents (read-only) + packages: write # Allows pushing to GHCR + id-token: write # Allows identity token write access for authentication + attestations: write # Needed for signing and attestation (if required) + + strategy: + fail-fast: false + matrix: + platform: + - linux/amd64 + - linux/arm64 + - linux/arm/v7 steps: - name: Checkout repository uses: actions/checkout@v4 - # Set up BuildKit Docker container builder to be able to build - # multi-platform images and export cache - # https://github.com/docker/setup-buildx-action + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + branch=${{ github.event.pull_request.number || github.ref_name }} + echo "BRANCH=${branch//\//-}" >> $GITHUB_ENV + + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.DOCKERHUB_REPO }} + ${{ env.GHCR_REPO }} + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} # The GitHub token with the necessary permissions + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + image: ghcr.io/amitie10g/binfmt:latest + - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.0.0 # v3.0.0 + uses: docker/setup-buildx-action@v3 + with: + driver-opts: | + image=ghcr.io/amitie10g/buildkit:master + + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6 + with: + platforms: ${{ matrix.platform }} + labels: ${{ steps.meta.outputs.labels }} + outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true + cache-from: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR }}-${{ env.BRANCH }}-rootless + cache-to: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR}}-${{ env.BRANCH }}-rootless,mode=max + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" - # Login against a Docker registry except on PR - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} - if: github.event_name != 'pull_request' - uses: docker/login-action@v3.0.0 # v3.0.0 + - name: Upload digest + uses: actions/upload-artifact@v4 with: - registry: ${{ env.REGISTRY }} + name: digests-${{ env.PLATFORM_PAIR }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + permissions: + contents: read # Allows access to repository contents (read-only) + packages: write # Allows pushing to GHCR! + id-token: write # Allows identity token write access for authentication + attestations: write # Needed for signing and attestation (if required) + needs: + - build + + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - # Extract metadata (tags, labels) for Docker - # https://github.com/docker/metadata-action - - name: Extract Docker metadata - id: metadata - uses: docker/metadata-action@v5.0.0 # v5.0.0 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + driver-opts: | + image=ghcr.io/amitie10g/buildkit:master + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + images: | + ${{ env.DOCKERHUB_REPO }} + ${{ env.GHCR_REPO }} tags: | type=ref,event=branch type=ref,event=pr @@ -80,29 +165,16 @@ jobs: type=schedule,pattern=nightly flavor: | suffix=-rootless,onlatest=true - - # Build and push Docker image with Buildx (don't push on PR) - # https://github.com/docker/build-push-action - - name: Build and push Docker image - id: build-and-push - uses: docker/build-push-action@v5.0.0 # v5.0.0 - with: - context: . - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.metadata.outputs.tags }} - labels: ${{ steps.metadata.outputs.labels }} - platforms: linux/amd64 - cache-from: type=gha - cache-to: type=gha,mode=max - build-args: | - VERSION=${{ github.ref_name }} - COMMIT=${{ github.sha }} - - - name: Attest - uses: actions/attest-build-provenance@v1 - id: attest - if: ${{ github.event_name != 'pull_request' }} - with: - subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - subject-digest: ${{ steps.build-and-push.outputs.digest }} - push-to-registry: true + + - name: Create manifest list and push + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *) + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.GHCR_REPO }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ env.DOCKERHUB_REPO }}:${{ steps.meta.outputs.version }} + docker buildx imagetools inspect ${{ env.GHCR_REPO }}:${{ steps.meta.outputs.version }} diff --git a/.github/workflows/docker-publish.yaml b/.github/workflows/docker-publish.yaml index ab226bdb..5c4afac5 100644 --- a/.github/workflows/docker-publish.yaml +++ b/.github/workflows/docker-publish.yaml @@ -9,10 +9,8 @@ on: - 'backend/**' - 'frontend/**' - 'Dockerfile' - - 'Dockerfile.rootless' - '.dockerignore' - - '.github/workflows' - # Publish semver tags as releases. + - '.github/workflows/**' tags: [ 'v*.*.*' ] pull_request: branches: [ "main" ] @@ -20,56 +18,141 @@ on: - 'backend/**' - 'frontend/**' - 'Dockerfile' - - 'Dockerfile.rootless' - '.dockerignore' - - '.github/workflows' + - '.github/workflows/**' env: - # Use docker.io for Docker Hub if empty - REGISTRY: ghcr.io - # github.repository as / - IMAGE_NAME: ${{ github.repository }} - + DOCKERHUB_REPO: sysadminsmedia/homebox + GHCR_REPO: ghcr.io/sysadminsmedia/homebox jobs: build: - runs-on: ubuntu-latest permissions: - contents: read - packages: write - # This is used to complete the identity challenge - # with sigstore/fulcio when running outside of PRs. - attestations: write - id-token: write + contents: read # Allows access to repository contents (read-only) + packages: write # Allows pushing to GHCR + id-token: write # Allows identity token write access for authentication + attestations: write # Needed for signing and attestation (if required) + + strategy: + fail-fast: false + matrix: + platform: + - linux/amd64 + - linux/arm64 + - linux/arm/v7 steps: - name: Checkout repository uses: actions/checkout@v4 - # Set up BuildKit Docker container builder to be able to build - # multi-platform images and export cache - # https://github.com/docker/setup-buildx-action + - name: Prepare + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + branch=${{ github.event.pull_request.number || github.ref_name }} + echo "BRANCH=${branch//\//-}" >> $GITHUB_ENV + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.DOCKERHUB_REPO }} + ${{ env.GHCR_REPO }} + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + image: ghcr.io/amitie10g/binfmt:latest + - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.0.0 # v3.0.0 + uses: docker/setup-buildx-action@v3 + with: + driver-opts: | + image=ghcr.io/amitie10g/buildkit:master - # Login against a Docker registry except on PR - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} - if: github.event_name != 'pull_request' - uses: docker/login-action@v3.0.0 # v3.0.0 + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6 with: - registry: ${{ env.REGISTRY }} + platforms: ${{ matrix.platform }} + labels: ${{ steps.meta.outputs.labels }} + outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true + cache-from: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR }}-${{ env.BRANCH }} + cache-to: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR}}-${{ env.BRANCH }},mode=max + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + permissions: + contents: read # Allows access to repository contents (read-only) + packages: write # Allows pushing to GHCR + id-token: write # Allows identity token write access for authentication + attestations: write # Needed for signing and attestation (if required) + needs: + - build + + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - # Extract metadata (tags, labels) for Docker - # https://github.com/docker/metadata-action - - name: Extract Docker metadata + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + driver-opts: | + image=ghcr.io/amitie10g/buildkit:master + + - name: Docker meta id: meta - uses: docker/metadata-action@v5.0.0 # v5.0.0 + uses: docker/metadata-action@v5 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + images: | + ${{ env.DOCKERHUB_REPO }} + ${{ env.GHCR_REPO }} tags: | type=ref,event=branch type=ref,event=pr @@ -78,28 +161,15 @@ jobs: type=semver,pattern={{major}} type=schedule,pattern=nightly - # Build and push Docker image with Buildx (don't push on PR) - # https://github.com/docker/build-push-action - - name: Build and push Docker image - id: build-and-push - uses: docker/build-push-action@v5.0.0 # v5.0.0 - with: - context: . - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - platforms: linux/amd64 - cache-from: type=gha - cache-to: type=gha,mode=max - build-args: | - VERSION=${{ github.ref_name }} - COMMIT=${{ github.sha }} - - - name: Attest - uses: actions/attest-build-provenance@v1 - id: attest - if: ${{ github.event_name != 'pull_request' }} - with: - subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - subject-digest: ${{ steps.build-and-push.outputs.digest }} - push-to-registry: true + - name: Create manifest list and push + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *) + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.GHCR_REPO }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ env.DOCKERHUB_REPO }}:${{ steps.meta.outputs.version }} + docker buildx imagetools inspect ${{ env.GHCR_REPO }}:${{ steps.meta.outputs.version }} diff --git a/.github/workflows/dockerhub-publish.yaml b/.github/workflows/dockerhub-publish.yaml deleted file mode 100644 index 599b0ffa..00000000 --- a/.github/workflows/dockerhub-publish.yaml +++ /dev/null @@ -1,100 +0,0 @@ -name: Dockerhub publish - -on: - schedule: - - cron: '00 0 * * *' - push: - branches: [ "main" ] - paths: - - 'backend/**' - - 'frontend/**' - - 'Dockerfile' - - 'Dockerfile.rootless' - - '.dockerignore' - - '.github/workflows' - # Publish semver tags as releases. - tags: [ 'v*.*.*' ] - pull_request: - branches: [ "main" ] - paths: - - 'backend/**' - - 'frontend/**' - - 'Dockerfile' - - 'Dockerfile.rootless' - - '.dockerignore' - - '.github/workflows' - -env: - # Use docker.io for Docker Hub - REGISTRY: docker.io - # Set the image name under sysadminsmedia organization - IMAGE_NAME: sysadminsmedia/homebox - -jobs: - build: - - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - # This is used to complete the identity challenge - # with sigstore/fulcio when running outside of PRs. - attestations: write - id-token: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Set up BuildKit Docker container builder to be able to build - # multi-platform images and export cache - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.0.0 # v3.0.0 - - # Login against Docker Hub registry - - name: Log into Docker Hub - if: github.event_name != 'pull_request' - uses: docker/login-action@v3.0.0 # v3.0.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - # Extract metadata (tags, labels) for Docker - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@v5.0.0 # v5.0.0 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - type=schedule,pattern=nightly - - # Build and push Docker image with Buildx (don't push on PR) - - name: Build and push Docker image - id: build-and-push - uses: docker/build-push-action@v5.0.0 # v5.0.0 - with: - context: . - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - platforms: linux/amd64 - cache-from: type=gha - cache-to: type=gha,mode=max - build-args: | - VERSION=${{ github.ref_name }} - COMMIT=${{ github.sha }} - - - name: Attest - uses: actions/attest-build-provenance@v1 - id: attest - if: ${{ github.event_name != 'pull_request' }} - with: - subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - subject-digest: ${{ steps.build-and-push.outputs.digest }} - push-to-registry: true diff --git a/Dockerfile b/Dockerfile index c702dd35..8942a834 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Node dependencies stage -FROM --platform=$TARGETPLATFORM node:18-alpine AS frontend-dependencies +FROM public.ecr.aws/docker/library/node:18-alpine AS frontend-dependencies WORKDIR /app # Install pnpm globally (caching layer) @@ -10,7 +10,7 @@ COPY frontend/package.json frontend/pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile --shamefully-hoist # Build Nuxt (frontend) stage -FROM --platform=$TARGETPLATFORM node:18-alpine AS frontend-builder +FROM public.ecr.aws/docker/library/node:18-alpine AS frontend-builder WORKDIR /app # Install pnpm globally again (it can reuse the cache if not changed) @@ -22,7 +22,7 @@ COPY --from=frontend-dependencies /app/node_modules ./node_modules RUN pnpm build # Go dependencies stage -FROM --platform=$TARGETPLATFORM golang:alpine AS builder-dependencies +FROM public.ecr.aws/docker/library/golang:alpine AS builder-dependencies WORKDIR /go/src/app # Copy go.mod and go.sum for better caching @@ -30,7 +30,7 @@ COPY ./backend/go.mod ./backend/go.sum ./ RUN go mod download # Build API stage -FROM --platform=$TARGETPLATFORM golang:alpine AS builder +FROM public.ecr.aws/docker/library/golang:alpine AS builder ARG BUILD_TIME ARG COMMIT ARG VERSION @@ -58,7 +58,7 @@ RUN --mount=type=cache,target=/root/.cache/go-build \ -v ./app/api/*.go # Production stage -FROM --platform=$TARGETPLATFORM alpine:latest +FROM public.ecr.aws/docker/library/alpine:latest ENV HBOX_MODE=production ENV HBOX_STORAGE_DATA=/data/ ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_pragma=busy_timeout=2000&_pragma=journal_mode=WAL&_fk=1&_time_format=sqlite diff --git a/Dockerfile.rootless b/Dockerfile.rootless index 59307a5d..f38e50a0 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,33 +1,35 @@ # Node dependencies -FROM node:18-alpine AS frontend-dependencies +FROM public.ecr.aws/docker/library/node:18-alpine AS frontend-dependencies WORKDIR /app RUN npm install -g pnpm -COPY frontend/package.json frontend/pnpm-lock.yaml ./ +COPY frontend/package.json frontend/pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile --shamefully-hoist # Build Nuxt -FROM node:18-alpine AS frontend-builder +FROM public.ecr.aws/docker/library/node:18-alpine AS frontend-builder WORKDIR /app -COPY frontend ./ +COPY frontend ./ COPY --from=frontend-dependencies /app/node_modules ./node_modules RUN pnpm build # Build Go dependencies -FROM golang:alpine AS builder-dependencies +FROM public.ecr.aws/docker/library/golang:alpine AS builder-dependencies WORKDIR /go/src/app -COPY ./backend/go.mod ./backend/go.sum ./ -RUN go mod download +COPY ./backend/go.mod ./backend/go.sum ./ +RUN apk update && apk add --no-cache git \ + && go mod download # Build API -FROM golang:alpine AS builder +FROM public.ecr.aws/docker/library/golang:alpine AS builder ARG BUILD_TIME ARG COMMIT ARG VERSION -RUN apk update && apk upgrade && apk add --no-cache git build-base gcc g++ +RUN apk update && apk upgrade && apk add --no-cache git build-base gcc g++ \ + && addgroup -S nonroot && adduser -S nonroot -G nonroot WORKDIR /go/src/app -COPY ./backend . +COPY ./backend ./ RUN rm -rf ./app/api/public COPY --from=frontend-builder /app/.output/public ./app/api/static/public COPY --from=builder-dependencies /go/pkg/mod /go/pkg/mod @@ -38,22 +40,20 @@ RUN --mount=type=cache,target=/root/.cache/go-build \ -ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \ -o /go/bin/api ./app/api/*.go +# Change ownership of files to nonroot +RUN chown -R nonroot:nonroot /go/bin/api /go/src/app + # Production stage with distroless -FROM gcr.io/distroless/static:latest +FROM ghcr.io/distroless/static:latest ENV HBOX_MODE=production ENV HBOX_STORAGE_DATA=/data/ ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_fk=1&_time_format=sqlite # Copy the binary and data directory, change ownership -COPY --from=builder --chown=nonroot /go/bin/api /app -COPY --from=builder --chown=nonroot /data /data - -# Add wget to the image -# Note: If using distroless, this may not be applicable -# as distroless images do not include package managers. -# This line may be omitted if you're relying on another way to handle healthchecks. -COPY --from=alpine:latest /bin/wget /usr/bin/wget +COPY --from=builder /go/bin/api /app +COPY --from=builder /data /data +COPY --from=ghcr.io/rockylinux/alpine:latest /bin/wget /usr/bin/wget LABEL Name=homebox Version=0.0.1 LABEL org.opencontainers.image.source="https://github.com/sysadminsmedia/homebox" @@ -67,7 +67,7 @@ HEALTHCHECK --interval=30s \ VOLUME ["/data"] -# Drop root and run as a low-privileged user +# Use nonroot user USER nonroot ENTRYPOINT ["/app"] CMD ["/data/config.yml"]