Zum Hauptinhalt springen

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. Öffentliche mittwald GitHub Actions kümmern sich um die API-Aufrufe, wenden deine Stack-Definition an und erstellen (falls erforderlich) die betroffenen Dienste neu.

Voraussetzungen

  • mStudio API-Token; siehe die Dokumentation zu API-Token erhalten
  • GitHub Actions Runner; jeder Runner mit Docker-Unterstützung, z.B. ubuntu-latest

Welche Action solltest du verwenden?

Du hast jetzt zwei unterschiedliche Deployment-Ansätze:

AnwendungsfallEmpfohlene ActionWarum
Du willst schnell direkt aus dem Quellcode deployen, ohne zuerst Dockerfiles oder Stack-Dateien anzulegenmittwald/zerodeploy-actionNutzt Railpack, erkennt Build-Schritte automatisch und deployt mit nahezu null Konfiguration in mittwald Container Hosting.
Du hast bereits ein Dockerfile und/oder eine explizite Stack-Definition (stack.yaml) und willst volle Kontrolle über Services, Ports und Rollout-Verhaltenmittwald/deploy-container-actionIdeal für einen expliziten, infrastrukturfokussierten Deployment-Ansatz.

Wenn du den kürzesten Weg vom Repository zum laufenden Service willst, nutze zerodeploy-action. Wenn dein Team bereits Build- und Runtime-Definitionen für Container pflegt, bleib bei deploy-container-action.

Deploy mit mittwald/zerodeploy-action

mittwald/zerodeploy-action ist für Repositories gedacht, die noch kein Docker-Setup haben. Sie bestimmt automatisch die beste Methode, um ein Docker-Image aus deinem Code zu erstellen, und deployt dieses in dein Zielprojekt, indem eine dynamisch bereitgestellte Container-Registry verwendet wird.

Benötigte Inputs

  • MITTWALD_API_TOKEN Secret; API-Token aus mStudio
  • Projekt-ID (zum Beispiel p-XXXXXX)

Beispiel-Workflow

Erstelle .github/workflows/zerodeploy.yml:

name: Deploy to mittwald Container Hosting

on:
workflow_dispatch:

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Create .env for deployment
run: |
{
echo "APP_ENV=production"
echo "APP_SECRET=${{ secrets.APP_SECRET }}"
} > .env

- name: Deploy with zerodeploy
uses: mittwald/zerodeploy-action@v1
with:
mittwald-api-token: ${{ secrets.MITTWALD_API_TOKEN }}
mittwald-project-id: "p-XXXXXX"

Die Action prüft automatisch, ob .env unter $GITHUB_WORKSPACE/.env existiert, und bindet die Datei beim Deployment ein, wenn sie vorhanden ist.

Deploy mit mittwald/deploy-container-action

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 für mittwald/deploy-container-action

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 oder (wenn du in mehrere Umgebungen deployst) ein GitHub Environment Secret zu verwenden, 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/v2/stacks/{stackId}/-Operation haben.

deploy/stack.yaml
services:
app:
image: "{{ .Env.IMAGE_TAG }}"
description: "Meine Webanwendung"
ports:
- "8080/tcp"
environment:
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-API
  • STACK_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:
tags: [v*]
# alternatively:
# push:
# branches: [main]
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 }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}

- name: Build & Push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Bereitstellung an mStudio
uses: mittwald/deploy-container-action@v1
env:
IMAGE_TAG: ${{ fromJSON(steps.meta.outputs.json).tags[0] }}
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 eines neuen Git-Tags (oder je nach Konfiguration, bei jedem Push zu main) GitHub ein neues Image erstellen, es in die GitHub Container Registry hochladen und die neuen Images ins mStudio deployen.

Fortgeschrittene Muster für mittwald/deploy-container-action

Die folgenden Optionen gelten für mittwald/deploy-container-action (den stack-basierten Workflow), nicht für mittwald/zerodeploy-action.

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.