Meet kubepatch — a simple tool for deploying Kubernetes manifests using a patch-based approach.
Unlike tools that embed logic into YAML or require custom template languages, kubepatch
keeps your base manifests clean and idiomatic.
- Simple: No templates, DSLs, or logic in YAML, zero magic
- Predictable: No string substitutions or regex hacks
- Safe: Only native Kubernetes YAML manifests - readable, valid, untouched
- Layered: Patch logic is externalized and explicit via JSON Patch (RFC 6902)
- Declarative: Cross-environment deployment with predictable, understandable changes
🛠 Example
Given a base set of manifests for deploy a basic microservice
see examples
---
apiVersion: v1
kind: Service
metadata:
name: myapp
labels:
app: myapp
spec:
type: NodePort
selector:
app: myapp
ports:
- protocol: TCP
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app: myapp
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: "localhost:5000/restapiapp:latest"
A patches/prod.yaml
might look like:
name: myapp-prod
labels:
app: myapp-prod
patches:
# deployment
- target:
kind: Deployment
name: myapp
patches:
- op: replace
path: /spec/replicas
value: 1
- op: replace
path: /spec/template/spec/containers/0/image
value: "localhost:5000/restapiapp:1.21"
- op: add
path: /spec/template/spec/containers/0/env
value:
- name: RESTAPIAPP_VERSION
value: prod
- name: LOG_LEVEL
value: info
- op: add
path: /spec/template/spec/containers/0/resources
value:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "64m"
memory: "128Mi"
# service
- target:
kind: Service
name: myapp
patches:
- op: add
path: /spec/ports/0/nodePort
value: 30266
A patches/dev.yaml
might look like:
name: myapp-dev
labels:
app: myapp-dev
patches:
# deployment
- target:
kind: Deployment
name: myapp
patches:
- op: add
path: /spec/template/spec/containers/0/env
value:
- name: RESTAPIAPP_VERSION
value: dev
- name: LOG_LEVEL
value: debug
# service
- target:
kind: Service
name: myapp
patches:
- op: add
path: /spec/ports/0/nodePort
value: 30265
Apply the appropriate patch set based on the target environment.
kubepatch patch -f base/ -p patches/dev.yaml | kubectl apply -f -
Rendered manifest may look like this (note that all labels are set, as well as all patches are applied)
---
apiVersion: v1
kind: Service
metadata:
labels:
app: myapp-dev
name: myapp-dev
spec:
ports:
- nodePort: 30265
port: 8080
protocol: TCP
targetPort: 8080
selector:
app: myapp-dev
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myapp-dev
name: myapp-dev
spec:
replicas: 1
selector:
matchLabels:
app: myapp-dev
template:
metadata:
labels:
app: myapp-dev
spec:
containers:
- env:
- name: RESTAPIAPP_VERSION
value: dev
- name: LOG_LEVEL
value: debug
image: localhost:5000/restapiapp:1.22
name: myapp
Installation
Manual Installation
- Download the latest binary for your platform from the Releases page.
- Place the binary in your system's
PATH
(e.g.,/usr/local/bin
).
Installation script
(
set -euo pipefail
OS="$(uname | tr '[:upper:]' '[:lower:]')"
ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')"
TAG="$(curl -s https://api.github.com/repos/kubepatch/kubepatch/releases/latest | jq -r .tag_name)"
curl -L "https://github.com/kubepatch/kubepatch/releases/download/${TAG}/kubepatch_${TAG}_${OS}_${ARCH}.tar.gz" |
tar -xzf - -C /usr/local/bin && \
chmod +x /usr/local/bin/kubepatch
)
Package-Based installation (suitable in CI/CD)
Debian
sudo apt update -y && sudo apt install -y curl
curl -LO https://github.com/kubepatch/kubepatch/releases/latest/download/kubepatch_linux_amd64.deb
sudo dpkg -i kubepatch_linux_amd64.deb
Alpine Linux
apk update && apk add --no-cache bash curl
curl -LO https://github.com/kubepatch/kubepatch/releases/latest/download/kubepatch_linux_amd64.apk
apk add kubepatch_linux_amd64.apk --allow-untrusted
✨ Key Features
JSON Patch Only
Patches are applied using JSON Patch:
- op: replace
path: /spec/replicas
value: 1
Every patch is minimal, explicit, and easy to understand. No string manipulation or text templating involved.
Plain Kubernetes YAML Manifests
Your base manifests are 100% pure Kubernetes objects - no logic, no annotations, no overrides, no preprocessing. This
ensures:
- Easy editing
- Compatibility with other tools
- Clean Git diffs
Cross-Environment Deploys
Deploy to dev
, staging
, or prod
just by selecting the right set of patches. All logic lives in patch files, not
your base manifests.
Common Labels Support
Inject common labels (like env
, team
, app
), including deep paths like pod templates and selectors.
Env Var Substitution (in Patch Values Only)
You can inject secrets and configuration values directly into patch files:
- op: add
path: /spec/template/spec/containers/0/env
value:
- name: PGPASSWORD
value: ${IAM_SERVICE_PGPASS}
Strict env-var substitution (prefix-based) is only allowed inside patches - never in base manifests.
Feedback
Have a feature request or issue? Feel free to open an issue or submit a PR!
Top comments (0)