Deployment von containerisierten Anwendungen mit GitHub Actions
Mit GitHub Actions kannst du dein Container-Image direkt aus deinem Quellcode-Repository erstellen und veröffentlichen und dann sofort deine Anwendung auf der mittwald Cloud-Plattform deployen. Die offizielle mittwald/deploy-container-action
kümmert sich um die API-Aufrufe, wendet deine Stack-Definition an und erstellt (falls erforderlich) die betroffenen Dienste neu.
Voraussetzungen
- mStudio API-Token; siehe die Dokumentation zu API-Token erhalten
- Stack-ID; siehe die Dokumentation zu Standard-Stack identifizieren
- (Optional) Private Registry; siehe Verwendung privater Registries
- GitHub Actions Runner; jeder Runner mit Docker-Unterstützung, z.B.
ubuntu-latest
Identifiziere deinen Stack
Folge der Dokumentation zu Standard-Stack identifizieren deines Projekts. Zur Vereinfachung empfehlen wir, die Stack-ID in einer GitHub-Variablen zu speichern, z.B. STACK_ID
.
Schreibe deine stack.yaml
Erstelle als nächstes eine Datei, die deine Stack-Definition irgendwo in deinem Repository enthält (für dieses Beispiel nehmen wir an, deploy/stack.yaml
). Diese Datei sollte das gleiche Format wie die PUT/
-Operation haben.
services:
app:
image: ghcr.io/<OWNER>/<REPO>:{{ .Env.IMAGE_TAG }}
description: "Meine Webanwendung"
ports:
- "8080/tcp"
envs:
APP_ENV: production
volumes: {}
Die Platzhalter innerhalb von {{ … }}
werden aus Umgebungsvariablen aufgelöst, die du im Workflow übergibst, sodass deine Secrets in GitHub bleiben und niemals im Repository eingecheckt werden müssen.
Füge Geheimnisse und Variablen zum Repository hinzu
MITTWALD_API_TOKEN
; API-Token für die mStudio-APISTACK_ID
; die in Schritt 1 kopierte ID. Du könntest dies als einfache Konfigurationsvariable festlegen, könntest diese Variable aber auch deiner Ziel-Environment zuordnen, wenn du environment-abhängig in verschiedene Stacks deployen möchtest.
Erstelle den GitHub Action Workflow
Erstelle .github/workflows/deploy.yml
:
name: Build & Deploy to mittwald
on:
push:
branches: [main]
# alternativ:
# push:
# tags: [v*]
workflow_dispatch:
jobs:
build-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
environment:
name: production
url: https://your-app.example
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- name: Anmelden bei GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Metadaten (Tags, Labels) für Docker extrahieren
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
- name: Build & Push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Bereitstellung an mStudio
uses: mittwald/deploy-container-action@v1
env:
IMAGE_TAG: ${{ github.sha }}
with:
api_token: ${{ secrets.MITTWALD_API_TOKEN }}
stack_id: ${{ vars.STACK_ID }}
stack_file: "${{ github.workspace }}/configs/stack.yaml"
Mit diesem Workflow wird bei jedem Push zu main
(oder je nach Konfiguration, bei jedem neuen Git-Tag) GitHub ein neues Image erstellen, es in die GitHub Container Registry hochladen und die neuen Images ins mStudio deployen.
Fortgeschrittene Muster
Selektive Neustarts
Wenn du Ausfallzeiten für zustandsbehaftete Dienste (z.B. Datenbanken) vermeiden möchtest, kannst du der Action sagen, dass sie die Neuerstellung nach dem Update überspringen soll:
with:
skip_recreation: "mysql,redis"
Nicht aufgelistete Dienste werden nur neu gestartet, wenn die API meldet, dass ein Neustart tatsächlich erforderlich ist.
Nächste Schritte
- Füge ein Ingress hinzu, um HTTP-Ports für das öffentliche Internet freizugeben.
- Verwende Terraform für vollständig deklarative Infrastruktur und lasse GitHub Actions
terraform apply
aufrufen. - Definiere Umgebungen dynamisch pro Pull-Request, um kurzlebige Überprüfungsumgebungen für jeden PR zu erstellen.