name: Build Container on: push: branches: [main] paths: - "container/**" - ".gitea/workflows/build.yml" pull_request: branches: [main] paths: - "container/**" - ".gitea/workflows/build.yml" env: REGISTRY: repo.anhonesthost.net IMAGE_NAME: cybercovellc/triple-c/triple-c-sandbox jobs: build-container: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: # Put BuildKit in the host's network namespace so it can reach # act_runner's cache service. # # The `docker-container` driver — which the multi-arch build below # requires, since the plain `docker` driver cannot do # linux/amd64+linux/arm64 — runs BuildKit in its *own* container on # Docker's default bridge. act_runner advertises ACTIONS_CACHE_URL as # an address the *job* container can reach, and nothing teaches the # BuildKit container about it: the job could reach # 192.168.1.126:40649 while the container actually making the request # could not, and the build died with `no route to host`. # # `no route to host` is EHOSTUNREACH — a firewall rejecting, not a # missing route (a wrong address times out instead) — which is what a # default firewalld zone does to traffic arriving from the docker # bridge. Sharing the host's namespace sidesteps the question # entirely: the cache address becomes local to BuildKit. # # No effect on runners where this already worked. driver-opts: network=host - name: Login to Gitea Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ gitea.actor }} password: ${{ secrets.REGISTRY_TOKEN }} - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: shadowdao password: ${{ secrets.GH_PAT }} - name: Build and push container image uses: docker/build-push-action@v5 with: context: ./container file: ./container/Dockerfile platforms: linux/amd64,linux/arm64 push: ${{ gitea.event_name == 'push' }} tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ gitea.sha }} ghcr.io/shadowdao/triple-c-sandbox:latest ghcr.io/shadowdao/triple-c-sandbox:${{ gitea.sha }} # `ignore-error` is what stops a cache failure failing a build that # already succeeded. act_runner emulates the GitHub Actions cache # service on the runner host's LAN address, and the `docker-container` # builder `setup-buildx-action` creates could not route to it — # every layer of both arches built, then the job died on # `GetCacheEntryDownloadURL: no route to host` while exporting. # # On a pull_request `push:` above is false, so this job pushes # nothing and the cache is its only output: failing it discarded a # complete, successful validation of the Dockerfile for both # architectures. A cache is an optimisation and must degrade to # "slow", never to "red". # # The import is already non-fatal — the build ran all 37 layers after # warning that it could not read the cache — so only the exporter # needs the flag. cache-from: type=gha cache-to: type=gha,mode=max,ignore-error=true