TL;DR
- Helm-Charts direkt per CLI zu deployen funktioniert – aber erst mit Ansible und Polycrate werden Deployments wirklich idempotent, versioniert und teamfähig.
block.configmacht deine Helm-Values zum zentralen, versionierten Konfigurationspunkt – inklusive Jinja2-Template, das komplexevalues.yaml-Strukturen sauber generiert.- Über Ansible-Module wie
kubernetes.core.helm_repository,kubernetes.core.helm,kubernetes.core.helm_rollbackbekommst du Upgrade-, Diff- und Rollback-Logik als wiederverwendbare Actions in einem Polycrate-Block. - Polycrate löst das Dependency-Problem: Helm,
kubectl, Python, Ansible-Collections laufen im Container – keine lokalen Installationsorgien oder Versionskonflikte, Workspaces können verschlüsselt werden. - ayedo unterstützt Teams mit erprobten Patterns, Tooling und Workshops rund um Helm, Ansible und Polycrate – inklusive maßgeschneiderten Kubernetes-Lösungen.
Warum Helm über Ansible und Polycrate?
Helm ist das Standardwerkzeug, um komplexe Anwendungen auf Kubernetes zu deployen. Viele Teams starten mit:
helm repo add bitnami https://charts.bitnami.com/bitnami
helm upgrade --install postgres bitnami/postgresql -f values-prod.yaml
Solange ein einzelner Admin sein Cluster verwaltet, ist das okay. Spätestens wenn mehrere Umgebungen, mehrere Personen und Compliance-Anforderungen dazukommen, tauchen typische Probleme auf:
- Wo liegt eigentlich die gültige
values.yamlfürprod? - Wer hat wann welche Version des Charts deployed?
- Wie mache ich einen strukturierten Rollback, ohne in Shell-Historys zu suchen?
- Wie stelle ich sicher, dass alle Kolleg:innen dieselbe Helm/Ansible-Version nutzen?
Genau hier spielt die Kombination aus Ansible und Polycrate ihre Stärken aus:
- Ansible bringt Idempotenz, modulare Tasks und API-Integrationen (z. B.
kubernetes.core.helm). - Polycrate gibt Ansible eine Struktur über das Block-Modell und löst das Dependency-Problem durch Container-Ausführung.
block.configmacht deine Helm-Values zu sauber versionierter Konfiguration, die sich über Workspaces, Teams und sogar via OCI-Registry teilen lässt.
In diesem Beitrag baust du einen vollständigen Polycrate-Block, der ein PostgreSQL Helm-Chart deployt – inklusive:
- Jinja2-Values-Template
- Install/Upgrade-Action
- Diff-Action per
dry_run - Rollback-Action
Und wir schauen ehrlich darauf, wann du trotzdem Helm direkt nutzen solltest.
Architektur: Helm über Ansible im Polycrate-Workspace
Wir nehmen als Ausgangspunkt einen Workspace:
# workspace.poly
name: acme-corp-automation
organization: acme
blocks:
- name: postgres
from: registry.acme-corp.com/acme/helm/postgres-helm:0.1.0
config:
namespace: "databases-prod"
chart_version: "12.1.2"
postgres:
storage_size: "50Gi"
Wichtige Punkte:
from:verweist auf einen Block in einer OCI-Registry (hier fiktivregistry.acme-corp.com/...; öffentlich z. B.cargo.ayedo.cloudoder PolyHub). Nachpolycrate blocks pullliegt der Block unterblocks/registry.acme-corp.com/acme/helm/postgres-helm/– die Version ist imfrom:gepinnt (:0.1.0).- Die
configunter dem Block-Eintrag überschreibt Defaults ausblock.poly– so kannst du denselben Block z. B. fürdev,stage,prodmit jeweils anderen Werten nutzen. - Die
workspace.poly-Struktur folgt den Workspaces-Best Practices.
Für den Kubernetes-Zugriff legen wir die Kubeconfig in den Workspace:
artifacts/secrets/kubeconfig.yml
Polycrate lädt Dateien unter artifacts/secrets/ automatisch in workspace.secrets. Sensible Inhalte kannst du mit der integrierten Workspace-Verschlüsselung schützen, siehe Workspace-Verschlüsselung. Kein kubeconfig_path in workspace.poly oder block.poly nötig: Polycrate setzt im Action-Container KUBECONFIG und K8S_AUTH_KUBECONFIG auf die Workspace-Kubeconfig; kubernetes.core.helm* und andere Kubernetes-Module nutzen das automatisch.
Der postgres-helm Block: Konfiguration und Actions
Unser Block liegt unter blocks/registry.acme-corp.com/acme/helm/postgres-helm/. Die block.poly definiert Konfiguration und Actions (name = vollständiger Registry-Pfad ohne Tag):
# blocks/registry.acme-corp.com/acme/helm/postgres-helm/block.poly
name: registry.acme-corp.com/acme/helm/postgres-helm
version: 0.1.0
kind: generic
description: "Deploys a PostgreSQL Helm chart via Ansible and kubernetes.core modules"
config:
helm_release_name: "acme-postgres"
namespace: "databases"
chart_repo_name: "bitnami"
chart_repo_url: "https://charts.bitnami.com/bitnami"
chart_name: "postgresql"
chart_version: "12.1.2"
postgres:
username: "app"
database: "appdb"
storage_size: "10Gi"
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
actions:
- name: install
description: "Install or upgrade PostgreSQL release"
playbook: install.yml
- name: upgrade
description: "Upgrade PostgreSQL Helm release to configured chart_version"
playbook: upgrade.yml
- name: rollback
description: "Rollback PostgreSQL Helm release to previous revision"
playbook: rollback.yml
- name: diff
description: "Show diff of pending changes for PostgreSQL Helm release"
playbook: diff.yml
Wichtige Details:
- Chart-Parameter (
chart_repo_url,chart_version,postgres.*) sitzen inconfigund sind damit: - versioniert im Git-Repo
- überschreibbar pro Block-Instanz im Workspace
- verwendbar in Jinja2-Templates und Ansible-Playbooks
Über das Block-Modell verhindert Polycrate den typischen Playbook-Wildwuchs, den viele Teams mit plain Ansible erleben. Alles, was zu diesem Chart gehört, sitzt in einem Block: block.poly, Playbooks, Templates.
Jinja2-Template für komplexe Helm-Values
Statt eine statische values.yaml pro Umgebung zu pflegen, generieren wir sie aus block.config. Das Template liegt im Block:
# blocks/registry.acme-corp.com/acme/helm/postgres-helm/templates/values.yml.j2
global:
postgresql:
auth:
username: "{{ block.config.postgres.username }}"
database: "{{ block.config.postgres.database }}"
primary:
persistence:
size: "{{ block.config.postgres.storage_size }}"
resources:
requests:
cpu: "{{ block.config.postgres.resources.requests.cpu }}"
memory: "{{ block.config.postgres.resources.requests.memory }}"
limits:
cpu: "{{ block.config.postgres.resources.limits.cpu }}"
memory: "{{ block.config.postgres.resources.limits.memory }}"
Damit erreichst du:
- Alle Helm-Values sind zentral in
block.configund ggf.workspace.blocks[].configdefiniert. - Das Template kann beliebig komplex werden (verschachtelte Strukturen, Bedingungen, Loops).
- Änderungen an der Konfiguration sind Git-diffbar und nachvollziehbar.
Mit plain Helm würdest du typischerweise values-dev.yaml, values-prod.yaml und Kopien davon verwalten – oft mit Copy&Paste-Abweichungen, die niemand mehr im Blick hat.
Install-Playbook: Helm-Repo und Chart-Deployment
Die Ansible-Module aus kubernetes.core sprechen das Kubernetes-API an. Da es sich um API-Calls handelt, ist hier hosts: localhost mit connection: local korrekt – der Code läuft im Polycrate-Container, nicht auf einem Remote-Host.
# blocks/registry.acme-corp.com/acme/helm/postgres-helm/install.yml
- name: Install or upgrade PostgreSQL Helm release
hosts: localhost
connection: local
gather_facts: false
vars:
release_name: "{{ block.config.helm_release_name }}"
namespace: "{{ block.config.namespace }}"
chart_repo_name: "{{ block.config.chart_repo_name }}"
chart_repo_url: "{{ block.config.chart_repo_url }}"
chart_name: "{{ block.config.chart_name }}"
chart_version: "{{ block.config.chart_version }}"
values_file: "{{ block.artifacts.path }}/{{ release_name }}-values.yml"
tasks:
- name: Ensure Helm repository is configured
kubernetes.core.helm_repository:
name: "{{ chart_repo_name }}"
repo_url: "{{ chart_repo_url }}"
state: present
- name: Render Helm values from template
ansible.builtin.template:
src: "templates/values.yml.j2"
dest: "{{ values_file }}"
- name: Install or upgrade PostgreSQL Helm release
kubernetes.core.helm:
name: "{{ release_name }}"
chart_ref: "{{ chart_repo_name }}/{{ chart_name }}"
release_namespace: "{{ namespace }}"
chart_version: "{{ chart_version }}"
values_files:
- "{{ values_file }}"
create_namespace: true
wait: true
atomic: true
state: present
Gerenderte Values landen unter {{ block.artifacts.path }} (typisch artifacts/blocks/<block-name>/), nicht unter einem festen /workspace/-Pfad – siehe Artefakte und Best Practices.
Einmal gebaut, läuft das mit einem simplen Polycrate-Aufruf:
polycrate run postgres install
Im Hintergrund startet Polycrate einen Container mit einer konsistenten Toolchain (Ansible, Python, kubectl, Helm – konfigurierbar per Dockerfile), wie in der Ansible-Integration beschrieben. Kubeconfig: Polycrate setzt KUBECONFIG / K8S_AUTH_KUBECONFIG – die kubernetes.core.helm*-Module brauchen kein kubeconfig: pro Task. Kein pip install, kein helm-Binary-Chaos, keine globalen Python-Interpreter – das löst das klassische Dependency-Problem von Automatisierungs-Stacks.
Mit plain Ansible müsstest du im Team:
- Ansible und
kubernetes.coreauf allen Laptops/Runnern installieren. ansible.cfgund Python-Umgebungen synchron halten.- Helm selbst installieren oder Scripts schreiben, die das übernehmen.
Polycrate nimmt dir das ab und sorgt dafür, dass die Actions überall identisch laufen.
Upgrade-Workflow: Chart-Version in block.config, Action ausführen
Ein Upgrade ist aus Sicht von Helm nur ein weiteres helm upgrade. Wir modellieren das als eigene Action:
# blocks/registry.acme-corp.com/acme/helm/postgres-helm/upgrade.yml
- name: Upgrade PostgreSQL Helm release to configured chart_version
hosts: localhost
connection: local
gather_facts: false
vars:
release_name: "{{ block.config.helm_release_name }}"
namespace: "{{ block.config.namespace }}"
chart_repo_name: "{{ block.config.chart_repo_name }}"
chart_repo_url: "{{ block.config.chart_repo_url }}"
chart_name: "{{ block.config.chart_name }}"
chart_version: "{{ block.config.chart_version }}"
values_file: "{{ block.artifacts.path }}/{{ release_name }}-values.yml"
tasks:
- name: Ensure Helm repository is configured
kubernetes.core.helm_repository:
name: "{{ chart_repo_name }}"
repo_url: "{{ chart_repo_url }}"
state: present
- name: Render Helm values from template
ansible.builtin.template:
src: "templates/values.yml.j2"
dest: "{{ values_file }}"
- name: Upgrade PostgreSQL Helm release
kubernetes.core.helm:
name: "{{ release_name }}"
chart_ref: "{{ chart_repo_name }}/{{ chart_name }}"
release_namespace: "{{ namespace }}"
chart_version: "{{ chart_version }}"
values_files:
- "{{ values_file }}"
create_namespace: true
wait: true
atomic: true
state: present
Der Upgrade-Workflow in der Praxis:
- Du passt die Chart-Version in
block.polyoder im Workspace an, z. B.:
# workspace.poly – Ausschnitt
blocks:
- name: postgres
from: registry.acme-corp.com/acme/helm/postgres-helm:0.1.0
config:
chart_version: "12.2.0"
- Commit & Push – die Änderung ist damit nachvollziehbar versioniert.
- Upgrade ausführen:
polycrate run postgres upgrade
Du kombinierst damit:
- Versionierung der Chart-Version über Git.
- Reproduzierbare Ausführung über Polycrate (Container + Block).
- Idempotente Upgrade-Logik über Ansible.
Möchtest du diesen Block mit anderen Teams teilen? Push ihn in eine OCI-Registry, z. B.:
registry.acme-corp.com/acme/helm/postgres-helm:0.1.0
(Öffentlich oder gehostet z. B. cargo.ayedo.cloud/....) Über die Registry-Dokumentation und PolyHub kannst du solche Blöcke team- oder organisationsweit teilen. Das ist Sharable Automation statt lokalem Helm-Skript.
Diff-Action: Was würde sich ändern?
Bevor du ein Upgrade durchführst, willst du oft wissen: Was ändert sich konkret? Dafür nutzen wir dry_run:
# blocks/registry.acme-corp.com/acme/helm/postgres-helm/diff.yml
- name: Show pending changes for PostgreSQL Helm release
hosts: localhost
connection: local
gather_facts: false
vars:
release_name: "{{ block.config.helm_release_name }}"
namespace: "{{ block.config.namespace }}"
chart_repo_name: "{{ block.config.chart_repo_name }}"
chart_repo_url: "{{ block.config.chart_repo_url }}"
chart_name: "{{ block.config.chart_name }}"
chart_version: "{{ block.config.chart_version }}"
values_file: "{{ block.artifacts.path }}/{{ release_name }}-values.yml"
tasks:
- name: Ensure Helm repository is configured
kubernetes.core.helm_repository:
name: "{{ chart_repo_name }}"
repo_url: "{{ chart_repo_url }}"
state: present
- name: Render Helm values from template
ansible.builtin.template:
src: "templates/values.yml.j2"
dest: "{{ values_file }}"
- name: Run Helm dry-run to show diff
kubernetes.core.helm:
name: "{{ release_name }}"
chart_ref: "{{ chart_repo_name }}/{{ chart_name }}"
release_namespace: "{{ namespace }}"
chart_version: "{{ chart_version }}"
values_files:
- "{{ values_file }}"
dry_run: true
state: present
Ausführung:
polycrate run postgres diff
Die Ausgabe zeigt dir, was Helm ändern würde, ohne etwas zu deployen. Du kannst das in Logs archivieren, an Auditor:innen weitergeben oder als Voraussetzung für ein manuelles Approval nutzen.
Rollback-Action: kubernetes.core.helm_rollback
Wenn ein Upgrade schiefgeht, möchtest du möglichst wenig nachdenken müssen. Die Rollback-Action kapselt das in einem Befehl:
# blocks/registry.acme-corp.com/acme/helm/postgres-helm/rollback.yml
- name: Rollback PostgreSQL Helm release
hosts: localhost
connection: local
gather_facts: false
vars:
release_name: "{{ block.config.helm_release_name }}"
namespace: "{{ block.config.namespace }}"
tasks:
- name: Rollback to previous revision
kubernetes.core.helm_rollback:
name: "{{ release_name }}"
namespace: "{{ namespace }}"
Ausführung:
polycrate run postgres rollback
Ohne Polycrate/Ansible würdest du typischerweise:
helm historyaufrufen,- eine Revision auswählen,
helm rollback postgres 12von Hand tippen.
Mit Polycrate wird das zu einer Action, die:
- als Code dokumentiert ist,
- im Team geteilt werden kann,
- in Pipelines genauso funktioniert wie auf der Admin-Workstation.
Wann Helm direkt, wann via Ansible und Polycrate?
Helm direkt von der CLI ist weiterhin ein wichtiges Werkzeug. Eine ehrliche Abwägung:
Helm direkt ist sinnvoll, wenn:
- du lokal ein neues Chart ausprobierst oder debuggen möchtest,
- eine Person ad-hoc in einem Test-Cluster etwas ändert,
- du sehr kleine, einfache Deployments ohne Teamkontext managst.
Helm via Ansible in Polycrate ist im Vorteil, wenn:
- mehrere Umgebungen (dev/stage/prod) mit je eigenen Values existieren,
- mehrere Personen Deployments durchführen und nachvollziehbar sein muss, wer was wann gemacht hat,
- du wiederverwendbare, versionierte Bausteine brauchst (z. B. ein „Standard-Postgres“ für alle Teams),
- Compliance-Anforderungen (z. B. in regulierten Branchen) verlangen, dass Kubeconfigs verschlüsselt liegen und Deployments auditierbar sind.
Polycrate bringt dazu:
- Containerisierte Ausführung (keine lokalen Helm/Ansible-Installationen).
- Eingebaute Workspace-Verschlüsselung mit age – ohne externe Tools wie Vault.
- Eine gute UX über Actions (
polycrate run postgres install) statt langer Ansible-CLI-Befehle. - Ein Block-Modell, das Helm-Deployments strukturiert und als wiederverwendbare Bausteine verfügbar macht.
Mehr dazu findest du in den Best Practices für Blocks und den Best Practices zur Nutzung von Polycrate.
Häufige Fragen
Brauche ich noch ein lokal installiertes Helm, wenn ich Helm über Polycrate nutze?
Für automatisierte Deployments via Polycrate: nein. Polycrate führt Ansible-Playbooks in einem Container aus, der Helm, kubectl, Python und die benötigten Collections enthält. Du musst auf deiner Workstation nur Polycrate bereitstellen, nicht Helm selbst.
Für lokale Experimente, Debugging oder schnelles Ausprobieren eines neuen Charts ist ein lokales Helm aber weiterhin praktisch. Viele Teams nutzen beides: Lokal Helm-CLI, in Automatisierung und CI/CD Ansible+Polycrate.
Wie gehe ich mit sensiblen Werten wie Passwörtern um?
Konfigurationswerte wie Benutzername, Datenbankname oder Ressourcenlimits können problemlos in block.config liegen. Für Passwörter solltest du einen anderen Weg wählen:
- Lege sie als K8s-Secret an, das dein Chart konsumiert.
- Oder speichere sie in
artifacts/secrets/und greife überworkspace.secrets[...]zu. - Verschlüssele den Workspace mit Polycrate (siehe Workspace-Verschlüsselung), damit Kubeconfigs und Secret-Dateien im Git-Repo geschützt sind.
Das Schöne: Du brauchst keinen externen Vault, wenn du ein leichtgewichtiges, aber sicheres Setup möchtest – Polycrate bringt die nötige Verschlüsselung schon mit.
Kann ich denselben Block für mehrere Cluster und Stages nutzen?
Ja. Du definierst pro Umgebung einen eigenen Block-Eintrag in workspace.poly mit eigener config – derselbe Block-Typ aus der Registry, mit gepinntem from::
blocks:
- name: postgres-dev
from: registry.acme-corp.com/acme/helm/postgres-helm:0.1.0
config:
namespace: "databases-dev"
chart_version: "12.1.2"
- name: postgres-prod
from: registry.acme-corp.com/acme/helm/postgres-helm:0.1.0
config:
namespace: "databases-prod"
chart_version: "12.2.0"
Die Logik (Playbooks, Template) bleibt gleich; Namespace, Chart-Version und Ressourcen unterscheiden sich pro Instanz. Pro Workspace gibt es genau eine Kubeconfig (artifacts/secrets/kubeconfig.yml) – Polycrate integriert sie automatisch für Ansible. Zwei Einträge wie oben sind sinnvoll für dev vs. prod im selben Cluster (andere Namespaces). Für getrennte Cluster nutzt du typischerweise eigenen Workspace pro Cluster mit eigener kubeconfig, kannst aber denselben Registry-Block in jedem Workspace referenzieren.
Weitere Fragen? Siehe unsere FAQ
Von der Theorie zur Umsetzung
Mit dem PostgreSQL-Beispiel-Block hast du gesehen, wie sich Helm-Deployments in einen strukturierten, wiederverwendbaren Baustein verwandeln:
- Die Chart-Konfiguration lebt in
block.configund ist damit versioniert und teamfähig. - Ein Jinja2-Template erzeugt eine vollständige
values.yamlaus diesem Config-Modell. - Aktionen wie Install, Upgrade, Diff und Rollback werden zu klar benannten, einfach auszuführenden Polycrate-Actions.
- Dank containerisierter Ausführung und integrierter Workspace-Verschlüsselung bleiben Abhängigkeiten beherrschbar und sensible Daten geschützt.
Aus Sicht von Platform- und Kubernetes-Teams ist das ein wichtiger Schritt: Weg von individuell gepflegten Helm-Skripten, hin zu wiederverwendbaren, per Registry teilbaren Blöcken, die andere Teams sofort nutzen können – oder die in einer zentralen Block-Bibliothek (intern oder über PolyHub) bereitstehen.
ayedo unterstützt genau diesen Weg: von ersten Helm-Deployments über strukturierte Polycrate-Workspaces bis hin zu unternehmensweiten Automatisierungsbibliotheken. In unseren Projekten kombinieren wir Ansible, Polycrate und Kubernetes-Lösungen, um wiederverwendbare Bausteine für Datenbanken, Messaging, Monitoring oder Security aufzubauen – inklusive Governance, Compliance und Dokumentation.
Wenn du Helm heute schon einsetzt und den nächsten Schritt hin zu reproduzierbaren, teamfähigen Deployments gehen willst, ist ein gemeinsamer Deep-Dive oft der effizienteste Weg. In unserem Helm-Workshop entwickeln wir mit deinem Team konkrete Blocks, Workspaces und Upgrade-Strategien – direkt an euren realen Charts und Clustern.
Mehr dazu erfährst du im persönlichen Austausch: Helm-Workshop