on: workflow_call: inputs: version-number: required: true type: string version-number-major: required: true type: string version-number-minor: required: true type: string version-number-patch: required: true type: string container-name: required: true type: string dockerfile: required: true type: string docker-context: required: true type: string image-owner: description: >- Owner segment of the pushed image, i.e. the middle part of //. Used to be hardcoded to "suer", which sent every image of every calling project to the same account. Kept as the default so existing callers stay unchanged. required: false default: suer type: string timeout-minutes: description: 'Hard limit for the build job. Without one a wedged build runs into the 6h default.' required: false default: 45 type: number platforms: description: >- Target platforms of the pushed manifest list. The build stages of all dockerfiles are pinned to the build platform, so an extra platform only adds its runtime stage, not another compile run. required: false default: linux/amd64,linux/arm64 type: string build-args: description: >- Extra build arguments for the image, one NAME=value per line. The docs image uses it to stamp the released version into writerside.cfg. required: false default: '' type: string name: build and push Docker Image env: REGISTRY: git.jk-dev.de jobs: build-image: name: Build ${{ inputs.container-name }} Container permissions: packages: write contents: read runs-on: [ ubuntu-docker ] timeout-minutes: ${{ inputs.timeout-minutes }} env: # Ohne Angabe suchen Buildx und die Docker-CLI unter # unix:///var/run/docker.sock. Laeuft der Daemon des Runners rootless, # liegt sein Socket stattdessen unter /run/user//docker.sock. Der # Pfad kommt deshalb aus einer Repository-Variablen; ist sie nicht # gesetzt, bleibt die Variable leer und Docker nutzt seinen Default. DOCKER_HOST: ${{ vars.DOCKER_HOST }} steps: # Der Token, den Gitea jedem Job stellt, taugt fuer zwei Dinge nicht: # Er gilt nur fuer das ausfuehrende Repository, waehrend die Submodule in # eigenen, privaten Repositories liegen — deren Klon scheitert an # "Repository not found". Und die Container-Registry lehnt ihn ab # (container.Authenticate antwortet mit 401). Beides deckt je ein eigener # Zugang ab, gepflegt in 1Password und hier zur Laufzeit ueber den # Connect-Server im Cluster geholt; in Gitea liegt nur dessen Zugang. - name: Zugangsdaten aus 1Password laden id: op-secrets uses: 1password/load-secrets-action@v2 with: # Die Werte sollen nur als Step-Outputs entstehen und nicht in die # Umgebung aller folgenden Schritte wandern. export-env: false env: OP_CONNECT_HOST: ${{ vars.OP_CONNECT_HOST }} OP_CONNECT_TOKEN: ${{ secrets.OP_CONNECT_TOKEN }} # Klont die privaten Submodul-Repositories. CHECKOUT_TOKEN: op://GitHub-Actions/jlab-git-checkout-token/credential # Eigener Zugang fuer die Registry — der Checkout-Token darf dort # nicht schreiben. Benutzername und Token kommen aus demselben Item, # damit sie zwangslaeufig zusammenpassen; die Registry prueft den # Token gegen genau das Konto aus `username`. REGISTRY_USER: op://GitHub-Actions/jlab-registry-access/username REGISTRY_TOKEN: op://GitHub-Actions/jlab-registry-access/password - uses: actions/checkout@v4 with: submodules: true # Die Action legt je Referenz einen Output an, benannt wie die # Umgebungsvariable, in der die op://-Referenz stand. token: ${{ steps.op-secrets.outputs.CHECKOUT_TOKEN }} # Schlaegt der Buildx-Start fehl, ist die erste Frage immer, welcher # Socket im Job-Container ueberhaupt ankommt. Der Schritt beantwortet sie, # ohne den Job scheitern zu lassen. - name: Docker-Socket ermitteln run: | echo "DOCKER_HOST=${DOCKER_HOST:-}" ls -l /var/run/docker.sock /run/docker.sock 2>&1 || true ls -l /run/user/*/docker.sock 2>&1 || true docker version 2>&1 || true - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@master - name: Authenticate To Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ steps.op-secrets.outputs.REGISTRY_USER }} password: ${{ steps.op-secrets.outputs.REGISTRY_TOKEN }} - name: Build uses: docker/build-push-action@v5 with: builder: ${{ steps.buildx.outputs.name }} context: ${{ inputs.docker-context }} file: ${{ inputs.dockerfile }} platforms: ${{ inputs.platforms }} build-args: ${{ inputs.build-args }} push: true # Der Eigentümer stand frueher als IMAGE_OWNER im env-Block des # Workflows. Dort kann er nicht bleiben: env auf Workflow-Ebene wird # ausgewertet, bevor es einen inputs-Kontext gibt. Der Wert wird # deshalb hier unmittelbar aus inputs gelesen — an dieser Stelle ist # der Kontext sicher vorhanden, anders als in jedem env-Block. tags: | ${{ env.REGISTRY }}/${{ inputs.image-owner }}/${{ inputs.container-name }}:latest ${{ env.REGISTRY }}/${{ inputs.image-owner }}/${{ inputs.container-name }}:${{ inputs.version-number }} ${{ env.REGISTRY }}/${{ inputs.image-owner }}/${{ inputs.container-name }}:${{ inputs.version-number-major }} ${{ env.REGISTRY }}/${{ inputs.image-owner }}/${{ inputs.container-name }}:${{ inputs.version-number-major }}.${{ inputs.version-number-minor }} ${{ env.REGISTRY }}/${{ inputs.image-owner }}/${{ inputs.container-name }}:${{ inputs.version-number-major }}.${{ inputs.version-number-minor }}.${{ inputs.version-number-patch }}