Neuigkeiten von trion.
Immer gut informiert.

Multi-Arch Docker Build mit GitHub Actions und DockerHub

Docker

Nachdem DockerHub die automatischen Builds von Docker Images nicht mehr kostenlos für jeden anbietet, bieten sich GitHub Actions als eine praktische Alternative an. ( Die Umsetzung von Multi-Arch Builds mit DockerHub wurde in dem Beitrag Docker Multi Arch Images mit DockerHub behandelt.)
In diesem Beitrag wird eine Umsetzung von Multi-Arch Images am Beispiel das Angular-CLI Docker Images vorgestellt.

Das Prinzip ist im Vergleich zu DockerHub Autobuilds ähnlich, jedoch ist der Einsatz mehrerer, unterschiedlicher, Dockerfiles pro Plattform nicht mehr nötig.
Durch die fehlende Integration in DockerHub werden jedoch keine automatischen Builds durch die Aktualisierung von Upstream-Images ermöglicht, sondern lediglich auf Basis von git Änderungen.

GitHub Actions Secrets für DockerHub

Damit von GitHub Actions aus ein Push auf die DockerHub Registry erfolgen darf, werden zunächst Credentials (Username und Passwort) zur Authentifizierung benötigt. Statt des regulären Passworts sollte hier ein Personal Access Token (PAT) erstellt werden. Ein Access Token für DockerHub ist in den Einstellungen abzurufen: https://hub.docker.com/settings/security
Als Name kann hier z.B. "GitHub Actions" gewählt werden.

Anschließend müssen in GitHub für das jeweilige Repository zugehörige Secrets angelegt werden. Das geschieht auch hier in den Einstellungen im Bereich Secrets: https://github.com/<USERNAME>/<REPOSITORY>/settings/secrets
(Das Secret kann als 'Repository Secret' angelegt werden, es muss nicht als 'Environment Secret' angelegt werden.)

Als Namen werden im Beispiel DOCKER_USERNAME und DOCKER_PASSWORD verwendet. Dabei wird der Inhalt des Access Token als DOCKER_PASSWORD und der Login Name auf DockerHub als DOCKER_USERNAME verwendet.

Die Secrets können dann im Worklow der GitHub Actions mit der Schreibwise ${{secrets.DOCKER_USERNAME}} verwendet werden.

GitHub Actions Build Job

Um einen Build des Docker Image auf GitHub auszulösen gibt es unterschiedliche Trigger Varianten. Um stets ein aktuelles :latest Image bereitzustellen, bietet sich ein zeitgesteuerter nächtlicher Build an. Die Umsetzung erfolgt mit einem Cron-Ausdruck und dem schedule Schlüssel.
Bei jeder Änderung am GitHub Repository soll natürlich ebenfalls ein Build ausgelöst werden. Dies wird durch durch push konfiguriert.
Um einen manuell getriggerten Build ebenfalls zu unterstützen kann workflow_dispatch angegeben werden.

Die vollständige Trigger Konfiguration könnten dann wie folgt aussehen:

Beispiel für GitHub Actions Trigger.
name: 'build images'

on:
  workflow_dispatch:
  schedule:
    - cron: '7 5 * * *'
  push:

Der eigentlich Build gliedert sich in die folgenden Schritte:

  • Checkout des Repository

  • Ermittlung des Ziel Tags für das Image

  • Aktivierung von QEMU für Multi-Arch Images

  • Einrichtung von Docker buildx zum eigentlich Build

  • Konfiguration des Docker Layercache für buildx

  • Authentifizierung zu DockerHub

  • Build und push zu DockerHub

Die Implementierung der Schritte ist im folgenden Quellcode gezeigt.

Beispiel .github/workflows/build.yaml zum Build von Angular CLI
name: 'build images'

on:
  workflow_dispatch:
  schedule:
    - cron: '7 5 * * *'
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/[email protected]

      - name: Prepare
        id: prep
        run: |
          #determine dockehub image using dockerhub username and github repo suffix
          DOCKER_IMAGE=${{ secrets.DOCKER_USERNAME }}/${GITHUB_REPOSITORY#*/}
          VERSION=latest
          SHORTREF=${GITHUB_SHA::8}

          #use branch as version
          if [[ $GITHUB_REF == refs/heads/* ]]; then
            VERSION=${GITHUB_REF#refs/heads/}
            [ $VERSION == "master" ] && VERSION=latest
          fi

          #use tag as version
          if [[ $GITHUB_REF == refs/tags/* ]]; then
            VERSION=${GITHUB_REF#refs/tags/}
          fi

          #use version as image tag
          TAGS="${DOCKER_IMAGE}:${VERSION}"

          # If version is a number also tag it 'latest'.
          if [[ $VERSION =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
            TAGS="$TAGS,${DOCKER_IMAGE}:latest"
          fi

          echo ::set-output name=tags::${TAGS}
          echo ::set-output name=docker_image::${DOCKER_IMAGE}

      - name: Set up QEMU
        uses: docker/[email protected]
        with:
          platforms: all

      - name: Set up Docker Buildx
        id: buildx
        uses: docker/[email protected]

      - name: Cache Docker layers
        uses: actions/[email protected]
        with:
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-buildx-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-buildx-

      - name: Login to DockerHub
        if: github.event_name != 'pull_request'
        uses: docker/[email protected]
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build
        uses: docker/[email protected]
        with:
          builder: ${{ steps.buildx.outputs.name }}
          context: .
          file: ./Dockerfile
          platforms: linux/amd64,linux/arm64,linux/arm/v7
          push: true
          tags: ${{ steps.prep.outputs.tags }}
          cache-from: type=local,src=/tmp/.buildx-cache
          cache-to: type=local,dest=/tmp/.buildx-cache-new

Mit dieser Konfiguration ist ein effizienter Build für die von GitHub unterstützten Plattformen einfach umzusetzen. Im Gegensatz zu dem automatischen Build auf DockerHub sind jedoch einige Einschränkungen zu beachten: So sind abgeleitete Downstream Images nicht so einfach umzusetzen. Analog kann das Image nicht auf Basis von aktualisierten Upstream Images gebaut werden.




Zu den Themen Kubernetes, Docker und Angular bieten wir sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:

Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.

Feedback oder Fragen zu einem Artikel - per Twitter @triondevelop oder E-Mail freuen wir uns auf eine Kontaktaufnahme!

Los geht's!

Bitte teilen Sie uns mit, wie wir Sie am besten erreichen können.