TL;DR
- Sie erstellen in diesem Beitrag einen vollständigen Polycrate-Block für eine eigene Kubernetes-App – inklusive
block.poly, Ansible-Playbook und drei Kubernetes-Templates für Deployment, Service und Ingress. block.configdient als Single Source of Truth für Image, Replikas, Namespace und Domain; der Upgrade-Workflow reduziert sich auf: Image-Tag im Workspace ändern,polycrate run myapp installausführen, fertig.- Dank Container-Ausführung von Polycrate brauchen Sie lokal kein Ansible, kein Python, kein
kubectl– die komplette Toolchain wird im Container bereitgestellt und ist für das ganze Team identisch. - Über das Block-Modell mit Actions
install,uninstallundstatusbekommen Sie ein sauberes, wiederverwendbares Interface statt lose verteilter Playbooks; der Block kann versioniert und in einer OCI-Registry geteilt werden. - ayedo unterstützt Teams mit erprobten Kubernetes-Lösungen, Workshops und Best Practices rund um Polycrate und Ansible – von der ersten App bis zu umfassenden Plattformen.
Warum ein eigener Kubernetes-Block sinnvoll ist
Viele Kubernetes-Teams starten mit Helm-Charts und ein paar YAML-Dateien im Git-Repo. Spätestens wenn mehrere interne Services, unterschiedliche Umgebungen und Compliance-Anforderungen dazukommen, wird es unübersichtlich:
- Jede App hat ihre eigene Ordnerstruktur und Konventionen.
- Variablen wie Image, Replikas oder Domain sind über mehrere Dateien verteilt.
- Neue Kolleg:innen brauchen viel Kontext, um „das richtige“ Manifest-Set zu finden.
- Automatisierung hängt am lokalen Setup: Python-Version,
kubectl, Ansible, Auth-Tools.
Mit Polycrate bringen Sie Ordnung in diese Automatisierung, ohne auf Ansible oder bekannte Kubernetes-Patterns zu verzichten:
- Guardrails durch das Block-Modell: Jede App wird zu einem Block mit definierten Actions (
install,uninstall,status). Kein „Playbook-Wildwuchs“, sondern ein klares Interface. - Sharable Automation: Was Sie für Ihre interne App bauen, können Sie später als versionierten Block über eine OCI-Registry teilen – oder im PolyHub veröffentlichen, wenn es über den internen Bedarf hinausgeht.
- Dependency-Problem gelöst: Ansible, Python,
kubectl,kubernetes.core-Collection – alles läuft im Polycrate-Container. Keine lokal installierten Tools, keine Version-Hölle.
Ein eigener Block lohnt sich immer dann, wenn:
- Ihre App (noch) nicht als offizieller Block im PolyHub existiert.
- Sie einen internen Service (z. B. „billing“, „customer-portal“, „reporting“) wiederholbar auf verschiedenen Clustern deployen wollen.
- Sie ein standardisiertes Interface für Betriebsteams oder andere Abteilungen bereitstellen möchten:
polycrate run myapp installstatt „lies bitte die README und ruf diese fünfkubectl-Kommandos auf“.
In diesem Beitrag bauen wir genau so einen Block – komplett, von der Struktur bis zum Registry-Push.
Ausgangsszenario: Interne App „myapp“ im Kubernetes-Cluster
Unser Beispiel:
- Firma: ACME Corp.
- Workspace:
acme-corp-automation - App:
myapp, ein interner Webservice (HTTP auf Port 8080) - Cluster: Bereits vorhanden, kubeconfig liegt lokal vor
- Domain:
myapp.acme-corp.com - Ziel: Ein Polycrate-Block
myapp-k8s, den wir mit
polycrate run myapp install
für verschiedene Cluster/Umgebungen nutzen können.
Wichtig: Wir verwenden das Ansible-Modul kubernetes.core.k8s, das direkt mit der Kubernetes-API spricht. Das Playbook läuft innerhalb des Polycrate-Containers mit hosts: localhost und connection: local. Es wird also nichts im Container selbst installiert, sondern nur via API im Cluster geändert.
Die Details zur Kubernetes-Integration finden Sie auch in der offiziellen Dokumentation:
https://docs.ayedo.de/polycrate/kubernetes/
Workspace vorbereiten
Zuerst definieren wir unseren Workspace und binden dort den Block ein. Die workspace.poly liegt im Root-Verzeichnis Ihres Git-Repos:
# workspace.poly
name: acme-corp-automation
organization: acme
blocks:
- name: myapp
from: registry.acme.corp/blocks/myapp-k8s:0.1.0
config:
image: "registry.acme-corp.com/myapp"
image_tag: "1.0.0"
replicas: 2
namespace: "apps"
domain: "myapp.acme-corp.com"
Ein paar Hinweise:
from:nutzt die Registry-Notation (<registry>/<pfad>:<version>).registry.acme.corpist hier nur ein fiktives Beispiel; in der Praxis ziehen Sie den Block z. B. mitpolycrate blocks pull …oder aus Ihrer OCI-Registry.- Unter
config:geben wir App-spezifische Werte an. Diese landen alsblock.config.*im Block und sind unsere Single Source of Truth. - Image-Versionen sind bewusst im Workspace konfiguriert: So können Sie später pro Umgebung unterschiedliche Tags setzen (z. B.
dev,staging,prod).
Die kubeconfig legen wir – Polycrate-konform – im Workspace unter artifacts/secrets/kubeconfig.yml ab. Im Workspace-Repository liegt typischerweise nur Konfiguration und Secrets – kein eingechecktes blocks/myapp-k8s/, wenn der Block aus der Registry kommt:
acme-corp-automation/
workspace.poly
artifacts/
secrets/
kubeconfig.yml
Polycrate setzt im Action-Container KUBECONFIG auf die Workspace-Kubeconfig; kubectl und Ansible (kubernetes.core) nutzen sie ohne extra Pfadvariable. Sie können den Workspace (inklusive kubeconfig) mit der eingebauten Encryption-Funktion und age verschlüsseln, um Compliance-Anforderungen sauber abzudecken (siehe Workspace-Verschlüsselung) – ganz ohne zusätzliches Tool wie Vault.
Block-Struktur für die Kubernetes-App
So sieht der Block aus – beim lokalen Entwickeln unter blocks/myapp-k8s/ oder im Workspace-Cache nach dem Pull aus der Registry:
blocks/myapp-k8s/
block.poly
install.yml
templates/
deployment.yml.j2
service.yml.j2
ingress.yml.j2
block.polybeschreibt den Block, seine Konfiguration und Actions.install.ymlist das zentrale Ansible-Playbook. Wir nutzen es fürinstall,uninstallundstatus.- Unter
templates/liegen die Jinja2-Templates für die Kubernetes-Manifeste.
block.poly: Interface und Konfiguration definieren
Hier die vollständige block.poly:
# blocks/myapp-k8s/block.poly
name: myapp-k8s
version: 0.1.0
kind: generic
config:
image: "registry.acme-corp.com/myapp"
image_tag: "1.0.0"
replicas: 2
namespace: "apps"
domain: "myapp.acme-corp.com"
actions:
- name: install
playbook: install.yml
- name: uninstall
playbook: install.yml
- name: status
playbook: install.yml
Wichtiges dazu:
config:definiert Default-Werte. Sie werden durchworkspace.blocks[].configüberschrieben. In den Templates und im Playbook greifen wir immer überblock.config.*darauf zu.- Die Actions
install,uninstallundstatusbilden ein Standard-Interface, das sich für alle Kubernetes-Apps anbietet: install: Erzeugt/aktualisiert alle Ressourcen.uninstall: Entfernt alle Ressourcen.status: Zeigt den aktuellen Zustand im Cluster an.- Alle drei Actions nutzen dasselbe Playbook
install.yml. Über die Polycrate-Variableaction.nameunterscheiden wir später im Playbook, welcher Pfad genommen wird.
Dieses Interface ist auch für Betriebsteams wertvoll: egal welche App – das Interface bleibt gleich.
Jinja2-Templates für Deployment, Service und Ingress
Jetzt kommen die Kubernetes-Manifeste. Sie werden als Jinja2-Templates definiert und greifen direkt auf block.config.* zu. So ist block.config unsere Single Source of Truth.
Deployment-Template
# blocks/myapp-k8s/templates/deployment.yml.j2
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: {{ block.config.namespace }}
labels:
app: myapp
spec:
replicas: {{ block.config.replicas }}
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: "{{ block.config.image }}:{{ block.config.image_tag }}"
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
Service-Template
# blocks/myapp-k8s/templates/service.yml.j2
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: {{ block.config.namespace }}
labels:
app: myapp
spec:
type: ClusterIP
selector:
app: myapp
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
Ingress-Template
# blocks/myapp-k8s/templates/ingress.yml.j2
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp
namespace: {{ block.config.namespace }}
labels:
app: myapp
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
ingressClassName: nginx
rules:
- host: {{ block.config.domain }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
number: 80
tls:
- hosts:
- {{ block.config.domain }}
secretName: myapp-tls
Sie sehen: Alle variablen Werte (Namespace, Replikas, Domain, Image + Tag) kommen direkt aus block.config. Ein Upgrade wird später einfach, weil wir nur dort drehen müssen.
Ansible-Playbook install.yml mit kubernetes.core.k8s
Jetzt bauen wir das Herzstück: ein Playbook, das je nach Action install, uninstall oder status ausführt.
Wichtig: Das Playbook läuft innerhalb des Polycrate-Containers auf localhost und spricht über die kubernetes.core-Collection mit dem Kubernetes-API-Server. Polycrate setzt KUBECONFIG; die Module brauchen kein explizites kubeconfig: im Task.
# blocks/myapp-k8s/install.yml
- name: Manage myapp Kubernetes resources
hosts: localhost
connection: local
gather_facts: false
vars:
manifest_dir: "/tmp/myapp-k8s"
tasks:
- name: Ensure manifest directory exists (container-local)
ansible.builtin.file:
path: "{{ manifest_dir }}"
state: directory
mode: "0755"
when: action.name in ['install', 'uninstall', 'status']
# INSTALL: Namespace + Manifeste anwenden
- name: Ensure namespace exists
kubernetes.core.k8s:
api_version: v1
kind: Namespace
name: "{{ block.config.namespace }}"
state: present
when: action.name == 'install'
- name: Render Deployment manifest
ansible.builtin.template:
src: "templates/deployment.yml.j2"
dest: "{{ manifest_dir }}/deployment.yml"
mode: "0644"
when: action.name == 'install'
- name: Render Service manifest
ansible.builtin.template:
src: "templates/service.yml.j2"
dest: "{{ manifest_dir }}/service.yml"
mode: "0644"
when: action.name == 'install'
- name: Render Ingress manifest
ansible.builtin.template:
src: "templates/ingress.yml.j2"
dest: "{{ manifest_dir }}/ingress.yml"
mode: "0644"
when: action.name == 'install'
- name: Apply Deployment
kubernetes.core.k8s:
state: present
src: "{{ manifest_dir }}/deployment.yml"
wait: true
wait_timeout: 300
when: action.name == 'install'
- name: Apply Service
kubernetes.core.k8s:
state: present
src: "{{ manifest_dir }}/service.yml"
when: action.name == 'install'
- name: Apply Ingress
kubernetes.core.k8s:
state: present
src: "{{ manifest_dir }}/ingress.yml"
when: action.name == 'install'
# UNINSTALL: Ressourcen entfernen
- name: Delete Ingress
kubernetes.core.k8s:
state: absent
api_version: networking.k8s.io/v1
kind: Ingress
name: "myapp"
namespace: "{{ block.config.namespace }}"
when: action.name == 'uninstall'
- name: Delete Service
kubernetes.core.k8s:
state: absent
api_version: v1
kind: Service
name: "myapp"
namespace: "{{ block.config.namespace }}"
when: action.name == 'uninstall'
- name: Delete Deployment
kubernetes.core.k8s:
state: absent
api_version: apps/v1
kind: Deployment
name: "myapp"
namespace: "{{ block.config.namespace }}"
when: action.name == 'uninstall'
# STATUS: Aktueller Zustand abfragen
- name: Get Deployment status
kubernetes.core.k8s_info:
api_version: apps/v1
kind: Deployment
namespace: "{{ block.config.namespace }}"
name: "myapp"
register: deployment_info
when: action.name == 'status'
- name: Show Deployment status
ansible.builtin.debug:
var: deployment_info.resources[0].status
when:
- action.name == 'status'
- deployment_info.resources | length > 0
Ein paar zentrale Punkte:
- Kubeconfig: Polycrate setzt
KUBECONFIGim Container;kubernetes.corenutzt sie ohnekubeconfig:-Parameter im Task. manifest_dir: Für gerenderte YAML-Dateien ist ein temporäres Verzeichnis unter/tmp/…üblich (verschwindet mit dem Container). Sollen die Manifeste dauerhaft im Workspace landen (z. B. Review, GitOps), verwenden Sie stattdessen z. B.{{ block.artifacts.path }}/…– siehe Artefakte.- Für
install: - Wir erzeugen zunächst den Namespace (idempotent).
- Dann rendern wir die drei Templates in
manifest_dir. - Anschließend wendet
kubernetes.core.k8sdie Dateien an und wartet auf einen „Ready“-Status des Deployments. - Für
uninstallwerden die Ressourcen explizit mitstate: absententfernt. - Für
statusnutzen wirkubernetes.core.k8s_info, um den aktuellen Status zu ermitteln.
Die Variable action.name stellt Polycrate automatisch bereit (siehe Actions-Dokumentation). Damit können Sie bequem in einem Playbook unterschiedliche Pfade steuern.
Den Block ausführen und testen
Mit der obigen Struktur können Sie den Block direkt lokal testen:
# Im Workspace-Root
cd /pfad/zu/acme-corp-automation
# Install: Ressourcen im Cluster erzeugen/aktualisieren
polycrate run myapp install
Polycrate startet nun einen Container mit einer vollständig konfigurierten Toolchain (Ansible, kubernetes.core, Python, ggf. kubectl), mounted den Workspace hinein und führt install.yml mit dem Kontext des Blocks myapp aus.
Weitere Actions:
# Status abfragen
polycrate run myapp status
# Ressourcen wieder entfernen
polycrate run myapp uninstall
Im Gegensatz zu plain Ansible müssen Sie:
- keine
ansible.cfgpflegen, - keine lokale Python-/Ansible-/Collection-Installation synchron halten,
- keine separaten „Deploy-Skripte“ dokumentieren.
Alles ist im Block gekapselt und wird im Container reproduzierbar ausgeführt.
Kurzer Blick: Wie würde das mit plain Ansible aussehen?
Ohne Polycrate würden Sie typischerweise:
- Eine eigene Verzeichnisstruktur definieren (
playbooks/,roles/,group_vars/). - Ansible lokal installieren, inklusive
kubernetes.core-Collection. - Entscheiden, wie Sie
kubeconfigverteilen und schützen (Polycrate setztKUBECONFIGim Container). - Sich überlegen, wie andere Teams Ihre Playbooks aufrufen sollen:
ansible-playbook install.yml -e env=prod?- separate Skripte pro Environment?
Playbooks teilen bedeutet in der Regel: Git-Repo clonen, lokale Umgebung einrichten, README lesen, manuell Kommandozeilen eintippen.
Mit Polycrate:
- Standard-Interface:
polycrate run myapp install|uninstall|status. - Containerisierte Toolchain: Jedes Teammitglied hat dieselbe Umgebung, ohne Setup-Aufwand.
- Sharable Block: Sie können den Block als OCI-Image in einer Registry speichern und versioniert wiederverwenden.
Ansible bleibt das gleiche starke Werkzeug – Polycrate gibt ihm Struktur, Reproduzierbarkeit und ein klares Packaging-Modell.
Block in die Registry pushen und teilen
Sobald Sie mit dem Ergebnis zufrieden sind, können Sie den Block in eine Registry pushen. Das macht ihn:
- versionierbar (
:0.1.0,:0.2.0, …), - leicht in anderen Workspaces nutzbar,
- optional im PolyHub sichtbar, wenn Sie ihn öffentlich machen möchten.
Push erfolgt mit polycrate blocks push, nicht mit registry push: Sie übergeben den vollständigen Registry-Pfad zum Block (wie bei from:), z. B. cargo.ayedo.cloud/acme/myapp-k8s – nicht den Workspace-Instanznamen myapp. Das OCI-Tag kommt aus version in der block.poly (kein Versions-Suffix im Push-Befehl). Details: CLI-Referenz – polycrate blocks push.
Beispiel: Push in eine OCI-Registry (z. B. cargo.ayedo.cloud):
# Im Workspace-Root, in dem blocks/myapp-k8s liegt (oder --workspace <pfad>)
polycrate blocks push cargo.ayedo.cloud/acme/myapp-k8s
# Kurzform (Alias):
# polycrate push cargo.ayedo.cloud/acme/myapp-k8s
In einem anderen Workspace können Sie diesen Block dann referenzieren:
# workspace.poly in einem anderen Projekt
name: another-workspace
organization: acme
blocks:
- name: myapp-prod
from: cargo.ayedo.cloud/acme/myapp-k8s:0.1.0
config:
image: "registry.acme-corp.com/myapp"
image_tag: "1.0.0"
replicas: 3
namespace: "apps-prod"
domain: "myapp.acme-corp.com"
Wichtig: Versionen immer explizit pinnen (:0.1.0), niemals :latest verwenden. Das ist eine zentrale Best Practice in Polycrate (siehe Best Practices).
Upgrade-Workflow: Neue Image-Version ausrollen
Der wahrscheinlich wichtigste Use Case im Alltag: eine neue Version der App ausrollen.
Mit unserem Setup ist der Workflow bewusst simpel:
- Image-Tag im Workspace anpassen
# workspace.poly (Ausschnitt)
blocks:
- name: myapp
from: registry.acme.corp/blocks/myapp-k8s:0.1.0
config:
image: "registry.acme-corp.com/myapp"
image_tag: "1.1.0" # <-- Neues Tag
replicas: 2
namespace: "apps"
domain: "myapp.acme-corp.com"
- Install-Action erneut ausführen
polycrate run myapp install
Da Ansible und das kubernetes.core.k8s-Modul idempotent arbeiten, wird das Deployment erkannt und mit dem neuen Image-Tag aktualisiert. Sie müssen keine zusätzlichen Flags oder „Upgrade“-Kommandos erfinden – die Idempotenz plus Single Source of Truth erledigen den Rest.
- Optional: Status prüfen
polycrate run myapp status
So behalten Sie im Blick, ob das Deployment tatsächlich so läuft, wie erwartet.
Dieser Ansatz skaliert gut:
- Für unterschiedliche Umgebungen (DEV, STAGE, PROD) definieren Sie einfach mehrere Block-Instanzen mit unterschiedlichen
config-Werten. - Für Rollbacks ändern Sie das Tag zurück und rufen erneut
installauf.
Häufige Fragen
Brauche ich für Kubernetes-Blöcke immer Ansible?
Polycrate unterstützt verschiedene Technologien, aber Ansible ist für Kubernetes-Workloads eine sehr gute Wahl:
- Sie profitieren von der Idempotenz der
kubernetes.core-Module. - Sie können denselben Ansatz auch für andere Aufgaben nutzen (z. B. Linux-/Windows-Server, Cloud-APIs).
- Playbooks bleiben deklarativ und gut lesbar, was besonders für Compliance und Audits wichtig ist.
Wenn Sie heute schon stark mit Ansible arbeiten, ist der Schritt zu Kubernetes-Blöcken mit Polycrate sehr klein – Sie erweitern Ihre Playbooks lediglich um Kubernetes-spezifische Tasks.
Wie gehe ich mit sensiblen Daten wie kubeconfig um?
Polycrate bringt einen eigenen Mechanismus für Workspace-Verschlüsselung mit:
- Dateien unter
artifacts/secrets/– wie unserekubeconfig.yml– können mitageverschlüsselt werden. - Der Schlüssel liegt typischerweise außerhalb des Repos (z. B. in einem separaten Secret-Store).
- Beim Ausführen von Actions entschlüsselt Polycrate die Secrets im Container, sodass sie nicht im Klartext im Git-Repo liegen.
Details dazu finden Sie in der Dokumentation zur Workspace-Verschlüsselung. Sie brauchen dafür kein zusätzliches Vault-Produkt – ein echter Vorteil für Teams, die schnell, aber trotzdem compliant arbeiten möchten.
Kann ich denselben Block für mehrere Cluster und Umgebungen verwenden?
Ja, genau dafür ist das Zusammenspiel von Workspace und Block gedacht:
- Der Block beschreibt wie deployt wird (Templates, Actions, Standard-Konfiguration).
- Der Workspace beschreibt wo und mit welchen Werten deployt wird (Namespace, Domain, Image-Tag, kubeconfig).
Für mehrere Cluster definieren Sie einfach mehrere Workspaces (oder mehrere Block-Instanzen im gleichen Workspace) mit unterschiedlichen kubeconfigs und Config-Werten. Der Block-Code bleibt unverändert.
Weitere Fragen? Siehe unsere FAQ
Von der Theorie zur Umsetzung
Mit dem Block myapp-k8s haben Sie einen vollständigen, wiederverwendbaren Baustein geschaffen:
- Ihre Kubernetes-App ist in einem klar strukturierten Block gekapselt.
block.configdient als Single Source of Truth – Image, Replikas, Namespace und Domain sind zentral definiert.- Über die Actions
install,uninstallundstatusentsteht ein stabiles Interface, das auch Betriebsteams und Compliance-Verantwortliche nachvollziehen können. - Dank der Container-Ausführung von Polycrate läuft alles in einer kontrollierten Umgebung – inklusive Ansible,
kubernetes.coreund allen Abhängigkeiten. Lokale Setups werden deutlich einfacher.
In vielen Organisationen ist dieser erste Block der Auftakt zu einer breiteren Automatisierungsstrategie:
- Weitere Services erhalten denselben Standard (
install/uninstall/status). - Gemeinsame Patterns werden in interne Block-Bibliotheken ausgelagert und über eine Registry verteilt.
- Compliance-Anforderungen lassen sich besser nachweisen, weil Deployments reproduzierbar und versioniert sind.
Als ayedo begleiten wir Teams genau auf diesem Weg – von den ersten Schritten mit einem einzelnen Kubernetes-Service bis hin zu umfassenden Plattform- und Automatisierungs-Landschaften. In unseren Workshops zeigen wir praxisnah, wie Sie:
- vorhandene Helm-Charts, YAML-Stacks und Ansible-Playbooks in Polycrate-Blöcke überführen,
- ein konsistentes Block-Design für Ihre Services etablieren,
- Registry-Workflows, Workspace-Verschlüsselung und Team-Kollaboration sauber aufsetzen.
Wenn Sie Ihre eigenen Kubernetes-Apps als Polycrate-Blöcke strukturieren und dabei von erprobten Best Practices profitieren möchten, ist unser Kubernetes-Block Workshop ein guter nächster Schritt:
Kubernetes-Block Workshop