A Python library for rendering Helm charts and Kubernetes resources with optional ArgoCD Application generation. Features an abstract Template base class for consistent template management.
Project description
Kubeman
A Python library for rendering Helm charts and Kubernetes resources with optional ArgoCD Application generation. Features an abstract Template base class for consistent template management.
Features
- Abstract
Templatebase class for all template types HelmChartclass for defining Helm chartsKubernetesResourceclass for raw Kubernetes resources (no Helm required)TemplateRegistryfor managing multiple templates (charts and resources)- Command-line interface (CLI) for rendering and applying manifests
- Git operations for manifest repository management
- Docker image build and push utilities
- Optional ArgoCD Application manifest generation (opt-in)
Installation
From Source
Using uv (recommended):
uv pip install -e .
Or using pip (not recommended):
pip install -e .
Development Setup
Install development dependencies:
uv sync --dev
Format code:
uv tool run black .
Pre-commit Hooks
This project uses pre-commit hooks to automatically format code with black before commits.
Install pre-commit as a tool (recommended):
uv tool install pre-commit
This installs pre-commit globally and makes it available in your PATH. Then install the git hooks:
pre-commit install
Now, every time you commit, black will automatically format your Python files. You can also run the hooks manually:
pre-commit run --all-files
Alternative: If you prefer to use pre-commit from the virtual environment, you can install it as a dev dependency and use the Python module:
uv sync --dev
uv run python -m pre_commit install
uv run python -m pre_commit run --all-files
Usage
Template Architecture
Both HelmChart and KubernetesResource inherit from the abstract Template base class, which provides common functionality for:
- Optional ArgoCD Application manifest generation (opt-in)
- Manifest directory management
- Namespace and name properties
- Rendering to filesystem
This shared base class ensures consistent behavior across all template types while allowing each subclass to implement its specific rendering logic.
Creating a Helm Chart
To create a Helm chart, subclass HelmChart and implement the required abstract methods:
from kubeman import HelmChart, TemplateRegistry
@TemplateRegistry.register
class MyChart(HelmChart):
@property
def name(self) -> str:
return "my-chart"
@property
def repository(self) -> dict:
"""Return repository information"""
return {
"type": "classic", # or "oci" or "none"
"remote": "https://charts.example.com"
}
@property
def namespace(self) -> str:
return "my-namespace"
@property
def version(self) -> str:
return "1.0.0"
def generate_values(self) -> dict:
"""Generate values.yaml content"""
return {
"replicaCount": 3,
"image": {
"repository": "my-app",
"tag": "latest"
}
}
Creating a Kubernetes Resource (Without Helm)
For projects that don't need Helm but still want optional ArgoCD Application generation and manifest management, use the KubernetesResource class. This class supports two usage patterns:
Pattern 1: Using Helper Methods (Recommended)
Use the built-in helper methods to build Kubernetes resources:
from kubeman import KubernetesResource, TemplateRegistry
@TemplateRegistry.register
class DogBreedsDbChart(KubernetesResource):
"""Dog Breeds PostgreSQL database resources."""
def __init__(self):
super().__init__()
self.namespace = "dog-breeds"
# Add Namespace
self.add_namespace(
name="dog-breeds",
labels={"app": "dog-breeds", "component": "database"},
)
# Add ConfigMap for database configuration
self.add_configmap(
name="dog-breeds-db-config",
namespace="dog-breeds",
data={
"POSTGRES_DB": "dog_breeds_db",
"POSTGRES_USER": "airflow",
},
labels={"app": "dog-breeds", "component": "database"},
)
# Add Secret for database password
self.add_secret(
name="dog-breeds-db-secret",
namespace="dog-breeds",
string_data={
"POSTGRES_PASSWORD": "airflow",
},
labels={"app": "dog-breeds", "component": "database"},
)
# Add PersistentVolumeClaim
self.add_persistent_volume_claim(
name="dog-breeds-db-pvc",
namespace="dog-breeds",
access_modes=["ReadWriteOnce"],
storage="5Gi",
labels={"app": "dog-breeds", "component": "database"},
)
# Add Deployment
self.add_deployment(
name="dog-breeds-db",
namespace="dog-breeds",
replicas=1,
strategy_type="Recreate",
labels={"app": "dog-breeds", "component": "database"},
containers=[
{
"name": "postgres",
"image": "postgres:16-alpine",
"ports": [{"name": "postgres", "containerPort": 5432}],
"env": [
{
"name": "POSTGRES_PASSWORD",
"valueFrom": {
"secretKeyRef": {
"name": "dog-breeds-db-secret",
"key": "POSTGRES_PASSWORD",
},
},
},
],
"volumeMounts": [
{"name": "postgres-storage", "mountPath": "/var/lib/postgresql/data"},
],
}
],
volumes=[
{"name": "postgres-storage", "persistentVolumeClaim": {"claimName": "dog-breeds-db-pvc"}},
],
init_containers=[
{
"name": "init-db",
"image": "busybox:latest",
"command": ["sh", "-c", "echo Initializing database schema"],
}
],
)
# Add Service
self.add_service(
name="dog-breeds-db",
namespace="dog-breeds",
service_type="ClusterIP",
selector={"app": "dog-breeds", "component": "database"},
ports=[{"name": "postgres", "port": 5432, "targetPort": 5432}],
labels={"app": "dog-breeds", "component": "database"},
)
Available Helper Methods:
add_namespace()- Create a Namespaceadd_configmap()- Create a ConfigMapadd_secret()- Create a Secretadd_persistent_volume_claim()- Create a PVCadd_deployment()- Create a Deploymentadd_statefulset()- Create a StatefulSetadd_service()- Create a Service (ClusterIP, NodePort, LoadBalancer)add_ingress()- Create an Ingressadd_service_account()- Create a ServiceAccountadd_role()- Create a Roleadd_role_binding()- Create a RoleBindingadd_cluster_role()- Create a ClusterRoleadd_cluster_role_binding()- Create a ClusterRoleBindingadd_custom_resource()- Add any custom Kubernetes resource
Pattern 2: Override manifests() Method
For more complex logic or custom manifest generation, override the manifests() method:
from kubeman import KubernetesResource, TemplateRegistry
@TemplateRegistry.register
class MyAppResources(KubernetesResource):
def __init__(self):
super().__init__()
self.namespace = "production"
def manifests(self) -> list[dict]:
"""Return list of Kubernetes manifests"""
return [
{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": {
"name": "my-app-config",
"namespace": "production"
},
"data": {
"DATABASE_URL": "postgres://db:5432/myapp",
}
},
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "my-app",
"namespace": "production"
},
"spec": {
"replicas": 3,
"selector": {"matchLabels": {"app": "my-app"}},
"template": {
"metadata": {"labels": {"app": "my-app"}},
"spec": {
"containers": [{
"name": "my-app",
"image": "gcr.io/my-project/my-app:v1.0.0",
"envFrom": [{
"configMapRef": {"name": "my-app-config"}
}]
}]
}
}
}
}
]
The KubernetesResource class provides a simpler interface than HelmChart when you don't need Helm's templating capabilities. It supports optional ArgoCD Application generation and integrates with the TemplateRegistry system.
Rendering Charts and Resources
Once your charts and resources are registered, you can render them using either the CLI or Python API.
Using the CLI (Recommended)
The easiest way to render and apply your templates is using the kubeman CLI command:
# Render all templates from a Python file
kubeman render --file templates.py
# Render and apply to Kubernetes cluster
kubeman apply --file templates.py
# Apply with a specific namespace
kubeman apply --file templates.py --namespace my-namespace
The CLI will:
- Import your template file (which should contain
@TemplateRegistry.registerdecorated classes) - Discover all registered templates
- Render each template to the
manifests/directory - For
apply, also runkubectl applyon the rendered manifests
Example template file (templates.py):
from kubeman import KubernetesResource, TemplateRegistry
@TemplateRegistry.register
class MyAppResources(KubernetesResource):
def __init__(self):
super().__init__()
self.namespace = "production"
# ... add resources using helper methods ...
Using the Python API
You can also render templates programmatically:
from kubeman import TemplateRegistry
# Get all registered templates (charts and resources)
templates = TemplateRegistry.get_registered_templates()
# Render each template
for template_class in templates:
template = template_class()
template.render() # Generates manifests and ArgoCD Application
The render() method will:
For HelmChart:
- Render the Helm chart templates to
manifests/{chart-name}/{chart-name}-manifests.yaml - Write any extra manifests to
manifests/{chart-name}/ - Generate an ArgoCD Application manifest to
manifests/apps/{chart-name}-application.yaml(if ArgoCD is enabled)
For KubernetesResource:
- Write each Kubernetes manifest to
manifests/{name}/{manifest-name}-{kind}.yaml - Generate an ArgoCD Application manifest to
manifests/apps/{name}-application.yaml(if ArgoCD is enabled)
Advanced Chart Configuration
Custom Repository Package Name
If your repository uses a different package name than the chart name:
@property
def repository_package(self) -> str:
return "different-package-name"
OCI Registry Support
For OCI-based Helm repositories:
@property
def repository(self) -> dict:
return {
"type": "oci",
"remote": "oci://registry.example.com/charts"
}
Extra Manifests
Add additional Kubernetes manifests alongside your Helm chart:
def extra_manifests(self) -> list[dict]:
return [
{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": {"name": "my-config"},
"data": {"key": "value"}
}
]
Enabling ArgoCD Application Generation (Opt-In)
ArgoCD Application generation is disabled by default. To enable it, you have two options:
Option 1: Set environment variable
export ARGOCD_APP_REPO_URL="https://github.com/org/manifests-repo"
Option 2: Override enable_argocd() method
@TemplateRegistry.register
class MyChart(HelmChart):
# ... other methods ...
def enable_argocd(self) -> bool:
"""Enable ArgoCD Application generation for this chart"""
return True
When ArgoCD is enabled, the Application manifest will be generated during the render process. If ARGOCD_APP_REPO_URL is not set and enable_argocd() returns True, you must also override application_repo_url() to provide the repository URL.
Custom ArgoCD Application Settings
Customize the ArgoCD Application generation:
def enable_argocd(self) -> bool:
"""Enable ArgoCD Application generation (opt-in)"""
return True
def application_repo_url(self) -> str:
"""Override the repository URL for ArgoCD applications"""
return "https://github.com/org/manifests-repo"
def application_target_revision(self) -> str:
"""Override the target revision (defaults to current branch)"""
return "main"
def managed_namespace_metadata(self) -> dict:
"""Add labels to managed namespaces"""
return {
"app.kubernetes.io/managed-by": "argocd"
}
def argo_ignore_spec(self) -> list:
"""Configure ArgoCD ignore differences"""
return [
{
"group": "apps",
"kind": "Deployment",
"jsonPointers": ["/spec/replicas"]
}
]
Git Operations
The GitManager class provides utilities for working with Git repositories:
from kubeman import GitManager
git = GitManager()
# Get current commit hash (from STABLE_GIT_COMMIT env var)
commit_hash = git.fetch_commit_hash()
# Get current branch name (from STABLE_GIT_BRANCH env var)
branch_name = git.fetch_branch_name()
# Push rendered manifests to a repository
git.push_manifests(repo_url="https://github.com/org/manifests-repo")
The push_manifests() method will:
- Clone the manifests repository
- Checkout or create the branch matching
STABLE_GIT_BRANCH - Copy rendered manifests from
RENDERED_MANIFEST_DIR - Commit and push the changes
Docker Operations
The DockerManager class helps build and push Docker images to container registries:
from kubeman import DockerManager
# Initialize with project ID (or set DOCKER_PROJECT_ID env var)
docker = DockerManager(
project_id="my-project",
repository_name="my-repo" # Optional, defaults to "default"
)
# Build an image
image_name = docker.build_image(
component="frontend",
context_path="./frontend",
tag="v1.0.0"
)
# Push an image
docker.push_image(component="frontend", tag="v1.0.0")
# Build and push in one step
image_name = docker.build_and_push(
component="backend",
context_path="./backend",
tag="latest"
)
Environment Variables
Required for Git Operations
STABLE_GIT_COMMIT- Current git commit hashSTABLE_GIT_BRANCH- Current git branch nameRENDERED_MANIFEST_DIR- Path to directory containing rendered manifestsMANIFEST_REPO_URL- Git repository URL for pushing manifests (optional if passed topush_manifests())
Optional for ArgoCD Applications
ArgoCD Application generation is opt-in and disabled by default. To enable:
ARGOCD_APP_REPO_URL- Repository URL for ArgoCD applications (or overrideapplication_repo_url()). Required if ArgoCD is enabled.ARGOCD_APPS_SUBDIR- Subdirectory for applications (defaults to "apps")
You can also enable ArgoCD by overriding the enable_argocd() method in your template class to return True.
Required for Docker Operations
DOCKER_PROJECT_ID- Registry project ID (or pass toDockerManagerconstructor)DOCKER_REGION- Registry region (defaults to "us-central1")DOCKER_REPOSITORY_NAME- Docker repository name (defaults to "default")GITHUB_REPOSITORY- GitHub repository name (optional)
Complete Example
Here's a complete example that ties everything together, using both HelmChart and KubernetesResource:
from kubeman import HelmChart, KubernetesResource, TemplateRegistry, GitManager, DockerManager
# Define a Helm chart for a third-party application
@TemplateRegistry.register
class PostgresChart(HelmChart):
@property
def name(self) -> str:
return "postgres"
@property
def repository(self) -> dict:
return {
"type": "classic",
"remote": "https://charts.bitnami.com/bitnami"
}
@property
def namespace(self) -> str:
return "database"
@property
def version(self) -> str:
return "12.5.0"
def generate_values(self) -> dict:
return {
"auth": {
"postgresPassword": "changeme"
},
"persistence": {
"enabled": True,
"size": "10Gi"
}
}
def enable_argocd(self) -> bool:
"""Enable ArgoCD Application generation (opt-in)"""
return True
# Define custom Kubernetes resources for your application
@TemplateRegistry.register
class MyAppResources(KubernetesResource):
@property
def name(self) -> str:
return "my-app"
@property
def namespace(self) -> str:
return "production"
def manifests(self) -> list[dict]:
return [
{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": {"name": "my-app-config", "namespace": "production"},
"data": {"DATABASE_HOST": "postgres.database.svc.cluster.local"}
},
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {"name": "my-app", "namespace": "production"},
"spec": {
"replicas": 3,
"selector": {"matchLabels": {"app": "my-app"}},
"template": {
"metadata": {"labels": {"app": "my-app"}},
"spec": {
"containers": [{
"name": "my-app",
"image": "gcr.io/my-project/my-app:v1.0.0",
"envFrom": [{"configMapRef": {"name": "my-app-config"}}]
}]
}
}
}
}
]
# Build and push Docker images
docker = DockerManager()
docker.build_and_push("my-app", "./app", tag="v1.0.0")
# Option 1: Use CLI to render and apply
# kubeman render --file templates.py
# kubeman apply --file templates.py
# Option 2: Render programmatically
for template_class in TemplateRegistry.get_registered_templates():
template = template_class()
template.render()
# Push manifests to repository
git = GitManager()
git.push_manifests()
Publishing
This package is automatically published to PyPI via GitHub Actions when:
- A new release is published on GitHub
- A version tag is pushed (e.g.,
v0.1.0,v1.0.0) - Manual trigger via the GitHub Actions workflow
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kubeman-0.4.0.tar.gz.
File metadata
- Download URL: kubeman-0.4.0.tar.gz
- Upload date:
- Size: 22.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2b74ea70c6a6d89828e118a86635911713816609df535ef444da14ed27c4eaa9
|
|
| MD5 |
16d6fca29fbe16221680f3b2430bbcb9
|
|
| BLAKE2b-256 |
a2b6ebfabe21c97bd41afcfd2e54a9593bd5efd14743ad1349d23bcfc23b5242
|
Provenance
The following attestation bundles were made for kubeman-0.4.0.tar.gz:
Publisher:
publish.yml on jasonzh0/kubeman
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kubeman-0.4.0.tar.gz -
Subject digest:
2b74ea70c6a6d89828e118a86635911713816609df535ef444da14ed27c4eaa9 - Sigstore transparency entry: 716253024
- Sigstore integration time:
-
Permalink:
jasonzh0/kubeman@041c96a83c8ce1fe4fdc3cb5d77fd7ea94f634a4 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/jasonzh0
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@041c96a83c8ce1fe4fdc3cb5d77fd7ea94f634a4 -
Trigger Event:
release
-
Statement type:
File details
Details for the file kubeman-0.4.0-py3-none-any.whl.
File metadata
- Download URL: kubeman-0.4.0-py3-none-any.whl
- Upload date:
- Size: 25.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
489ffd17e829dea9818f920ea726559fab81a28b331705ba7563a10161085845
|
|
| MD5 |
c3b619b5ca51612369b3c5c7cbae1f85
|
|
| BLAKE2b-256 |
a6e67896affb13943bd9d92141aad4aa1085b307d4baa9adee6e95771fe97d59
|
Provenance
The following attestation bundles were made for kubeman-0.4.0-py3-none-any.whl:
Publisher:
publish.yml on jasonzh0/kubeman
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kubeman-0.4.0-py3-none-any.whl -
Subject digest:
489ffd17e829dea9818f920ea726559fab81a28b331705ba7563a10161085845 - Sigstore transparency entry: 716253043
- Sigstore integration time:
-
Permalink:
jasonzh0/kubeman@041c96a83c8ce1fe4fdc3cb5d77fd7ea94f634a4 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/jasonzh0
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@041c96a83c8ce1fe4fdc3cb5d77fd7ea94f634a4 -
Trigger Event:
release
-
Statement type: