A Terraform-like tool for Kubernetes applications
Transform simple app definitions into production-ready Kubernetes manifests using the power of bjw-s-app-template.
curl -L https://github.com/calebsargeant/maniforge/releases/latest/download/maniforge-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m) -o maniforge
chmod +x maniforge
sudo mv maniforge /usr/local/bin/brew tap calebsargeant/tap
brew install maniforgegit clone https://github.com/calebsargeant/maniforge.git
cd maniforge
./build.sh
sudo cp dist/maniforge /usr/local/bin/Instead of writing complex Kubernetes YAML, define apps like Docker Compose and let Maniforge handle the Kubernetes complexity.
No Python required - maniforge is distributed as a universal executable!
./maniforge init --cluster my-clusterThis creates a maniforge.yaml with an example app.
./maniforge planSee what Maniforge will create (like terraform plan):
๐ Plan: 1 changes
๐ข nginx-example
App will be created
Image: nginx:latest
Namespace: default
./maniforge applyGenerates Kubernetes manifests in the apps/ directory.
git add apps/
git commit -m "Deploy apps with Maniforge"
git push # Flux/ArgoCD picks up changesmaniforge.yaml - Your infrastructure as code (single file):
cluster:
name: homelab
domain: sargeant.co
defaults:
profile: c.small
nodeSelector: pi
output:
directory: apps
nodes:
pi:
count: 2
cpu: 4
mem: 16Gi
apps:
homebridge:
image: ghcr.io/homebridge/homebridge:latest
type: daemonset
network: host
profile: c.pico
storage:
config:
type: hostPath
path: /mnt/nvme/homebridge-config
mount: /homebridge
env:
TZ: Europe/Amsterdam
plex:
image: plexinc/pms-docker:latest
type: deployment
network: nodeport
profile: r.large
ports:
- name: plex
port: 32400
nodePort: 32400
storage:
config:
type: hostPath
path: /mnt/raid/plex-config
mount: /config
media:
type: hostPath
path: /mnt/raid/media
mount: /data
readonly: true
env:
PLEX_CLAIM: token-123456789
postgres:
image: postgres:15
type: deployment
network: clusterip
profile: m.small
storage:
data:
type: pvc
size: 20Gi
mount: /var/lib/postgresql/data
storageClass: fast-ssd
env:
POSTGRES_DB: myapp
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret./maniforge init [--cluster name]Create a new project with example configuration.
./maniforge planShow what changes would be made (like terraform plan).
./maniforge applyGenerate/update Kubernetes manifests.
./maniforge validateCheck configuration for errors.
apps:
myapp:
image: nginx:latest # Docker image (required) # Workload type
type: deployment # deployment|daemonset|statefulset (default: deployment)
# Networking
network: clusterip # clusterip|nodeport|loadbalancer|host (default: clusterip)
ports: # Custom ports (for nodeport/loadbalancer)
- name: web
port: 80
targetPort: 8080
nodePort: 30080 # Only for nodeport
# Resources & Placement
profile: c.small # Resource profile (default: from cluster.defaults)
nodeSelector: pi # Node selector (default: from cluster.defaults)
namespace: default # Kubernetes namespace (default: default)
# Storage
storage:
data:
type: pvc # pvc|hostPath|nfs
size: 10Gi # PVC size (required for pvc)
mount: /data # Container mount path
storageClass: fast # Storage class (optional)
readonly: false # Read-only mount (default: false)
config:
type: hostPath
path: /host/path/to/config
mount: /config
# Environment
env:
TZ: Europe/Amsterdam
DEBUG: "true"
# Ingress (automatic if cluster.domain is set)
ingress: false # Disable ingress (default: true if domain set)Maniforge uses resource-profiles.yaml as the master definition for all AWS-style resource allocation profiles. It defines CPU and memory requests/limits for different workload types.
โจ New: This repository now includes pre-generated Kubernetes resource profiles in the _components/resource-profiles directory!
You can directly reference these profiles in your Kustomize configurations without needing to generate them yourself. The pre-generated profiles include:
- 40 profile variations across 5 types (P, T, C, M, R) and 8 sizes
- Ready-to-use Kustomize components for Deployments, StatefulSets, and DaemonSets
- HelmRelease patches for Flux CD integrations
- Full documentation in
_components/resource-profiles/README.md
Quick Start:
# In your kustomization.yaml
components:
- https://github.com/calebsargeant/maniforge/_components/resource-profiles?ref=mainThen add profile labels to your workloads:
metadata:
labels:
resource-profile: c.small- P-type (2:1 CPU:Memory) - Video transcoding, image processing, ML inference
- T-type (1:1 CPU:Memory) - Web servers, APIs, general-purpose applications
- C-type (1:2 CPU:Memory) - Compute-optimized, load balancers
- M-type (1:4 CPU:Memory) - Memory-optimized, balanced workloads
- R-type (1:8 CPU:Memory) - In-memory databases, caches, large datasets
Each type has 8 sizes: pico, nano, micro, small, medium, large, xlarge, 2xlarge
| Profile | CPU Requests | CPU Limits | Memory Requests | Memory Limits | Use Case |
|---|---|---|---|---|---|
c.pico |
100m | 250m | 256Mi | 512Mi | Tiny apps |
c.small |
250m | 500m | 512Mi | 1Gi | Small apps |
c.medium |
500m | 1000m | 1Gi | 2Gi | Medium apps |
r.large |
500m | 1000m | 4Gi | 8Gi | Memory-intensive |
The resource-profiles.yaml file:
- Defines all available resource profiles with CPU/memory requests and limits
- Can be used to generate Kubernetes component structures
- Is automatically loaded by maniforge for app configuration
- Can be customized by users for their own profile definitions
If you want to generate profiles from a custom resource-profiles.yaml:
./maniforge generate-profiles --output /path/to/outputThis generates:
- Main
kustomization.yamlwith all profile patches - Individual profile directories (e.g.,
c.small/,r.large/) containing:kustomization.yaml: Component definitionpatches.yaml: Resource patches for Deployments/StatefulSets/DaemonSetshelmrelease-patches.yaml: Patches for Flux HelmRelease resources
README.md: Documentation of all available profiles
Note: The default profiles are already pre-generated in _components/resource-profiles, so you only need to run this command if you're creating custom profiles.
Option 1: Use Pre-Generated Profiles (Recommended)
Reference the pre-generated profiles directly from this repository:
# Label-based selection (applies to resources with matching labels)
components:
- https://github.com/calebsargeant/maniforge/_components/resource-profiles?ref=main
# Or use a specific profile directly
components:
- https://github.com/calebsargeant/maniforge/_components/resource-profiles/c.small?ref=mainOption 2: Use Local Copy
If you've cloned this repository or want to use profiles locally:
components:
- ../../_components/resource-profilesThen add profile labels to your resources:
metadata:
labels:
resource-profile: m.mediumOption 3: Generate Custom Profiles
Create your own resource-profiles.yaml and generate components:
./maniforge generate-profiles --profiles-yaml custom-profiles.yaml --output my-components/| Type | Description | Use Case |
|---|---|---|
clusterip |
Cluster-internal access only | Internal services, databases |
nodeport |
External access via node ports | Development, specific port requirements |
loadbalancer |
External LoadBalancer service | Production external services |
host |
Host networking | HomeAssistant, network-sensitive apps |
| Type | Configuration | Use Case |
|---|---|---|
pvc |
size, storageClass, accessMode |
Persistent data, databases |
hostPath |
path |
Host directory mounts |
nfs |
server, path |
Shared storage |
Maniforge creates a clean structure:
apps/
โโโ homebridge/
โ โโโ kustomization.yaml # Kustomize config
โ โโโ helm-release.yaml # HelmRelease with bjw-s-app-template
โโโ plex/
โโโ kustomization.yaml
โโโ helm-release.yaml
Each app gets its own directory with:
kustomization.yaml- Kustomize configurationhelm-release.yaml- Complete HelmRelease using bjw-s-app-template
โ
Terraform-like Workflow - Plan, apply, version control
โ
Simple Configuration - Docker Compose-like syntax
โ
Powerful Output - Full Kubernetes capabilities via bjw-s-app-template
โ
GitOps Ready - Generated manifests work with Flux/ArgoCD
โ
Validation - Catch errors before deployment
โ
Diff-Aware - Shows exactly what changed
- Edit
maniforge.yaml(your infrastructure as code) - Plan with
./maniforge plan(see what will change) - Apply with
./maniforge apply(generate manifests) - Commit generated files to git
- Deploy automatically via GitOps
# Initialize new project
./maniforge init --cluster homelab
# Edit maniforge.yaml to add your apps
vim maniforge.yaml
# See what will be created
./maniforge plan
# Generate manifests
./maniforge apply
# Deploy via GitOps
git add apps/ maniforge.yaml
git commit -m "Add homebridge and plex"
git pushUse maniforge in CI/CD workflows:
name: Validate Manifests
on: [pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate maniforge config
uses: calebsargeant/maniforge@v1
with:
command: validate
config: maniforge.yaml
- name: Plan changes
uses: calebsargeant/maniforge@v1
with:
command: plan
config: maniforge.yamlInputs:
command- Command to run:plan,apply,validate,init(default:plan)config- Path to config file (default:maniforge.yaml)version- Version to use (default:latest)
Outputs:
exit-code- Command exit codechanges-detected- Whether changes were detected (plan only)
./build.sh # Creates dist/maniforge executableReleases are automatic using semantic versioning. Use conventional commits:
# Features (bumps minor version)
git commit -m "feat: add new storage type support"
# Fixes (bumps patch version)
git commit -m "fix: resolve port mapping issue"
# Breaking changes (bumps major version)
git commit -m "feat!: redesign configuration format"
# Push to main - automatic release triggers
git push origin mainThe workflow automatically:
- Determines version based on commits
- Creates git tag and GitHub release
- Builds binaries for all platforms
- Uploads binaries + SHA256SUMS
- Generates CHANGELOG.md
Download SHA256SUMS from release and update maniforge.rb checksums.
# Create homebrew-tap repo
mkdir homebrew-tap && cd homebrew-tap
mkdir Formula
cp ../maniforge.rb Formula/maniforge.rb
git init && git add . && git commit -m "Add maniforge"
git remote add origin git@github.com:calebsargeant/homebrew-tap.git
git push -u origin mainManiforge now includes built-in capacity planning that analyzes resource usage across your node groups!
When you run maniforge plan, you'll see:
- CPU and Memory usage per node type
- Visual progress bars showing capacity utilization
- Requests vs Limits analysis
- Over-capacity warnings when limits exceed node capacity
- Per-app resource breakdown
Define capacity at the top level in maniforge.yaml:
nodes:
pi:
count: 2 # number of nodes of this type
cpu: 4 # per-node CPU (cores or millicores, e.g. 4000m)
mem: 16Gi # per-node memory (alias: memory)
disk: 100Gi # optional, informational๐ Capacity Planning Analysis
================================================================================
๐ฅ๏ธ Node Type: pi
Apps: 3
Node Capacity: CPU=4.00 Memory=8.00Gi
CPU Usage:
Requests: 850m / 4.00 (21.2%)
[โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ]
Limits: 1.75 / 4.00 (43.8%)
[โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ]
Memory Usage:
Requests: 4.75Gi / 8.00Gi (59.4%)
[โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ]
Limits: 9.50Gi / 8.00Gi (118.8%)
โ ๏ธ [โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ]
โ
Capacity available (40.6% free)
Apps on this node type:
โข homebridge: CPU=100m Memory=256.00Mi
โข plex: CPU=500m Memory=4.00Gi
โข nginx: CPU=250m Memory=512.00Mi
Important: Maniforge currently assumes 1 replica per node for capacity planning calculations. This is the typical pattern for:
- DaemonSets - Run exactly one pod per node
- Node-pinned deployments - Deployments with specific node selectors that spread across nodes
Limitations:
- If you have multi-replica deployments targeting the same node type, the capacity analysis will undercount resource usage
- Future versions may support configurable replica counts or cluster state inspection
Best Practice: Use capacity planning as a guideline for node sizing and to identify potential over-allocation. Always monitor actual cluster resource usage in production.
- ๐ Remote Platforms - Load profiles from GitHub repos
- ๐ Live Diffing - Compare with running cluster state
- ๐ฆ App Templates - Pre-built app configurations
- ๐๏ธ Advanced Networking - Service mesh, network policies
Maniforge - Because Kubernetes apps should be as easy as docker run.