Kubernetes Manifest Generator
Generate production-ready Kubernetes manifests with security and scalability best practices.
Core Workflow
-
Define resources: Identify required K8s objects
-
Create namespace: Isolate application resources
-
Configure deployments: Pods, replicas, resources
-
Setup services: Networking and load balancing
-
Add ingress: External access routing
-
Configure scaling: HPA and resource limits
Deployment Manifest
k8s/deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: app-deployment namespace: production labels: app: myapp version: v1 spec: replicas: 3 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: "9090" spec: serviceAccountName: myapp-sa securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 1000 containers: - name: app image: myregistry/myapp:v1.0.0 imagePullPolicy: Always ports: - name: http containerPort: 3000 protocol: TCP - name: metrics containerPort: 9090 protocol: TCP env: - name: NODE_ENV value: production - name: DATABASE_URL valueFrom: secretKeyRef: name: app-secrets key: database-url - name: REDIS_HOST valueFrom: configMapKeyRef: name: app-config key: redis-host resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi 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 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL volumeMounts: - name: tmp mountPath: /tmp - name: config mountPath: /app/config readOnly: true volumes: - name: tmp emptyDir: {} - name: config configMap: name: app-config affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app: myapp topologyKey: kubernetes.io/hostname topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app: myapp
Service Manifest
k8s/service.yaml
apiVersion: v1 kind: Service metadata: name: app-service namespace: production labels: app: myapp spec: type: ClusterIP selector: app: myapp ports: - name: http port: 80 targetPort: http protocol: TCP - name: metrics port: 9090 targetPort: metrics protocol: TCP
Headless service for StatefulSet
apiVersion: v1 kind: Service metadata: name: app-headless namespace: production spec: type: ClusterIP clusterIP: None selector: app: myapp ports: - name: http port: 80 targetPort: http
Ingress Configuration
k8s/ingress.yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: app-ingress namespace: production annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt-prod nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/rate-limit: "100" nginx.ingress.kubernetes.io/rate-limit-window: "1m" nginx.ingress.kubernetes.io/proxy-body-size: "10m" nginx.ingress.kubernetes.io/proxy-read-timeout: "60" spec: tls: - hosts: - app.example.com - api.example.com secretName: app-tls-secret rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: app-service port: number: 80 - host: api.example.com http: paths: - path: /api pathType: Prefix backend: service: name: api-service port: number: 80
ConfigMap and Secrets
k8s/configmap.yaml
apiVersion: v1 kind: ConfigMap metadata: name: app-config namespace: production data: redis-host: redis-master.redis.svc.cluster.local log-level: info feature-flags: | { "newFeature": true, "betaAccess": false }
k8s/secret.yaml
apiVersion: v1 kind: Secret metadata: name: app-secrets namespace: production type: Opaque stringData: database-url: postgresql://user:pass@host:5432/db api-key: your-api-key-here
External Secrets (with external-secrets operator)
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: app-external-secrets namespace: production spec: refreshInterval: 1h secretStoreRef: name: aws-secrets-manager kind: ClusterSecretStore target: name: app-secrets creationPolicy: Owner data: - secretKey: database-url remoteRef: key: production/myapp/database property: url
Horizontal Pod Autoscaler
k8s/hpa.yaml
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: app-hpa namespace: production spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: app-deployment minReplicas: 3 maxReplicas: 20 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 - type: Pods pods: metric: name: http_requests_per_second target: type: AverageValue averageValue: 1000 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
Pod Disruption Budget
k8s/pdb.yaml
apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: app-pdb namespace: production spec: minAvailable: 2 selector: matchLabels: app: myapp
Network Policy
k8s/network-policy.yaml
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: app-network-policy namespace: production spec: podSelector: matchLabels: app: myapp policyTypes: - Ingress - Egress ingress: - from: - namespaceSelector: matchLabels: name: ingress-nginx - podSelector: matchLabels: app: frontend ports: - protocol: TCP port: 3000 egress: - to: - namespaceSelector: matchLabels: name: database ports: - protocol: TCP port: 5432 - to: - namespaceSelector: matchLabels: name: redis ports: - protocol: TCP port: 6379 - to: - ipBlock: cidr: 0.0.0.0/0 except: - 10.0.0.0/8 ports: - protocol: TCP port: 443
Service Account & RBAC
k8s/rbac.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: myapp-sa namespace: production
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: myapp-role namespace: production rules:
- apiGroups: [""] resources: ["configmaps", "secrets"] verbs: ["get", "list", "watch"]
- apiGroups: [""] resources: ["pods"] verbs: ["get", "list"]
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: myapp-rolebinding namespace: production subjects:
- kind: ServiceAccount name: myapp-sa namespace: production roleRef: kind: Role name: myapp-role apiGroup: rbac.authorization.k8s.io
StatefulSet for Stateful Apps
k8s/statefulset.yaml
apiVersion: apps/v1 kind: StatefulSet metadata: name: database namespace: production spec: serviceName: database-headless replicas: 3 selector: matchLabels: app: database template: metadata: labels: app: database spec: containers: - name: postgres image: postgres:15 ports: - containerPort: 5432 env: - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: db-secrets key: password volumeMounts: - name: data mountPath: /var/lib/postgresql/data volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] storageClassName: fast-ssd resources: requests: storage: 100Gi
CronJob
k8s/cronjob.yaml
apiVersion: batch/v1 kind: CronJob metadata: name: backup-job namespace: production spec: schedule: "0 2 * * *" timeZone: "America/New_York" concurrencyPolicy: Forbid successfulJobsHistoryLimit: 3 failedJobsHistoryLimit: 1 jobTemplate: spec: backoffLimit: 3 activeDeadlineSeconds: 3600 template: spec: restartPolicy: OnFailure containers: - name: backup image: myregistry/backup:latest env: - name: S3_BUCKET value: my-backups resources: requests: cpu: 100m memory: 256Mi limits: cpu: 500m memory: 512Mi
Kustomize Structure
k8s/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
- hpa.yaml
- pdb.yaml
commonLabels: app.kubernetes.io/name: myapp app.kubernetes.io/managed-by: kustomize
k8s/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization
namespace: production
resources:
- ../../base
- ingress.yaml
- network-policy.yaml
replicas:
- name: app-deployment count: 5
images:
- name: myregistry/myapp newTag: v1.2.3
patches:
- path: deployment-patch.yaml
Best Practices
-
Resource limits: Always set requests and limits
-
Health probes: Configure liveness and readiness
-
Security context: Run as non-root, drop capabilities
-
Pod anti-affinity: Spread across nodes/zones
-
Network policies: Restrict pod communication
-
Secrets management: Use external secrets operator
-
Rolling updates: Configure maxSurge and maxUnavailable
-
PDB: Ensure minimum availability during updates
Output Checklist
Every Kubernetes deployment should include:
-
Namespace isolation
-
Deployment with resource limits
-
Health probes (liveness/readiness)
-
Security context (non-root, read-only fs)
-
Service for networking
-
Ingress with TLS
-
ConfigMaps for configuration
-
Secrets (preferably external)
-
HPA for autoscaling
-
PDB for availability
-
Network policies
-
ServiceAccount with minimal RBAC