Multi-Arch Docker Build mit GitHub Actions und DockerHub
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:
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.
name: 'build images'
on:
workflow_dispatch:
schedule:
- cron: '7 5 * * *'
push:
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- 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/setup-qemu-action@master
with:
platforms: all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@master
- name: Cache Docker layers
uses: actions/cache@v2
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/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build
uses: docker/build-push-action@v2
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.