Claude-skill-registry k8s-manifests
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/k8s-manifests" ~/.claude/skills/majiayu000-claude-skill-registry-k8s-manifests && rm -rf "$T"
manifest:
skills/data/k8s-manifests/SKILL.mdsource content
Kubernetes / OpenShift Manifest Generator
Current Versions & CLI Documentation (January 2026)
| Platform | Current Version | CLI | Documentation |
|---|---|---|---|
| Kubernetes | 1.31.x | | https://kubernetes.io/docs/ |
| OpenShift | 4.17.x | | https://docs.openshift.com/ |
| EKS | 1.31 | , | https://docs.aws.amazon.com/eks/ |
| AKS | 1.31 | | https://learn.microsoft.com/azure/aks/ |
| GKE | 1.31 | | https://cloud.google.com/kubernetes-engine/docs |
| ARO | 4.17 | , | https://learn.microsoft.com/azure/openshift/ |
| ROSA | 4.17 | , | https://docs.openshift.com/rosa/ |
CLI Installation Quick Reference
# kubectl (latest stable) curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/$(uname -s | tr '[:upper:]' '[:lower:]')/amd64/kubectl" chmod +x kubectl && sudo mv kubectl /usr/local/bin/ # OR brew install kubectl # oc (OpenShift CLI) - download from mirror.openshift.com or: brew install openshift-cli # eksctl (AWS EKS) brew install eksctl # OR curl -sLO "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" # Azure CLI + AKS brew install azure-cli az extension add --name aks-preview # Google Cloud SDK + GKE brew install google-cloud-sdk gcloud components install gke-gcloud-auth-plugin # ROSA CLI rosa download cli
Command Usage Convention
IMPORTANT: This skill uses
kubectl as the primary command in all examples. When working with:
- OpenShift/ARO clusters: Replace all
commands withkubectloc - Standard Kubernetes clusters (AKS, EKS, GKE, etc.): Use
as shownkubectl
The agent will automatically detect the cluster type and use the appropriate command.
Generate production-ready YAML manifests following security best practices and operational excellence.
Core Principles
- Security by Default: Always include security contexts, never run as root unless explicitly required
- Resource Management: Always specify resource requests/limits
- High Availability: Default to multiple replicas with anti-affinity for production
- Observability: Include health probes, annotations for monitoring
- GitOps Ready: Generate manifests suitable for version control and GitOps workflows
Manifest Generation Workflow
- Identify resource type and target platform (K8s vanilla, OCP, EKS, GKE, AKS)
- Gather requirements (replicas, resources, networking, storage)
- Apply security best practices
- Generate YAML with appropriate labels and annotations
- Validate against best practices checklist
Resource Templates
Deployment (Production-Ready)
apiVersion: apps/v1 kind: Deployment metadata: name: ${APP_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/instance: ${INSTANCE} app.kubernetes.io/version: "${VERSION}" app.kubernetes.io/component: ${COMPONENT} app.kubernetes.io/part-of: ${PART_OF} app.kubernetes.io/managed-by: cluster-code annotations: description: "${DESCRIPTION}" spec: replicas: ${REPLICAS:-3} revisionHistoryLimit: 5 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 selector: matchLabels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/instance: ${INSTANCE} template: metadata: labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/instance: ${INSTANCE} annotations: prometheus.io/scrape: "true" prometheus.io/port: "${METRICS_PORT:-8080}" prometheus.io/path: "/metrics" spec: serviceAccountName: ${SERVICE_ACCOUNT:-default} securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 seccompProfile: type: RuntimeDefault affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app.kubernetes.io/name: ${APP_NAME} topologyKey: kubernetes.io/hostname topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app.kubernetes.io/name: ${APP_NAME} containers: - name: ${APP_NAME} image: ${IMAGE}:${TAG} imagePullPolicy: IfNotPresent securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL ports: - name: http containerPort: ${PORT:-8080} protocol: TCP env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace envFrom: - configMapRef: name: ${APP_NAME}-config optional: true - secretRef: name: ${APP_NAME}-secrets optional: true resources: requests: cpu: ${CPU_REQUEST:-100m} memory: ${MEMORY_REQUEST:-128Mi} limits: cpu: ${CPU_LIMIT:-500m} memory: ${MEMORY_LIMIT:-512Mi} livenessProbe: httpGet: path: /healthz port: http initialDelaySeconds: 15 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /ready port: http initialDelaySeconds: 5 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 3 startupProbe: httpGet: path: /healthz port: http initialDelaySeconds: 10 periodSeconds: 5 failureThreshold: 30 volumeMounts: - name: tmp mountPath: /tmp - name: cache mountPath: /var/cache volumes: - name: tmp emptyDir: {} - name: cache emptyDir: {} terminationGracePeriodSeconds: 30
Service
apiVersion: v1 kind: Service metadata: name: ${APP_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code spec: type: ${SERVICE_TYPE:-ClusterIP} ports: - name: http port: ${SERVICE_PORT:-80} targetPort: http protocol: TCP selector: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/instance: ${INSTANCE}
Ingress (K8s)
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ${APP_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code annotations: nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/proxy-body-size: "10m" cert-manager.io/cluster-issuer: ${CLUSTER_ISSUER:-letsencrypt-prod} spec: ingressClassName: ${INGRESS_CLASS:-nginx} tls: - hosts: - ${HOST} secretName: ${APP_NAME}-tls rules: - host: ${HOST} http: paths: - path: / pathType: Prefix backend: service: name: ${APP_NAME} port: name: http
OpenShift Route
apiVersion: route.openshift.io/v1 kind: Route metadata: name: ${APP_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code annotations: haproxy.router.openshift.io/timeout: 60s spec: host: ${HOST} to: kind: Service name: ${APP_NAME} weight: 100 port: targetPort: http tls: termination: edge insecureEdgeTerminationPolicy: Redirect wildcardPolicy: None
ConfigMap
apiVersion: v1 kind: ConfigMap metadata: name: ${APP_NAME}-config namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code data: # Application configuration APP_ENV: "${ENVIRONMENT:-production}" LOG_LEVEL: "${LOG_LEVEL:-info}" # Add application-specific config here
Secret (Template - values should be base64 encoded or use stringData)
apiVersion: v1 kind: Secret metadata: name: ${APP_NAME}-secrets namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code type: Opaque stringData: # Use stringData for plain text (auto-encoded) # Use data: for pre-encoded base64 values DATABASE_URL: "${DATABASE_URL}"
PersistentVolumeClaim
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: ${APP_NAME}-data namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code spec: accessModes: - ${ACCESS_MODE:-ReadWriteOnce} storageClassName: ${STORAGE_CLASS:-standard} resources: requests: storage: ${STORAGE_SIZE:-10Gi}
StatefulSet
apiVersion: apps/v1 kind: StatefulSet metadata: name: ${APP_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code spec: serviceName: ${APP_NAME}-headless replicas: ${REPLICAS:-3} podManagementPolicy: Parallel updateStrategy: type: RollingUpdate selector: matchLabels: app.kubernetes.io/name: ${APP_NAME} template: metadata: labels: app.kubernetes.io/name: ${APP_NAME} spec: securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 1000 seccompProfile: type: RuntimeDefault containers: - name: ${APP_NAME} image: ${IMAGE}:${TAG} securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL ports: - name: http containerPort: ${PORT:-8080} resources: requests: cpu: ${CPU_REQUEST:-100m} memory: ${MEMORY_REQUEST:-256Mi} limits: cpu: ${CPU_LIMIT:-1000m} memory: ${MEMORY_LIMIT:-1Gi} volumeMounts: - name: data mountPath: /data volumeClaimTemplates: - metadata: name: data spec: accessModes: - ReadWriteOnce storageClassName: ${STORAGE_CLASS:-standard} resources: requests: storage: ${STORAGE_SIZE:-10Gi}
NetworkPolicy
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: ${APP_NAME}-netpol namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code spec: podSelector: matchLabels: app.kubernetes.io/name: ${APP_NAME} policyTypes: - Ingress - Egress ingress: - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: ${INGRESS_NAMESPACE:-ingress-nginx} - podSelector: matchLabels: app.kubernetes.io/name: ${ALLOWED_APP} ports: - protocol: TCP port: ${PORT:-8080} egress: - to: - namespaceSelector: {} ports: - protocol: UDP port: 53 - to: - podSelector: matchLabels: app.kubernetes.io/name: ${EGRESS_TARGET} ports: - protocol: TCP port: ${EGRESS_PORT}
HorizontalPodAutoscaler
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: ${APP_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: ${APP_NAME} minReplicas: ${MIN_REPLICAS:-2} maxReplicas: ${MAX_REPLICAS:-10} metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: ${CPU_TARGET:-70} - type: Resource resource: name: memory target: type: Utilization averageUtilization: ${MEMORY_TARGET:-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
ServiceAccount with RBAC
apiVersion: v1 kind: ServiceAccount metadata: name: ${APP_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code automountServiceAccountToken: false --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: ${APP_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code 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: ${APP_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: ${APP_NAME} subjects: - kind: ServiceAccount name: ${APP_NAME} namespace: ${NAMESPACE}
CronJob
apiVersion: batch/v1 kind: CronJob metadata: name: ${JOB_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${JOB_NAME} app.kubernetes.io/managed-by: cluster-code spec: schedule: "${SCHEDULE}" concurrencyPolicy: ${CONCURRENCY:-Forbid} successfulJobsHistoryLimit: 3 failedJobsHistoryLimit: 3 startingDeadlineSeconds: 300 jobTemplate: spec: backoffLimit: 3 activeDeadlineSeconds: ${TIMEOUT:-3600} template: spec: securityContext: runAsNonRoot: true runAsUser: 1000 seccompProfile: type: RuntimeDefault restartPolicy: OnFailure containers: - name: ${JOB_NAME} image: ${IMAGE}:${TAG} securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL resources: requests: cpu: ${CPU_REQUEST:-100m} memory: ${MEMORY_REQUEST:-128Mi} limits: cpu: ${CPU_LIMIT:-500m} memory: ${MEMORY_LIMIT:-512Mi} command: ${COMMAND} args: ${ARGS}
PodDisruptionBudget
apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: ${APP_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code spec: minAvailable: ${MIN_AVAILABLE:-1} # OR use maxUnavailable: ${MAX_UNAVAILABLE:-1} selector: matchLabels: app.kubernetes.io/name: ${APP_NAME}
OpenShift-Specific Resources
SecurityContextConstraints (Cluster-Admin)
apiVersion: security.openshift.io/v1 kind: SecurityContextConstraints metadata: name: ${SCC_NAME} labels: app.kubernetes.io/managed-by: cluster-code allowHostDirVolumePlugin: false allowHostIPC: false allowHostNetwork: false allowHostPID: false allowHostPorts: false allowPrivilegeEscalation: false allowPrivilegedContainer: false allowedCapabilities: null defaultAddCapabilities: null fsGroup: type: MustRunAs ranges: - min: 1000 max: 65534 priority: null readOnlyRootFilesystem: true requiredDropCapabilities: - ALL runAsUser: type: MustRunAsRange uidRangeMin: 1000 uidRangeMax: 65534 seLinuxContext: type: MustRunAs supplementalGroups: type: MustRunAs ranges: - min: 1000 max: 65534 users: [] groups: [] volumes: - configMap - downwardAPI - emptyDir - persistentVolumeClaim - projected - secret
BuildConfig (S2I)
apiVersion: build.openshift.io/v1 kind: BuildConfig metadata: name: ${APP_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code spec: source: type: Git git: uri: ${GIT_URI} ref: ${GIT_REF:-main} contextDir: ${CONTEXT_DIR:-/} strategy: type: Source sourceStrategy: from: kind: ImageStreamTag namespace: openshift name: ${BUILDER_IMAGE:-python:3.11-ubi8} env: - name: APP_ENV value: ${ENVIRONMENT:-production} output: to: kind: ImageStreamTag name: ${APP_NAME}:latest triggers: - type: ConfigChange - type: ImageChange - type: GitHub github: secret: ${WEBHOOK_SECRET} resources: limits: cpu: "1" memory: 2Gi requests: cpu: 500m memory: 1Gi
ImageStream
apiVersion: image.openshift.io/v1 kind: ImageStream metadata: name: ${APP_NAME} namespace: ${NAMESPACE} labels: app.kubernetes.io/name: ${APP_NAME} app.kubernetes.io/managed-by: cluster-code spec: lookupPolicy: local: true tags: - name: latest annotations: description: Latest build of ${APP_NAME}
Best Practices Checklist
Before finalizing any manifest, verify:
Security
-
in securityContextrunAsNonRoot: true -
allowPrivilegeEscalation: false -
(with emptyDir for temp/cache)readOnlyRootFilesystem: true -
capabilities.drop: [ALL] -
seccompProfile.type: RuntimeDefault - ServiceAccount with minimal RBAC permissions
- NetworkPolicy restricting ingress/egress
- Secrets not hardcoded, using Secret resources or external secrets operator
Reliability
- Resource requests AND limits defined
- Liveness, readiness, and startup probes configured
- PodDisruptionBudget for HA workloads
- Anti-affinity rules for multi-replica deployments
- TopologySpreadConstraints for zone distribution
Operations
- Standard Kubernetes labels (app.kubernetes.io/*)
- Prometheus annotations for metrics scraping
- Appropriate terminationGracePeriodSeconds
- RevisionHistoryLimit set (default 5)
- RollingUpdate strategy with maxSurge/maxUnavailable
Observability
- Logging to stdout/stderr
- Metrics endpoint exposed
- Health check endpoints (/healthz, /ready)
- Resource annotations for monitoring dashboards
Common Patterns
Sidecar Container Pattern
Add sidecars for logging, monitoring, or service mesh:
containers: - name: app # main application - name: sidecar image: sidecar-image resources: requests: cpu: 10m memory: 32Mi limits: cpu: 50m memory: 64Mi
Init Container Pattern
For initialization, migrations, or waiting on dependencies:
initContainers: - name: wait-for-db image: busybox command: ['sh', '-c', 'until nc -z ${DB_HOST} 5432; do sleep 2; done'] - name: migrations image: ${IMAGE}:${TAG} command: ['./migrate.sh']
External Secrets Pattern
For HashiCorp Vault, AWS Secrets Manager, etc.:
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: ${APP_NAME}-secrets spec: refreshInterval: 1h secretStoreRef: name: vault-backend kind: ClusterSecretStore target: name: ${APP_NAME}-secrets data: - secretKey: DATABASE_URL remoteRef: key: ${VAULT_PATH} property: database_url
Platform-Specific Notes
EKS (AWS) - v1.31
CLI Commands:
# Create cluster with eksctl eksctl create cluster --name ${CLUSTER} --region ${REGION} \ --version 1.31 --nodegroup-name standard \ --node-type m6i.large --nodes 3 --nodes-min 1 --nodes-max 5 \ --managed --spot # Get kubeconfig aws eks update-kubeconfig --name ${CLUSTER} --region ${REGION} # Check add-ons aws eks list-addons --cluster-name ${CLUSTER} # Install EKS Pod Identity (replaces IRSA in 1.31+) eksctl create podidentityassociation --cluster ${CLUSTER} \ --namespace ${NS} --service-account-name ${SA} \ --role-arn arn:aws:iam::${ACCOUNT}:role/${ROLE}
Key Features (1.31):
- EKS Pod Identity (simplified IAM for pods, replaces IRSA complexity)
- EKS Auto Mode (automatic node management)
- EBS CSI driver for gp3 volumes (default)
- AWS Load Balancer Controller v2.9+ for ALB/NLB
- Karpenter v1.0+ for autoscaling
Manifest Annotations:
# ALB Ingress (AWS Load Balancer Controller) apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: alb alb.ingress.kubernetes.io/scheme: internet-facing alb.ingress.kubernetes.io/target-type: ip alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06 alb.ingress.kubernetes.io/certificate-arn: ${ACM_CERT_ARN} alb.ingress.kubernetes.io/healthcheck-path: /healthz alb.ingress.kubernetes.io/wafv2-acl-arn: ${WAF_ARN} # Optional WAF # NLB Service apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/aws-load-balancer-type: nlb service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
GKE (Google Cloud) - v1.31
CLI Commands:
# Create Autopilot cluster (recommended) gcloud container clusters create-auto ${CLUSTER} \ --region ${REGION} \ --release-channel regular # Create Standard cluster gcloud container clusters create ${CLUSTER} \ --region ${REGION} \ --num-nodes 3 \ --machine-type e2-standard-4 \ --enable-autoscaling --min-nodes 1 --max-nodes 10 \ --workload-pool=${PROJECT}.svc.id.goog \ --enable-dataplane-v2 # Cilium-based networking # Get credentials gcloud container clusters get-credentials ${CLUSTER} --region ${REGION} # Check GKE version gcloud container get-server-config --region ${REGION}
Key Features (1.31):
- Autopilot mode (fully managed nodes)
- GKE Dataplane V2 (Cilium-based eBPF networking)
- Workload Identity Federation (replaces node SA)
- Gateway API support (standard)
- Config Connector for GCP resource management
Manifest Annotations:
# GCE Ingress with Google-managed cert apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: gce kubernetes.io/ingress.global-static-ip-name: ${STATIC_IP} networking.gke.io/managed-certificates: ${MANAGED_CERT} networking.gke.io/v1beta1.FrontendConfig: ${FRONTEND_CONFIG} # NEG for container-native load balancing (recommended) apiVersion: v1 kind: Service metadata: annotations: cloud.google.com/neg: '{"ingress": true}' cloud.google.com/backend-config: '{"default": "${BACKEND_CONFIG}"}'
AKS (Azure) - v1.31
CLI Commands:
# Create AKS cluster az aks create --resource-group ${RG} --name ${CLUSTER} \ --kubernetes-version 1.31 \ --node-count 3 --node-vm-size Standard_D4s_v5 \ --enable-managed-identity \ --enable-workload-identity \ --enable-oidc-issuer \ --network-plugin azure \ --network-plugin-mode overlay \ --network-dataplane cilium \ --enable-addons monitoring # Get credentials az aks get-credentials --resource-group ${RG} --name ${CLUSTER} # Check cluster az aks show --resource-group ${RG} --name ${CLUSTER} # Enable addons az aks enable-addons --addons azure-keyvault-secrets-provider \ --resource-group ${RG} --name ${CLUSTER}
Key Features (1.31):
- Azure CNI Overlay with Cilium (eBPF networking)
- Workload Identity (Azure AD pod identity replacement)
- KEDA add-on (event-driven autoscaling)
- Azure Key Vault Secrets Provider (CSI driver)
- Automatic image cleaner and node autoprovision
Manifest Annotations:
# Azure Application Gateway Ingress apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: azure/application-gateway appgw.ingress.kubernetes.io/ssl-redirect: "true" appgw.ingress.kubernetes.io/use-private-ip: "false" appgw.ingress.kubernetes.io/backend-path-prefix: "/" appgw.ingress.kubernetes.io/waf-policy-for-path: ${WAF_POLICY_ID} # Azure Internal Load Balancer apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/azure-load-balancer-internal: "true" service.beta.kubernetes.io/azure-load-balancer-internal-subnet: ${SUBNET} service.beta.kubernetes.io/azure-pls-create: "true" # Private Link
OpenShift / ARO / ROSA - v4.17
CLI Commands:
# OpenShift CLI basics oc login ${API_URL} --token=${TOKEN} oc project ${NAMESPACE} oc new-project ${PROJECT} # ARO (Azure Red Hat OpenShift) az aro create --resource-group ${RG} --name ${CLUSTER} \ --vnet ${VNET} --master-subnet ${MASTER_SUBNET} \ --worker-subnet ${WORKER_SUBNET} \ --pull-secret @pull-secret.txt az aro show --resource-group ${RG} --name ${CLUSTER} --query consoleProfile.url az aro list-credentials --resource-group ${RG} --name ${CLUSTER} # ROSA (Red Hat OpenShift on AWS) rosa create cluster --cluster-name ${CLUSTER} \ --region ${REGION} \ --sts --mode auto \ --hosted-cp # Hosted control plane (HCP) for faster provisioning rosa describe cluster --cluster ${CLUSTER} rosa create admin --cluster ${CLUSTER}
Key Features (4.17):
- OVN-Kubernetes (default CNI with eBPF)
- ROSA with Hosted Control Planes (HCP)
- SecurityContextConstraints (SCC) with Pod Security Admission
- OpenShift GitOps (ArgoCD) and Pipelines (Tekton) operators
- Service Mesh 3.0 (Istio-based)
- OpenShift AI (machine learning platform)
OpenShift-specific Resources:
# Route (instead of Ingress) apiVersion: route.openshift.io/v1 kind: Route metadata: name: ${APP_NAME} annotations: haproxy.router.openshift.io/timeout: 60s haproxy.router.openshift.io/rate-limit-connections: "true" haproxy.router.openshift.io/rate-limit-connections.rate-http: "100" spec: host: ${HOST} to: kind: Service name: ${APP_NAME} port: targetPort: http tls: termination: edge insecureEdgeTerminationPolicy: Redirect certificate: | ${CERT} key: | ${KEY}