Kubernetes Specialist When to Use This Skill - Deploying workloads (Deployments, StatefulSets, DaemonSets, Jobs) - Configuring networking (Services, Ingress, NetworkPolicies) - Managing configuration (ConfigMaps, Secrets, environment variables) - Setting up persistent storage (PV, PVC, StorageClasses) - Creating Helm charts for application packaging - Troubleshooting cluster and workload issues - Implementing security best practices Core Workflow 1. Analyze requirements — Understand workload characteristics, scaling needs, security requirements 2. Design architecture — Choose workload types,…

\n replicas:\n type: integer\n minimum: 1\n maximum: 5\n default: 1\n status:\n type: object\n properties:\n phase:\n type: string\n enum: [Pending, Creating, Running, Failed, Terminating]\n ready:\n type: boolean\n message:\n type: string\n endpoint:\n type: string\n subresources:\n status: {}\n scale:\n specReplicasPath: .spec.replicas\n statusReplicasPath: .status.replicas\n additionalPrinterColumns:\n - name: Engine\n type: string\n jsonPath: .spec.engine\n - name: Version\n type: string\n jsonPath: .spec.version\n - name: Status\n type: string\n jsonPath: .status.phase\n - name: Age\n type: date\n jsonPath: .metadata.creationTimestamp\n```\n\n## Custom Resource Instance\n\n```yaml\napiVersion: mycompany.io/v1\nkind: Database\nmetadata:\n name: orders-db\n namespace: production\nspec:\n engine: postgres\n version: \"15.4\"\n storage: 100Gi\n replicas: 3\n```\n\n## Operator SDK Project Structure\n\n```\nmy-operator/\n├── Dockerfile\n├── Makefile\n├── PROJECT # Kubebuilder project config\n├── config/\n│ ├── crd/ # CRD manifests\n│ │ └── bases/\n│ │ └── mycompany.io_databases.yaml\n│ ├── manager/ # Operator deployment\n│ │ └── manager.yaml\n│ ├── rbac/ # RBAC configuration\n│ │ ├── role.yaml\n│ │ ├── role_binding.yaml\n│ │ └── service_account.yaml\n│ └── samples/ # Example CRs\n│ └── mycompany_v1_database.yaml\n├── api/\n│ └── v1/\n│ ├── database_types.go # API type definitions\n│ ├── groupversion_info.go\n│ └── zz_generated.deepcopy.go\n├── controllers/\n│ └── database_controller.go # Reconciliation logic\n├── main.go # Entry point\n└── go.mod\n```\n\n## API Type Definition (Go)\n\n```go\n// api/v1/database_types.go\npackage v1\n\nimport (\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)\n\n// DatabaseSpec defines the desired state of Database\ntype DatabaseSpec struct {\n\t// Engine is the database engine type\n\t// +kubebuilder:validation:Enum=postgres;mysql;mongodb\n\tEngine string `json:\"engine\"`\n\n\t// Version is the database version\n\tVersion string `json:\"version\"`\n\n\t// Storage is the size of persistent storage\n\t// +kubebuilder:validation:Pattern=`^[0-9]+Gi kubernetes-specialist — Skillopedia \n\tStorage string `json:\"storage\"`\n\n\t// Replicas is the number of database instances\n\t// +kubebuilder:validation:Minimum=1\n\t// +kubebuilder:validation:Maximum=5\n\t// +kubebuilder:default=1\n\t// +optional\n\tReplicas int32 `json:\"replicas,omitempty\"`\n}\n\n// DatabaseStatus defines the observed state of Database\ntype DatabaseStatus struct {\n\t// Phase represents the current lifecycle phase\n\tPhase string `json:\"phase,omitempty\"`\n\n\t// Ready indicates if the database is ready to accept connections\n\tReady bool `json:\"ready,omitempty\"`\n\n\t// Message provides additional status information\n\tMessage string `json:\"message,omitempty\"`\n\n\t// Endpoint is the connection endpoint\n\tEndpoint string `json:\"endpoint,omitempty\"`\n\n\t// Replicas is the current number of running replicas\n\tReplicas int32 `json:\"replicas,omitempty\"`\n}\n\n// +kubebuilder:object:root=true\n// +kubebuilder:subresource:status\n// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas\n// +kubebuilder:printcolumn:name=\"Engine\",type=string,JSONPath=`.spec.engine`\n// +kubebuilder:printcolumn:name=\"Version\",type=string,JSONPath=`.spec.version`\n// +kubebuilder:printcolumn:name=\"Status\",type=string,JSONPath=`.status.phase`\n// +kubebuilder:printcolumn:name=\"Age\",type=\"date\",JSONPath=\".metadata.creationTimestamp\"\n\n// Database is the Schema for the databases API\ntype Database struct {\n\tmetav1.TypeMeta `json:\",inline\"`\n\tmetav1.ObjectMeta `json:\"metadata,omitempty\"`\n\n\tSpec DatabaseSpec `json:\"spec,omitempty\"`\n\tStatus DatabaseStatus `json:\"status,omitempty\"`\n}\n\n// +kubebuilder:object:root=true\n\n// DatabaseList contains a list of Database\ntype DatabaseList struct {\n\tmetav1.TypeMeta `json:\",inline\"`\n\tmetav1.ListMeta `json:\"metadata,omitempty\"`\n\tItems []Database `json:\"items\"`\n}\n\nfunc init() {\n\tSchemeBuilder.Register(&Database{}, &DatabaseList{})\n}\n```\n\n## Controller Implementation\n\n```go\n// controllers/database_controller.go\npackage controllers\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\t\"k8s.io/apimachinery/pkg/api/errors\"\n\t\"k8s.io/apimachinery/pkg/api/resource\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/apimachinery/pkg/types\"\n\tctrl \"sigs.k8s.io/controller-runtime\"\n\t\"sigs.k8s.io/controller-runtime/pkg/client\"\n\t\"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil\"\n\t\"sigs.k8s.io/controller-runtime/pkg/log\"\n\n\tmycompanyv1 \"github.com/mycompany/database-operator/api/v1\"\n)\n\nconst databaseFinalizer = \"databases.mycompany.io/finalizer\"\n\ntype DatabaseReconciler struct {\n\tclient.Client\n\tScheme *runtime.Scheme\n}\n\n// +kubebuilder:rbac:groups=mycompany.io,resources=databases,verbs=get;list;watch;create;update;patch;delete\n// +kubebuilder:rbac:groups=mycompany.io,resources=databases/status,verbs=get;update;patch\n// +kubebuilder:rbac:groups=mycompany.io,resources=databases/finalizers,verbs=update\n// +kubebuilder:rbac:groups=apps,resources=statefulsets,verbs=get;list;watch;create;update;patch;delete\n// +kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;update;patch;delete\n// +kubebuilder:rbac:groups=core,resources=persistentvolumeclaims,verbs=get;list;watch\n\nfunc (r *DatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {\n\tlogger := log.FromContext(ctx)\n\n\t// Fetch the Database instance\n\tdatabase := &mycompanyv1.Database{}\n\tif err := r.Get(ctx, req.NamespacedName, database); err != nil {\n\t\tif errors.IsNotFound(err) {\n\t\t\treturn ctrl.Result{}, nil\n\t\t}\n\t\treturn ctrl.Result{}, err\n\t}\n\n\t// Handle deletion with finalizer\n\tif !database.DeletionTimestamp.IsZero() {\n\t\tif controllerutil.ContainsFinalizer(database, databaseFinalizer) {\n\t\t\tif err := r.cleanupResources(ctx, database); err != nil {\n\t\t\t\treturn ctrl.Result{}, err\n\t\t\t}\n\t\t\tcontrollerutil.RemoveFinalizer(database, databaseFinalizer)\n\t\t\tif err := r.Update(ctx, database); err != nil {\n\t\t\t\treturn ctrl.Result{}, err\n\t\t\t}\n\t\t}\n\t\treturn ctrl.Result{}, nil\n\t}\n\n\t// Add finalizer if not present\n\tif !controllerutil.ContainsFinalizer(database, databaseFinalizer) {\n\t\tcontrollerutil.AddFinalizer(database, databaseFinalizer)\n\t\tif err := r.Update(ctx, database); err != nil {\n\t\t\treturn ctrl.Result{}, err\n\t\t}\n\t}\n\n\t// Reconcile StatefulSet\n\tstatefulSet := r.buildStatefulSet(database)\n\tif err := controllerutil.SetControllerReference(database, statefulSet, r.Scheme); err != nil {\n\t\treturn ctrl.Result{}, err\n\t}\n\n\tfound := &appsv1.StatefulSet{}\n\terr := r.Get(ctx, types.NamespacedName{Name: statefulSet.Name, Namespace: statefulSet.Namespace}, found)\n\tif err != nil && errors.IsNotFound(err) {\n\t\tlogger.Info(\"Creating StatefulSet\", \"name\", statefulSet.Name)\n\t\tif err := r.Create(ctx, statefulSet); err != nil {\n\t\t\treturn ctrl.Result{}, err\n\t\t}\n\t\treturn r.updateStatus(ctx, database, \"Creating\", false, \"StatefulSet created\")\n\t} else if err != nil {\n\t\treturn ctrl.Result{}, err\n\t}\n\n\t// Reconcile Service\n\tservice := r.buildService(database)\n\tif err := controllerutil.SetControllerReference(database, service, r.Scheme); err != nil {\n\t\treturn ctrl.Result{}, err\n\t}\n\n\tfoundSvc := &corev1.Service{}\n\terr = r.Get(ctx, types.NamespacedName{Name: service.Name, Namespace: service.Namespace}, foundSvc)\n\tif err != nil && errors.IsNotFound(err) {\n\t\tif err := r.Create(ctx, service); err != nil {\n\t\t\treturn ctrl.Result{}, err\n\t\t}\n\t}\n\n\t// Update status based on StatefulSet state\n\tif found.Status.ReadyReplicas == *found.Spec.Replicas {\n\t\treturn r.updateStatus(ctx, database, \"Running\", true,\n\t\t\tfmt.Sprintf(\"%d/%d replicas ready\", found.Status.ReadyReplicas, *found.Spec.Replicas))\n\t}\n\n\t// Requeue to check status\n\treturn ctrl.Result{RequeueAfter: 10 * time.Second}, nil\n}\n\nfunc (r *DatabaseReconciler) buildStatefulSet(db *mycompanyv1.Database) *appsv1.StatefulSet {\n\treplicas := db.Spec.Replicas\n\tlabels := map[string]string{\n\t\t\"app\": db.Name,\n\t\t\"controller\": db.Name,\n\t}\n\n\treturn &appsv1.StatefulSet{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName: db.Name,\n\t\t\tNamespace: db.Namespace,\n\t\t},\n\t\tSpec: appsv1.StatefulSetSpec{\n\t\t\tReplicas: &replicas,\n\t\t\tSelector: &metav1.LabelSelector{\n\t\t\t\tMatchLabels: labels,\n\t\t\t},\n\t\t\tServiceName: db.Name,\n\t\t\tTemplate: corev1.PodTemplateSpec{\n\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\tLabels: labels,\n\t\t\t\t},\n\t\t\t\tSpec: corev1.PodSpec{\n\t\t\t\t\tContainers: []corev1.Container{{\n\t\t\t\t\t\tName: \"database\",\n\t\t\t\t\t\tImage: fmt.Sprintf(\"%s:%s\", db.Spec.Engine, db.Spec.Version),\n\t\t\t\t\t\tPorts: []corev1.ContainerPort{{\n\t\t\t\t\t\t\tContainerPort: 5432,\n\t\t\t\t\t\t\tName: \"db\",\n\t\t\t\t\t\t}},\n\t\t\t\t\t}},\n\t\t\t\t},\n\t\t\t},\n\t\t\tVolumeClaimTemplates: []corev1.PersistentVolumeClaim{{\n\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\tName: \"data\",\n\t\t\t\t},\n\t\t\t\tSpec: corev1.PersistentVolumeClaimSpec{\n\t\t\t\t\tAccessModes: []corev1.PersistentVolumeAccessMode{\n\t\t\t\t\t\tcorev1.ReadWriteOnce,\n\t\t\t\t\t},\n\t\t\t\t\tResources: corev1.VolumeResourceRequirements{\n\t\t\t\t\t\tRequests: corev1.ResourceList{\n\t\t\t\t\t\t\tcorev1.ResourceStorage: resource.MustParse(db.Spec.Storage),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}},\n\t\t},\n\t}\n}\n\nfunc (r *DatabaseReconciler) buildService(db *mycompanyv1.Database) *corev1.Service {\n\treturn &corev1.Service{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName: db.Name,\n\t\t\tNamespace: db.Namespace,\n\t\t},\n\t\tSpec: corev1.ServiceSpec{\n\t\t\tSelector: map[string]string{\"app\": db.Name},\n\t\t\tPorts: []corev1.ServicePort{{\n\t\t\t\tPort: 5432,\n\t\t\t\tName: \"db\",\n\t\t\t}},\n\t\t\tClusterIP: \"None\", // Headless service for StatefulSet\n\t\t},\n\t}\n}\n\nfunc (r *DatabaseReconciler) updateStatus(ctx context.Context, db *mycompanyv1.Database,\n\tphase string, ready bool, message string) (ctrl.Result, error) {\n\tdb.Status.Phase = phase\n\tdb.Status.Ready = ready\n\tdb.Status.Message = message\n\tdb.Status.Endpoint = fmt.Sprintf(\"%s.%s.svc.cluster.local:5432\", db.Name, db.Namespace)\n\treturn ctrl.Result{}, r.Status().Update(ctx, db)\n}\n\nfunc (r *DatabaseReconciler) cleanupResources(ctx context.Context, db *mycompanyv1.Database) error {\n\t// Custom cleanup logic (e.g., backup before deletion)\n\treturn nil\n}\n\nfunc (r *DatabaseReconciler) SetupWithManager(mgr ctrl.Manager) error {\n\treturn ctrl.NewControllerManagedBy(mgr).\n\t\tFor(&mycompanyv1.Database{}).\n\t\tOwns(&appsv1.StatefulSet{}).\n\t\tOwns(&corev1.Service{}).\n\t\tComplete(r)\n}\n```\n\n## Operator RBAC\n\n```yaml\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: database-operator\n namespace: operators\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n name: database-operator-role\nrules:\n - apiGroups: [\"mycompany.io\"]\n resources: [\"databases\"]\n verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\", \"delete\"]\n - apiGroups: [\"mycompany.io\"]\n resources: [\"databases/status\"]\n verbs: [\"get\", \"update\", \"patch\"]\n - apiGroups: [\"mycompany.io\"]\n resources: [\"databases/finalizers\"]\n verbs: [\"update\"]\n - apiGroups: [\"apps\"]\n resources: [\"statefulsets\"]\n verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\", \"delete\"]\n - apiGroups: [\"\"]\n resources: [\"services\", \"configmaps\", \"secrets\"]\n verbs: [\"get\", \"list\", \"watch\", \"create\", \"update\", \"patch\", \"delete\"]\n - apiGroups: [\"\"]\n resources: [\"persistentvolumeclaims\"]\n verbs: [\"get\", \"list\", \"watch\"]\n - apiGroups: [\"\"]\n resources: [\"events\"]\n verbs: [\"create\", \"patch\"]\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n name: database-operator-rolebinding\nroleRef:\n apiGroup: rbac.authorization.k8s.io\n kind: ClusterRole\n name: database-operator-role\nsubjects:\n - kind: ServiceAccount\n name: database-operator\n namespace: operators\n```\n\n## Operator Deployment\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: database-operator\n namespace: operators\n labels:\n app: database-operator\nspec:\n replicas: 1\n selector:\n matchLabels:\n app: database-operator\n template:\n metadata:\n labels:\n app: database-operator\n spec:\n serviceAccountName: database-operator\n securityContext:\n runAsNonRoot: true\n seccompProfile:\n type: RuntimeDefault\n containers:\n - name: manager\n image: myregistry.io/database-operator:v1.0.0\n args:\n - --leader-elect\n - --health-probe-bind-address=:8081\n securityContext:\n allowPrivilegeEscalation: false\n capabilities:\n drop: [\"ALL\"]\n readOnlyRootFilesystem: true\n ports:\n - containerPort: 8080\n name: metrics\n livenessProbe:\n httpGet:\n path: /healthz\n port: 8081\n initialDelaySeconds: 15\n periodSeconds: 20\n readinessProbe:\n httpGet:\n path: /readyz\n port: 8081\n initialDelaySeconds: 5\n periodSeconds: 10\n resources:\n limits:\n cpu: 500m\n memory: 128Mi\n requests:\n cpu: 10m\n memory: 64Mi\n```\n\n## Operator SDK Commands\n\n```bash\n# Initialize new operator project\noperator-sdk init --domain mycompany.io --repo github.com/mycompany/database-operator\n\n# Create new API (CRD + controller)\noperator-sdk create api --group mycompany --version v1 --kind Database --resource --controller\n\n# Generate manifests (CRD, RBAC)\nmake manifests\n\n# Generate deep copy methods\nmake generate\n\n# Build operator image\nmake docker-build docker-push IMG=myregistry.io/database-operator:v1.0.0\n\n# Deploy to cluster\nmake deploy IMG=myregistry.io/database-operator:v1.0.0\n\n# Undeploy\nmake undeploy\n```\n\n## Best Practices\n\n1. **Use finalizers** for cleanup of external resources before CR deletion\n2. **Set owner references** so owned resources are garbage collected with the CR\n3. **Implement idempotent reconciliation** - same input should produce same output\n4. **Use status subresource** to separate desired state (spec) from observed state (status)\n5. **Add validation** via OpenAPI schema or webhooks\n6. **Emit events** for significant state changes\n7. **Use leader election** for high availability\n8. **Set resource limits** on the operator deployment\n9. **Follow least privilege** RBAC principles\n10. **Test with envtest** for unit testing controllers\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":15917,"content_sha256":"381e5cdc26f12cb0ba47039075027d2f167166de2ac15cfb485704f4677162e5"},{"filename":"references/gitops.md","content":"# GitOps\n\n---\n\n## GitOps Principles\n\n1. **Declarative** - Entire system described declaratively\n2. **Versioned and immutable** - Desired state stored in Git\n3. **Pulled automatically** - Agents pull state from Git\n4. **Continuously reconciled** - Agents ensure actual matches desired\n\n## ArgoCD Installation\n\n```bash\n# Create namespace\nkubectl create namespace argocd\n\n# Install ArgoCD\nkubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml\n\n# Wait for pods\nkubectl wait --for=condition=Ready pods --all -n argocd --timeout=300s\n\n# Get initial admin password\nkubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath=\"{.data.password}\" | base64 -d\n\n# Install CLI\nbrew install argocd\n\n# Login\nargocd login localhost:8080 --username admin --password \u003cpassword>\n\n# Access UI\nkubectl port-forward svc/argocd-server -n argocd 8080:443\n```\n\n## ArgoCD Application\n\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: Application\nmetadata:\n name: myapp\n namespace: argocd\n finalizers:\n - resources-finalizer.argocd.argoproj.io\nspec:\n project: default\n source:\n repoURL: https://github.com/myorg/myapp-manifests.git\n targetRevision: main\n path: overlays/production\n destination:\n server: https://kubernetes.default.svc\n namespace: production\n syncPolicy:\n automated:\n prune: true\n selfHeal: true\n allowEmpty: false\n syncOptions:\n - CreateNamespace=true\n - PrunePropagationPolicy=foreground\n - PruneLast=true\n retry:\n limit: 5\n backoff:\n duration: 5s\n factor: 2\n maxDuration: 3m\n revisionHistoryLimit: 10\n```\n\n## ArgoCD ApplicationSet\n\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: ApplicationSet\nmetadata:\n name: myapp-environments\n namespace: argocd\nspec:\n generators:\n - list:\n elements:\n - cluster: dev\n namespace: development\n revision: develop\n - cluster: staging\n namespace: staging\n revision: main\n - cluster: prod\n namespace: production\n revision: main\n template:\n metadata:\n name: 'myapp-{{cluster}}'\n spec:\n project: default\n source:\n repoURL: https://github.com/myorg/myapp-manifests.git\n targetRevision: '{{revision}}'\n path: 'overlays/{{cluster}}'\n destination:\n server: https://kubernetes.default.svc\n namespace: '{{namespace}}'\n syncPolicy:\n automated:\n prune: true\n selfHeal: true\n```\n\n## ArgoCD with Helm\n\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: Application\nmetadata:\n name: myapp-helm\n namespace: argocd\nspec:\n project: default\n source:\n repoURL: https://charts.example.com\n chart: myapp\n targetRevision: 1.2.0\n helm:\n releaseName: myapp\n valueFiles:\n - values-production.yaml\n values: |\n replicaCount: 5\n image:\n tag: v2.0.0\n parameters:\n - name: service.type\n value: LoadBalancer\n destination:\n server: https://kubernetes.default.svc\n namespace: production\n```\n\n## ArgoCD Project\n\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: AppProject\nmetadata:\n name: production\n namespace: argocd\nspec:\n description: Production applications\n sourceRepos:\n - 'https://github.com/myorg/*'\n - 'https://charts.example.com'\n destinations:\n - namespace: production\n server: https://kubernetes.default.svc\n - namespace: production-*\n server: https://kubernetes.default.svc\n clusterResourceWhitelist:\n - group: ''\n kind: Namespace\n namespaceResourceBlacklist:\n - group: ''\n kind: ResourceQuota\n - group: ''\n kind: LimitRange\n roles:\n - name: developer\n description: Developer access\n policies:\n - p, proj:production:developer, applications, get, production/*, allow\n - p, proj:production:developer, applications, sync, production/*, allow\n groups:\n - developers\n```\n\n## Flux Installation\n\n```bash\n# Install Flux CLI\nbrew install fluxcd/tap/flux\n\n# Check prerequisites\nflux check --pre\n\n# Bootstrap Flux (GitHub)\nflux bootstrap github \\\n --owner=myorg \\\n --repository=fleet-infra \\\n --branch=main \\\n --path=clusters/production \\\n --personal\n\n# Bootstrap Flux (GitLab)\nflux bootstrap gitlab \\\n --owner=myorg \\\n --repository=fleet-infra \\\n --branch=main \\\n --path=clusters/production\n```\n\n## Flux GitRepository\n\n```yaml\napiVersion: source.toolkit.fluxcd.io/v1\nkind: GitRepository\nmetadata:\n name: myapp\n namespace: flux-system\nspec:\n interval: 1m\n url: https://github.com/myorg/myapp-manifests\n ref:\n branch: main\n secretRef:\n name: github-credentials\n ignore: |\n # Exclude files\n .git/\n *.md\n```\n\n## Flux Kustomization\n\n```yaml\napiVersion: kustomize.toolkit.fluxcd.io/v1\nkind: Kustomization\nmetadata:\n name: myapp\n namespace: flux-system\nspec:\n interval: 10m\n targetNamespace: production\n sourceRef:\n kind: GitRepository\n name: myapp\n path: ./overlays/production\n prune: true\n timeout: 2m\n healthChecks:\n - apiVersion: apps/v1\n kind: Deployment\n name: myapp\n namespace: production\n postBuild:\n substitute:\n environment: production\n replicas: \"5\"\n substituteFrom:\n - kind: ConfigMap\n name: cluster-vars\n```\n\n## Flux HelmRepository\n\n```yaml\napiVersion: source.toolkit.fluxcd.io/v1beta2\nkind: HelmRepository\nmetadata:\n name: bitnami\n namespace: flux-system\nspec:\n interval: 1h\n url: https://charts.bitnami.com/bitnami\n---\napiVersion: helm.toolkit.fluxcd.io/v2beta1\nkind: HelmRelease\nmetadata:\n name: redis\n namespace: production\nspec:\n interval: 5m\n chart:\n spec:\n chart: redis\n version: '17.x'\n sourceRef:\n kind: HelmRepository\n name: bitnami\n namespace: flux-system\n values:\n architecture: standalone\n auth:\n enabled: true\n existingSecret: redis-credentials\n master:\n persistence:\n size: 10Gi\n```\n\n## Flux ImageUpdateAutomation\n\n```yaml\napiVersion: image.toolkit.fluxcd.io/v1beta1\nkind: ImageRepository\nmetadata:\n name: myapp\n namespace: flux-system\nspec:\n image: myregistry.io/myapp\n interval: 1m\n secretRef:\n name: registry-credentials\n---\napiVersion: image.toolkit.fluxcd.io/v1beta1\nkind: ImagePolicy\nmetadata:\n name: myapp\n namespace: flux-system\nspec:\n imageRepositoryRef:\n name: myapp\n policy:\n semver:\n range: '>=1.0.0'\n---\napiVersion: image.toolkit.fluxcd.io/v1beta1\nkind: ImageUpdateAutomation\nmetadata:\n name: myapp\n namespace: flux-system\nspec:\n interval: 1m\n sourceRef:\n kind: GitRepository\n name: myapp\n git:\n checkout:\n ref:\n branch: main\n commit:\n author:\n email: [email protected]\n name: fluxcdbot\n messageTemplate: 'Update image to {{.NewTag}}'\n push:\n branch: main\n update:\n path: ./overlays/production\n strategy: Setters\n```\n\n## Progressive Delivery with Flagger\n\n```yaml\n# Install Flagger\nkubectl apply -k github.com/fluxcd/flagger/kustomize/istio\n\n---\napiVersion: flagger.app/v1beta1\nkind: Canary\nmetadata:\n name: myapp\n namespace: production\nspec:\n targetRef:\n apiVersion: apps/v1\n kind: Deployment\n name: myapp\n progressDeadlineSeconds: 600\n service:\n port: 80\n targetPort: 8080\n gateways:\n - myapp-gateway\n hosts:\n - myapp.example.com\n analysis:\n interval: 1m\n threshold: 5\n maxWeight: 50\n stepWeight: 10\n metrics:\n - name: request-success-rate\n thresholdRange:\n min: 99\n interval: 1m\n - name: request-duration\n thresholdRange:\n max: 500\n interval: 1m\n webhooks:\n - name: load-test\n url: http://flagger-loadtester.test/\n timeout: 5s\n metadata:\n cmd: \"hey -z 1m -q 10 -c 2 http://myapp-canary.production:80/\"\n```\n\n## Sealed Secrets\n\n```bash\n# Install controller\nkubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml\n\n# Install kubeseal CLI\nbrew install kubeseal\n\n# Create sealed secret\nkubectl create secret generic db-credentials \\\n --from-literal=username=admin \\\n --from-literal=password=\u003cpassword> \\\n --dry-run=client -o yaml | \\\n kubeseal --format yaml > sealed-db-credentials.yaml\n\n# Apply sealed secret\nkubectl apply -f sealed-db-credentials.yaml\n```\n\n```yaml\napiVersion: bitnami.com/v1alpha1\nkind: SealedSecret\nmetadata:\n name: db-credentials\n namespace: production\nspec:\n encryptedData:\n username: \u003csealed-ciphertext>\n password: \u003csealed-ciphertext>\n template:\n type: Opaque\n metadata:\n labels:\n app: myapp\n```\n\n## SOPS with Age\n\n```bash\n# Install SOPS\nbrew install sops\n\n# Generate age key\nage-keygen -o age.agekey\n\n# Create SOPS config\ncat > .sops.yaml \u003c\u003c EOF\ncreation_rules:\n - path_regex: .*\\.enc\\.yaml$\n encrypted_regex: ^(data|stringData)$\n age: age1...publickey...\nEOF\n\n# Encrypt secret\nsops --encrypt --in-place secrets.enc.yaml\n\n# Configure Flux decryption\nkubectl create secret generic sops-age \\\n --namespace=flux-system \\\n --from-file=age.agekey\n```\n\n```yaml\n# Flux Kustomization with SOPS\napiVersion: kustomize.toolkit.fluxcd.io/v1\nkind: Kustomization\nmetadata:\n name: myapp\n namespace: flux-system\nspec:\n decryption:\n provider: sops\n secretRef:\n name: sops-age\n # ... rest of spec\n```\n\n## Repository Strategies\n\n### Mono-repo\n```\nfleet-repo/\n├── apps/\n│ ├── myapp/\n│ │ ├── base/\n│ │ └── overlays/\n│ └── another-app/\n├── infrastructure/\n│ ├── cert-manager/\n│ └── ingress-nginx/\n└── clusters/\n ├── dev/\n ├── staging/\n └── production/\n```\n\n### Multi-repo\n```\n# App repos (one per app)\nmyapp-manifests/\n├── base/\n└── overlays/\n\n# Infrastructure repo\ninfrastructure/\n├── cert-manager/\n└── ingress-nginx/\n\n# Fleet repo (references others)\nfleet-infra/\n├── apps.yaml # Points to app repos\n└── infra.yaml # Points to infra repo\n```\n\n## ArgoCD vs Flux Comparison\n\n| Feature | ArgoCD | Flux |\n|---------|--------|------|\n| UI | Built-in web UI | Third-party (Weave GitOps) |\n| Multi-tenancy | AppProject | Namespaced resources |\n| Helm | Native support | HelmController |\n| Image automation | ArgoCD Image Updater | Native ImagePolicy |\n| Notifications | ArgoCD Notifications | Alerts/Receivers |\n| RBAC | Built-in | Kubernetes RBAC |\n| Architecture | Centralized | Distributed |\n\n## Best Practices\n\n1. **Use separate repos** for app code and manifests\n2. **Protect main branch** with required reviews\n3. **Use sealed secrets or SOPS** for sensitive data\n4. **Enable auto-sync with prune** for drift correction\n5. **Set up notifications** for sync failures\n6. **Use ApplicationSets/Kustomizations** for multi-environment\n7. **Implement progressive delivery** for safe rollouts\n8. **Version your Helm charts** semantically\n9. **Keep manifests DRY** with Kustomize overlays\n10. **Monitor reconciliation metrics** and alerts\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":11081,"content_sha256":"74ae0f8ef62749e6e22bfe50e6ad07eb53d3bc8b46498275d528651a842fd71e"},{"filename":"references/helm-charts.md","content":"# Helm Charts\n\n## Chart Structure\n\n```\nmychart/\n├── Chart.yaml # Chart metadata\n├── values.yaml # Default values\n├── values.schema.json # Values validation schema\n├── charts/ # Dependency charts\n├── templates/ # Template files\n│ ├── NOTES.txt # Post-install notes\n│ ├── _helpers.tpl # Template helpers\n│ ├── deployment.yaml\n│ ├── service.yaml\n│ ├── ingress.yaml\n│ ├── configmap.yaml\n│ ├── secret.yaml\n│ ├── serviceaccount.yaml\n│ ├── hpa.yaml\n│ └── tests/\n│ └── test-connection.yaml\n├── .helmignore # Ignore patterns\n└── README.md # Chart documentation\n```\n\n## Chart.yaml\n\n```yaml\napiVersion: v2\nname: myapp\ndescription: A Helm chart for MyApp on Kubernetes\ntype: application\nversion: 1.2.0\nappVersion: \"2.5.0\"\n\nkeywords:\n - web\n - application\n - microservice\n\nhome: https://example.com\nsources:\n - https://github.com/example/myapp\n\nmaintainers:\n - name: DevOps Team\n email: [email protected]\n url: https://example.com/team\n\nicon: https://example.com/logo.png\n\ndependencies:\n - name: postgresql\n version: \"12.x.x\"\n repository: https://charts.bitnami.com/bitnami\n condition: postgresql.enabled\n tags:\n - database\n\n - name: redis\n version: \"17.x.x\"\n repository: https://charts.bitnami.com/bitnami\n condition: redis.enabled\n tags:\n - cache\n\nannotations:\n category: Application\n```\n\n## values.yaml\n\n```yaml\n# Default values for myapp\nreplicaCount: 3\n\nimage:\n repository: myregistry.io/myapp\n pullPolicy: IfNotPresent\n tag: \"\" # Overrides the image tag (default is .Chart.AppVersion)\n\nimagePullSecrets:\n - name: registry-credentials\n\nnameOverride: \"\"\nfullnameOverride: \"\"\n\nserviceAccount:\n create: true\n annotations: {}\n name: \"\"\n\npodAnnotations:\n prometheus.io/scrape: \"true\"\n prometheus.io/port: \"8080\"\n\npodSecurityContext:\n runAsNonRoot: true\n runAsUser: 1000\n fsGroup: 2000\n seccompProfile:\n type: RuntimeDefault\n\nsecurityContext:\n allowPrivilegeEscalation: false\n capabilities:\n drop:\n - ALL\n readOnlyRootFilesystem: true\n\nservice:\n type: ClusterIP\n port: 80\n targetPort: 8080\n annotations: {}\n\ningress:\n enabled: true\n className: \"nginx\"\n annotations:\n cert-manager.io/cluster-issuer: \"letsencrypt-prod\"\n nginx.ingress.kubernetes.io/ssl-redirect: \"true\"\n hosts:\n - host: myapp.example.com\n paths:\n - path: /\n pathType: Prefix\n tls:\n - secretName: myapp-tls\n hosts:\n - myapp.example.com\n\nresources:\n limits:\n cpu: 500m\n memory: 512Mi\n requests:\n cpu: 100m\n memory: 128Mi\n\nautoscaling:\n enabled: true\n minReplicas: 3\n maxReplicas: 10\n targetCPUUtilizationPercentage: 80\n targetMemoryUtilizationPercentage: 80\n\nnodeSelector: {}\n\ntolerations: []\n\naffinity:\n podAntiAffinity:\n preferredDuringSchedulingIgnoredDuringExecution:\n - weight: 100\n podAffinityTerm:\n labelSelector:\n matchExpressions:\n - key: app.kubernetes.io/name\n operator: In\n values:\n - myapp\n topologyKey: kubernetes.io/hostname\n\nlivenessProbe:\n httpGet:\n path: /health\n port: http\n initialDelaySeconds: 30\n periodSeconds: 10\n timeoutSeconds: 5\n failureThreshold: 3\n\nreadinessProbe:\n httpGet:\n path: /ready\n port: http\n initialDelaySeconds: 10\n periodSeconds: 5\n timeoutSeconds: 3\n failureThreshold: 2\n\nenv:\n - name: ENVIRONMENT\n value: production\n - name: LOG_LEVEL\n value: info\n\nenvFrom: []\n\nvolumeMounts: []\nvolumes: []\n\n# PostgreSQL dependency\npostgresql:\n enabled: true\n auth:\n username: myapp\n password: \"\" # Set via --set or separate secret\n database: myapp\n primary:\n persistence:\n enabled: true\n size: 10Gi\n\n# Redis dependency\nredis:\n enabled: true\n architecture: standalone\n auth:\n enabled: true\n password: \"\"\n master:\n persistence:\n enabled: true\n size: 5Gi\n```\n\n## templates/_helpers.tpl\n\n```yaml\n{{/*\nExpand the name of the chart.\n*/}}\n{{- define \"myapp.name\" -}}\n{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix \"-\" }}\n{{- end }}\n\n{{/*\nCreate a default fully qualified app name.\n*/}}\n{{- define \"myapp.fullname\" -}}\n{{- if .Values.fullnameOverride }}\n{{- .Values.fullnameOverride | trunc 63 | trimSuffix \"-\" }}\n{{- else }}\n{{- $name := default .Chart.Name .Values.nameOverride }}\n{{- if contains $name .Release.Name }}\n{{- .Release.Name | trunc 63 | trimSuffix \"-\" }}\n{{- else }}\n{{- printf \"%s-%s\" .Release.Name $name | trunc 63 | trimSuffix \"-\" }}\n{{- end }}\n{{- end }}\n{{- end }}\n\n{{/*\nCreate chart name and version as used by the chart label.\n*/}}\n{{- define \"myapp.chart\" -}}\n{{- printf \"%s-%s\" .Chart.Name .Chart.Version | replace \"+\" \"_\" | trunc 63 | trimSuffix \"-\" }}\n{{- end }}\n\n{{/*\nCommon labels\n*/}}\n{{- define \"myapp.labels\" -}}\nhelm.sh/chart: {{ include \"myapp.chart\" . }}\n{{ include \"myapp.selectorLabels\" . }}\n{{- if .Chart.AppVersion }}\napp.kubernetes.io/version: {{ .Chart.AppVersion | quote }}\n{{- end }}\napp.kubernetes.io/managed-by: {{ .Release.Service }}\n{{- end }}\n\n{{/*\nSelector labels\n*/}}\n{{- define \"myapp.selectorLabels\" -}}\napp.kubernetes.io/name: {{ include \"myapp.name\" . }}\napp.kubernetes.io/instance: {{ .Release.Name }}\n{{- end }}\n\n{{/*\nCreate the name of the service account to use\n*/}}\n{{- define \"myapp.serviceAccountName\" -}}\n{{- if .Values.serviceAccount.create }}\n{{- default (include \"myapp.fullname\" .) .Values.serviceAccount.name }}\n{{- else }}\n{{- default \"default\" .Values.serviceAccount.name }}\n{{- end }}\n{{- end }}\n```\n\n## templates/deployment.yaml\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: {{ include \"myapp.fullname\" . }}\n labels:\n {{- include \"myapp.labels\" . | nindent 4 }}\nspec:\n {{- if not .Values.autoscaling.enabled }}\n replicas: {{ .Values.replicaCount }}\n {{- end }}\n selector:\n matchLabels:\n {{- include \"myapp.selectorLabels\" . | nindent 6 }}\n template:\n metadata:\n annotations:\n checksum/config: {{ include (print $.Template.BasePath \"/configmap.yaml\") . | sha256sum }}\n {{- with .Values.podAnnotations }}\n {{- toYaml . | nindent 8 }}\n {{- end }}\n labels:\n {{- include \"myapp.selectorLabels\" . | nindent 8 }}\n spec:\n {{- with .Values.imagePullSecrets }}\n imagePullSecrets:\n {{- toYaml . | nindent 8 }}\n {{- end }}\n serviceAccountName: {{ include \"myapp.serviceAccountName\" . }}\n securityContext:\n {{- toYaml .Values.podSecurityContext | nindent 8 }}\n containers:\n - name: {{ .Chart.Name }}\n securityContext:\n {{- toYaml .Values.securityContext | nindent 12 }}\n image: \"{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}\"\n imagePullPolicy: {{ .Values.image.pullPolicy }}\n ports:\n - name: http\n containerPort: {{ .Values.service.targetPort }}\n protocol: TCP\n {{- with .Values.env }}\n env:\n {{- toYaml . | nindent 12 }}\n {{- end }}\n {{- with .Values.envFrom }}\n envFrom:\n {{- toYaml . | nindent 12 }}\n {{- end }}\n livenessProbe:\n {{- toYaml .Values.livenessProbe | nindent 12 }}\n readinessProbe:\n {{- toYaml .Values.readinessProbe | nindent 12 }}\n resources:\n {{- toYaml .Values.resources | nindent 12 }}\n {{- with .Values.volumeMounts }}\n volumeMounts:\n {{- toYaml . | nindent 12 }}\n {{- end }}\n {{- with .Values.volumes }}\n volumes:\n {{- toYaml . | nindent 8 }}\n {{- end }}\n {{- with .Values.nodeSelector }}\n nodeSelector:\n {{- toYaml . | nindent 8 }}\n {{- end }}\n {{- with .Values.affinity }}\n affinity:\n {{- toYaml . | nindent 8 }}\n {{- end }}\n {{- with .Values.tolerations }}\n tolerations:\n {{- toYaml . | nindent 8 }}\n {{- end }}\n```\n\n## templates/hpa.yaml\n\n```yaml\n{{- if .Values.autoscaling.enabled }}\napiVersion: autoscaling/v2\nkind: HorizontalPodAutoscaler\nmetadata:\n name: {{ include \"myapp.fullname\" . }}\n labels:\n {{- include \"myapp.labels\" . | nindent 4 }}\nspec:\n scaleTargetRef:\n apiVersion: apps/v1\n kind: Deployment\n name: {{ include \"myapp.fullname\" . }}\n minReplicas: {{ .Values.autoscaling.minReplicas }}\n maxReplicas: {{ .Values.autoscaling.maxReplicas }}\n metrics:\n {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}\n - type: Resource\n resource:\n name: cpu\n target:\n type: Utilization\n averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}\n {{- end }}\n {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}\n - type: Resource\n resource:\n name: memory\n target:\n type: Utilization\n averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}\n {{- end }}\n{{- end }}\n```\n\n## Helm Hooks\n\n### Pre-Install Hook (Database Migration)\n\n```yaml\napiVersion: batch/v1\nkind: Job\nmetadata:\n name: {{ include \"myapp.fullname\" . }}-migration\n labels:\n {{- include \"myapp.labels\" . | nindent 4 }}\n annotations:\n \"helm.sh/hook\": pre-install,pre-upgrade\n \"helm.sh/hook-weight\": \"0\"\n \"helm.sh/hook-delete-policy\": before-hook-creation,hook-succeeded\nspec:\n backoffLimit: 3\n template:\n metadata:\n labels:\n app: migration\n spec:\n restartPolicy: Never\n containers:\n - name: migrate\n image: \"{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}\"\n command: [\"/app/migrate\", \"up\"]\n env:\n - name: DATABASE_URL\n valueFrom:\n secretKeyRef:\n name: {{ include \"myapp.fullname\" . }}-secrets\n key: database-url\n```\n\n### Post-Install Hook (Test)\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: {{ include \"myapp.fullname\" . }}-test\n labels:\n {{- include \"myapp.labels\" . | nindent 4 }}\n annotations:\n \"helm.sh/hook\": test\n \"helm.sh/hook-weight\": \"0\"\n \"helm.sh/hook-delete-policy\": before-hook-creation,hook-succeeded\nspec:\n restartPolicy: Never\n containers:\n - name: test\n image: curlimages/curl:latest\n command: ['sh', '-c']\n args:\n - |\n curl -f http://{{ include \"myapp.fullname\" . }}:{{ .Values.service.port }}/health || exit 1\n```\n\n## Helm Commands\n\n```bash\n# Create new chart\nhelm create myapp\n\n# Lint chart\nhelm lint myapp/\n\n# Template rendering (dry-run)\nhelm template myapp ./myapp -f values-prod.yaml\n\n# Install chart\nhelm install myapp ./myapp \\\n --namespace production \\\n --create-namespace \\\n --values values-prod.yaml \\\n --set image.tag=v1.2.0\n\n# Upgrade chart\nhelm upgrade myapp ./myapp \\\n --namespace production \\\n --values values-prod.yaml \\\n --set image.tag=v1.3.0 \\\n --atomic \\\n --timeout 5m\n\n# Rollback\nhelm rollback myapp 1 --namespace production\n\n# List releases\nhelm list --namespace production\n\n# Get values\nhelm get values myapp --namespace production\n\n# Get manifest\nhelm get manifest myapp --namespace production\n\n# Uninstall\nhelm uninstall myapp --namespace production\n\n# Test\nhelm test myapp --namespace production\n\n# Package chart\nhelm package myapp/ --version 1.2.0\n\n# Dependency update\nhelm dependency update myapp/\n```\n\n## values-prod.yaml (Environment Override)\n\n```yaml\nreplicaCount: 5\n\nimage:\n tag: v1.2.0\n\nresources:\n limits:\n cpu: 1000m\n memory: 1Gi\n requests:\n cpu: 250m\n memory: 256Mi\n\nautoscaling:\n enabled: true\n minReplicas: 5\n maxReplicas: 20\n\ningress:\n hosts:\n - host: app.production.example.com\n paths:\n - path: /\n pathType: Prefix\n\npostgresql:\n enabled: true\n primary:\n persistence:\n size: 100Gi\n resources:\n limits:\n cpu: 2000m\n memory: 4Gi\n requests:\n cpu: 500m\n memory: 1Gi\n\nredis:\n enabled: true\n master:\n persistence:\n size: 20Gi\n```\n\n## Chart Testing\n\n### Helm Test Command\n\n```bash\n# Run chart tests after installation\nhelm test myapp --namespace production\n\n# Run tests with logs\nhelm test myapp --namespace production --logs\n\n# Run tests with timeout\nhelm test myapp --namespace production --timeout 5m\n```\n\n### Chart Testing Tool (ct)\n\n```bash\n# Install chart-testing\nbrew install chart-testing\n\n# Lint charts\nct lint --config ct.yaml\n\n# Lint and install (CI/CD)\nct lint-and-install --config ct.yaml\n\n# Test changed charts only\nct lint-and-install --target-branch main --config ct.yaml\n```\n\n```yaml\n# ct.yaml - Chart Testing configuration\nremote: origin\ntarget-branch: main\nchart-dirs:\n - charts\nchart-repos:\n - bitnami=https://charts.bitnami.com/bitnami\nhelm-extra-args: --timeout 600s\nvalidate-maintainers: true\ncheck-version-increment: true\n```\n\n### Unit Testing with helm-unittest\n\n```bash\n# Install plugin\nhelm plugin install https://github.com/helm-unittest/helm-unittest\n\n# Run tests\nhelm unittest ./mychart\n```\n\n```yaml\n# tests/deployment_test.yaml\nsuite: deployment tests\ntemplates:\n - templates/deployment.yaml\n - templates/configmap.yaml # deployment.yaml includes it for the checksum annotation\n - templates/hpa.yaml\ntests:\n - it: should create deployment with correct replicas\n template: templates/deployment.yaml\n set:\n replicaCount: 5\n autoscaling:\n enabled: false # spec.replicas is omitted while the HPA manages scaling\n asserts:\n - isKind:\n of: Deployment\n - equal:\n path: spec.replicas\n value: 5\n\n - it: should set resource limits\n template: templates/deployment.yaml\n set:\n resources:\n limits:\n cpu: 500m\n memory: 256Mi\n asserts:\n - equal:\n path: spec.template.spec.containers[0].resources.limits.cpu\n value: 500m\n\n - it: should not create HPA when autoscaling disabled\n set:\n autoscaling:\n enabled: false\n template: templates/hpa.yaml\n asserts:\n - hasDocuments:\n count: 0\n```\n\n## Values Schema Validation\n\n```json\n{\n \"$schema\": \"https://json-schema.org/draft-07/schema#\",\n \"type\": \"object\",\n \"required\": [\"image\", \"service\"],\n \"properties\": {\n \"replicaCount\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 100,\n \"default\": 1\n },\n \"image\": {\n \"type\": \"object\",\n \"required\": [\"repository\"],\n \"properties\": {\n \"repository\": {\n \"type\": \"string\",\n \"pattern\": \"^[a-z0-9.-/]+$\"\n },\n \"tag\": {\n \"type\": \"string\"\n },\n \"pullPolicy\": {\n \"type\": \"string\",\n \"enum\": [\"Always\", \"IfNotPresent\", \"Never\"]\n }\n }\n },\n \"service\": {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\",\n \"enum\": [\"ClusterIP\", \"NodePort\", \"LoadBalancer\"]\n },\n \"port\": {\n \"type\": \"integer\",\n \"minimum\": 1,\n \"maximum\": 65535\n }\n }\n },\n \"resources\": {\n \"type\": \"object\",\n \"properties\": {\n \"limits\": {\n \"$ref\": \"#/definitions/resourceRequirements\"\n },\n \"requests\": {\n \"$ref\": \"#/definitions/resourceRequirements\"\n }\n }\n }\n },\n \"definitions\": {\n \"resourceRequirements\": {\n \"type\": \"object\",\n \"properties\": {\n \"cpu\": {\n \"type\": \"string\",\n \"pattern\": \"^[0-9]+m?$\"\n },\n \"memory\": {\n \"type\": \"string\",\n \"pattern\": \"^[0-9]+(Mi|Gi)$\"\n }\n }\n }\n }\n}\n```\n\n## Chart Repository\n\n### Create Repository\n\n```bash\n# Package chart\nhelm package mychart/ --version 1.2.0 --destination ./repo\n\n# Generate index\nhelm repo index ./repo --url https://charts.example.com\n\n# Update index with new chart\nhelm repo index ./repo --url https://charts.example.com --merge ./repo/index.yaml\n```\n\n### GitHub Pages Repository\n\n```yaml\n# .github/workflows/release.yaml\nname: Release Charts\non:\n push:\n branches: [main]\n paths: ['charts/**']\njobs:\n release:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n with:\n fetch-depth: 0\n - name: Configure Git\n run: |\n git config user.name \"$GITHUB_ACTOR\"\n git config user.email \"[email protected]\"\n - name: Install Helm\n uses: azure/setup-helm@v3\n - name: Run chart-releaser\n uses: helm/[email protected]\n env:\n CR_TOKEN: \"${{ secrets.GITHUB_TOKEN }}\"\n```\n\n### OCI Registry\n\n```bash\n# Login to registry\nhelm registry login myregistry.io -u \u003cusername> -p \u003cregistry-token>\n\n# Push chart to OCI registry\nhelm push mychart-1.2.0.tgz oci://myregistry.io/charts\n\n# Pull from OCI\nhelm pull oci://myregistry.io/charts/mychart --version 1.2.0\n\n# Install from OCI\nhelm install myapp oci://myregistry.io/charts/mychart --version 1.2.0\n```\n\n## Helm Plugins\n\n```bash\n# helm-diff - preview upgrades\nhelm plugin install https://github.com/databus23/helm-diff\nhelm diff upgrade myapp ./mychart -f values-prod.yaml\n\n# helm-secrets - manage encrypted secrets\nhelm plugin install https://github.com/jkroepke/helm-secrets\nhelm secrets encrypt secrets.yaml\nhelm secrets decrypt secrets.yaml.enc\nhelm secrets install myapp ./mychart -f secrets.yaml.enc\n\n# helm-git - use git repos as chart sources\nhelm plugin install https://github.com/aslafy-z/helm-git\nhelm repo add mycharts git+https://github.com/myorg/charts@charts?ref=main\n\n# helm-s3 - S3 as chart repository\nhelm plugin install https://github.com/hypnoglow/helm-s3\nhelm s3 init s3://my-bucket/charts\nhelm s3 push mychart-1.2.0.tgz my-s3-repo\n```\n\n## Complex Upgrade/Rollback\n\n```bash\n# Upgrade with atomic (rollback on failure)\nhelm upgrade myapp ./mychart \\\n --namespace production \\\n --atomic \\\n --timeout 10m \\\n --wait\n\n# Upgrade with cleanup on failure\nhelm upgrade myapp ./mychart \\\n --namespace production \\\n --cleanup-on-fail\n\n# Force resource update (recreate)\nhelm upgrade myapp ./mychart \\\n --namespace production \\\n --force\n\n# Dry run before upgrade\nhelm upgrade myapp ./mychart \\\n --namespace production \\\n --dry-run \\\n --debug\n\n# Compare current vs new\nhelm get manifest myapp -n production > current.yaml\nhelm template myapp ./mychart -f values-prod.yaml > new.yaml\ndiff current.yaml new.yaml\n\n# Rollback to specific revision\nhelm rollback myapp 3 --namespace production\n\n# Rollback with wait\nhelm rollback myapp 3 --namespace production --wait --timeout 5m\n\n# View revision history\nhelm history myapp --namespace production\n```\n\n## Library Charts\n\n```yaml\n# Chart.yaml for library chart\napiVersion: v2\nname: mylib\ntype: library\nversion: 1.0.0\n```\n\n```yaml\n# templates/_deployment.tpl in library\n{{- define \"mylib.deployment\" -}}\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: {{ include \"mylib.fullname\" . }}\n labels:\n {{- include \"mylib.labels\" . | nindent 4 }}\nspec:\n replicas: {{ .Values.replicaCount }}\n selector:\n matchLabels:\n {{- include \"mylib.selectorLabels\" . | nindent 6 }}\n template:\n metadata:\n labels:\n {{- include \"mylib.selectorLabels\" . | nindent 8 }}\n spec:\n containers:\n - name: {{ .Chart.Name }}\n image: \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\"\n{{- end }}\n```\n\n```yaml\n# Using library chart\n# Chart.yaml\ndependencies:\n - name: mylib\n version: \"1.x.x\"\n repository: https://charts.example.com\n\n# templates/deployment.yaml\n{{- include \"mylib.deployment\" . }}\n```\n\n## Best Practices\n\n1. **Versioning**: Follow semantic versioning for charts\n2. **Values**: Provide sensible defaults, allow overrides\n3. **Documentation**: Document all values in README\n4. **Testing**: Include tests in templates/tests/\n5. **Helpers**: Use _helpers.tpl for reusable templates\n6. **Labels**: Include standard Kubernetes labels\n7. **Annotations**: Use annotations for metadata and tools\n8. **Hooks**: Use hooks for migrations, cleanup\n9. **Dependencies**: Pin dependency versions\n10. **Schema**: Validate values with values.schema.json\n11. **Use ct** for comprehensive chart testing in CI\n12. **Use helm-diff** before production upgrades\n13. **Encrypt secrets** with helm-secrets or sealed-secrets\n14. **Use library charts** for shared patterns\n15. **Push to OCI registries** for better artifact management\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":20445,"content_sha256":"e0c6bb2aa8921db22fdc465ec10c0719e6248fe38c1376658a2ec482eb9bc03b"},{"filename":"references/multi-cluster.md","content":"# Multi-Cluster Management\n\n---\n\n## Cluster API\n\n### Installation\n\n```bash\n# Install clusterctl CLI\ncurl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.6.0/clusterctl-linux-amd64 -o clusterctl\nchmod +x clusterctl && sudo mv clusterctl /usr/local/bin/\n\n# Initialize management cluster with AWS provider\nclusterctl init --infrastructure aws\n\n# Initialize with multiple providers\nclusterctl init \\\n --infrastructure aws,azure \\\n --control-plane kubeadm \\\n --bootstrap kubeadm\n```\n\n### Cluster Definition\n\n```yaml\napiVersion: cluster.x-k8s.io/v1beta1\nkind: Cluster\nmetadata:\n name: production-cluster\n namespace: clusters\nspec:\n clusterNetwork:\n pods:\n cidrBlocks: [\"192.168.0.0/16\"]\n services:\n cidrBlocks: [\"10.96.0.0/12\"]\n controlPlaneRef:\n apiVersion: controlplane.cluster.x-k8s.io/v1beta1\n kind: KubeadmControlPlane\n name: production-control-plane\n infrastructureRef:\n apiVersion: infrastructure.cluster.x-k8s.io/v1beta2\n kind: AWSCluster\n name: production-cluster\n---\napiVersion: infrastructure.cluster.x-k8s.io/v1beta2\nkind: AWSCluster\nmetadata:\n name: production-cluster\n namespace: clusters\nspec:\n region: us-west-2\n sshKeyName: production-key\n network:\n vpc:\n cidrBlock: 10.0.0.0/16\n subnets:\n - availabilityZone: us-west-2a\n cidrBlock: 10.0.1.0/24\n isPublic: true\n - availabilityZone: us-west-2b\n cidrBlock: 10.0.2.0/24\n isPublic: true\n```\n\n### Control Plane\n\n```yaml\napiVersion: controlplane.cluster.x-k8s.io/v1beta1\nkind: KubeadmControlPlane\nmetadata:\n name: production-control-plane\n namespace: clusters\nspec:\n replicas: 3\n version: v1.28.0\n machineTemplate:\n infrastructureRef:\n apiVersion: infrastructure.cluster.x-k8s.io/v1beta2\n kind: AWSMachineTemplate\n name: production-control-plane\n kubeadmConfigSpec:\n clusterConfiguration:\n apiServer:\n extraArgs:\n cloud-provider: aws\n controllerManager:\n extraArgs:\n cloud-provider: aws\n initConfiguration:\n nodeRegistration:\n kubeletExtraArgs:\n cloud-provider: aws\n joinConfiguration:\n nodeRegistration:\n kubeletExtraArgs:\n cloud-provider: aws\n```\n\n### Machine Deployment (Worker Nodes)\n\n```yaml\napiVersion: cluster.x-k8s.io/v1beta1\nkind: MachineDeployment\nmetadata:\n name: production-workers\n namespace: clusters\nspec:\n clusterName: production-cluster\n replicas: 5\n selector:\n matchLabels:\n cluster.x-k8s.io/cluster-name: production-cluster\n template:\n spec:\n clusterName: production-cluster\n version: v1.28.0\n bootstrap:\n configRef:\n apiVersion: bootstrap.cluster.x-k8s.io/v1beta1\n kind: KubeadmConfigTemplate\n name: production-workers\n infrastructureRef:\n apiVersion: infrastructure.cluster.x-k8s.io/v1beta2\n kind: AWSMachineTemplate\n name: production-workers\n---\napiVersion: infrastructure.cluster.x-k8s.io/v1beta2\nkind: AWSMachineTemplate\nmetadata:\n name: production-workers\n namespace: clusters\nspec:\n template:\n spec:\n instanceType: m5.xlarge\n iamInstanceProfile: nodes.cluster-api-provider-aws.sigs.k8s.io\n sshKeyName: production-key\n rootVolume:\n size: 100\n type: gp3\n```\n\n## Cross-Cluster Networking\n\n### Submariner Installation\n\n```bash\n# Install subctl\ncurl -Ls https://get.submariner.io | bash\n\n# Join clusters to broker\nsubctl deploy-broker --kubeconfig kubeconfig-cluster1\n\n# Join workload clusters\nsubctl join --kubeconfig kubeconfig-cluster1 broker-info.subm --clusterid cluster1\nsubctl join --kubeconfig kubeconfig-cluster2 broker-info.subm --clusterid cluster2\n\n# Verify connectivity\nsubctl show all\n```\n\n### ServiceExport/ServiceImport\n\n```yaml\n# Export service from cluster1\napiVersion: multicluster.x-k8s.io/v1alpha1\nkind: ServiceExport\nmetadata:\n name: myapp\n namespace: production\n---\n# Service is auto-imported to other clusters as:\n# myapp.production.svc.clusterset.local\n```\n\n### Cilium Cluster Mesh\n\n```bash\n# Enable cluster mesh on both clusters\ncilium clustermesh enable --context cluster1\ncilium clustermesh enable --context cluster2\n\n# Connect clusters\ncilium clustermesh connect --context cluster1 --destination-context cluster2\n\n# Verify\ncilium clustermesh status --context cluster1\n```\n\n```yaml\n# Global service accessible from all clusters\napiVersion: v1\nkind: Service\nmetadata:\n name: myapp\n namespace: production\n annotations:\n service.cilium.io/global: \"true\"\nspec:\n type: ClusterIP\n selector:\n app: myapp\n ports:\n - port: 80\n```\n\n## Multi-Cluster DNS\n\n### ExternalDNS with Route53\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: external-dns\n namespace: kube-system\nspec:\n template:\n spec:\n containers:\n - name: external-dns\n image: k8s.gcr.io/external-dns/external-dns:v0.14.0\n args:\n - --source=service\n - --source=ingress\n - --provider=aws\n - --aws-zone-type=public\n - --registry=txt\n - --txt-owner-id=my-cluster\n - --domain-filter=example.com\n```\n\n### CoreDNS Federation\n\n```yaml\n# Forward queries for other clusters\napiVersion: v1\nkind: ConfigMap\nmetadata:\n name: coredns\n namespace: kube-system\ndata:\n Corefile: |\n .:53 {\n errors\n health\n kubernetes cluster.local in-addr.arpa ip6.arpa {\n pods insecure\n fallthrough in-addr.arpa ip6.arpa\n }\n forward . /etc/resolv.conf\n cache 30\n loop\n reload\n loadbalance\n }\n # Forward to cluster2 DNS (a separate server block, not nested in .:53)\n cluster2.local:53 {\n errors\n cache 30\n forward . 10.0.0.10\n }\n```\n\n## Workload Distribution\n\n### Kubernetes Federation v2\n\n```yaml\napiVersion: types.kubefed.io/v1beta1\nkind: FederatedDeployment\nmetadata:\n name: myapp\n namespace: production\nspec:\n template:\n metadata:\n labels:\n app: myapp\n spec:\n replicas: 3\n selector:\n matchLabels:\n app: myapp\n template:\n metadata:\n labels:\n app: myapp\n spec:\n containers:\n - name: myapp\n image: myregistry.io/myapp:v1.0.0\n placement:\n clusters:\n - name: cluster-us-west\n - name: cluster-us-east\n - name: cluster-eu-west\n overrides:\n - clusterName: cluster-us-west\n clusterOverrides:\n - path: \"/spec/replicas\"\n value: 5\n - clusterName: cluster-eu-west\n clusterOverrides:\n - path: \"/spec/replicas\"\n value: 3\n```\n\n### ArgoCD Multi-Cluster\n\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: ApplicationSet\nmetadata:\n name: myapp-global\n namespace: argocd\nspec:\n generators:\n - clusters:\n selector:\n matchLabels:\n environment: production\n template:\n metadata:\n name: 'myapp-{{name}}'\n spec:\n project: default\n source:\n repoURL: https://github.com/myorg/myapp-manifests.git\n targetRevision: main\n path: overlays/production\n destination:\n server: '{{server}}'\n namespace: production\n syncPolicy:\n automated:\n prune: true\n selfHeal: true\n```\n\n## Disaster Recovery\n\n### Velero Backup Configuration\n\n```bash\n# Install Velero with S3\nvelero install \\\n --provider aws \\\n --plugins velero/velero-plugin-for-aws:v1.8.0 \\\n --bucket velero-backups \\\n --backup-location-config region=us-west-2 \\\n --snapshot-location-config region=us-west-2 \\\n --secret-file ./credentials-velero\n```\n\n```yaml\n# Scheduled backup\napiVersion: velero.io/v1\nkind: Schedule\nmetadata:\n name: daily-backup\n namespace: velero\nspec:\n schedule: \"0 2 * * *\"\n template:\n includedNamespaces:\n - production\n - staging\n excludedResources:\n - events\n storageLocation: default\n volumeSnapshotLocations:\n - default\n ttl: 720h # 30 days\n---\n# Restore to different cluster\napiVersion: velero.io/v1\nkind: Restore\nmetadata:\n name: restore-production\n namespace: velero\nspec:\n backupName: daily-backup-20240115\n includedNamespaces:\n - production\n restorePVs: true\n preserveNodePorts: true\n```\n\n### Active-Passive Failover\n\n```yaml\n# Primary cluster ingress\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n name: myapp\n annotations:\n external-dns.alpha.kubernetes.io/hostname: myapp.example.com\n external-dns.alpha.kubernetes.io/set-identifier: primary\n external-dns.alpha.kubernetes.io/aws-weight: \"100\"\nspec:\n rules:\n - host: myapp.example.com\n http:\n paths:\n - path: /\n pathType: Prefix\n backend:\n service:\n name: myapp\n port:\n number: 80\n---\n# Secondary cluster ingress\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n name: myapp\n annotations:\n external-dns.alpha.kubernetes.io/hostname: myapp.example.com\n external-dns.alpha.kubernetes.io/set-identifier: secondary\n external-dns.alpha.kubernetes.io/aws-weight: \"0\"\nspec:\n rules:\n - host: myapp.example.com\n # ... same backend config\n```\n\n## Centralized Management Tools\n\n### Rancher Setup\n\n```bash\n# Install Rancher with Helm\nhelm repo add rancher-stable https://releases.rancher.com/server-charts/stable\nhelm install rancher rancher-stable/rancher \\\n --namespace cattle-system \\\n --create-namespace \\\n --set hostname=rancher.example.com \\\n --set bootstrapPassword=\u003crancher-bootstrap-password>\n```\n\n### Kubeconfig Management\n\n```yaml\n# Merge multiple kubeconfigs\n# ~/.kube/config\napiVersion: v1\nkind: Config\nclusters:\n - name: cluster-us-west\n cluster:\n server: https://cluster-us-west.example.com\n certificate-authority-data: ...\n - name: cluster-us-east\n cluster:\n server: https://cluster-us-east.example.com\n certificate-authority-data: ...\ncontexts:\n - name: us-west\n context:\n cluster: cluster-us-west\n user: admin-us-west\n namespace: default\n - name: us-east\n context:\n cluster: cluster-us-east\n user: admin-us-east\n namespace: default\nusers:\n - name: admin-us-west\n user:\n token: \u003ccluster-token>\n - name: admin-us-east\n user:\n token: \u003ccluster-token>\ncurrent-context: us-west\n```\n\n```bash\n# Switch between clusters\nkubectl config use-context us-west\nkubectl config use-context us-east\n\n# Run command against specific cluster\nkubectl --context=us-west get pods\nkubectl --context=us-east get pods\n\n# Use kubectx for easier switching\nkubectx us-west\n```\n\n## Best Practices\n\n1. **Use Cluster API** for declarative cluster lifecycle management\n2. **Implement service mesh** for secure cross-cluster communication\n3. **Set up DNS-based routing** for global service discovery\n4. **Configure automated backups** with Velero across clusters\n5. **Use GitOps** (ArgoCD/Flux) for consistent multi-cluster deployments\n6. **Implement network policies** consistently across clusters\n7. **Centralize observability** with cross-cluster metrics and logs\n8. **Test failover procedures** regularly\n9. **Use namespaces consistently** across clusters\n10. **Document cluster topology** and dependencies\n11. **Implement RBAC** with cross-cluster access patterns\n12. **Monitor cluster health** from centralized dashboard\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":11364,"content_sha256":"d4ff900981af1c394ab237c9deedbc37788e26a57132fd42a80335ba303a88ba"},{"filename":"references/networking.md","content":"# Kubernetes Networking\n\n## Service Types\n\n### ClusterIP (Default)\n\n```yaml\napiVersion: v1\nkind: Service\nmetadata:\n name: web-app-service\n namespace: production\n labels:\n app: web-app\nspec:\n type: ClusterIP\n selector:\n app: web-app\n tier: frontend\n ports:\n - name: http\n port: 80\n targetPort: 8080\n protocol: TCP\n - name: metrics\n port: 9090\n targetPort: metrics\n protocol: TCP\n sessionAffinity: ClientIP\n sessionAffinityConfig:\n clientIP:\n timeoutSeconds: 3600\n```\n\n### Headless Service (StatefulSet)\n\n```yaml\napiVersion: v1\nkind: Service\nmetadata:\n name: postgres-headless\n namespace: database\nspec:\n clusterIP: None # Headless\n selector:\n app: postgres\n ports:\n - name: postgres\n port: 5432\n targetPort: 5432\n```\n\n### NodePort\n\n```yaml\napiVersion: v1\nkind: Service\nmetadata:\n name: external-app\n namespace: production\nspec:\n type: NodePort\n selector:\n app: external-app\n ports:\n - name: http\n port: 80\n targetPort: 8080\n nodePort: 30080 # Range: 30000-32767\n protocol: TCP\n```\n\n### LoadBalancer\n\n```yaml\napiVersion: v1\nkind: Service\nmetadata:\n name: public-web\n namespace: production\n annotations:\n service.beta.kubernetes.io/aws-load-balancer-type: \"nlb\"\n service.beta.kubernetes.io/aws-load-balancer-internal: \"false\"\nspec:\n type: LoadBalancer\n selector:\n app: web-app\n ports:\n - name: http\n port: 80\n targetPort: 8080\n - name: https\n port: 443\n targetPort: 8443\n loadBalancerSourceRanges:\n - 203.0.113.0/24 # Restrict source IPs\n```\n\n## Ingress Resources\n\n### NGINX Ingress\n\n```yaml\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n name: web-ingress\n namespace: production\n annotations:\n nginx.ingress.kubernetes.io/rewrite-target: /\n nginx.ingress.kubernetes.io/ssl-redirect: \"true\"\n nginx.ingress.kubernetes.io/force-ssl-redirect: \"true\"\n nginx.ingress.kubernetes.io/proxy-body-size: \"10m\"\n nginx.ingress.kubernetes.io/rate-limit: \"100\"\n cert-manager.io/cluster-issuer: \"letsencrypt-prod\"\nspec:\n ingressClassName: nginx\n tls:\n - hosts:\n - www.example.com\n - api.example.com\n secretName: example-tls\n rules:\n - host: www.example.com\n http:\n paths:\n - path: /\n pathType: Prefix\n backend:\n service:\n name: frontend-service\n port:\n number: 80\n - host: api.example.com\n http:\n paths:\n - path: /v1\n pathType: Prefix\n backend:\n service:\n name: api-service\n port:\n number: 8080\n - path: /v2\n pathType: Prefix\n backend:\n service:\n name: api-v2-service\n port:\n number: 8080\n```\n\n### Path-Based Routing\n\n```yaml\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n name: app-ingress\n namespace: production\nspec:\n ingressClassName: nginx\n rules:\n - host: app.example.com\n http:\n paths:\n - path: /api\n pathType: Prefix\n backend:\n service:\n name: backend-api\n port:\n number: 8080\n - path: /\n pathType: Prefix\n backend:\n service:\n name: frontend\n port:\n number: 80\n```\n\n## NetworkPolicy (Zero Trust)\n\n### Default Deny All\n\n```yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n name: default-deny-all\n namespace: production\nspec:\n podSelector: {}\n policyTypes:\n - Ingress\n - Egress\n```\n\n### Allow Frontend to Backend\n\n```yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n name: frontend-to-backend\n namespace: production\nspec:\n podSelector:\n matchLabels:\n tier: backend\n policyTypes:\n - Ingress\n ingress:\n - from:\n - podSelector:\n matchLabels:\n tier: frontend\n ports:\n - protocol: TCP\n port: 8080\n```\n\n### Backend to Database\n\n```yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n name: backend-to-database\n namespace: production\nspec:\n podSelector:\n matchLabels:\n app: postgres\n policyTypes:\n - Ingress\n ingress:\n - from:\n - podSelector:\n matchLabels:\n tier: backend\n - namespaceSelector:\n matchLabels:\n name: production\n ports:\n - protocol: TCP\n port: 5432\n```\n\n### Allow DNS and External HTTPS\n\n```yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n name: allow-dns-and-https\n namespace: production\nspec:\n podSelector:\n matchLabels:\n tier: backend\n policyTypes:\n - Egress\n egress:\n - to:\n - namespaceSelector:\n matchLabels:\n name: kube-system\n ports:\n - protocol: UDP\n port: 53\n - to:\n - namespaceSelector: {}\n ports:\n - protocol: TCP\n port: 443\n```\n\n### Cross-Namespace Communication\n\n```yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n name: allow-monitoring\n namespace: production\nspec:\n podSelector:\n matchLabels:\n app: web-app\n policyTypes:\n - Ingress\n ingress:\n - from:\n - namespaceSelector:\n matchLabels:\n name: monitoring\n podSelector:\n matchLabels:\n app: prometheus\n ports:\n - protocol: TCP\n port: 8080\n```\n\n## DNS Configuration\n\n### Service DNS Names\n\n```yaml\n# Within same namespace\nhttp://web-app-service\n\n# Cross-namespace\nhttp://web-app-service.production.svc.cluster.local\n\n# Headless service (StatefulSet)\npostgres-0.postgres-headless.database.svc.cluster.local\npostgres-1.postgres-headless.database.svc.cluster.local\npostgres-2.postgres-headless.database.svc.cluster.local\n```\n\n### Custom DNS Policy\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: custom-dns\nspec:\n dnsPolicy: None\n dnsConfig:\n nameservers:\n - 8.8.8.8\n - 8.8.4.4\n searches:\n - production.svc.cluster.local\n - svc.cluster.local\n - cluster.local\n options:\n - name: ndots\n value: \"2\"\n containers:\n - name: app\n image: myapp:latest\n```\n\n## Service Mesh (Istio Example)\n\n### VirtualService\n\n```yaml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n name: web-app-routes\n namespace: production\nspec:\n hosts:\n - web-app-service\n http:\n - match:\n - headers:\n canary:\n exact: \"true\"\n route:\n - destination:\n host: web-app-service\n subset: v2\n - route:\n - destination:\n host: web-app-service\n subset: v1\n weight: 90\n - destination:\n host: web-app-service\n subset: v2\n weight: 10\n```\n\n### DestinationRule\n\n```yaml\napiVersion: networking.istio.io/v1beta1\nkind: DestinationRule\nmetadata:\n name: web-app-destination\n namespace: production\nspec:\n host: web-app-service\n trafficPolicy:\n connectionPool:\n tcp:\n maxConnections: 100\n http:\n http1MaxPendingRequests: 50\n http2MaxRequests: 100\n loadBalancer:\n simple: LEAST_REQUEST\n subsets:\n - name: v1\n labels:\n version: v1.0.0\n - name: v2\n labels:\n version: v2.0.0\n```\n\n## EndpointSlice (Modern Alternative to Endpoints)\n\n```yaml\napiVersion: discovery.k8s.io/v1\nkind: EndpointSlice\nmetadata:\n name: web-app-abc123\n namespace: production\n labels:\n kubernetes.io/service-name: web-app-service\naddressType: IPv4\nports:\n- name: http\n protocol: TCP\n port: 8080\nendpoints:\n- addresses:\n - \"10.244.1.5\"\n conditions:\n ready: true\n nodeName: node-1\n- addresses:\n - \"10.244.2.7\"\n conditions:\n ready: true\n nodeName: node-2\n```\n\n## Best Practices\n\n1. **Default Deny**: Start with deny-all NetworkPolicy, then allow specific traffic\n2. **Least Privilege**: Only open required ports and protocols\n3. **Service Selection**: Use ClusterIP by default, LoadBalancer sparingly\n4. **DNS Names**: Use service DNS names, avoid hardcoded IPs\n5. **TLS Termination**: Terminate TLS at Ingress when possible\n6. **Health Checks**: Configure proper health check paths\n7. **Rate Limiting**: Apply rate limits at Ingress level\n8. **Monitoring**: Expose metrics endpoints for Prometheus\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8049,"content_sha256":"12ff07c3364397775f56ee42666050c9a18493004a46bbb7bf66356b8a6ef675"},{"filename":"references/service-mesh.md","content":"# Service Mesh\n\n---\n\n## Istio Installation\n\n```bash\n# Install Istio CLI\ncurl -L https://istio.io/downloadIstio | sh -\nexport PATH=$PWD/istio-*/bin:$PATH\n\n# Install Istio with default profile\nistioctl install --set profile=default -y\n\n# Enable sidecar injection for namespace\nkubectl label namespace production istio-injection=enabled\n\n# Verify installation\nistioctl verify-install\nkubectl get pods -n istio-system\n```\n\n## Istio Profiles\n\n```bash\n# Minimal - only control plane\nistioctl install --set profile=minimal\n\n# Default - control plane + ingress gateway\nistioctl install --set profile=default\n\n# Demo - includes egress gateway, extra features\nistioctl install --set profile=demo\n\n# Production - tuned for production\nistioctl install --set profile=default \\\n --set values.global.proxy.resources.requests.cpu=100m \\\n --set values.global.proxy.resources.requests.memory=128Mi \\\n --set values.global.proxy.resources.limits.cpu=500m \\\n --set values.global.proxy.resources.limits.memory=256Mi\n```\n\n## VirtualService\n\n```yaml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n name: myapp\n namespace: production\nspec:\n hosts:\n - myapp\n - myapp.example.com\n gateways:\n - mesh # Internal mesh traffic\n - myapp-gateway # External gateway\n http:\n # Route based on headers\n - match:\n - headers:\n x-version:\n exact: \"v2\"\n route:\n - destination:\n host: myapp\n subset: v2\n\n # Canary release (90/10 split)\n - match:\n - uri:\n prefix: /api\n route:\n - destination:\n host: myapp\n subset: v1\n weight: 90\n - destination:\n host: myapp\n subset: v2\n weight: 10\n\n # Default route\n - route:\n - destination:\n host: myapp\n subset: v1\n timeout: 30s\n retries:\n attempts: 3\n perTryTimeout: 10s\n retryOn: connect-failure,refused-stream,503\n```\n\n## DestinationRule\n\n```yaml\napiVersion: networking.istio.io/v1beta1\nkind: DestinationRule\nmetadata:\n name: myapp\n namespace: production\nspec:\n host: myapp\n trafficPolicy:\n connectionPool:\n tcp:\n maxConnections: 100\n connectTimeout: 5s\n http:\n h2UpgradePolicy: UPGRADE\n http1MaxPendingRequests: 100\n http2MaxRequests: 1000\n maxRequestsPerConnection: 100\n loadBalancer:\n simple: LEAST_REQUEST\n outlierDetection:\n consecutive5xxErrors: 5\n interval: 10s\n baseEjectionTime: 30s\n maxEjectionPercent: 50\n subsets:\n - name: v1\n labels:\n version: v1\n trafficPolicy:\n loadBalancer:\n simple: ROUND_ROBIN\n - name: v2\n labels:\n version: v2\n```\n\n## Gateway\n\n```yaml\napiVersion: networking.istio.io/v1beta1\nkind: Gateway\nmetadata:\n name: myapp-gateway\n namespace: production\nspec:\n selector:\n istio: ingressgateway\n servers:\n - port:\n number: 80\n name: http\n protocol: HTTP\n hosts:\n - myapp.example.com\n tls:\n httpsRedirect: true\n - port:\n number: 443\n name: https\n protocol: HTTPS\n hosts:\n - myapp.example.com\n tls:\n mode: SIMPLE\n credentialName: myapp-tls-secret\n```\n\n## Traffic Mirroring (Shadow Traffic)\n\n```yaml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n name: myapp-mirror\n namespace: production\nspec:\n hosts:\n - myapp\n http:\n - route:\n - destination:\n host: myapp\n subset: v1\n mirror:\n host: myapp\n subset: v2\n mirrorPercentage:\n value: 100.0\n```\n\n## mTLS Configuration\n\n```yaml\n# Strict mTLS for namespace\napiVersion: security.istio.io/v1beta1\nkind: PeerAuthentication\nmetadata:\n name: default\n namespace: production\nspec:\n mtls:\n mode: STRICT\n---\n# Per-workload mTLS\napiVersion: security.istio.io/v1beta1\nkind: PeerAuthentication\nmetadata:\n name: legacy-service\n namespace: production\nspec:\n selector:\n matchLabels:\n app: legacy-service\n mtls:\n mode: PERMISSIVE # Allow both mTLS and plaintext\n---\n# Mesh-wide mTLS policy\napiVersion: security.istio.io/v1beta1\nkind: PeerAuthentication\nmetadata:\n name: default\n namespace: istio-system\nspec:\n mtls:\n mode: STRICT\n```\n\n## Authorization Policy\n\n```yaml\napiVersion: security.istio.io/v1beta1\nkind: AuthorizationPolicy\nmetadata:\n name: myapp-authz\n namespace: production\nspec:\n selector:\n matchLabels:\n app: myapp\n action: ALLOW\n rules:\n # Allow from specific service accounts\n - from:\n - source:\n principals:\n - \"cluster.local/ns/production/sa/frontend\"\n - \"cluster.local/ns/production/sa/api-gateway\"\n to:\n - operation:\n methods: [\"GET\", \"POST\"]\n paths: [\"/api/*\"]\n\n # Allow health checks from anywhere\n - to:\n - operation:\n methods: [\"GET\"]\n paths: [\"/health\", \"/ready\"]\n\n # Deny all other traffic (implicit deny when rules exist)\n```\n\n## Circuit Breaker\n\n```yaml\napiVersion: networking.istio.io/v1beta1\nkind: DestinationRule\nmetadata:\n name: myapp-circuit-breaker\n namespace: production\nspec:\n host: myapp\n trafficPolicy:\n connectionPool:\n tcp:\n maxConnections: 50\n http:\n http1MaxPendingRequests: 100\n http2MaxRequests: 100\n maxRequestsPerConnection: 10\n outlierDetection:\n consecutive5xxErrors: 3\n interval: 10s\n baseEjectionTime: 30s\n maxEjectionPercent: 100\n minHealthPercent: 0\n```\n\n## Fault Injection (Testing)\n\n```yaml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n name: myapp-fault\n namespace: production\nspec:\n hosts:\n - myapp\n http:\n - match:\n - headers:\n x-test-fault:\n exact: \"inject\"\n fault:\n delay:\n percentage:\n value: 50\n fixedDelay: 5s\n abort:\n percentage:\n value: 10\n httpStatus: 503\n route:\n - destination:\n host: myapp\n - route:\n - destination:\n host: myapp\n```\n\n## Linkerd Installation\n\n```bash\n# Install Linkerd CLI\ncurl --proto '=https' --tlsv1.2 -sSfL https://run.linkerd.io/install | sh\nexport PATH=$HOME/.linkerd2/bin:$PATH\n\n# Validate cluster\nlinkerd check --pre\n\n# Install CRDs\nlinkerd install --crds | kubectl apply -f -\n\n# Install control plane\nlinkerd install | kubectl apply -f -\n\n# Check installation\nlinkerd check\n\n# Enable injection for namespace\nkubectl annotate namespace production linkerd.io/inject=enabled\n\n# Inject existing deployments\nkubectl get deploy -n production -o yaml | linkerd inject - | kubectl apply -f -\n```\n\n## Linkerd Service Profile\n\n```yaml\napiVersion: linkerd.io/v1alpha2\nkind: ServiceProfile\nmetadata:\n name: myapp.production.svc.cluster.local\n namespace: production\nspec:\n routes:\n - name: GET /api/users\n condition:\n method: GET\n pathRegex: /api/users\n responseClasses:\n - condition:\n status:\n min: 500\n max: 599\n isFailure: true\n timeout: 5s\n\n - name: POST /api/orders\n condition:\n method: POST\n pathRegex: /api/orders\n isRetryable: true\n timeout: 10s\n\n retryBudget:\n retryRatio: 0.2\n minRetriesPerSecond: 10\n ttl: 10s\n```\n\n## Linkerd Traffic Split (Canary)\n\n```yaml\napiVersion: split.smi-spec.io/v1alpha1\nkind: TrafficSplit\nmetadata:\n name: myapp-canary\n namespace: production\nspec:\n service: myapp\n backends:\n - service: myapp-v1\n weight: 900m # 90%\n - service: myapp-v2\n weight: 100m # 10%\n```\n\n## Multi-Cluster Mesh (Istio)\n\n```yaml\n# Primary cluster - create remote secret\nistioctl x create-remote-secret \\\n --context=cluster1 \\\n --name=cluster1 | kubectl apply -f - --context=cluster2\n\n# Enable endpoint discovery\napiVersion: install.istio.io/v1alpha1\nkind: IstioOperator\nspec:\n values:\n global:\n meshID: mesh1\n multiCluster:\n clusterName: cluster1\n network: network1\n```\n\n## Kiali Dashboard\n\n```bash\n# Install Kiali\nkubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/kiali.yaml\n\n# Access dashboard\nistioctl dashboard kiali\n```\n\n## Jaeger Tracing\n\n```bash\n# Install Jaeger\nkubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/jaeger.yaml\n\n# Access dashboard\nistioctl dashboard jaeger\n```\n\n## Service Mesh Comparison\n\n| Feature | Istio | Linkerd |\n|---------|-------|---------|\n| Sidecar | Envoy | linkerd2-proxy (Rust) |\n| Resource usage | Higher | Lower |\n| Features | More extensive | Focused/simpler |\n| mTLS | Built-in | Built-in |\n| Traffic management | Advanced | Basic (SMI) |\n| Multi-cluster | Native support | Requires setup |\n| Learning curve | Steeper | Gentler |\n\n## Best Practices\n\n1. **Start with permissive mTLS**, migrate to strict gradually\n2. **Use circuit breakers** to prevent cascade failures\n3. **Set reasonable timeouts** and retry budgets\n4. **Enable distributed tracing** for observability\n5. **Test with fault injection** before production\n6. **Monitor sidecar resource usage** and tune accordingly\n7. **Use traffic mirroring** to validate new versions safely\n8. **Implement authorization policies** for zero-trust\n9. **Keep service mesh version updated** for security patches\n10. **Document traffic routing decisions** in VirtualServices\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9546,"content_sha256":"cbacae822f338e9cf3c7cc0bc7b80c9ea66af8e5621534c5adb79f9f98c5be22"},{"filename":"references/storage.md","content":"# Kubernetes Storage\n\n## StorageClass Definitions\n\n### AWS EBS (gp3)\n\n```yaml\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n name: fast-ssd\n annotations:\n storageclass.kubernetes.io/is-default-class: \"true\"\nprovisioner: ebs.csi.aws.com\nparameters:\n type: gp3\n iops: \"3000\"\n throughput: \"125\"\n encrypted: \"true\"\n kmsKeyId: \"arn:aws:kms:us-east-1:123456789012:key/...\"\nvolumeBindingMode: WaitForFirstConsumer\nallowVolumeExpansion: true\nreclaimPolicy: Delete\n```\n\n### GCE Persistent Disk (SSD)\n\n```yaml\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n name: fast-ssd-gce\nprovisioner: pd.csi.storage.gke.io\nparameters:\n type: pd-ssd\n replication-type: regional-pd\nvolumeBindingMode: WaitForFirstConsumer\nallowVolumeExpansion: true\nreclaimPolicy: Delete\n```\n\n### Azure Disk (Premium SSD)\n\n```yaml\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n name: fast-ssd-azure\nprovisioner: disk.csi.azure.com\nparameters:\n storageaccounttype: Premium_LRS\n kind: Managed\nvolumeBindingMode: WaitForFirstConsumer\nallowVolumeExpansion: true\nreclaimPolicy: Delete\n```\n\n### NFS Storage\n\n```yaml\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n name: nfs-storage\nprovisioner: nfs.csi.k8s.io\nparameters:\n server: nfs-server.example.com\n share: /exports/kubernetes\nvolumeBindingMode: Immediate\nreclaimPolicy: Retain\n```\n\n## PersistentVolume (Static Provisioning)\n\n```yaml\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n name: legacy-database-pv\n labels:\n type: local\n app: legacy-db\nspec:\n capacity:\n storage: 100Gi\n volumeMode: Filesystem\n accessModes:\n - ReadWriteOnce\n persistentVolumeReclaimPolicy: Retain\n storageClassName: manual\n hostPath:\n path: /mnt/data/legacy-db\n nodeAffinity:\n required:\n nodeSelectorTerms:\n - matchExpressions:\n - key: kubernetes.io/hostname\n operator: In\n values:\n - node-01\n```\n\n## PersistentVolumeClaim Patterns\n\n### Basic PVC (Dynamic Provisioning)\n\n```yaml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n name: database-pvc\n namespace: production\n labels:\n app: postgres\nspec:\n accessModes:\n - ReadWriteOnce\n storageClassName: fast-ssd\n resources:\n requests:\n storage: 50Gi\n```\n\n### Shared Storage (ReadWriteMany)\n\n```yaml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n name: shared-assets\n namespace: production\nspec:\n accessModes:\n - ReadWriteMany\n storageClassName: nfs-storage\n resources:\n requests:\n storage: 100Gi\n```\n\n### Block Volume\n\n```yaml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n name: block-storage\n namespace: production\nspec:\n accessModes:\n - ReadWriteOnce\n volumeMode: Block\n storageClassName: fast-ssd\n resources:\n requests:\n storage: 10Gi\n```\n\n## Using PVCs in Pods\n\n### Single PVC Mount\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: database-pod\nspec:\n containers:\n - name: postgres\n image: postgres:15\n volumeMounts:\n - name: data\n mountPath: /var/lib/postgresql/data\n volumes:\n - name: data\n persistentVolumeClaim:\n claimName: database-pvc\n```\n\n### Multiple PVCs\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: app-pod\nspec:\n containers:\n - name: app\n image: myapp:latest\n volumeMounts:\n - name: data\n mountPath: /data\n - name: logs\n mountPath: /var/log/app\n - name: shared\n mountPath: /shared\n volumes:\n - name: data\n persistentVolumeClaim:\n claimName: app-data-pvc\n - name: logs\n persistentVolumeClaim:\n claimName: app-logs-pvc\n - name: shared\n persistentVolumeClaim:\n claimName: shared-assets\n```\n\n## StatefulSet with VolumeClaimTemplates\n\n```yaml\napiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n name: postgres-cluster\n namespace: database\nspec:\n serviceName: postgres\n replicas: 3\n selector:\n matchLabels:\n app: postgres\n template:\n metadata:\n labels:\n app: postgres\n spec:\n containers:\n - name: postgres\n image: postgres:15-alpine\n ports:\n - containerPort: 5432\n volumeMounts:\n - name: data\n mountPath: /var/lib/postgresql/data\n - name: config\n mountPath: /etc/postgresql\n volumes:\n - name: config\n configMap:\n name: postgres-config\n volumeClaimTemplates:\n - metadata:\n name: data\n labels:\n app: postgres\n spec:\n accessModes: [\"ReadWriteOnce\"]\n storageClassName: fast-ssd\n resources:\n requests:\n storage: 50Gi\n```\n\n## Volume Snapshots\n\n### VolumeSnapshotClass\n\n```yaml\napiVersion: snapshot.storage.k8s.io/v1\nkind: VolumeSnapshotClass\nmetadata:\n name: csi-snapclass\ndriver: ebs.csi.aws.com\ndeletionPolicy: Delete\nparameters:\n encrypted: \"true\"\n```\n\n### VolumeSnapshot\n\n```yaml\napiVersion: snapshot.storage.k8s.io/v1\nkind: VolumeSnapshot\nmetadata:\n name: database-snapshot-20231214\n namespace: production\nspec:\n volumeSnapshotClassName: csi-snapclass\n source:\n persistentVolumeClaimName: database-pvc\n```\n\n### Restore from Snapshot\n\n```yaml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n name: database-restored\n namespace: production\nspec:\n accessModes:\n - ReadWriteOnce\n storageClassName: fast-ssd\n dataSource:\n name: database-snapshot-20231214\n kind: VolumeSnapshot\n apiGroup: snapshot.storage.k8s.io\n resources:\n requests:\n storage: 50Gi\n```\n\n## Volume Expansion\n\n```yaml\n# 1. Ensure StorageClass allows expansion\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n name: fast-ssd\nallowVolumeExpansion: true\n# ... rest of config\n\n---\n# 2. Expand PVC by updating size\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n name: database-pvc\nspec:\n accessModes:\n - ReadWriteOnce\n storageClassName: fast-ssd\n resources:\n requests:\n storage: 100Gi # Increased from 50Gi\n```\n\n## EmptyDir Volumes\n\n### Memory-Backed EmptyDir\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: cache-pod\nspec:\n containers:\n - name: app\n image: myapp:latest\n volumeMounts:\n - name: cache\n mountPath: /cache\n volumes:\n - name: cache\n emptyDir:\n medium: Memory\n sizeLimit: 1Gi\n```\n\n### Disk-Backed EmptyDir\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: worker-pod\nspec:\n containers:\n - name: worker\n image: worker:latest\n volumeMounts:\n - name: scratch\n mountPath: /tmp/scratch\n volumes:\n - name: scratch\n emptyDir:\n sizeLimit: 10Gi\n```\n\n## ConfigMap and Secret Volumes\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: app-pod\nspec:\n containers:\n - name: app\n image: myapp:latest\n volumeMounts:\n - name: config\n mountPath: /etc/config\n readOnly: true\n - name: secrets\n mountPath: /etc/secrets\n readOnly: true\n volumes:\n - name: config\n configMap:\n name: app-config\n items:\n - key: app.yaml\n path: config.yaml\n mode: 0644\n - name: secrets\n secret:\n secretName: app-secrets\n defaultMode: 0400\n items:\n - key: db-password\n path: database/password\n```\n\n## Projected Volumes\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: projected-pod\nspec:\n containers:\n - name: app\n image: myapp:latest\n volumeMounts:\n - name: combined\n mountPath: /combined\n readOnly: true\n volumes:\n - name: combined\n projected:\n sources:\n - secret:\n name: app-secrets\n items:\n - key: password\n path: secrets/password\n - configMap:\n name: app-config\n items:\n - key: config.yaml\n path: config/app.yaml\n - downwardAPI:\n items:\n - path: pod/labels\n fieldRef:\n fieldPath: metadata.labels\n - path: pod/annotations\n fieldRef:\n fieldPath: metadata.annotations\n```\n\n## CSI Driver Examples\n\n### AWS EBS CSI Driver\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: app-pod\nspec:\n containers:\n - name: app\n image: myapp:latest\n volumeMounts:\n - name: data\n mountPath: /data\n volumes:\n - name: data\n csi:\n driver: ebs.csi.aws.com\n volumeAttributes:\n type: gp3\n iops: \"3000\"\n encrypted: \"true\"\n```\n\n### Secrets Store CSI Driver\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: secrets-pod\nspec:\n serviceAccountName: app-sa\n containers:\n - name: app\n image: myapp:latest\n volumeMounts:\n - name: secrets-store\n mountPath: /mnt/secrets\n readOnly: true\n volumes:\n - name: secrets-store\n csi:\n driver: secrets-store.csi.k8s.io\n readOnly: true\n volumeAttributes:\n secretProviderClass: aws-secrets\n```\n\n## HostPath Volumes (Use with Caution)\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: privileged-pod\nspec:\n containers:\n - name: app\n image: myapp:latest\n volumeMounts:\n - name: host-data\n mountPath: /host-data\n securityContext:\n privileged: true\n volumes:\n - name: host-data\n hostPath:\n path: /data\n type: DirectoryOrCreate\n```\n\n## Best Practices\n\n1. **Dynamic Provisioning**: Prefer dynamic provisioning with StorageClasses\n2. **Access Modes**: Use correct access mode (RWO for single node, RWX for multi-node)\n3. **Reclaim Policy**: Use Retain for critical data, Delete for temporary\n4. **Backup**: Regular snapshots and offsite backups\n5. **Monitoring**: Monitor disk usage and performance metrics\n6. **Expansion**: Enable volume expansion in StorageClass\n7. **Performance**: Choose appropriate storage type for workload\n8. **Security**: Encrypt volumes at rest and in transit\n9. **Limits**: Set size limits on emptyDir volumes\n10. **Labels**: Label PVCs for organization and backup policies\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":9723,"content_sha256":"6d93a1f63bc7101eb98647d68143161b21d9e4a640d38086adb55871dae0d90d"},{"filename":"references/troubleshooting.md","content":"# Kubernetes Troubleshooting\n\n## Essential kubectl Commands\n\n### Pod Inspection\n\n```bash\n# Get pods with details\nkubectl get pods -n production -o wide\nkubectl get pods --all-namespaces\nkubectl get pods --field-selector status.phase=Running\nkubectl get pods --selector app=web-app\n\n# Describe pod (shows events)\nkubectl describe pod web-app-7d5c8b9f4-xk2pm -n production\n\n# Get pod logs\nkubectl logs web-app-7d5c8b9f4-xk2pm -n production\nkubectl logs web-app-7d5c8b9f4-xk2pm -n production --previous # Previous container\nkubectl logs web-app-7d5c8b9f4-xk2pm -n production -c init-container\nkubectl logs -f web-app-7d5c8b9f4-xk2pm -n production # Follow logs\nkubectl logs --tail=100 web-app-7d5c8b9f4-xk2pm -n production\nkubectl logs --since=1h web-app-7d5c8b9f4-xk2pm -n production\n\n# Get all pod logs from deployment\nkubectl logs deployment/web-app -n production --all-containers=true\n\n# Execute commands in pod\nkubectl exec -it web-app-7d5c8b9f4-xk2pm -n production -- /bin/sh\nkubectl exec web-app-7d5c8b9f4-xk2pm -n production -- env\nkubectl exec web-app-7d5c8b9f4-xk2pm -n production -- cat /etc/config/app.yaml\n\n# Copy files to/from pod\nkubectl cp web-app-7d5c8b9f4-xk2pm:/app/logs/app.log ./app.log -n production\nkubectl cp ./config.yaml web-app-7d5c8b9f4-xk2pm:/tmp/config.yaml -n production\n\n# Port forward\nkubectl port-forward web-app-7d5c8b9f4-xk2pm 8080:8080 -n production\nkubectl port-forward service/web-app 8080:80 -n production\n```\n\n### Deployment Debugging\n\n```bash\n# Check deployment status\nkubectl get deployment web-app -n production\nkubectl describe deployment web-app -n production\nkubectl rollout status deployment/web-app -n production\nkubectl rollout history deployment/web-app -n production\n\n# Check replica sets\nkubectl get rs -n production\nkubectl describe rs web-app-7d5c8b9f4 -n production\n\n# Scale deployment\nkubectl scale deployment web-app --replicas=5 -n production\n\n# Rollback deployment\nkubectl rollout undo deployment/web-app -n production\nkubectl rollout undo deployment/web-app --to-revision=2 -n production\n\n# Restart deployment (recreate pods)\nkubectl rollout restart deployment/web-app -n production\n```\n\n### Service and Network Debugging\n\n```bash\n# Get services\nkubectl get svc -n production\nkubectl describe svc web-app -n production\n\n# Get endpoints\nkubectl get endpoints web-app -n production\nkubectl describe endpoints web-app -n production\n\n# Get ingress\nkubectl get ingress -n production\nkubectl describe ingress web-app -n production\n\n# Get network policies\nkubectl get networkpolicy -n production\nkubectl describe networkpolicy frontend-to-backend -n production\n```\n\n### Resource and Configuration\n\n```bash\n# Get ConfigMaps and Secrets\nkubectl get configmap -n production\nkubectl describe configmap app-config -n production\nkubectl get configmap app-config -n production -o yaml\n\nkubectl get secret -n production\nkubectl describe secret app-secrets -n production\nkubectl get secret app-secrets -n production -o jsonpath='{.data.password}' | base64 -d\n\n# Get PVCs and PVs\nkubectl get pvc -n production\nkubectl describe pvc database-pvc -n production\nkubectl get pv\n\n# Get events (sorted by timestamp)\nkubectl get events -n production --sort-by='.lastTimestamp'\nkubectl get events -n production --field-selector involvedObject.name=web-app-7d5c8b9f4-xk2pm\n```\n\n## Debug Pod\n\n### Ephemeral Debug Container\n\n```bash\n# Attach debug container to running pod\nkubectl debug -it web-app-7d5c8b9f4-xk2pm -n production \\\n --image=busybox:latest \\\n --target=web-app\n\n# Create copy of pod with debug tools\nkubectl debug web-app-7d5c8b9f4-xk2pm -n production \\\n -it \\\n --image=ubuntu:latest \\\n --share-processes \\\n --copy-to=web-app-debug\n\n# Debug with different image\nkubectl debug web-app-7d5c8b9f4-xk2pm -n production \\\n -it \\\n --image=nicolaka/netshoot:latest \\\n --target=web-app\n```\n\n### Debug on Node\n\n```bash\n# Create privileged pod on specific node\nkubectl debug node/node-01 -it --image=ubuntu:latest\n\n# Access node filesystem\nkubectl debug node/node-01 -it --image=ubuntu:latest -- chroot /host\n```\n\n## Common Issues and Solutions\n\n### Issue 1: Pod in Pending State\n\n```bash\n# Check pod status and events\nkubectl describe pod web-app-7d5c8b9f4-xk2pm -n production\n\n# Common causes:\n# 1. Insufficient resources\nkubectl top nodes\nkubectl describe nodes\n\n# 2. PVC not bound\nkubectl get pvc -n production\nkubectl describe pvc database-pvc -n production\n\n# 3. ImagePullBackOff\nkubectl describe pod web-app-7d5c8b9f4-xk2pm -n production | grep -A 10 Events\n\n# 4. Node selector/affinity issues\nkubectl get pod web-app-7d5c8b9f4-xk2pm -n production -o yaml | grep -A 5 nodeSelector\n```\n\n### Issue 2: CrashLoopBackOff\n\n```bash\n# Check logs from crashed container\nkubectl logs web-app-7d5c8b9f4-xk2pm -n production --previous\n\n# Check if liveness probe is failing\nkubectl describe pod web-app-7d5c8b9f4-xk2pm -n production | grep -A 10 \"Liveness\"\n\n# Debug with different command\nkubectl run debug-pod --image=myapp:latest -it --rm --restart=Never -- /bin/sh\n\n# Check resource limits\nkubectl describe pod web-app-7d5c8b9f4-xk2pm -n production | grep -A 10 \"Limits\"\n```\n\n### Issue 3: ImagePullBackOff\n\n```bash\n# Check image pull secret\nkubectl get secret registry-credentials -n production -o yaml\n\n# Test image pull manually\nkubectl run test-pull --image=myregistry.io/myapp:v1.2.0 \\\n --image-pull-policy=Always \\\n --restart=Never \\\n -n production\n\n# Create/update image pull secret\nkubectl create secret docker-registry registry-credentials \\\n --docker-server=myregistry.io \\\n --docker-username=myuser \\\n --docker-password=\u003cregistry-password> \\\n [email protected] \\\n -n production\n```\n\n### Issue 4: Service Not Accessible\n\n```bash\n# Check service endpoints\nkubectl get endpoints web-app -n production\nkubectl describe endpoints web-app -n production\n\n# Verify pod labels match service selector\nkubectl get pod web-app-7d5c8b9f4-xk2pm -n production --show-labels\nkubectl get service web-app -n production -o yaml | grep -A 3 selector\n\n# Test service connectivity from debug pod\nkubectl run debug --image=nicolaka/netshoot:latest -it --rm -n production -- bash\n# Inside pod:\ncurl http://web-app.production.svc.cluster.local\nnslookup web-app.production.svc.cluster.local\ntelnet web-app.production.svc.cluster.local 80\n```\n\n### Issue 5: DNS Resolution Issues\n\n```bash\n# Check CoreDNS pods\nkubectl get pods -n kube-system -l k8s-app=kube-dns\nkubectl logs -n kube-system -l k8s-app=kube-dns\n\n# Test DNS resolution\nkubectl run dnsutils --image=tutum/dnsutils -it --rm -- bash\n# Inside pod:\nnslookup kubernetes.default\nnslookup web-app.production.svc.cluster.local\ndig web-app.production.svc.cluster.local\n\n# Check DNS config in pod\nkubectl exec web-app-7d5c8b9f4-xk2pm -n production -- cat /etc/resolv.conf\n```\n\n### Issue 6: NetworkPolicy Blocking Traffic\n\n```bash\n# List network policies\nkubectl get networkpolicy -n production\nkubectl describe networkpolicy default-deny-all -n production\n\n# Test connectivity\nkubectl run test-connectivity --image=nicolaka/netshoot:latest -it --rm -n production -- bash\n# Inside pod:\ncurl -v http://web-app:80\nnc -zv web-app 80\n\n# Find the policies that select the destination pod (compare podSelector with these labels)\nkubectl get pods -n production -l app=web-app --show-labels\nkubectl get networkpolicy -n production -o custom-columns=NAME:.metadata.name,SELECTOR:.spec.podSelector\n\n# Fix forward: add a narrow allow rule for the blocked path (see networking.md) instead of removing policies.\n# Never delete production policies to test; if you must bisect, reproduce in a staging\n# namespace and remove one named policy at a time there.\nkubectl delete networkpolicy default-deny-all -n staging\n```\n\n### Issue 7: High Resource Usage\n\n```bash\n# Check resource usage\nkubectl top nodes\nkubectl top pods -n production\nkubectl top pod web-app-7d5c8b9f4-xk2pm -n production --containers\n\n# Check resource requests and limits\nkubectl describe pod web-app-7d5c8b9f4-xk2pm -n production | grep -A 10 \"Limits\"\n\n# Get pods sorted by CPU/memory usage\nkubectl top pods -n production --sort-by=cpu\nkubectl top pods -n production --sort-by=memory\n\n# Check node capacity\nkubectl describe node node-01 | grep -A 10 \"Allocated resources\"\n```\n\n### Issue 8: PersistentVolumeClaim Issues\n\n```bash\n# Check PVC status\nkubectl get pvc -n production\nkubectl describe pvc database-pvc -n production\n\n# Check PV status\nkubectl get pv\nkubectl describe pv pvc-abc123\n\n# Check storage class\nkubectl get storageclass\nkubectl describe storageclass fast-ssd\n\n# Events related to PVC\nkubectl get events -n production --field-selector involvedObject.name=database-pvc\n```\n\n## Advanced Debugging\n\n### API Server Debugging\n\n```bash\n# Enable verbose output\nkubectl get pods -n production -v=9\n\n# Check API server logs (on master node)\njournalctl -u kube-apiserver -f\n\n# Check cluster info\nkubectl cluster-info\nkubectl cluster-info dump > cluster-dump.txt\n```\n\n### RBAC Debugging\n\n```bash\n# Check if ServiceAccount can perform action\nkubectl auth can-i get pods --as=system:serviceaccount:production:web-app-sa -n production\n\n# List permissions for ServiceAccount\nkubectl describe sa web-app-sa -n production\nkubectl describe role web-app-role -n production\nkubectl describe rolebinding web-app-rolebinding -n production\n\n# Check all permissions\nkubectl auth can-i --list --as=system:serviceaccount:production:web-app-sa -n production\n```\n\n### Performance Debugging\n\n```bash\n# Get resource metrics\nkubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes\nkubectl get --raw /apis/metrics.k8s.io/v1beta1/pods\n\n# Check pod overhead\nkubectl get pod web-app-7d5c8b9f4-xk2pm -n production -o json | jq '.spec.overhead'\n\n# Check priority classes\nkubectl get priorityclasses\nkubectl describe priorityclass high-priority\n```\n\n## Diagnostic Tools\n\n### Network Tools Container\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: netshoot\n namespace: production\nspec:\n containers:\n - name: netshoot\n image: nicolaka/netshoot:latest\n command: [\"/bin/sleep\", \"3600\"]\n restartPolicy: Never\n```\n\n### Database Client Container\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n name: postgres-client\n namespace: production\nspec:\n containers:\n - name: postgres\n image: postgres:15-alpine\n command: [\"/bin/sleep\", \"3600\"]\n env:\n - name: PGHOST\n value: postgres-service\n - name: PGUSER\n value: myapp\n - name: PGPASSWORD\n valueFrom:\n secretKeyRef:\n name: postgres-secrets\n key: password\n restartPolicy: Never\n```\n\n## Quick Reference\n\n### Pod States\n- **Pending**: Waiting to be scheduled\n- **ContainerCreating**: Pulling image / creating container\n- **Running**: Pod is running\n- **Succeeded**: All containers exited successfully\n- **Failed**: At least one container failed\n- **CrashLoopBackOff**: Container keeps crashing\n- **ImagePullBackOff**: Cannot pull image\n- **ErrImagePull**: Image pull error\n- **Unknown**: Cannot get pod status\n\n### Common Exit Codes\n- **0**: Success\n- **1**: General error\n- **137**: SIGKILL (OOMKilled - out of memory)\n- **139**: SIGSEGV (segmentation fault)\n- **143**: SIGTERM (graceful termination)\n\n## Best Practices\n\n1. **Logs**: Always check logs first with `kubectl logs`\n2. **Events**: Use `kubectl describe` to see events\n3. **Labels**: Use consistent labels for easier debugging\n4. **Resources**: Set appropriate requests and limits\n5. **Health Checks**: Implement proper liveness and readiness probes\n6. **Monitoring**: Set up comprehensive monitoring and alerting\n7. **Debug Tools**: Keep debug containers ready\n8. **Documentation**: Document common issues and solutions\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":11616,"content_sha256":"148f204d9a494ad41f3edd5e2ee2e7c27e5d44fc80e5f27c254649b9355dc225"},{"filename":"references/workloads.md","content":"# Kubernetes Workloads\n\n## Deployment Pattern\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: web-app\n namespace: production\n labels:\n app: web-app\n tier: frontend\nspec:\n replicas: 3\n revisionHistoryLimit: 10\n strategy:\n type: RollingUpdate\n rollingUpdate:\n maxSurge: 1\n maxUnavailable: 0\n selector:\n matchLabels:\n app: web-app\n template:\n metadata:\n labels:\n app: web-app\n tier: frontend\n version: v1.2.0\n annotations:\n prometheus.io/scrape: \"true\"\n prometheus.io/port: \"8080\"\n spec:\n serviceAccountName: web-app-sa\n securityContext:\n runAsNonRoot: true\n runAsUser: 1000\n fsGroup: 2000\n containers:\n - name: app\n image: myregistry.io/web-app:v1.2.0\n imagePullPolicy: IfNotPresent\n ports:\n - name: http\n containerPort: 8080\n protocol: TCP\n env:\n - name: ENVIRONMENT\n value: production\n - name: DB_HOST\n valueFrom:\n configMapKeyRef:\n name: app-config\n key: database.host\n - name: DB_PASSWORD\n valueFrom:\n secretKeyRef:\n name: app-secrets\n key: db-password\n resources:\n requests:\n cpu: 100m\n memory: 128Mi\n limits:\n cpu: 500m\n memory: 512Mi\n livenessProbe:\n httpGet:\n path: /health\n port: http\n initialDelaySeconds: 30\n periodSeconds: 10\n timeoutSeconds: 5\n failureThreshold: 3\n readinessProbe:\n httpGet:\n path: /ready\n port: http\n initialDelaySeconds: 10\n periodSeconds: 5\n timeoutSeconds: 3\n failureThreshold: 2\n volumeMounts:\n - name: config\n mountPath: /etc/config\n readOnly: true\n - name: cache\n mountPath: /var/cache\n volumes:\n - name: config\n configMap:\n name: app-config\n - name: cache\n emptyDir: {}\n```\n\n## StatefulSet Pattern\n\n```yaml\napiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n name: postgres\n namespace: database\nspec:\n serviceName: postgres-headless\n replicas: 3\n podManagementPolicy: OrderedReady\n updateStrategy:\n type: RollingUpdate\n selector:\n matchLabels:\n app: postgres\n template:\n metadata:\n labels:\n app: postgres\n spec:\n serviceAccountName: postgres-sa\n securityContext:\n runAsUser: 999\n fsGroup: 999\n containers:\n - name: postgres\n image: postgres:15-alpine\n ports:\n - name: postgres\n containerPort: 5432\n env:\n - name: POSTGRES_PASSWORD\n valueFrom:\n secretKeyRef:\n name: postgres-secrets\n key: password\n - name: PGDATA\n value: /var/lib/postgresql/data/pgdata\n resources:\n requests:\n cpu: 500m\n memory: 1Gi\n limits:\n cpu: 2000m\n memory: 4Gi\n volumeMounts:\n - name: data\n mountPath: /var/lib/postgresql/data\n livenessProbe:\n exec:\n command:\n - pg_isready\n - -U\n - postgres\n initialDelaySeconds: 30\n periodSeconds: 10\n readinessProbe:\n exec:\n command:\n - pg_isready\n - -U\n - postgres\n initialDelaySeconds: 10\n periodSeconds: 5\n volumeClaimTemplates:\n - metadata:\n name: data\n spec:\n accessModes: [\"ReadWriteOnce\"]\n storageClassName: fast-ssd\n resources:\n requests:\n storage: 50Gi\n```\n\n## DaemonSet Pattern\n\n```yaml\napiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n name: node-exporter\n namespace: monitoring\nspec:\n selector:\n matchLabels:\n app: node-exporter\n updateStrategy:\n type: RollingUpdate\n rollingUpdate:\n maxUnavailable: 1\n template:\n metadata:\n labels:\n app: node-exporter\n spec:\n hostNetwork: true\n hostPID: true\n serviceAccountName: node-exporter-sa\n tolerations:\n - effect: NoSchedule\n operator: Exists\n containers:\n - name: node-exporter\n image: prom/node-exporter:latest\n args:\n - --path.procfs=/host/proc\n - --path.sysfs=/host/sys\n - --collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($|/)\n ports:\n - name: metrics\n containerPort: 9100\n protocol: TCP\n resources:\n requests:\n cpu: 50m\n memory: 64Mi\n limits:\n cpu: 200m\n memory: 128Mi\n volumeMounts:\n - name: proc\n mountPath: /host/proc\n readOnly: true\n - name: sys\n mountPath: /host/sys\n readOnly: true\n volumes:\n - name: proc\n hostPath:\n path: /proc\n - name: sys\n hostPath:\n path: /sys\n```\n\n## Job Pattern\n\n```yaml\napiVersion: batch/v1\nkind: Job\nmetadata:\n name: db-migration-20231214\n namespace: production\nspec:\n backoffLimit: 3\n ttlSecondsAfterFinished: 3600\n template:\n metadata:\n labels:\n app: db-migration\n spec:\n restartPolicy: OnFailure\n serviceAccountName: migration-sa\n containers:\n - name: migrate\n image: myregistry.io/migrations:v1.2.0\n command: [\"/bin/sh\", \"-c\"]\n args:\n - |\n echo \"Starting migration...\"\n /app/migrate up\n echo \"Migration complete\"\n env:\n - name: DATABASE_URL\n valueFrom:\n secretKeyRef:\n name: db-secrets\n key: connection-string\n resources:\n requests:\n cpu: 100m\n memory: 128Mi\n limits:\n cpu: 500m\n memory: 512Mi\n```\n\n## CronJob Pattern\n\n```yaml\napiVersion: batch/v1\nkind: CronJob\nmetadata:\n name: backup-database\n namespace: production\nspec:\n schedule: \"0 2 * * *\" # Daily at 2 AM\n timeZone: \"America/New_York\"\n successfulJobsHistoryLimit: 3\n failedJobsHistoryLimit: 1\n concurrencyPolicy: Forbid\n jobTemplate:\n spec:\n backoffLimit: 2\n ttlSecondsAfterFinished: 86400\n template:\n metadata:\n labels:\n app: backup\n spec:\n restartPolicy: OnFailure\n serviceAccountName: backup-sa\n containers:\n - name: backup\n image: myregistry.io/backup-tool:latest\n command: [\"/usr/local/bin/backup.sh\"]\n env:\n - name: S3_BUCKET\n valueFrom:\n configMapKeyRef:\n name: backup-config\n key: s3-bucket\n - name: AWS_ACCESS_KEY_ID\n valueFrom:\n secretKeyRef:\n name: backup-secrets\n key: aws-access-key\n - name: AWS_SECRET_ACCESS_KEY\n valueFrom:\n secretKeyRef:\n name: backup-secrets\n key: aws-secret-key\n resources:\n requests:\n cpu: 200m\n memory: 256Mi\n limits:\n cpu: 1000m\n memory: 1Gi\n volumeMounts:\n - name: backup-volume\n mountPath: /backup\n volumes:\n - name: backup-volume\n emptyDir:\n sizeLimit: 10Gi\n```\n\n## Init Containers\n\n```yaml\nspec:\n initContainers:\n - name: wait-for-db\n image: busybox:latest\n command: ['sh', '-c']\n args:\n - |\n until nc -z postgres-service 5432; do\n echo \"Waiting for database...\"\n sleep 2\n done\n echo \"Database is ready\"\n - name: migrate-schema\n image: myregistry.io/migrations:latest\n command: [\"/app/migrate\", \"up\"]\n env:\n - name: DATABASE_URL\n valueFrom:\n secretKeyRef:\n name: db-secrets\n key: url\n containers:\n - name: app\n image: myregistry.io/app:latest\n```\n\n## Best Practices\n\n1. **Resource Management**: Always set requests and limits\n2. **Health Checks**: Include both liveness and readiness probes\n3. **Security**: Use non-root users, read-only filesystems when possible\n4. **Labels**: Consistent labeling for organization and selection\n5. **Update Strategy**: Choose appropriate strategy (RollingUpdate, Recreate)\n6. **Service Accounts**: Never use default, create specific SAs\n7. **Image Tags**: Use specific versions, not `latest` in production\n8. **Cleanup**: Set TTL for Jobs to auto-cleanup completed pods\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":8716,"content_sha256":"46e70a6ced471246dff79551bcdb9b30c61750112705192cdb740c9ea9bba9b5"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Kubernetes Specialist","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When to Use This Skill","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Deploying workloads (Deployments, StatefulSets, DaemonSets, Jobs)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Configuring networking (Services, Ingress, NetworkPolicies)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Managing configuration (ConfigMaps, Secrets, environment variables)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting up persistent storage (PV, PVC, StorageClasses)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Creating Helm charts for application packaging","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Troubleshooting cluster and workload issues","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Implementing security best practices","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Core Workflow","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Analyze requirements","type":"text","marks":[{"type":"strong"}]},{"text":" — Understand workload characteristics, scaling needs, security requirements","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Design architecture","type":"text","marks":[{"type":"strong"}]},{"text":" — Choose workload types, networking patterns, storage solutions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Implement manifests","type":"text","marks":[{"type":"strong"}]},{"text":" — Create declarative YAML with proper resource limits, health checks","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Secure","type":"text","marks":[{"type":"strong"}]},{"text":" — Apply RBAC, NetworkPolicies, Pod Security Standards, least privilege","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validate","type":"text","marks":[{"type":"strong"}]},{"text":" — Run ","type":"text"},{"text":"kubectl rollout status","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"kubectl get pods -w","type":"text","marks":[{"type":"code_inline"}]},{"text":", and ","type":"text"},{"text":"kubectl describe pod \u003cname>","type":"text","marks":[{"type":"code_inline"}]},{"text":" to confirm health; roll back with ","type":"text"},{"text":"kubectl rollout undo","type":"text","marks":[{"type":"code_inline"}]},{"text":" if needed","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Reference Guide","type":"text"}]},{"type":"paragraph","content":[{"text":"Load detailed guidance based on context:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Topic","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reference","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Load When","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Workloads","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/workloads.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Deployments, StatefulSets, DaemonSets, Jobs, CronJobs","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Networking","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/networking.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Services, Ingress, NetworkPolicies, DNS","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Configuration","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/configuration.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ConfigMaps, Secrets, environment variables","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Storage","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/storage.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"PV, PVC, StorageClasses, CSI drivers","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Helm Charts","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/helm-charts.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Chart structure, values, templates, hooks, testing, repositories","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Troubleshooting","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/troubleshooting.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"kubectl debug, logs, events, common issues","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Custom Operators","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/custom-operators.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CRD, Operator SDK, controller-runtime, reconciliation","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Service Mesh","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/service-mesh.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Istio, Linkerd, traffic management, mTLS, canary","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"GitOps","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/gitops.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ArgoCD, Flux, progressive delivery, sealed secrets","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cost Optimization","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/cost-optimization.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"VPA, HPA tuning, spot instances, quotas, right-sizing","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Multi-Cluster","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/multi-cluster.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cluster API, federation, cross-cluster networking, DR","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Constraints","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"MUST DO","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use declarative YAML manifests (avoid imperative kubectl commands)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Set resource requests and limits on all containers","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Include liveness and readiness probes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use secrets for sensitive data (never hardcode credentials)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Apply least privilege RBAC permissions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Implement NetworkPolicies for network segmentation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use namespaces for logical isolation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Label resources consistently for organization","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Document configuration decisions in annotations","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"MUST NOT DO","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Deploy to production without resource limits","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Store secrets in ConfigMaps or as plain environment variables","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use default ServiceAccount for application pods","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Allow unrestricted network access (default allow-all)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run containers as root without justification","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Skip health checks (liveness/readiness probes)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use latest tag for production images","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Expose unnecessary ports or services","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Common YAML Patterns","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Deployment with resource limits, probes, and security context","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"yaml"},"content":[{"text":"apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: my-app\n namespace: my-namespace\n labels:\n app: my-app\n version: \"1.2.3\"\nspec:\n replicas: 3\n selector:\n matchLabels:\n app: my-app\n template:\n metadata:\n labels:\n app: my-app\n version: \"1.2.3\"\n spec:\n serviceAccountName: my-app-sa # never use default SA\n securityContext:\n runAsNonRoot: true\n runAsUser: 1000\n fsGroup: 2000\n containers:\n - name: my-app\n image: my-registry/my-app:1.2.3 # never use latest\n ports:\n - containerPort: 8080\n resources:\n requests:\n cpu: \"100m\"\n memory: \"128Mi\"\n limits:\n cpu: \"500m\"\n memory: \"512Mi\"\n livenessProbe:\n httpGet:\n path: /healthz\n port: 8080\n initialDelaySeconds: 15\n periodSeconds: 20\n readinessProbe:\n httpGet:\n path: /ready\n port: 8080\n initialDelaySeconds: 5\n periodSeconds: 10\n securityContext:\n allowPrivilegeEscalation: false\n readOnlyRootFilesystem: true\n capabilities:\n drop: [\"ALL\"]\n envFrom:\n - secretRef:\n name: my-app-secret # pull credentials from Secret, not ConfigMap","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Minimal RBAC (least privilege)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"yaml"},"content":[{"text":"apiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: my-app-sa\n namespace: my-namespace\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n name: my-app-role\n namespace: my-namespace\nrules:\n - apiGroups: [\"\"]\n resources: [\"configmaps\"]\n verbs: [\"get\", \"list\"] # grant only what is needed\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n name: my-app-rolebinding\n namespace: my-namespace\nsubjects:\n - kind: ServiceAccount\n name: my-app-sa\n namespace: my-namespace\nroleRef:\n kind: Role\n name: my-app-role\n apiGroup: rbac.authorization.k8s.io","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"NetworkPolicy (default-deny + explicit allow)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"yaml"},"content":[{"text":"# Deny all ingress and egress by default\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n name: default-deny-all\n namespace: my-namespace\nspec:\n podSelector: {}\n policyTypes: [\"Ingress\", \"Egress\"]\n---\n# Allow only specific traffic\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n name: allow-my-app\n namespace: my-namespace\nspec:\n podSelector:\n matchLabels:\n app: my-app\n policyTypes: [\"Ingress\"]\n ingress:\n - from:\n - podSelector:\n matchLabels:\n app: frontend\n ports:\n - protocol: TCP\n port: 8080","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Validation Commands","type":"text"}]},{"type":"paragraph","content":[{"text":"After deploying, verify health and security posture:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Watch rollout complete\nkubectl rollout status deployment/my-app -n my-namespace\n\n# Stream pod events to catch crash loops or image pull errors\nkubectl get pods -n my-namespace -w\n\n# Inspect a specific pod for failures\nkubectl describe pod \u003cpod-name> -n my-namespace\n\n# Check container logs\nkubectl logs \u003cpod-name> -n my-namespace --previous # use --previous for crashed containers\n\n# Verify resource usage vs. limits\nkubectl top pods -n my-namespace\n\n# Audit RBAC permissions for a service account\nkubectl auth can-i --list --as=system:serviceaccount:my-namespace:my-app-sa\n\n# Roll back a failed deployment\nkubectl rollout undo deployment/my-app -n my-namespace","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Output Templates","type":"text"}]},{"type":"paragraph","content":[{"text":"When implementing Kubernetes resources, provide:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Complete YAML manifests with proper structure","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"RBAC configuration if needed (ServiceAccount, Role, RoleBinding)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NetworkPolicy for network isolation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Brief explanation of design decisions and security considerations","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Maintained by ","type":"text"},{"text":"@jeffallan","type":"text","marks":[{"type":"link","attrs":{"href":"https://github.com/jeffallan","title":null}}]},{"text":", Principal Consultant at ","type":"text"},{"text":"Synergetic Solutions","type":"text","marks":[{"type":"link","attrs":{"href":"https://synergetic.solutions","title":null}}]}]},{"type":"paragraph","content":[{"text":"Documentation","type":"text","marks":[{"type":"link","attrs":{"href":"https://jeffallan.github.io/claude-skills/skills/infrastructure/kubernetes-specialist/","title":null}}]}]}]},"metadata":{"date":"2026-11-02","name":"kubernetes-specialist","author":"@skillopedia","source":{"stars":12181,"repo_name":"claude-skills","origin_url":"https://github.com/Jeffallan/claude-skills/blob/HEAD/skills/kubernetes-specialist/SKILL.md","repo_owner":"Jeffallan","body_sha256":"4fa03569789141e52e6cd4d42922c84c7ef2dc299de5fc3aea4ceed506140d56","cluster_key":"ed96dc87299ed07ac2fab650661e0f3013fe7d591341111cdd7e9af9712abeee","clean_bundle":{"format":"clean-skill-bundle-v1","source":"Jeffallan/claude-skills/skills/kubernetes-specialist/SKILL.md","text_bytes":125145,"source_commit":"078a25cc5bfd8011459be7b91d004e900c1d02d3","skills_sh_rank":1805,"attachment_count":11,"text_attachments":11,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/kubernetes-specialist/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"devops-infrastructure","category_label":"DevOps"},"exact_dupes_collapsed_into_this":0},"license":"MIT","version":"v1","category":"devops-infrastructure","metadata":{"role":"specialist","scope":"infrastructure","author":"https://github.com/Jeffallan","domain":"infrastructure","company":"https://synergetic.solutions","version":"1.1.2","triggers":"Kubernetes, K8s, kubectl, Helm, container orchestration, pod deployment, RBAC, NetworkPolicy, Ingress, StatefulSet, Operator, CRD, CustomResourceDefinition, ArgoCD, Flux, GitOps, Istio, Linkerd, service mesh, multi-cluster, cost optimization, VPA, spot instances","output-format":"manifests","related-skills":"devops-engineer, cloud-architect, sre-engineer, terraform-engineer, security-reviewer, chaos-engineer"},"import_tag":"skills-sh-top20k-2026-11","description":"Use when deploying or managing Kubernetes workloads. Invoke to create deployment manifests, configure pod security policies, set up service accounts, define network isolation rules, debug pod crashes, analyze resource limits, inspect container logs, or right-size workloads. Use for Helm charts, RBAC policies, NetworkPolicies, storage configuration, performance optimization, GitOps pipelines, and multi-cluster management."}},"renderedAt":1793672036096}

Kubernetes Specialist When to Use This Skill - Deploying workloads (Deployments, StatefulSets, DaemonSets, Jobs) - Configuring networking (Services, Ingress, NetworkPolicies) - Managing configuration (ConfigMaps, Secrets, environment variables) - Setting up persistent storage (PV, PVC, StorageClasses) - Creating Helm charts for application packaging - Troubleshooting cluster and workload issues - Implementing security best practices Core Workflow 1. Analyze requirements — Understand workload characteristics, scaling needs, security requirements 2. Design architecture — Choose workload types,…