home / skills / ehtbanton / claudeskillsrepo / kubernetes-manifest-generator
This skill generates production-ready Kubernetes YAML manifests with security and reliability best practices for deployments, services, and other resources.
npx playbooks add skill ehtbanton/claudeskillsrepo --skill kubernetes-manifest-generatorReview the files below or copy the command above to add this skill to your agents.
---
name: kubernetes-manifest-generator
description: Generate Kubernetes YAML manifests for deployments, services, ingress, configmaps, and other resources with best practices. Triggers on "create Kubernetes manifest", "generate k8s yaml", "kubernetes deployment for", "k8s config".
---
# Kubernetes Manifest Generator
Generate production-ready Kubernetes YAML manifests with best practices for security, scalability, and reliability.
## Output Requirements
**File Output:** `.yaml` files
**Format:** Valid Kubernetes YAML manifests
**Standards:** Kubernetes 1.28+
## When Invoked
Immediately generate complete Kubernetes manifests. Include resource requests/limits, health checks, and security contexts by default.
## Manifest Templates
### Complete Application Stack
```yaml
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: myapp
labels:
name: myapp
environment: production
---
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
namespace: myapp
labels:
app: myapp
data:
NODE_ENV: "production"
LOG_LEVEL: "info"
API_TIMEOUT: "30000"
---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: myapp-secrets
namespace: myapp
labels:
app: myapp
type: Opaque
stringData:
DATABASE_URL: "postgresql://user:pass@host:5432/db"
JWT_SECRET: "your-secret-key"
# In production, use external secrets or sealed secrets
# This is for example only
---
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: myapp
labels:
app: myapp
version: v1
spec:
replicas: 3
revisionHistoryLimit: 5
selector:
matchLabels:
app: myapp
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: myapp
version: v1
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
spec:
serviceAccountName: myapp
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: myapp
image: myregistry/myapp:1.0.0
imagePullPolicy: Always
ports:
- name: http
containerPort: 8080
protocol: TCP
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
envFrom:
- configMapRef:
name: myapp-config
- secretRef:
name: myapp-secrets
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
livenessProbe:
httpGet:
path: /health/live
port: http
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/ready
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
startupProbe:
httpGet:
path: /health/live
port: http
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/.cache
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp
topologyKey: kubernetes.io/hostname
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: myapp
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: myapp
labels:
app: myapp
spec:
type: ClusterIP
selector:
app: myapp
ports:
- name: http
port: 80
targetPort: http
protocol: TCP
---
# serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapp
namespace: myapp
labels:
app: myapp
automountServiceAccountToken: false
---
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp
namespace: myapp
labels:
app: myapp
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
---
# pdb.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: myapp
namespace: myapp
labels:
app: myapp
spec:
minAvailable: 2
selector:
matchLabels:
app: myapp
---
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp
namespace: myapp
labels:
app: myapp
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
name: http
---
# networkpolicy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: myapp
namespace: myapp
labels:
app: myapp
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
- podSelector:
matchLabels:
app: myapp
ports:
- protocol: TCP
port: 8080
egress:
- to:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 5432
- protocol: TCP
port: 6379
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
```
### StatefulSet with Persistent Storage
```yaml
# statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: database
labels:
app: postgres
spec:
serviceName: postgres-headless
replicas: 3
podManagementPolicy: OrderedReady
updateStrategy:
type: RollingUpdate
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
securityContext:
runAsNonRoot: true
runAsUser: 999
fsGroup: 999
containers:
- name: postgres
image: postgres:15-alpine
imagePullPolicy: IfNotPresent
ports:
- name: postgres
containerPort: 5432
env:
- name: POSTGRES_DB
value: "mydb"
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-secrets
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secrets
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
livenessProbe:
exec:
command:
- pg_isready
- -U
- $(POSTGRES_USER)
- -d
- $(POSTGRES_DB)
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
exec:
command:
- pg_isready
- -U
- $(POSTGRES_USER)
- -d
- $(POSTGRES_DB)
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
volumeClaimTemplates:
- metadata:
name: data
labels:
app: postgres
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
---
# headless-service.yaml
apiVersion: v1
kind: Service
metadata:
name: postgres-headless
namespace: database
labels:
app: postgres
spec:
type: ClusterIP
clusterIP: None
selector:
app: postgres
ports:
- name: postgres
port: 5432
targetPort: postgres
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: database
labels:
app: postgres
spec:
type: ClusterIP
selector:
app: postgres
ports:
- name: postgres
port: 5432
targetPort: postgres
```
### CronJob
```yaml
# cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: backup-job
namespace: myapp
labels:
app: backup
spec:
schedule: "0 2 * * *" # Daily at 2 AM
timeZone: "UTC"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
startingDeadlineSeconds: 300
jobTemplate:
spec:
backoffLimit: 3
activeDeadlineSeconds: 3600
ttlSecondsAfterFinished: 86400
template:
metadata:
labels:
app: backup
spec:
restartPolicy: OnFailure
serviceAccountName: backup-sa
securityContext:
runAsNonRoot: true
runAsUser: 1000
containers:
- name: backup
image: myregistry/backup:1.0.0
imagePullPolicy: Always
env:
- name: BACKUP_BUCKET
value: "my-backup-bucket"
envFrom:
- secretRef:
name: backup-credentials
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
```
## Common Patterns
### External Secrets
```yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: myapp-secrets
namespace: myapp
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: myapp-secrets
creationPolicy: Owner
data:
- secretKey: DATABASE_URL
remoteRef:
key: myapp/production
property: database_url
```
### Resource Quotas
```yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: myapp-quota
namespace: myapp
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"
persistentvolumeclaims: "10"
```
## Validation Checklist
Before outputting, verify:
- [ ] API versions are current
- [ ] Labels applied consistently
- [ ] Resource requests AND limits set
- [ ] Health probes configured
- [ ] Security context is restrictive
- [ ] Service selectors match pod labels
- [ ] Namespace specified
- [ ] Secrets not hardcoded
## Example Invocations
**Prompt:** "Create Kubernetes manifests for a Node.js API with Redis"
**Output:** Complete manifests with Deployment, Service, ConfigMap, HPA.
**Prompt:** "Generate k8s deployment with blue-green strategy"
**Output:** Complete manifests with two deployments, service switching.
**Prompt:** "Kubernetes StatefulSet for Elasticsearch cluster"
**Output:** Complete manifests with StatefulSet, Services, PVCs, init containers.
This skill generates production-ready Kubernetes YAML manifests for deployments, services, ingress, configmaps, secrets, StatefulSets, CronJobs, HPA, NetworkPolicies and other resources following current best practices. It outputs valid Kubernetes 1.28+ YAML files with sensible defaults for security, observability, and scalability. Manifests include resource requests/limits, health probes, and restrictive security contexts by default.
When invoked with prompts like "create Kubernetes manifest" or "generate k8s yaml", the skill produces complete multi-file YAML manifests tailored to the described application. It applies templates for common stacks (namespaces, configmaps, secrets, deployments, services, ingress, HPA, PDB, networkpolicies), stateful workloads, CronJobs, and external-secrets patterns. Before returning output it validates API versions, labels, selectors, and required fields such as probes and resource limits.
Which Kubernetes versions and APIs does this target?
Manifests are generated for Kubernetes 1.28+ and use current stable API versions where applicable; API versions are validated before output.
How are secrets handled?
Secrets are referenced but not hardcoded for production. The skill offers ExternalSecrets examples and notes to use external secret stores or sealed secrets in production.