kubernetes-manifest-generator について
kubernetes-manifest-generatorは、Kubernetesのデプロイマニフェストを作成するスキルです。ワークロード、ネットワーク、設定、アクセス制御、スケーリング、可用性を扱い、セキュリティと運用上の指針も含みます。
主な機能
- 01DeploymentとServiceのマニフェスト生成
- 02Ingressとアプリ設定の構成
- 03オートスケーリングと中断予算の作成
- 04StatefulSetとCronJobリソースへの対応
- 05NetworkPolicyとRBACの作成
- 06リソース、プローブ、セキュリティ設定の指針
活用シーン
- 01Kubernetesアプリのマニフェスト作成
- 02ネットワークと外部アクセスの設定
- 03スケーリングと中断時の可用性設定
- 04アクセス権限とネットワーク制限の定義
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ patricio0312rev/ skills --skill kubernetes-manifest-generatorインストール後、Claude Code で/kubernetes-manifest-generatorを入力して読み込まれたか確認します。
詳細
Kubernetes マニフェストジェネレーター
セキュリティとスケーラビリティのベストプラクティスに沿って、本番環境に対応した Kubernetes マニフェストを生成します。
基本的なワークフロー
- リソースを定義する:必要な K8s オブジェクトを特定します
- Namespace を作成する:アプリケーションのリソースを分離します
- Deployment を設定する:Pod、レプリカ、リソースを設定します
- Service を設定する:ネットワークとロードバランシングを設定します
- Ingress を追加する:外部アクセスのルーティングを設定します
- スケーリングを設定する:HPA とリソース制限を設定します
Deployment マニフェスト
# 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 マニフェスト
# 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 の設定
# 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 と 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
# 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 の構成
# 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
ベストプラクティス
- リソース制限:必ず requests と limits を設定します
- ヘルスプローブ:liveness と readiness を設定します
- セキュリティコンテキスト:root 以外のユーザーで実行し、ケイパビリティを削除します
- Pod のアンチアフィニティ:ノード/ゾーンに分散させます
- ネットワークポリシー:Pod 間の通信を制限します
- Secrets の管理:外部 Secrets Operator を使用します
- ローリングアップデート:maxSurge と maxUnavailable を設定します
- PDB:更新中の最小可用性を確保します
出力チェックリスト
すべての Kubernetes Deployment に以下を含めます。
- Namespace による分離
- リソース制限を設定した Deployment
- ヘルスプローブ(liveness/readiness)
- セキュリティコンテキスト(root 以外のユーザー、読み取り専用ファイルシステム)
- ネットワーク用の Service
- TLS を設定した Ingress
- 設定用の ConfigMap
- Secrets(可能であれば外部管理)
- オートスケーリング用の HPA
- 可用性を確保するための PDB
- Network Policy
- 最小限の RBAC を設定した ServiceAccount
コメント
Markdown 対応