Polycrate API für Teams: Zentrales Monitoring und Remote-Triggering
TL;DR Die Polycrate API macht aus einzelnen Workspaces eine Team-Plattform: alle Workspaces, Action …
Diese Serie zeigt Schritt für Schritt, wie Ansible mit Polycrate zu einer strukturierten, teilbaren und compliance-fähigen Automatisierungsplattform wird – von den Grundlagen bis zu Enterprise-Szenarien.
community.general.certbot) automatisiert auf einem Linux-Server bereitstellt – inkl. generischer nginx.conf als Jinja2-Template.block.config.* und kann in jedem Workspace mit anderen Werten eingesetzt werden – ohne Code-Kopie oder Wiki-Bastelei.from: cargo.ayedo.cloud/ayedo/infra/nginx-letsencrypt:1.0.0 in workspace.poly) teilst du den Block mit Kolleg:innen: vor dem Push muss name in der block.poly die volle OCI-Referenz ohne Tag sein; polycrate blocks push verwendet genau diesen Namen plus version als Tag – Sharing statt Screenshots.Viele Admins kennen das Szenario: Auf web01.acme-corp.com läuft seit Jahren ein Nginx, die nginx.conf wurde “damals schnell” angepasst, Let’s Encrypt irgendwo mit certbot eingerichtet – und niemand weiß mehr genau, wie.
Dokumentation, wenn überhaupt, liegt in einem Wiki-Eintrag, der längst nicht mehr zur Realität passt. Automatisierung besteht aus einzelnen Shell-Snippets, die nur auf genau diesem Server jemals ausprobiert wurden.
Mit plain Ansible lässt sich das besser machen, aber du kennst die Hürden:
In diesem Beitrag zeige ich dir, wie du aus genau diesem Setup einen wiederverwendbaren Polycrate-Block machst, den deine Kolleg:innen einfach verwenden können – ohne die Implementierung kennen zu müssen.
Polycrate setzt direkt auf Ansible auf, löst aber zwei typische Probleme:
Dependency-Problem:
Ansible läuft in einem Container. Keine lokale Installation, kein Python-Zoo, keine unterschiedlichen Versionsstände im Team. Der Block bringt alles mit, was er braucht.
Sharable Automation:
Dein Nginx-Setup ist kein fragiler Wiki-Artikel mehr, sondern ein versionierter Block, der in einer Registry liegt. Was du baust, können andere sofort nutzen – mit ihren eigenen Domains und Ports.
Wir konzentrieren uns auf einen konkreten Block:
nginx.conf auf Basis eines Jinja2-Templatesblock.config.domainblock.config.emailblock.config.upstream_portAusgangspunkt ist ein bestehender Polycrate-Workspace, z.B.:
# workspace.poly
name: acme-corp-automation
organization: acmeUnser Block liegt in ./blocks/nginx-letsencrypt/ und enthält:
block.polynginx-letsencrypt.yml (Ansible-Playbook)nginx.conf.j2 (Jinja2-Template)So hängen Workspace-Root und Block-Ordner zusammen (Beispiel-Workspace-Name acme-corp-automation):
acme-corp-automation/ # Workspace-Root
├── workspace.poly # Workspace-Konfiguration, u. a. Block-Instanzen
├── inventory.yml # Zentrales Ansible-Inventory (alle Blöcke)
├── blocks/
│ └── nginx-letsencrypt/ # Lokaler Block (Ordnername = Template-Name in from:)
│ ├── block.poly # Block-Definition, Version, config, actions
│ ├── nginx-letsencrypt.yml # Ansible-Playbook (Action deploy)
│ └── nginx.conf.j2 # Jinja2-Template für Nginx
└── … # weitere typische Einträge (z. B. artifacts/, secrets.poly)Später, wenn du den Block für eine Registry mit vollem OCI-name auslieferst, liegt derselbe Inhalt typischerweise unter einem Pfad, der den Registry-Namen spiegelt, z. B. blocks/registry.acme-corp.com/infra/nginx/ (siehe Abschnitt Registry).
name: nginx-letsencrypt
version: 1.0.0
kind: generic
config:
domain: ""
email: ""
upstream_port: 8080
actions:
- name: deploy
playbook: nginx-letsencrypt.ymlWichtige Punkte:
version: 1.0.0 – wir versionieren den Block explizit.config definiert die Parameter, die später im Workspace gesetzt werden:
domain – FQDN wie www.acme-corp.comemail – Kontakt-E-Mail für Let’s Encryptupstream_port – Port des Backends, auf das Nginx proxyt (z.B. eine App auf 8080)actions beschreibt, welche Playbooks verfügbar sind.polycrate run nginx-letsencrypt deploy führen wir das Playbook aus.Weitere Details zur Block-Struktur findest du in den offiziellen Block-Konzepte.
Das Herzstück für Wiederverwendbarkeit ist die Nginx-Konfiguration als Template. Statt fixem Domainnamen und Port verwenden wir die Polycrate-Variablen.
nginx.conf.j2# nginx.conf für {{ block.config.domain }} – generiert durch Polycrate
server {
listen 80;
server_name {{ block.config.domain }};
# HTTP → HTTPS Redirect
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name {{ block.config.domain }};
ssl_certificate /etc/letsencrypt/live/{{ block.config.domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ block.config.domain }}/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Optionales HSTS – bei Bedarf anpassen
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://127.0.0.1:{{ block.config.upstream_port }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Was hier passiert:
{{ block.config.domain }} und {{ block.config.upstream_port }} stammen direkt aus block.config im Block – und werden letztlich im Workspace gesetzt./etc/letsencrypt/live/...).Jetzt verbinden wir alles in einem Playbook. Wichtiger Hinweis in Polycrate: Die Playbooks laufen im Container, aber die Ziel-Hosts sind echte Server aus dem Inventory, nicht localhost.
Im Workspace-Root liegt die inventory.yml (Polycrate setzt ANSIBLE_INVENTORY automatisch):
# inventory.yml
all:
hosts:
web01.acme-corp.com:
ansible_user: ubuntu
ansible_become: truenginx-letsencrypt.yml---
- name: Nginx mit Let's Encrypt bereitstellen
hosts: all
become: true
vars:
domain_name: "{{ block.config.domain }}"
contact_email: "{{ block.config.email }}"
upstream_port: "{{ block.config.upstream_port }}"
pre_tasks:
- name: Domain muss gesetzt sein
ansible.builtin.assert:
that:
- domain_name | length > 0
- contact_email | length > 0
fail_msg: "block.config.domain und block.config.email müssen im Workspace gesetzt sein."
tasks:
- name: APT-Cache aktualisieren (Ubuntu/Debian)
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
- name: Nginx und Certbot installieren
ansible.builtin.apt:
name:
- nginx
- certbot
- python3-certbot
state: present
- name: Standard-Site deaktivieren
ansible.builtin.file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: reload nginx
- name: TLS-Zertifikat von Let's Encrypt holen (Standalone)
community.general.certbot:
email: "{{ contact_email }}"
domains:
- "{{ domain_name }}"
authenticator: standalone
agree_tos: true
installer: none
state: present
register: certbot_result
- name: Certbot-Output anzeigen (Debug)
ansible.builtin.debug:
var: certbot_result
- name: Nginx-Konfiguration deployen
ansible.builtin.template:
src: nginx.conf.j2
dest: "/etc/nginx/sites-available/{{ domain_name }}"
owner: root
group: root
mode: "0644"
notify: reload nginx
- name: Site aktivieren
ansible.builtin.file:
src: "/etc/nginx/sites-available/{{ domain_name }}"
dest: "/etc/nginx/sites-enabled/{{ domain_name }}"
state: link
notify: reload nginx
handlers:
- name: reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
enabled: trueErläuterungen:
hosts: all – alle Hosts aus inventory.yml. Keine connection: local, weil wir echte Server verwalten.community.general.certbot stammt aus der Collection community.general. Polycrate kann diese im Container installieren, ohne dein lokales System zu berühren (siehe Ansible-Integration).standalone-Authenticator:
vars binden wir die Polycrate-Variablen (block.config.*) an Ansible-Variablen, was das Lesen im Playbook vereinfacht.Nach dem Build und polycrate blocks push nutzen Workspaces denselben Block wie in den anderen Beiträgen dieser Reihe: vollständige OCI-Referenz unter cargo.ayedo.cloud (nicht nur der kurze Template-Name).
# workspace.poly
name: acme-corp-automation
organization: acme
blocks:
- name: webserver
from: cargo.ayedo.cloud/ayedo/infra/nginx-letsencrypt:1.0.0
config:
domain: "www.acme-corp.com"
email: "admin@acme-corp.com"
upstream_port: 8080name: webserver ist der Instanzname im Workspace.cargo.ayedo.cloud. Ein vorheriges polycrate blocks pull ist nicht nötig: Fehlt der Block lokal, erkennt Polycrate das beim Aufruf von polycrate run … und fragt, ob der Block aus der Registry automatisch installiert werden soll. Danach liegt die entpackte Struktur unter blocks/cargo.ayedo.cloud/ayedo/infra/nginx-letsencrypt/. In from: steht die vollständige Referenz inkl. Tag (Block Sharing per OCI statt nur lokalem Ordner blocks/nginx-letsencrypt/).config überschreiben wir die Default-Werte aus block.poly.polycrate run webserver deployPolycrate:
inventory.yml aus dem Workspace-Root.block.config.* und führt das Playbook im Container aus.Mit plain Ansible sähe das z.B. so aus:
ansible-playbook -i inventory.yml nginx-letsencrypt.yml \
-e "domain_name=www.acme-corp.com contact_email=admin@acme-corp.com upstream_port=8080"Und du müsstest sicherstellen, dass:
community.general vorhanden istMit Polycrate sind diese Abhängigkeiten Teil des Blocks bzw. des Workspaces und laufen im Container.
Jetzt kommt das Sharing-Argument: Statt einen Wiki-Eintrag zu schreiben, veröffentlichst du deinen Block in einer Registry.
Wichtig: Blöcke mit rein lokalen Namen wie nginx-letsencrypt oder nginx lassen sich nicht in eine Registry pushen. polycrate blocks push erwartet, dass name in der block.poly bereits die vollständige OCI-Referenz ohne Versions-Tag ist (Host und Pfad wie bei einem Container-Image-Namen ohne :tag). Die Version steht separat im Feld version: und wird beim Push zum OCI-Tag.
Angenommen, ihr betreibt eine interne Polycrate-/OCI-Registry unter registry.acme-corp.com.
block.poly für die Registry anpassenVor dem Push trägst du den Registry-Namen ein und versionierst wie gewohnt:
name: registry.acme-corp.com/infra/nginx
version: 1.0.0
kind: generic
config:
domain: ""
email: ""
upstream_port: 8080
actions:
- name: deploy
playbook: nginx-letsencrypt.ymlEmpfehlenswert: Das Block-Verzeichnis spiegelt den Namen, z. B. blocks/registry.acme-corp.com/infra/nginx/ (siehe Best Practices).
polycrate blocks push registry.acme-corp.com/infra/nginxEs gibt nur dieses eine Argument – den Block-Namen exakt wie in block.poly (name, ohne Tag). Kein zweites Argument für „Ziel-URL“; Host, Pfad und Tag leitet Polycrate aus name und version ab.
Was passiert:
block.poly, Playbook, Template) als OCI-Artifact.registry.acme-corp.com/infra/nginx:1.0.0 in eurer Registry (name + version als Tag).version in der block.poly (z. B. 1.1.0) und pushst erneut.Wenn andere den Block einbinden, referenzieren sie ihn mit from: inklusive Tag – nach Best Practices pinnt man die Block-Version beim Instanziieren im Workspace explizit, z. B. from: registry.acme-corp.com/infra/nginx:1.0.0 (siehe Registry-Dokumentation).
Dein Kollege hat einen anderen Workspace, z.B. für ein internes Portal. Er möchte denselben Nginx-/Let’s-Encrypt-Block nutzen, aber mit anderen Werten.
# workspace.poly im Workspace des Kollegen
name: acme-portal-automation
organization: acme
blocks:
- name: portal-web
from: registry.acme-corp.com/infra/nginx:1.0.0
config:
domain: "portal.acme-corp.com"
email: "ops@acme-corp.com"
upstream_port: 9000Er muss weder:
Er setzt nur die Konfiguration.
polycrate run portal-web deployBeim ersten Aufruf erkennt Polycrate, dass der Block registry.acme-corp.com/infra/nginx:1.0.0 noch nicht lokal installiert ist, und fragt:
Block 'registry.acme-corp.com/infra/nginx:1.0.0' ist nicht installiert.
Möchten Sie den Block jetzt aus der Registry ziehen? [y/N]Mit y zieht Polycrate den Block, legt ihn im Workspace an und führt die Action aus. Ab diesem Punkt ist der Webserver-Block Teil seines Workspaces – vollständig versioniert und testbar.
Was vorher ein Wiki-Eintrag mit “Bitte so machen” war, ist jetzt ein Block mit:
block.config.*Nein. Polycrate führt Ansible immer im Container aus. Der Container enthält:
community.general für certbot)Du brauchst lokal nur Polycrate und Zugang zur Registry. Das eliminiert das typische Dependency-Problem mit unterschiedlichen Python-/Ansible-Versionen auf Entwickler- und Admin-Maschinen.
Das Block-Modell ist exakt dafür gemacht:
nginx-letsencrypt).config-Werten, z.B.:blocks:
- name: web-prod
from: registry.acme-corp.com/infra/nginx:1.0.0
config:
domain: "www.acme-corp.com"
email: "admin@acme-corp.com"
upstream_port: 8080
- name: web-staging
from: registry.acme-corp.com/infra/nginx:1.0.0
config:
domain: "staging.acme-corp.com"
email: "admin@acme-corp.com"
upstream_port: 8081Du führst dann z.B. polycrate run web-staging deploy aus. Das Ansible-Playbook bleibt unverändert; nur die Parameter unterscheiden sich.
Der Block selbst enthält nur:
block.poly)Vertrauliche Daten wie Passwörter gehören in den Workspace – z.B. in verschlüsselte Secrets. Polycrate unterstützt dich hier mit integrierter Workspace-Verschlüsselung auf Basis von age (siehe Workspace-Verschlüsselung).
Du kannst also:
Weitere Fragen? Siehe unsere FAQ
Mit diesem Beispiel hast du gesehen, wie du aus einer einmaligen Server-Konfiguration eine wiederverwendbare, versionierte Automatisierung machst:
block.config.domain, block.config.email und block.config.upstream_portGenau hier liegt die Stärke von Polycrate in heterogenen Umgebungen: Du kannst bewährte Setups – ob Webserver, Windows-Policies oder IoT-Deployments – als strukturierte Blöcke kapseln, im Team teilen und über Workspaces sicher betreiben. Die Guardrails des Block-Modells verhindern Playbook-Wildwuchs, die Container-Ausführung löst das Dependency-Problem, und die Registry macht aus Einzelwissen gemeinsame Infrastruktur.
ayedo unterstützt Teams dabei, diese Art von wiederverwendbaren Bausteinen systematisch aufzubauen: vom Design der Block-Schnittstellen über die Einrichtung der Registry bis zur Integration in bestehende CI/CD- und Compliance-Prozesse. Wenn du sehen möchtest, wie ein solcher Webserver-Block in deiner Umgebung konkret aussehen kann, führt der nächste Schritt über unsere Webserver-Block Demo
TL;DR Die Polycrate API macht aus einzelnen Workspaces eine Team-Plattform: alle Workspaces, Action …
TL;DR Polycrate protokolliert nicht nur Action Runs (Ansible-Playbooks), sondern auch SSH-Sessions, …
TL;DR Das Model Context Protocol (MCP) ist ein offener Standard: KI-Clients sprechen per JSON-RPC …