diff --git a/.env.example b/.env.example index ce9df51..e0cf2e1 100644 --- a/.env.example +++ b/.env.example @@ -1,10 +1,10 @@ # --- Container images --- -# Published to GHCR by .github/workflows/release.yml, multi-architecture +# Published to the Gitea registry by .gitea/workflows/release.yml, multi-architecture # (linux/amd64 and linux/arm64). The deploy host pulls these instead of # compiling: `docker compose pull && docker compose up -d`. Running # `docker compose build` locally still overrides them with a local build. # Pin IMAGE_TAG to a released version (e.g. 1.2.3) or a sha- tag to roll back. -IMAGE_NAMESPACE=ghcr.io/lucasrguerra/lambdamail +IMAGE_NAMESPACE=git.lucasrguerra.dev.br/lucasrguerra/lambdamail IMAGE_TAG=latest # --- Postgres --- diff --git a/.env.production.example b/.env.production.example index 4157295..6d3f0e3 100644 --- a/.env.production.example +++ b/.env.production.example @@ -10,9 +10,9 @@ # and must be URL-safe - see the note above them. # --- Container images ------------------------------------------------------- -# Published by .github/workflows/release.yml for linux/amd64 and linux/arm64. +# Published by .gitea/workflows/release.yml for linux/amd64 and linux/arm64. # Pin IMAGE_TAG to a released version or a sha- tag to roll back. -IMAGE_NAMESPACE=ghcr.io/lucasrguerra/lambdamail +IMAGE_NAMESPACE=git.lucasrguerra.dev.br/lucasrguerra/lambdamail IMAGE_TAG=latest # --- Identity --------------------------------------------------------------- diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index a7a5438..3307d32 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -15,7 +15,7 @@ on: workflow_call: concurrency: - group: ci-${{ github.ref }} + group: ci-${{ gitea.ref }} cancel-in-progress: true jobs: diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 2f04576..3c2c272 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -1,8 +1,9 @@ name: Release -# Publishes the four service images to GHCR after a merge into main, and again -# under semver tags when a v* tag is pushed. The deploy host only pulls, so -# nothing has to be built on the server. +# Publishes the service images to the Gitea container registry after a merge +# into main, and again under semver tags when a v* tag is pushed. The deploy +# host only pulls, so nothing has to be built on the server. Needs the user +# secret REGISTRY_TOKEN (a Gitea token with the write:package scope). on: push: branches: [main] @@ -14,15 +15,15 @@ concurrency: cancel-in-progress: false env: - REGISTRY: ghcr.io + REGISTRY: git.lucasrguerra.dev.br jobs: # Nothing is published unless the full suite passes first. ci: - uses: ./.github/workflows/ci.yml + uses: ./.gitea/workflows/ci.yml - # GHCR rejects an uppercase path, and this repository is "lucasrguerra/LambdaMail". - # Lowercasing github.repository here keeps the workflow fork-safe instead of + # Registry paths must be lowercase, and this repository is "lucasrguerra/LambdaMail". + # Lowercasing gitea.repository here keeps the workflow fork-safe instead of # hardcoding the owner. prepare: name: Namespace das imagens @@ -31,7 +32,10 @@ jobs: namespace: ${{ steps.namespace.outputs.value }} steps: - id: namespace - run: echo "value=${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT" + # GITHUB_OUTPUT is the runner's own interface: Gitea sets it under that name. + run: | + repo='${{ gitea.repository }}' + echo "value=${repo,,}" >> "$GITHUB_OUTPUT" # Each architecture is built on a runner of its own kind. QEMU emulation # would also work, but it makes the Go and Next builds roughly an order of @@ -54,7 +58,7 @@ jobs: platform: [linux/amd64, linux/arm64] include: - platform: linux/amd64 - runner: ubuntu-latest + runner: linux-amd64 arch: amd64 - platform: linux/arm64 runner: ubuntu-24.04-arm @@ -64,12 +68,12 @@ jobs: - uses: docker/setup-buildx-action@v4 - - name: Autentica no GHCR + - name: Autentica no registro uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + username: ${{ gitea.actor }} + password: ${{ secrets.REGISTRY_TOKEN }} - name: Metadados id: meta @@ -77,9 +81,10 @@ jobs: with: images: ${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }} - # Pushed by digest only: the tags are attached later, once both - # architectures exist and can be joined into a single manifest list. - - name: Build e push por digest + # Each architecture is pushed under its own tag (no digest artifacts: they + # are not portable to Gitea). The final tags are attached later, once both + # exist and can be joined into a single manifest list. + - name: Build e push por arquitetura id: build uses: docker/build-push-action@v7 with: @@ -87,26 +92,10 @@ jobs: file: services/${{ matrix.service }}/Dockerfile platforms: ${{ matrix.platform }} labels: ${{ steps.meta.outputs.labels }} - outputs: type=image,name=${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }},push-by-digest=true,name-canonical=true,push=true - cache-from: type=gha,scope=${{ matrix.service }}-${{ matrix.arch }} - cache-to: type=gha,mode=max,scope=${{ matrix.service }}-${{ matrix.arch }} - - - name: Exporta o digest - run: | - mkdir -p /tmp/digests - # The output already carries the `sha256:` prefix; the file name must - # not, since the merge step prepends it again. - digest='${{ steps.build.outputs.digest }}' - touch "/tmp/digests/${digest#sha256:}" - - - name: Guarda o digest - uses: actions/upload-artifact@v7 - with: - # Slashes are not allowed in artifact names, hence the arch alias. - name: digest-${{ matrix.service }}-${{ matrix.arch }} - path: /tmp/digests/* - retention-days: 1 - if-no-files-found: error + push: true + tags: ${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }}:build-${{ gitea.sha }}-${{ matrix.arch }} + cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }}:buildcache-${{ matrix.arch }} + cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }}:buildcache-${{ matrix.arch }},mode=max publish: name: Publica ${{ matrix.service }} @@ -124,19 +113,12 @@ jobs: - uses: docker/setup-buildx-action@v4 - - name: Autentica no GHCR + - name: Autentica no registro uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Recupera os digests - uses: actions/download-artifact@v7 - with: - pattern: digest-${{ matrix.service }}-* - merge-multiple: true - path: /tmp/digests + username: ${{ gitea.actor }} + password: ${{ secrets.REGISTRY_TOKEN }} # `latest` is what compose pulls. The semver tags only materialise on a # v* tag push and make it possible to pin or roll back to an exact @@ -156,11 +138,11 @@ jobs: # Joins both architectures under one manifest list, so `docker pull` # resolves to the right one automatically. - name: Cria o manifesto multi-arquitetura - working-directory: /tmp/digests run: | + image='${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }}' docker buildx imagetools create \ $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}') \ - $(printf '${{ env.REGISTRY }}/${{ needs.prepare.outputs.namespace }}/${{ matrix.service }}@sha256:%s ' *) + "$image:build-${{ gitea.sha }}-amd64" "$image:build-${{ gitea.sha }}-arm64" - name: Confere o resultado run: | diff --git a/docker-compose.yaml b/docker-compose.yaml index 2a0e2a8..a450802 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -60,7 +60,7 @@ services: # probe - a health check on a container that is meant to stop would report # unhealthy exactly when it has done its job. migrate: - image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/migrations:${IMAGE_TAG:-latest} + image: ${IMAGE_NAMESPACE:-git.lucasrguerra.dev.br/lucasrguerra/lambdamail}/migrations:${IMAGE_TAG:-latest} # "latest" is a moving tag and Docker considers a tag it already holds # locally to be satisfied, so recreating this container silently reused # the cached image and the newly published one was never fetched: the @@ -80,7 +80,7 @@ services: # ------------------------------------------------------------ RSPAMD rspamd: - image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/rspamd:${IMAGE_TAG:-latest} + image: ${IMAGE_NAMESPACE:-git.lucasrguerra.dev.br/lucasrguerra/lambdamail}/rspamd:${IMAGE_TAG:-latest} # "latest" is a moving tag and Docker considers a tag it already holds # locally to be satisfied, so recreating this container silently reused # the cached image and the newly published one was never fetched: the @@ -140,7 +140,7 @@ services: # -------------------------------------------------------------- AUTH auth: - image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/auth:${IMAGE_TAG:-latest} + image: ${IMAGE_NAMESPACE:-git.lucasrguerra.dev.br/lucasrguerra/lambdamail}/auth:${IMAGE_TAG:-latest} # "latest" is a moving tag and Docker considers a tag it already holds # locally to be satisfied, so recreating this container silently reused # the cached image and the newly published one was never fetched: the @@ -178,7 +178,7 @@ services: # ----------------------------------------------------------- STORAGE storage: - image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/storage:${IMAGE_TAG:-latest} + image: ${IMAGE_NAMESPACE:-git.lucasrguerra.dev.br/lucasrguerra/lambdamail}/storage:${IMAGE_TAG:-latest} # "latest" is a moving tag and Docker considers a tag it already holds # locally to be satisfied, so recreating this container silently reused # the cached image and the newly published one was never fetched: the @@ -214,7 +214,7 @@ services: # --------------------------------------------------------- PROTOCOLS protocols: - image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/protocols:${IMAGE_TAG:-latest} + image: ${IMAGE_NAMESPACE:-git.lucasrguerra.dev.br/lucasrguerra/lambdamail}/protocols:${IMAGE_TAG:-latest} # "latest" is a moving tag and Docker considers a tag it already holds # locally to be satisfied, so recreating this container silently reused # the cached image and the newly published one was never fetched: the @@ -297,7 +297,7 @@ services: # -------------------------------------------------------------- WEB web: - image: ${IMAGE_NAMESPACE:-ghcr.io/lucasrguerra/lambdamail}/webmail:${IMAGE_TAG:-latest} + image: ${IMAGE_NAMESPACE:-git.lucasrguerra.dev.br/lucasrguerra/lambdamail}/webmail:${IMAGE_TAG:-latest} # "latest" is a moving tag and Docker considers a tag it already holds # locally to be satisfied, so recreating this container silently reused # the cached image and the newly published one was never fetched: the diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index c43357f..7b4d411 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -176,7 +176,7 @@ have propagated and the IP has some sending history. ## Upgrading -Images are published to GHCR for `linux/amd64` and `linux/arm64` on every merge +Images are published to the Gitea container registry for `linux/amd64` and `linux/arm64` on every merge to `main`. ```bash @@ -198,7 +198,7 @@ every release, which is what forces the pull. IMAGE_TAG=sha- The tags are published by `release.yml`; `docker buildx imagetools inspect -ghcr.io//lambdamail/webmail:latest` shows what `latest` currently points +git.lucasrguerra.dev.br//lambdamail/webmail:latest` shows what `latest` currently points at. **Pinning has a second edge: bump it on every release.** A pinned tag is an