The Polycrate Ecosystem: PolyHub, API, MCP, and the Future of Automation
TL;DR Polycrate is more than just a CLI tool: With PolyHub, an API platform, and MCP, it forms an …
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.
cargo.ayedo.cloud into your workspace and used without a local Ansible setup.workspace.poly and executing a few polycrate commands – including clean Kubeconfig handling and versioned blocks.:0.2.2 instead of :latest) is mandatory in production, and how to leverage the extensive ecosystem on PolyHub for your own workspaces.If you’ve ever set up an ingress stack manually with plain Ansible or Helm, you know the pattern:
With Polycrate and PolyHub, you reverse the principle: Instead of modeling everything yourself, you start with ready-made, tested building blocks.
PolyHub at https://hub.polycrate.io is a registry of Polycrate blocks, stored as OCI images in cargo.ayedo.cloud – similar to container images on Docker Hub, but specifically for automation. For Kubernetes, you’ll find among others:
cargo.ayedo.cloud/ayedo/k8s/nginx:* – Ingress Controllercargo.ayedo.cloud/ayedo/k8s/cert-manager:* – TLS Automationcargo.ayedo.cloud/ayedo/k8s/external-dns:* – DNS AutomationThe core ideas behind this:
In this post, we use exactly these building blocks to build a production-ready ingress stack for an example cluster.
We start with a workspace acme-corp-automation. It is the logical unit for your automation – whether you’re managing Linux servers, Windows hosts, or Kubernetes clusters.
A minimal workspace.poly could start like this:
name: acme-corp-automation
organization: acme
config: {}
blocks: []
workflows: []The top-level config field is for workspace/toolchain settings (for example the container image under config.image) – not a free-form bag for arbitrary automation variables; those belong in block config or secrets.poly. See Configuration. The empty config: {} here is only a placeholder until you set an image, for example.
Important for Kubernetes: The Kubeconfig of your cluster is always stored as a secret file in the workspace in Polycrate:
artifacts/secrets/kubeconfig.ymlThis file is treated as a secret by Polycrate and can be protected with the built-in workspace encryption, see Workspace Encryption.
To activate encryption, simply run on the CLI:
polycrate workspace encryptYou don’t need an external vault – Polycrate uses age internally and integrates it into your workflow execution, which often significantly simplifies compliance requirements.
The official ayedo blocks for Kubernetes apps are available as OCI images on cargo.ayedo.cloud. You can pull any block into your workspace:
polycrate blocks pull cargo.ayedo.cloud/ayedo/k8s/nginx:0.2.2Here’s what happens:
nginx block in version 0.2.2 from the registry.kubectl, or Helm is necessary – all of this comes from the Polycrate container.Important: The version specification :0.2.2 is not a detail – it is a best practice. In production, you should never use :latest, see also the Best Practices in the Documentation.
Now we integrate the block into our workspace.
In workspace.poly, you declare which block instances you want to use. For our ingress stack, we add three blocks:
name: acme-corp-automation
organization: acme
blocks:
- name: k8s-nginx
from: cargo.ayedo.cloud/ayedo/k8s/nginx:0.2.2
config:
namespace: "ingress-nginx"
ingress_class: "nginx"
- name: k8s-cert-manager
from: cargo.ayedo.cloud/ayedo/k8s/cert-manager:0.3.0
config:
namespace: "cert-manager"
email: "admin@acme-corp.com"
- name: k8s-external-dns
from: cargo.ayedo.cloud/ayedo/k8s/external-dns:0.4.1
config:
namespace: "external-dns"
provider: "route53"
domain_filter: "acme-corp.com"
workflows: []A few important points:
from: always references the full block name including version (:0.2.2).name: is the instance name in the workspace – this is how you refer to the block later (polycrate run k8s-nginx deploy).config: contains block-specific values. These later appear as block.config.* in your Ansible playbook.The beauty: You don’t need to know the internal logic of these blocks to use them. They are like meaningful building blocks in a kit – neatly encapsulated and versioned.
Let’s take a look at how such an ayedo block looks inside. Imagine you were developing cargo.ayedo.cloud/ayedo/k8s/nginx:0.2.2 locally. In the block directory, there would be a block.poly:
name: k8s-nginx
version: 0.2.2
kind: generic
config:
namespace: "ingress-nginx"
ingress_class: "nginx"
actions:
- name: deploy
playbook: deploy.yml
- name: delete
playbook: delete.ymlImportant details:
kubeconfig_path in block.poly. Polycrate takes the kubeconfig from artifacts/secrets/kubeconfig.yml and sets KUBECONFIG in the action container to the correct path – kubectl, Helm, and Ansible modules (for example community.kubernetes.helm) use it without extra block configuration. .poly files also do not support Jinja like {{ workspace.secrets[...] }}.actions define which commands you can execute via polycrate run (deploy, delete, …).0.2.2 is hard-coded in the block.poly and is also used in the registry.This includes an Ansible playbook, e.g., deploy.yml:
- name: Deploy ingress-nginx via Helm
hosts: localhost
gather_facts: false
tasks:
- name: Install ingress-nginx Helm chart
community.kubernetes.helm:
name: ingress-nginx
chart_ref: ingress-nginx/ingress-nginx
release_namespace: "{{ block.config.namespace }}"
create_namespace: true
values:
controller:
ingressClassResource:
name: "{{ block.config.ingress_class }}"A few explanations:
hosts: localhost is correct here because the playbook only interacts with the Kubernetes API. It does not alter local packages – it runs in the Polycrate container and controls the cluster from there.community.kubernetes.helm comes from an Ansible collection that is already installed in the Polycrate container. You don’t have to worry about this dependency. KUBECONFIG is already set in the container – an explicit kubeconfig: task parameter is not required.block.config.* are the values from your workspace.poly configuration for this block instance (here, among others, namespace, ingress_class). You control the deployment entirely from the workspace.With plain Ansible, you would need to:
kubectl, helm, Ansible plus collectionsKUBECONFIG)With Polycrate, you get a clearly structured block definition, a standardized execution environment in the container, and a consistent way to pass configuration from the workspace into the playbooks. See also the Ansible Integration in the Documentation.
A major advantage of the block structure is that you can build a reproducible workflow from multiple blocks. In our example:
k8s-nginx – Ingress Controllerk8s-cert-manager – TLS Certificatesk8s-external-dns – DNS Entries for your IngressesWe define this stack as a workflow in workspace.poly:
name: acme-corp-automation
organization: acme
blocks:
- name: k8s-nginx
from: cargo.ayedo.cloud/ayedo/k8s/nginx:0.2.2
config:
namespace: "ingress-nginx"
ingress_class: "nginx"
- name: k8s-cert-manager
from: cargo.ayedo.cloud/ayedo/k8s/cert-manager:0.3.0
config:
namespace: "cert-manager"
email: "admin@acme-corp.com"
- name: k8s-external-dns
from: cargo.ayedo.cloud/ayedo/k8s/external-dns:0.4.1
config:
namespace: "external-dns"
provider: "route53"
domain_filter: "acme-corp.com"
workflows:
- name: k8s-ingress-stack
actions:
- block: k8s-nginx
action: deploy
- block: k8s-cert-manager
action: deploy
- block: k8s-external-dns
action: deployWith this, you can roll out the complete stack with:
polycrate workflows run k8s-ingress-stackHere’s what happens:
artifacts/secrets/kubeconfig.yml into the container, without needing to be unencrypted in the repository.deploy, delete, upgrade).With plain Ansible, you would typically:
playbooks/k8s/nginx.yml, playbooks/k8s/cert-manager.yml, playbooks/k8s/external-dns.ymlWith Polycrate, these playbooks are packaged into reusable building blocks and orchestrated via workflows. This prevents the playbook overgrowth that many teams know from evolving environments and is detailed in the Best Practices.
:latest is Taboo in ProductionA central principle in productive Kubernetes solutions is reproducibility. That’s exactly why :latest is not a good idea for container images – and the same goes for Polycrate blocks.
The registry URL of a block always contains the version:
cargo.ayedo.cloud/ayedo/k8s/nginx:0.2.2Best practices include:
:0.2.2) in workspace.poly.TL;DR Polycrate is more than just a CLI tool: With PolyHub, an API platform, and MCP, it forms an …
TL;DR In this post, you’ll create a complete Polycrate block for your own Kubernetes app – …
TL;DR The Polycrate API transforms individual workspaces into a team platform: all workspaces, …