TL;DR
- Du baust einen wiederverwendbaren Polycrate-Workflow, der auf deinen Linux-Servern automatisch
backup → update → verifyausführt – inklusive Rollback über Ansibleblock/rescue. - Backups laufen als
pg_dump+tar+ Upload nach S3 mit rclone (S3-kompatibles Object Storage), Updates viaapt upgradeplus Service-Restart und Health-Checks, Verifikation über Systemd-Status und HTTP-Response. - Polycrate-Workflows geben deinen Ansible-Actions einen Namen, eine Reihenfolge und eine Dokumentation – statt lose verteilte Playbooks und README-Dateien.
- Alles läuft im Container: Kein lokales Python-/Ansible-Chaos, konsistente Toolchain auf jeder Admin-Workstation, Workspaces sind bei Bedarf komplett verschlüsselt.
- ayedo unterstützt Teams dabei, solche Betriebsprozesse als Code zu etablieren – von der ersten Block-Struktur bis zu unternehmensweiten, geteilten Workflows und Operations-Automatisierung Demos.
Polycrate-Workflows: Betriebsprozesse statt CI/CD-Pipelines
Wenn du „Workflow“ hörst, denkst du vielleicht an GitHub Actions oder GitLab CI. Polycrate-Workflows sind etwas anderes:
- Sie laufen dort, wo du Ansible einsetzt – auf deiner Admin-Workstation, einem Bastion-Host oder in einem Automation-Container.
- Sie orchestrieren Polycrate-Actions (z.B.
backup,update,verify) zu einem benannten Prozess. - Sie sind Teil deines Polycrate-Workspaces und damit versionierbar, verschlüsselbar und teilbar.
Ein Workflow in Polycrate ist ein Stück deklarative Orchestrierung: „Führe erst diese Action in diesem Block aus, dann jene Action in einem anderen Block, …“. Kein CI/CD-Server nötig, keine YAML-Speziallogik – nur dein Workspace und die Polycrate-CLI.
Dokumentation passiert damit im Code: Der Workflow ist die Dokumentation des Betriebsprozesses. Kein zusätzliches Word-Dokument, das nicht zur Realität passt.
Mehr Details zum Konzept findest du in der Dokumentation zu Workflows und Workspaces.
Szenario: Nächtliche Linux-Maintenance mit Backup und Rollback
Ausgangssituation – sehr typisch für Linux-/System-Admins:
- PostgreSQL-Datenbank auf Ubuntu 24.04
- Webapplikation als Systemd-Service (
acme-app.service) - Backups sollen nach S3 (S3-kompatibles Object Storage)
- Updates sollen automatisiert laufen, aber mit Safety-Net
- Am Ende brauchst du die Sicherheit: Service läuft, HTTP-Endpoint antwortet
Der Prozess, den wir als Polycrate-Workflow abbilden:
-
backup
Datenbank-Dump mitpg_dump, Tarball erzeugen, mit rclone nach S3 hochladen und einenlatest.tar.gz-Symlink pflegen. -
update
apt update && apt upgrade -y, Service neu starten, Health-Check – alles in einem Ansible-Play mitblock/rescue: - Imblocklaufen Updates und Checks. - Imrescuewird bei Fehlern automatisch auslatest.tar.gzwiederhergestellt. -
verify
Explizite Verifikation, dass Systemd-Service läuft und ein HTTP-Endpoint mit Status 200 antwortet.
Das Ganze orchestrieren wir als Workflow nightly-maintenance, den du z.B. über einen systemd-Timer jede Nacht ausführen lässt.
Workspace-Grundlage: Blocks, Workflows, Inventory
Wir starten mit einem Polycrate-Workspace acme-corp-automation. Die Struktur:
workspace.poly– zentrale Definition von Blocks und Workflowsinventory.yml– Ansible-Inventory (YAML, nicht INI!)blocks/registry.acme-corp.com/acme/infra/linux-maintenance/– Block mit Actions und Playbooks, sobald er lokal vorliegt (beim erstenpolycrate run …oder Workflow-Lauf kann Polycrate einen fehlenden Block automatisch installieren;polycrate blocks pullbleibt optional)artifacts/secrets/– z.B. Ausschnitte für rclone (Zugangsdaten zum Object Storage), bei Bedarf verschlüsselt
workspace.poly mit Workflow-Definition
name: acme-corp-automation
organization: acme
blocks:
- name: linux-maintenance
from: registry.acme-corp.com/acme/infra/linux-maintenance:0.1.0
config:
db_name: "acme_app"
db_user: "acme"
db_host: "localhost"
backup_dir: "/var/backups/acme-db"
rclone_destination: "acme-s3:acme-backups-db/postgres"
hosts: "db_servers"
web_hosts: "web_servers"
service_name: "acme-app.service"
health_url: "http://localhost:8080/health"
workflows:
- name: nightly-maintenance
description: "Nightly backup → update → verify for Linux application servers"
steps:
- name: backup
block: linux-maintenance
action: backup
- name: update
block: linux-maintenance
action: update
- name: verify
block: linux-maintenance
action: verify
Wichtig:
- Der Block liegt in der fiktiven Firmen-Registry unter
registry.acme-corp.com(kein Bezug zu ayedos Produkt-Registry); infrom:steht die vollständige Referenz inkl. Tag (0.1.0entspricht der Block-Version). Ein vorherigespolycrate blocks pullist nicht nötig: Fehlt der Block lokal, erkennt Polycrate das beim Aufruf vonpolycrate run …oder eines Workflows und fragt, ob der Block automatisch installiert werden soll. - Alle spezifischen Parameter liegen in
config. Sie stehen in den Actions überblock.config.*zur Verfügung. - Der Workflow
nightly-maintenancereferenziert nur Block- und Action-Namen – keine Pfade, keine Shell-Skripte.
Mehr zu Best Practices bei Blocks und Workflows: Polycrate Best Practices.
Inventory als YAML
Polycrate setzt automatisch ANSIBLE_INVENTORY auf inventory.yml im Workspace-Root. Alle Hosts stehen unter all.hosts; unter children verweisen die Gruppen nur noch per Hostnamen darauf (kanonisches Format wie im Beitrag Multi-Server-Inventories mit Ansible):
all:
vars:
ansible_user: "ubuntu"
ansible_ssh_port: 22
ansible_ssh_common_args: "-o StrictHostKeyChecking=no"
ansible_python_interpreter: /usr/bin/python3
hosts:
db01.acme-corp.com: {}
app01.acme-corp.com: {}
children:
db_servers:
hosts:
db01.acme-corp.com:
web_servers:
hosts:
app01.acme-corp.com:
Welche Gruppe oder welcher Host pro Action läuft, steuern Sie über Block-config (hosts / web_hosts) und im Playbook hosts: "{{ block.config.… }}" – nicht über fest eingetragene Gruppennamen allein. Kein localhost für SSH-basierte Administration: Polycrate führt Ansible im Container aus, die Zielhosts sind die Einträge im Inventory. Details: Ansible-Integration.
Der Maintenance-Block: Struktur und Actions
Die folgenden Listings zeigen den Block wie bei der Entwicklung unter dem vollständigen Registry-Pfad blocks/registry.acme-corp.com/acme/infra/linux-maintenance/ – so wie Sie einen OCI-Block mit echter from:-Referenz versionieren und veröffentlichen, nicht als kurzer „Demo-Ordnername“. In anderen Workspaces referenzieren Sie ihn über from: registry.acme-corp.com/acme/infra/linux-maintenance:0.1.0. Fehlt der Block lokal, bietet Polycrate beim ersten polycrate run … oder Workflow-Lauf die automatische Installation an; optional bleibt polycrate blocks pull. Die block.poly:
name: linux-maintenance
version: 0.1.0
kind: generic
config:
db_name: "acme_app"
db_user: "acme"
db_host: "localhost"
backup_dir: "/var/backups/acme-db"
rclone_destination: "acme-s3:acme-backups-db/postgres"
hosts: "db_servers"
web_hosts: "web_servers"
service_name: "acme-app.service"
health_url: "http://localhost:8080/health"
actions:
- name: backup
type: ansible
playbook: backup.yml
- name: update
type: ansible
playbook: update.yml
- name: verify
type: ansible
playbook: verify.yml
Hinweis: block.poly ist reines YAML – kein Jinja-Templating. Defaults stehen hier; Abweichungen tragen Sie in workspace.poly unter config ein (Merge). Ausdrücke wie {{ block.config.* }} und Ansible-Logik gehören nur in Playbooks, Tasks und Templates.
Hier siehst du typische Polycrate-Stärken:
- Guardrails durch das Block-Modell: Eine klare Struktur statt Playbook-Wildwuchs.
- Gute DX: Actions heißen einfach
backup,update,verify– die CLI-Befehle sind lesbar und copy-paste-bar.
Run-Befehle für einzelne Actions:
polycrate run linux-maintenance backup
polycrate run linux-maintenance update
polycrate run linux-maintenance verify
Workflow:
polycrate workflows run nightly-maintenance
Backup-Action: pg_dump, tar, rclone → S3
Die Datei blocks/registry.acme-corp.com/acme/infra/linux-maintenance/backup.yml (vereinfachtes Beispiel – Ziel-Hosts über block.config.hosts wie oben):
- name: Backup PostgreSQL database
hosts: "{{ block.config.hosts }}"
become: true
gather_facts: false
vars:
backup_dir: "{{ block.config.backup_dir }}"
db_name: "{{ block.config.db_name }}"
db_user: "{{ block.config.db_user }}"
db_host: "{{ block.config.db_host }}"
rclone_destination: "{{ block.config.rclone_destination }}"
timestamp: "{{ lookup('ansible.builtin.pipe', 'date +%Y%m%d-%H%M%S') }}"
backup_file: "{{ backup_dir }}/{{ db_name }}-{{ timestamp }}.sql"
backup_tar: "{{ backup_dir }}/{{ db_name }}-{{ timestamp }}.tar.gz"
latest_symlink: "{{ backup_dir }}/latest.tar.gz"
tasks:
- name: Ensure backup directory exists
ansible.builtin.file:
path: "{{ backup_dir }}"
state: directory
owner: postgres
group: postgres
mode: "0750"
- name: Dump PostgreSQL database
ansible.builtin.command:
cmd: >
pg_dump -h {{ db_host }} -U {{ db_user }} -F p -f {{ backup_file }} {{ db_name }}
environment:
PGPASSWORD: "{{ hostvars[inventory_hostname].pg_password | default('') }}"
become_user: postgres
- name: Create tar archive from SQL dump
ansible.builtin.archive:
path: "{{ backup_file }}"
dest: "{{ backup_tar }}"
format: gz
- name: Update latest backup symlink
ansible.builtin.file:
src: "{{ backup_tar }}"
dest: "{{ latest_symlink }}"
state: link
force: true
- name: Upload tarball to S3 with rclone
ansible.builtin.command:
argv:
- rclone
- copy
- "{{ backup_tar }}"
- "{{ rclone_destination }}/"
Anmerkungen:
- Upload mit rclone (
rclone copy … remote:bucket/pfad/) auf S3 oder S3-kompatibles Object Storage; Ziel kommt ausrclone_destination(Remote-Name ausrclone.confauf dem Zielhost, z.B.acme-s3, plus Bucket und Präfix). Authentifizierung wie gewohnt über rclone (Konfiguration, Umgebungsvariablen; siehe rclone S3). - Der
latest.tar.gz-Symlink ist unser Rollback-Anker. - DB-Passwort kann aus Host-Variablen oder – besser – aus einem verschlüsselten Workspace-Secret kommen.
Polycrate bringt eingebaute Workspace-Verschlüsselung mit age: Es gibt keinen Befehl polycrate secrets add. Sensible Dateien legen Sie direkt unter artifacts/secrets/ ab (workspace-weit oder block-spezifisch unter artifacts/secrets/BLOCKNAME/); polycrate workspace encrypt verschlüsselt sie zu *.age und pflegt u. a. .gitignore. Ohne Polycrate API setzen Sie vor dem ersten Verschlüsseln typischerweise WORKSPACE_ENCRYPTION_KEY – siehe Workspace-Verschlüsselung (Abschnitte zu Key-Quellen, Key-Erzeugung und „Verschlüsseln“).
mkdir -p artifacts/secrets
# z. B. rclone-Konfiguration (siehe https://rclone.org/s3/) – Klartext nur lokal, nicht committen
# cp /pfad/zur/rclone.conf artifacts/secrets/rclone.conf
# Ohne Polycrate API: age Private Key (siehe Doku „Encryption Key erzeugen“)
# export WORKSPACE_ENCRYPTION_KEY="AGE-SECRET-KEY-..."
polycrate workspace encrypt
Kein externer Vault nötig – Compliance wird damit deutlich einfacher.
Update-Action: apt upgrade mit Ansible block/rescue und automatischem Restore
Die Update-Action kümmert sich um Paketupdates, Service-Restart und initiale Health-Checks. Der Rollback-Mechanismus steckt in einem Ansible-block mit rescue.
blocks/registry.acme-corp.com/acme/infra/linux-maintenance/update.yml:
- name: Update application servers with rollback
hosts: "{{ block.config.web_hosts }}"
become: true
gather_facts: false
vars:
service_name: "{{ block.config.service_name }}"
health_url: "{{ block.config.health_url }}"
backup_dir: "{{ block.config.backup_dir }}"
latest_backup: "{{ backup_dir }}/latest.tar.gz"
tasks:
- name: Ensure latest backup exists before updating
ansible.builtin.stat:
path: "{{ latest_backup }}"
register: backup_stat
- name: Fail if no latest backup is available
ansible.builtin.fail:
msg: "No latest backup found at {{ latest_backup }}. Aborting update."
when: not backup_stat.stat.exists
- name: Perform apt upgrade with rollback safety
block:
- name: Update apt cache
ansible.builtin.apt:
update_cache: true
- name: Upgrade all packages
ansible.builtin.apt:
upgrade: dist
autoremove: true
- name: Restart application service
ansible.builtin.systemd:
name: "{{ service_name }}"
state: restarted
enabled: true
- name: Wait for application port 8080
ansible.builtin.wait_for:
port: 8080
state: started
delay: 5
timeout: 60
- name: HTTP health-check on application
ansible.builtin.uri:
url: "{{ health_url }}"
status_code: 200
validate_certs: false
rescue:
- name: Log update failure and start rollback
ansible.builtin.debug:
msg: "Update failed on {{ inventory_hostname }}, starting rollback from {{ latest_backup }}"
- name: Stop application service before restore
ansible.builtin.systemd:
name: "{{ service_name }}"
state: stopped
- name: Restore application data from latest backup
ansible.builtin.unarchive:
src: "{{ latest_backup }}"
dest: "/"
remote_src: true
- name: Start application service after rollback
ansible.builtin.systemd:
name: "{{ service_name }}"
state: started
enabled: true
- name: HTTP health-check after rollback
ansible.builtin.uri:
url: "{{ health_url }}"
status_code: 200
validate_certs: false
- name: Fail play to signal rollback occurred
ansible.builtin.fail:
msg: "Update failed and rollback from {{ latest_backup }} was executed."
So funktioniert der Safety-Net-Mechanismus:
- Schlägt irgendetwas im
blockfehl (z.B. Service startet nicht, HTTP-Check liefert 500), springt Ansible in denrescue-Block. - Der
rescue-Block spielt das Backup ein und startet den Service wieder. - Am Ende
failt der Task explizit, damit der Workflow (und du) wissen: Es gab ein Problem, aber der Zustand wurde zurückgesetzt.
Das ist deutlich robuster als ein README mit „Bitte vor Updates ein Backup machen“.
Verify-Action: Status- und HTTP-Checks
Die verify-Action ist bewusst simpel – sie codiert das, was sonst oft nur „gefühlte“ Checks sind.
blocks/registry.acme-corp.com/acme/infra/linux-maintenance/verify.yml:
- name: Verify application servers
hosts: "{{ block.config.web_hosts }}"
become: true
gather_facts: false
vars:
service_name: "{{ block.config.service_name }}"
health_url: "{{ block.config.health_url }}"
tasks:
- name: Check service status
ansible.builtin.systemd:
name: "{{ service_name }}"
register: service_state
- name: Fail if service is not running
ansible.builtin.fail:
msg: "Service {{ service_name }} is not running."
when: not service_state.status.ActiveState == "active"
- name: HTTP health-check
ansible.builtin.uri:
url: "{{ health_url }}"
status_code: 200
validate_certs: false
register: health_response
- name: Show response
ansible.builtin.debug:
msg: "Health-check OK: {{ health_response.status }} {{ health_response.msg }}"
Dieser Schritt gibt dem ganzen Prozess einen klaren Abschluss: „Ist die Applikation nach Backup und Update in einem guten Zustand?“
Workflow-Ausführung: vom einmaligen Run bis zum systemd-Timer
Manuell ausführbar ist der Workflow sofort:
# Im Workspace-Root
polycrate workflows run nightly-maintenance
Im Gegensatz zu plain Ansible musst du dir keinen eigenen Wrapper bauen:
- Kein Bash-Skript, das mehrere
ansible-playbook-Aufrufe verkettet. - Kein manuelles Weiterreichen von Variablen zwischen Schritten.
- Kein eigenes Logging-Konzept – Polycrate kümmert sich um konsistente Ausführung im Container.
Dank Containerisierung löst Polycrate das klassische Dependency-Problem:
- Ansible, Python, rclone und weitere Tools werden durch das Container-Image definiert.
- Dein Team arbeitet mit derselben Toolchain, unabhängig von der lokalen Workstation.
- Supply-Chain-Risiken reduzierst du, indem du das Image selbst kontrollierst (Dockerfile.poly / Bash-Build).
Mehr dazu in der CLI-Referenz.
Zeitgesteuerte Ausführung mit systemd-Timer
Angenommen, du betreibst einen zentralen Automation-Host (z.B. automation01.acme-corp.com), auf dem Polycrate installiert ist. Dann kannst du deinen Workflow mit einem systemd-Timer planen.
Service-Unit /etc/systemd/system/polycrate-nightly-maintenance.service:
[Unit]
Description=Polycrate nightly maintenance workflow
[Service]
Type=oneshot
WorkingDirectory=/opt/polycrate-workspaces/acme-corp-automation
ExecStart=/usr/local/bin/polycrate workflows run nightly-maintenance
User=automation
Group=automation
Timer-Unit /etc/systemd/system/polycrate-nightly-maintenance.timer:
[Unit]
Description=Run Polycrate nightly maintenance workflow at 2:00
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
Aktivieren:
sudo systemctl daemon-reload
sudo systemctl enable --now polycrate-nightly-maintenance.timer
Ab diesem Zeitpunkt läuft dein kompletter Prozess jede Nacht um 2:00 Uhr – klar definiert, versioniert und wiederholbar.
Polycrate vs. plain Ansible: Was ändert sich wirklich?
Mit plain Ansible würdest du typischerweise:
- Mehrere Playbooks (
backup.yml,update.yml,verify.yml) schreiben. - Ein Shell-Skript bauen, das sie in der richtigen Reihenfolge aufruft.
- Cronjobs oder systemd-Timer direkt auf
ansible-playbooklegen. - Deine Teamkollegen mit einem README versorgen, das erklärt, in welcher Reihenfolge was zu tun ist.
Das funktioniert – aber du kämpfst mit:
- Python-/Ansible-Versionen auf unterschiedlichen Admin-Rechnern.
- Individuellen Tool-Setups (rclone, pg_dump-Versionen, Remote-Konfiguration).
- Playbook-Wildwuchs ohne klaren Rahmen.
- Dokumentation, die schnell veraltet.
Mit Polycrate:
- Läuft Ansible immer im Container – keine lokalen Dependencies, keine Versionsdiskussionen.
- Bekommen Playbooks eine feste Heimat als Blöcke mit klaren Actions und Konfigurationsparametern.
- Kannst du komplette Betriebsprozesse als Workflows definieren und unter einem Namen ausführen.
- Verschlüsselst du den gesamten Workspace auf Wunsch mit einem Befehl – inklusive Credentials und Secrets.
- Teilt dein Team Blocks über OCI-Registries oder PolyHub – „Sharable Automation“ statt Copy-Paste zwischen Repositories.
Code ist damit nicht nur Implementierung, sondern auch Dokumentation: Wer den Workflow liest, versteht den Prozess.
Häufige Fragen
Ist ein Polycrate-Workflow das gleiche wie ein CI/CD-Workflow?
Nein. CI/CD-Workflows (GitHub Actions, GitLab CI, Jenkins-Pipelines) laufen typischerweise bei Code-Änderungen im Kontext eines Repositories. Polycrate-Workflows laufen dort, wo du Infrastruktur und Systeme verwaltest:
- Sie orchestrieren Actions in deinen Blöcken (z.B. Backup, Update, Verify).
- Sie sind eng an dein Ansible-Inventar und deine Betriebsrealität gekoppelt.
- Sie lassen sich per CLI, systemd-Timer oder externen Orchestratoren triggern.
Du kannst beides kombinieren: Ein CI/CD-Workflow kann zum Beispiel polycrate workflows run nightly-maintenance auf einem Automation-Host ausführen, wenn bestimmte Bedingungen erfüllt sind.
Wie integriere ich Polycrate-Workflows mit cron statt systemd?
Wenn du lieber cron nutzt, definierst du einfach einen Cronjob, der in das Workspace-Verzeichnis wechselt und den Workflow ausführt:
0 2 * * * cd /opt/polycrate-workspaces/acme-corp-automation && /usr/local/bin/polycrate workflows run nightly-maintenance >> /var/log/polycrate-nightly.log 2>&1
Der Vorteil von Polycrate bleibt derselbe:
- Ein einziger, stabiler Befehl pro Prozess.
- Die interne Ausführung läuft trotzdem containerisiert, mit konsistenter Toolchain.
- Deine Ansible-Playbooks bleiben im Block-Modell strukturiert.
Wie unterstützt ayedo Teams bei der Einführung solcher Maintenance-Workflows?
Wir sehen solche Workflows als Kern von professioneller Operations-Automatisierung:
- In Workshops und mit unseren Beratungspaketen helfen wir Teams, bestehende Playbooks in Polycrate-Blöcke und -Workflows zu überführen.
- Wir unterstützen beim Design von Block-Strukturen, der Nutzung von Workspace-Verschlüsselung und der Integration in bestehende Betriebsprozesse (z.B. via systemd, Cron oder Plattform-Automatisierung).
- Über PolyHub stellen wir offizielle Blöcke bereit, die du als Bausteine für eigene Workflows nutzen kannst (Monitoring, Kubernetes, Security, Storage und mehr).
Weitere Fragen? Siehe unsere FAQ
Von der Routine zur Reproduzierbarkeit
In diesem Beitrag hast du ein komplettes Beispiel für einen realen Betriebsprozess als Polycrate-Workflow gesehen:
- Ein Backup-Schritt, der Datenbank-Dumps erzeugt, tarballt und zuverlässig nach S3 hochlädt.
- Einen Update-Schritt, der mit Ansible-
block/rescue-Mechanik Paketupdates durchführt und bei Problemen automatisch ein Rollback aus dem letzten Backup fährt. - Einen Verify-Schritt, der explizit prüft, ob Service und HTTP-Endpoint nach dem Vorgang in Ordnung sind.
- Einen Workflow, der diese drei Schritte unter einem stabilen Namen kapselt und sich per CLI, systemd oder cron ausführen lässt.
Statt fragmentierter Skripte, impliziten Abhängigkeiten und veralteten README-Dateien hast du jetzt:
- Einen versionierten Workspace, der die Realität deiner Systeme beschreibt.
- Containerisierte Ausführung, die Abhängigkeiten und Team-Inkonsistenzen eliminiert.
- Die Möglichkeit, solche Blöcke im Unternehmen oder über Registries zu teilen – damit andere Teams denselben Standard nutzen können.
Bei ayedo arbeiten wir täglich mit Teams, die genau diesen Schritt gehen: von Ad-hoc-Automatisierung hin zu wiederverwendbaren, nachvollziehbaren Betriebsprozessen. Ob du gerade deine ersten Ansible-Playbooks strukturierst oder bestehende Runbooks in Code gießen willst – wir unterstützen dich dabei, ohne deine bestehende Umgebung über den Haufen zu werfen.
Wenn du sehen möchtest, wie ein solcher Workflow in deiner Umgebung aussehen kann – mit deinen Hosts, deinen Compliance-Anforderungen und deinen Toolchains – findest du passende Formate und den nächsten Schritt auf der Workshop-Übersicht (z. B. Operations-Automatisierung Demos).