@intentius/chant-lexicon-k8s 0.0.12 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/plugin.ts CHANGED
@@ -513,20 +513,6 @@ kubectl port-forward pod/<pod-name> 8080:8080
513
513
  | CreateContainerError | Container config issue | \`kubectl describe pod\` → Events | Check volume mounts, configmap/secret refs, security context |
514
514
  | Init:CrashLoopBackOff | Init container failing | \`kubectl logs -c <init-container>\` | Fix init container command, check dependencies |
515
515
 
516
- ### Resource inspection
517
-
518
- \`\`\`bash
519
- # Get all resources in namespace
520
- kubectl get all -n <namespace>
521
-
522
- # YAML output for debugging
523
- kubectl get deployment/my-app -o yaml
524
-
525
- # Check resource usage
526
- kubectl top pods -l app.kubernetes.io/name=my-app
527
- kubectl top nodes
528
- \`\`\`
529
-
530
516
  ## Production safety
531
517
 
532
518
  ### Pre-apply validation
@@ -542,22 +528,6 @@ kubectl apply -f manifests.yaml --dry-run=server
542
528
  kubectl apply -f manifests.yaml --dry-run=client
543
529
  \`\`\`
544
530
 
545
- ### Rollback
546
-
547
- \`\`\`bash
548
- # Check rollout history
549
- kubectl rollout history deployment/my-app
550
-
551
- # Undo last rollout
552
- kubectl rollout undo deployment/my-app
553
-
554
- # Roll back to a specific revision
555
- kubectl rollout undo deployment/my-app --to-revision=2
556
-
557
- # Watch rollout progress
558
- kubectl rollout status deployment/my-app --timeout=300s
559
- \`\`\`
560
-
561
531
  ### Deployment strategies
562
532
 
563
533
  - **RollingUpdate** (default): Gradually replaces pods. Set \`maxSurge\` and \`maxUnavailable\`.
@@ -565,157 +535,42 @@ kubectl rollout status deployment/my-app --timeout=300s
565
535
  - **Canary**: Deploy a second Deployment with 1 replica + same selector labels. Route percentage via Ingress annotations or service mesh.
566
536
  - **Blue/Green**: Two full Deployments (blue/green), switch Service selector between them.
567
537
 
568
- ## Composites
569
-
570
- Composites are higher-level functions that produce multiple coordinated K8s resources from a single call. They return plain prop objects — not class instances — that you pass to generated constructors or serialize directly.
571
-
572
- ### WebApp — Deployment + Service + optional Ingress
573
-
574
- \`\`\`typescript
575
- import { WebApp } from "@intentius/chant-lexicon-k8s";
576
-
577
- const { deployment, service, ingress } = WebApp({
578
- name: "frontend",
579
- image: "frontend:1.0",
580
- port: 3000,
581
- replicas: 3,
582
- ingressHost: "frontend.example.com",
583
- ingressTlsSecret: "frontend-tls",
584
- });
585
- \`\`\`
586
-
587
- ### StatefulApp StatefulSet + headless Service + PVC
588
-
589
- \`\`\`typescript
590
- import { StatefulApp } from "@intentius/chant-lexicon-k8s";
591
-
592
- const { statefulSet, service } = StatefulApp({
593
- name: "postgres",
594
- image: "postgres:16",
595
- storageSize: "20Gi",
596
- env: [{ name: "POSTGRES_DB", value: "mydb" }],
597
- });
598
- \`\`\`
599
-
600
- ### CronWorkloadCronJob + ServiceAccount + Role + RoleBinding
601
-
602
- \`\`\`typescript
603
- import { CronWorkload } from "@intentius/chant-lexicon-k8s";
604
-
605
- const { cronJob, serviceAccount, role, roleBinding } = CronWorkload({
606
- name: "db-backup",
607
- image: "postgres:16",
608
- schedule: "0 2 * * *",
609
- command: ["pg_dump", "-h", "postgres", "mydb"],
610
- rbacRules: [{ apiGroups: [""], resources: ["secrets"], verbs: ["get"] }],
611
- });
612
- \`\`\`
613
-
614
- ### AutoscaledService — Deployment + Service + HPA + PDB
615
-
616
- Production HTTP service with autoscaling, health probes, and optional topology spreading.
617
-
618
- \`\`\`typescript
619
- import { AutoscaledService } from "@intentius/chant-lexicon-k8s";
620
-
621
- const { deployment, service, hpa, pdb } = AutoscaledService({
622
- name: "api",
623
- image: "api:2.0",
624
- port: 8080,
625
- maxReplicas: 10,
626
- minReplicas: 3,
627
- cpuRequest: "200m",
628
- memoryRequest: "256Mi",
629
- cpuLimit: "1",
630
- memoryLimit: "1Gi",
631
- // Probe paths — defaults: /healthz and /readyz
632
- livenessPath: "/healthz",
633
- readinessPath: "/readyz",
634
- // Zone-aware topology spreading (default: false)
635
- topologySpread: true,
636
- // Custom: topologySpread: { maxSkew: 2, topologyKey: "kubernetes.io/hostname" }
637
- });
638
- \`\`\`
639
-
640
- Key features:
641
- - **Probe paths**: \`livenessPath\` (default \`/healthz\`) and \`readinessPath\` (default \`/readyz\`) — override for apps that don't serve those routes
642
- - **Topology spread**: \`topologySpread: true\` adds zone-aware spreading (maxSkew=1, DoNotSchedule); pass an object for custom key/skew
643
- - **PDB minAvailable**: accepts number or string percentage (e.g., \`"50%"\`)
644
-
645
- ### WorkerPool — Deployment + RBAC + optional ConfigMap + optional HPA
646
-
647
- Background queue workers with optional RBAC and autoscaling.
648
-
649
- \`\`\`typescript
650
- import { WorkerPool } from "@intentius/chant-lexicon-k8s";
651
-
652
- const { deployment, serviceAccount, role, roleBinding, configMap, hpa } = WorkerPool({
653
- name: "email-worker",
654
- image: "worker:1.0",
655
- command: ["bundle", "exec", "sidekiq"],
656
- config: { REDIS_URL: "redis://redis:6379", QUEUE: "emails" },
657
- autoscaling: { minReplicas: 2, maxReplicas: 20, targetCPUPercent: 60 },
658
- });
659
- \`\`\`
660
-
661
- Key features:
662
- - **RBAC opt-out**: Pass \`rbacRules: []\` to skip ServiceAccount/Role/RoleBinding creation entirely. Omitting \`rbacRules\` (undefined) creates default rules for secrets/configmaps.
663
- - \`serviceAccount\`, \`role\`, \`roleBinding\` are optional in the result — check before use
664
-
665
- ### NamespaceEnv — Namespace + ResourceQuota + LimitRange + NetworkPolicy
666
-
667
- Multi-tenant namespace provisioning with resource guardrails and network isolation.
668
-
669
- \`\`\`typescript
670
- import { NamespaceEnv } from "@intentius/chant-lexicon-k8s";
671
-
672
- const { namespace, resourceQuota, limitRange, networkPolicy } = NamespaceEnv({
673
- name: "team-alpha",
674
- cpuQuota: "8",
675
- memoryQuota: "16Gi",
676
- maxPods: 50,
677
- defaultCpuRequest: "100m",
678
- defaultMemoryRequest: "128Mi",
679
- defaultCpuLimit: "500m",
680
- defaultMemoryLimit: "512Mi",
681
- defaultDenyIngress: true,
682
- defaultDenyEgress: true,
683
- });
684
- \`\`\`
685
-
686
- Key features:
687
- - **Quota-without-limits warning**: Setting ResourceQuota without LimitRange defaults emits a warning — pods without explicit resource requests will fail to schedule
688
- - **Network policies**: \`defaultDenyIngress\` (default true), \`defaultDenyEgress\` (default false) — can be combined or used individually
689
-
690
- ### NodeAgent — DaemonSet + ServiceAccount + ClusterRole + ClusterRoleBinding + optional ConfigMap
691
-
692
- Per-node agents (log collectors, security scanners, monitoring exporters).
693
-
694
- \`\`\`typescript
695
- import { NodeAgent } from "@intentius/chant-lexicon-k8s";
696
-
697
- const { daemonSet, serviceAccount, clusterRole, clusterRoleBinding, configMap } = NodeAgent({
698
- name: "log-collector",
699
- image: "fluentd:v1.16",
700
- port: 24224,
701
- hostPaths: [
702
- { name: "varlog", hostPath: "/var/log", mountPath: "/var/log" },
703
- ],
704
- config: { "fluent.conf": "..." },
705
- rbacRules: [{ apiGroups: [""], resources: ["pods", "namespaces"], verbs: ["get", "list", "watch"] }],
706
- cpuRequest: "50m", // default: 50m
707
- memoryRequest: "64Mi", // default: 64Mi
708
- cpuLimit: "200m", // default: 200m
709
- memoryLimit: "128Mi", // default: 128Mi
710
- namespace: "monitoring",
711
- });
712
- \`\`\`
713
-
714
- Key features:
715
- - **Container resources**: Always set with sensible defaults (50m/64Mi requests, 200m/128Mi limits) — override per-agent
716
- - **Host paths**: Mounted read-only by default; set \`readOnly: false\` to enable writes
717
- - **Tolerations**: \`tolerateAllTaints: true\` (default) ensures agent runs on every node
718
- - Uses **ClusterRole/ClusterRoleBinding** (cluster-scoped) for node-level access
538
+ ## Choosing the Right Composite
539
+
540
+ Composites are higher-level functions that produce multiple coordinated K8s resources from a single call. They return plain prop objects — not class instances.
541
+
542
+ ### Decision Tree
543
+
544
+ | Need | Composite | Resources |
545
+ |------|-----------|-----------|
546
+ | Stateless web app | **WebApp** | Deployment + Service + optional Ingress + optional PDB |
547
+ | Stateful database/cache | **StatefulApp** | StatefulSet + headless Service + PVC + optional PDB |
548
+ | Production HTTP service with autoscaling | **AutoscaledService** | Deployment + Service + HPA + PDB |
549
+ | Background queue workers | **WorkerPool** | Deployment + RBAC + optional ConfigMap + optional HPA + optional PDB |
550
+ | Scheduled jobs | **CronWorkload** | CronJob + RBAC |
551
+ | One-shot batch jobs | **BatchJob** | Job + optional RBAC |
552
+ | App with ConfigMap/Secret mounts | **ConfiguredApp** | Deployment + Service + optional ConfigMap |
553
+ | Multi-container sidecar patterns | **SidecarApp** | Deployment + Service |
554
+ | App with Prometheus monitoring | **MonitoredService** | Deployment + Service + ServiceMonitor + optional PrometheusRule |
555
+ | App with fine-grained network policies | **NetworkIsolatedApp** | Deployment + Service + NetworkPolicy |
556
+ | Namespace with quotas and isolation | **NamespaceEnv** | Namespace + ResourceQuota + LimitRange + NetworkPolicy |
557
+ | Per-node agent (custom) | **NodeAgent** | DaemonSet + RBAC + optional ConfigMap |
558
+ | Multi-host TLS Ingress (cert-manager) | **SecureIngress** | Ingress + optional Certificate |
559
+ | EKS IRSA ServiceAccount | **IrsaServiceAccount** | ServiceAccount + optional RBAC |
560
+ | AWS ALB Ingress | **AlbIngress** | Ingress with ALB annotations |
561
+ | EBS StorageClass | **EbsStorageClass** | StorageClass (ebs.csi.aws.com) |
562
+ | EFS StorageClass | **EfsStorageClass** | StorageClass (efs.csi.aws.com) |
563
+ | Fluent Bit for CloudWatch | **FluentBitAgent** | DaemonSet + RBAC + ConfigMap |
564
+ | ExternalDNS for Route53 | **ExternalDnsAgent** | Deployment + IRSA SA + ClusterRole |
565
+ | ADOT for CloudWatch/X-Ray | **AdotCollector** | DaemonSet + RBAC + ConfigMap |
566
+
567
+ ### Hardening options (available on Deployment-based composites)
568
+
569
+ - \`minAvailable\` — creates a PodDisruptionBudget (WebApp, StatefulApp, WorkerPool; AutoscaledService always has one)
570
+ - \`initContainers\`run before main containers (WebApp, StatefulApp, AutoscaledService, ConfiguredApp, SidecarApp)
571
+ - \`securityContext\` — container security settings (WebApp, StatefulApp, AutoscaledService, WorkerPool)
572
+ - \`terminationGracePeriodSeconds\` — graceful shutdown (WebApp, StatefulApp, AutoscaledService, WorkerPool)
573
+ - \`priorityClassName\` pod scheduling priority (WebApp, StatefulApp, AutoscaledService, WorkerPool)
719
574
 
720
575
  ### Common patterns across all composites
721
576
 
@@ -724,49 +579,6 @@ Key features:
724
579
  - Pass \`namespace: "prod"\` to set namespace on all namespaced resources
725
580
  - Pass \`env: [{ name: "KEY", value: "val" }]\` for container environment variables
726
581
 
727
- ## Namespace management
728
-
729
- Use the **NamespaceEnv** composite (above) to manage namespaces declaratively. For manual kubectl management:
730
-
731
- \`\`\`bash
732
- # Create namespace
733
- kubectl create namespace my-project
734
-
735
- # Set default resource quotas
736
- kubectl apply -f - <<EOF
737
- apiVersion: v1
738
- kind: ResourceQuota
739
- metadata:
740
- name: default-quota
741
- namespace: my-project
742
- spec:
743
- hard:
744
- requests.cpu: "4"
745
- requests.memory: 8Gi
746
- limits.cpu: "8"
747
- limits.memory: 16Gi
748
- pods: "20"
749
- EOF
750
-
751
- # Set default container limits via LimitRange
752
- kubectl apply -f - <<EOF
753
- apiVersion: v1
754
- kind: LimitRange
755
- metadata:
756
- name: default-limits
757
- namespace: my-project
758
- spec:
759
- limits:
760
- - default:
761
- cpu: 500m
762
- memory: 256Mi
763
- defaultRequest:
764
- cpu: 100m
765
- memory: 128Mi
766
- type: Container
767
- EOF
768
- \`\`\`
769
-
770
582
  ## Troubleshooting reference table
771
583
 
772
584
  | Symptom | Likely cause | Resolution |
@@ -775,11 +587,8 @@ EOF
775
587
  | Pod stuck in Pending | PVC not bound | Check StorageClass exists, PV available |
776
588
  | Pod stuck in Pending | Node selector/affinity mismatch | Verify node labels match selectors |
777
589
  | Pod stuck in ContainerCreating | ConfigMap/Secret not found | Ensure referenced ConfigMaps/Secrets exist |
778
- | Pod stuck in ContainerCreating | Volume mount failure | Check PVC status, CSI driver health |
779
590
  | Service returns 503 | No ready endpoints | Check pod readiness probes, selector match |
780
- | Service returns 503 | Wrong port configuration | Verify targetPort matches containerPort |
781
591
  | Ingress returns 404 | Backend service not found | Check Ingress rules, service name/port |
782
- | Ingress returns 404 | Wrong path matching | Check pathType (Prefix vs Exact) |
783
592
  | HPA not scaling | Metrics server not installed | Install metrics-server |
784
593
  | HPA not scaling | Resource requests not set | Add CPU/memory requests to containers |
785
594
  | CronJob not running | Invalid cron expression | Validate cron syntax (5-field format) |
@@ -892,20 +701,522 @@ const { deployment, service, hpa, pdb } = AutoscaledService({
892
701
  });`,
893
702
  },
894
703
  {
895
- title: "NamespaceEnv composite",
896
- description: "Multi-tenant namespace with guardrails",
897
- input: "Set up a team namespace with quotas and network isolation",
898
- output: `import { NamespaceEnv } from "@intentius/chant-lexicon-k8s";
899
-
900
- const { namespace, resourceQuota, limitRange, networkPolicy } = NamespaceEnv({
901
- name: "team-alpha",
902
- cpuQuota: "8",
903
- memoryQuota: "16Gi",
904
- defaultCpuRequest: "100m",
905
- defaultMemoryRequest: "128Mi",
906
- defaultCpuLimit: "500m",
907
- defaultMemoryLimit: "512Mi",
908
- defaultDenyIngress: true,
704
+ title: "BatchJob composite",
705
+ description: "One-shot batch job with RBAC",
706
+ input: "Run a database migration job",
707
+ output: `import { BatchJob } from "@intentius/chant-lexicon-k8s";
708
+
709
+ const { job, serviceAccount, role, roleBinding } = BatchJob({
710
+ name: "db-migrate",
711
+ image: "api:1.0",
712
+ command: ["python", "manage.py", "migrate"],
713
+ backoffLimit: 3,
714
+ ttlSecondsAfterFinished: 3600,
715
+ });`,
716
+ },
717
+ ],
718
+ },
719
+ {
720
+ name: "chant-k8s-eks",
721
+ description: "EKS-specific Kubernetes composites — IRSA, ALB, EBS/EFS, Fluent Bit, ExternalDNS, ADOT",
722
+ content: `---
723
+ skill: chant-k8s-eks
724
+ description: EKS-specific Kubernetes patterns and composites
725
+ user-invocable: true
726
+ ---
727
+
728
+ # EKS Kubernetes Patterns
729
+
730
+ ## EKS Composites Overview
731
+
732
+ These composites produce K8s YAML with EKS-specific annotations and configurations.
733
+
734
+ ### IrsaServiceAccount — ServiceAccount with IAM Role annotation
735
+
736
+ \`\`\`typescript
737
+ import { IrsaServiceAccount } from "@intentius/chant-lexicon-k8s";
738
+
739
+ const { serviceAccount, role, roleBinding } = IrsaServiceAccount({
740
+ name: "app-sa",
741
+ iamRoleArn: "arn:aws:iam::123456789012:role/my-app-role",
742
+ rbacRules: [
743
+ { apiGroups: [""], resources: ["secrets"], verbs: ["get"] },
744
+ ],
745
+ namespace: "prod",
746
+ });
747
+ \`\`\`
748
+
749
+ ### AlbIngress — Ingress with AWS ALB Controller annotations
750
+
751
+ \`\`\`typescript
752
+ import { AlbIngress } from "@intentius/chant-lexicon-k8s";
753
+
754
+ const { ingress } = AlbIngress({
755
+ name: "api-ingress",
756
+ hosts: [
757
+ {
758
+ hostname: "api.example.com",
759
+ paths: [{ path: "/", serviceName: "api", servicePort: 80 }],
760
+ },
761
+ ],
762
+ scheme: "internet-facing",
763
+ certificateArn: "arn:aws:acm:us-east-1:123456789012:certificate/abc-123",
764
+ groupName: "shared-alb",
765
+ healthCheckPath: "/healthz",
766
+ });
767
+ \`\`\`
768
+
769
+ Features:
770
+ - Auto-sets \`alb.ingress.kubernetes.io/*\` annotations
771
+ - SSL redirect enabled by default when \`certificateArn\` set
772
+ - \`groupName\` for shared ALB across multiple Ingresses
773
+ - \`wafAclArn\` for WAFv2 integration
774
+
775
+ ### EbsStorageClass — StorageClass for EBS CSI
776
+
777
+ \`\`\`typescript
778
+ import { EbsStorageClass } from "@intentius/chant-lexicon-k8s";
779
+
780
+ const { storageClass } = EbsStorageClass({
781
+ name: "gp3-encrypted",
782
+ type: "gp3",
783
+ encrypted: true,
784
+ iops: "3000",
785
+ throughput: "125",
786
+ });
787
+ \`\`\`
788
+
789
+ ### EfsStorageClass — StorageClass for EFS CSI (ReadWriteMany)
790
+
791
+ \`\`\`typescript
792
+ import { EfsStorageClass } from "@intentius/chant-lexicon-k8s";
793
+
794
+ const { storageClass } = EfsStorageClass({
795
+ name: "efs-shared",
796
+ fileSystemId: "fs-12345678",
797
+ });
798
+ \`\`\`
799
+
800
+ Use EFS when you need ReadWriteMany (shared across pods/nodes). Use EBS for ReadWriteOnce (single pod).
801
+
802
+ ### FluentBitAgent — DaemonSet for CloudWatch logging
803
+
804
+ \`\`\`typescript
805
+ import { FluentBitAgent } from "@intentius/chant-lexicon-k8s";
806
+
807
+ const result = FluentBitAgent({
808
+ logGroup: "/aws/eks/my-cluster/containers",
809
+ region: "us-east-1",
810
+ clusterName: "my-cluster",
811
+ });
812
+ \`\`\`
813
+
814
+ ### ExternalDnsAgent — ExternalDNS for Route53
815
+
816
+ \`\`\`typescript
817
+ import { ExternalDnsAgent } from "@intentius/chant-lexicon-k8s";
818
+
819
+ const result = ExternalDnsAgent({
820
+ iamRoleArn: "arn:aws:iam::123456789012:role/external-dns-role",
821
+ domainFilters: ["example.com"],
822
+ txtOwnerId: "my-cluster",
823
+ });
824
+ \`\`\`
825
+
826
+ ### AdotCollector — ADOT for CloudWatch/X-Ray
827
+
828
+ \`\`\`typescript
829
+ import { AdotCollector } from "@intentius/chant-lexicon-k8s";
830
+
831
+ const result = AdotCollector({
832
+ region: "us-east-1",
833
+ clusterName: "my-cluster",
834
+ exporters: ["cloudwatch", "xray"],
835
+ });
836
+ \`\`\`
837
+
838
+ ## Pod Identity vs IRSA
839
+
840
+ | Feature | IRSA | Pod Identity |
841
+ |---------|------|-------------|
842
+ | K8s annotation needed | Yes (\`eks.amazonaws.com/role-arn\`) | No |
843
+ | Composite available | **IrsaServiceAccount** | None needed |
844
+ | Setup | OIDC provider + IAM role trust policy | EKS Pod Identity Agent add-on + association |
845
+ | When to use | Existing clusters, broad compatibility | New clusters (EKS 1.28+), simpler management |
846
+
847
+ For Pod Identity, no K8s-side composite is needed — configure the association via AWS API/CloudFormation and use a plain ServiceAccount.
848
+
849
+ ## Karpenter
850
+
851
+ Karpenter replaces Cluster Autoscaler for node provisioning. Karpenter NodePool and EC2NodeClass are simple CRDs — use CRD import rather than composites:
852
+
853
+ \`\`\`bash
854
+ # Import Karpenter CRDs into your chant project
855
+ chant import --url https://raw.githubusercontent.com/aws/karpenter/main/pkg/apis/crds/karpenter.sh_nodepools.yaml
856
+ \`\`\`
857
+
858
+ ## Fargate Considerations
859
+
860
+ When running on EKS Fargate:
861
+ - **No DaemonSets** — FluentBitAgent and AdotCollector cannot run on Fargate nodes
862
+ - **No hostPath volumes** — use EFS for shared storage
863
+ - **No privileged containers** — security context restrictions apply
864
+ - For Fargate logging, use the built-in Fluent Bit log router (Fargate logging configuration)
865
+
866
+ ## EKS Add-ons
867
+
868
+ Common add-ons managed via AWS (not K8s manifests):
869
+ - **vpc-cni** — Amazon VPC CNI plugin
870
+ - **coredns** — Cluster DNS
871
+ - **kube-proxy** — Network proxy
872
+ - **aws-ebs-csi-driver** — EBS CSI driver (required for EbsStorageClass)
873
+ - **aws-efs-csi-driver** — EFS CSI driver (required for EfsStorageClass)
874
+ - **adot** — AWS Distro for OpenTelemetry (alternative to AdotCollector composite)
875
+ - **aws-guardduty-agent** — Runtime threat detection
876
+
877
+ Configure add-ons via the AWS lexicon (\`@intentius/chant-lexicon-aws\`) CloudFormation resources.
878
+ `,
879
+ triggers: [
880
+ { type: "context", value: "eks" },
881
+ { type: "context", value: "irsa" },
882
+ { type: "context", value: "alb" },
883
+ { type: "context", value: "ebs" },
884
+ { type: "context", value: "efs" },
885
+ { type: "context", value: "fluent-bit" },
886
+ { type: "context", value: "cloudwatch" },
887
+ { type: "context", value: "karpenter" },
888
+ { type: "context", value: "fargate" },
889
+ ],
890
+ preConditions: [
891
+ "chant CLI is installed (chant --version succeeds)",
892
+ "EKS cluster is provisioned",
893
+ "kubectl is configured for the EKS cluster",
894
+ ],
895
+ postConditions: [
896
+ "EKS-specific resources are deployed and functional",
897
+ ],
898
+ parameters: [],
899
+ examples: [
900
+ {
901
+ title: "IRSA ServiceAccount",
902
+ description: "Create a ServiceAccount with IAM role for S3 access",
903
+ input: "Create an IRSA ServiceAccount for my app that needs S3 access",
904
+ output: `import { IrsaServiceAccount } from "@intentius/chant-lexicon-k8s";
905
+
906
+ const { serviceAccount } = IrsaServiceAccount({
907
+ name: "app-sa",
908
+ iamRoleArn: "arn:aws:iam::123456789012:role/app-s3-role",
909
+ namespace: "prod",
910
+ });`,
911
+ },
912
+ {
913
+ title: "ALB Ingress with TLS",
914
+ description: "Create an ALB Ingress with ACM certificate",
915
+ input: "Set up an internet-facing ALB with TLS for my API",
916
+ output: `import { AlbIngress } from "@intentius/chant-lexicon-k8s";
917
+
918
+ const { ingress } = AlbIngress({
919
+ name: "api-ingress",
920
+ hosts: [{ hostname: "api.example.com", paths: [{ path: "/", serviceName: "api", servicePort: 80 }] }],
921
+ certificateArn: "arn:aws:acm:us-east-1:123456789012:certificate/abc-123",
922
+ });`,
923
+ },
924
+ ],
925
+ },
926
+ {
927
+ name: "chant-k8s-patterns",
928
+ description: "Advanced K8s patterns — sidecars, observability, TLS, network isolation, config/secret mounting",
929
+ content: `---
930
+ skill: chant-k8s-patterns
931
+ description: Advanced Kubernetes deployment patterns and composites
932
+ user-invocable: true
933
+ ---
934
+
935
+ # Advanced Kubernetes Patterns
936
+
937
+ ## Sidecar Patterns
938
+
939
+ ### SidecarApp — multi-container Deployment
940
+
941
+ \`\`\`typescript
942
+ import { SidecarApp } from "@intentius/chant-lexicon-k8s";
943
+
944
+ // Envoy sidecar proxy
945
+ const { deployment, service } = SidecarApp({
946
+ name: "api",
947
+ image: "api:1.0",
948
+ port: 8080,
949
+ sidecars: [
950
+ {
951
+ name: "envoy",
952
+ image: "envoyproxy/envoy:v1.28",
953
+ ports: [{ containerPort: 9901, name: "admin" }],
954
+ resources: { requests: { cpu: "100m", memory: "128Mi" }, limits: { cpu: "200m", memory: "256Mi" } },
955
+ },
956
+ ],
957
+ initContainers: [
958
+ { name: "migrate", image: "api:1.0", command: ["python", "manage.py", "migrate"] },
959
+ ],
960
+ sharedVolumes: [{ name: "tmp", emptyDir: {} }],
961
+ });
962
+ \`\`\`
963
+
964
+ Common sidecar use cases:
965
+ - **Envoy proxy** — service mesh, mTLS, traffic management
966
+ - **Log forwarder** — Fluent Bit sidecar for app-specific log routing
967
+ - **Auth proxy** — OAuth2 Proxy for authentication
968
+ - **Config watcher** — reload config on ConfigMap changes
969
+
970
+ ## Config and Secret Mounting
971
+
972
+ ### ConfiguredApp — automatic volume wiring
973
+
974
+ \`\`\`typescript
975
+ import { ConfiguredApp } from "@intentius/chant-lexicon-k8s";
976
+
977
+ const { deployment, service, configMap } = ConfiguredApp({
978
+ name: "api",
979
+ image: "api:1.0",
980
+ port: 8080,
981
+ // Mount ConfigMap as volume
982
+ configData: { "app.conf": "key=value\\nother=setting" },
983
+ configMountPath: "/etc/api",
984
+ // Mount existing Secret as volume
985
+ secretName: "api-creds",
986
+ secretMountPath: "/secrets",
987
+ // Inject as environment variables
988
+ envFrom: { secretRef: "api-env-secret", configMapRef: "api-env-config" },
989
+ // Run migrations before the app starts
990
+ initContainers: [
991
+ { name: "migrate", image: "api:1.0", command: ["./migrate.sh"] },
992
+ ],
993
+ });
994
+ \`\`\`
995
+
996
+ ### Volume patterns
997
+
998
+ | Pattern | Use Case | ConfiguredApp Props |
999
+ |---------|----------|---------------------|
1000
+ | ConfigMap as file | Config files, templates | \`configData\` + \`configMountPath\` |
1001
+ | Secret as file | TLS certs, credentials | \`secretName\` + \`secretMountPath\` |
1002
+ | ConfigMap as env | Simple key-value config | \`envFrom.configMapRef\` |
1003
+ | Secret as env | Database URLs, API keys | \`envFrom.secretRef\` |
1004
+
1005
+ ## TLS / cert-manager
1006
+
1007
+ ### SecureIngress — multi-host TLS with cert-manager
1008
+
1009
+ \`\`\`typescript
1010
+ import { SecureIngress } from "@intentius/chant-lexicon-k8s";
1011
+
1012
+ const { ingress, certificate } = SecureIngress({
1013
+ name: "app-ingress",
1014
+ hosts: [
1015
+ {
1016
+ hostname: "api.example.com",
1017
+ paths: [
1018
+ { path: "/v1", serviceName: "api-v1", servicePort: 80 },
1019
+ { path: "/v2", serviceName: "api-v2", servicePort: 80 },
1020
+ ],
1021
+ },
1022
+ {
1023
+ hostname: "admin.example.com",
1024
+ paths: [{ path: "/", serviceName: "admin", servicePort: 80 }],
1025
+ },
1026
+ ],
1027
+ clusterIssuer: "letsencrypt-prod",
1028
+ ingressClassName: "nginx",
1029
+ });
1030
+ \`\`\`
1031
+
1032
+ Features:
1033
+ - Multiple hosts and paths per Ingress
1034
+ - Automatic cert-manager Certificate when \`clusterIssuer\` set
1035
+ - TLS secret auto-provisioned by cert-manager
1036
+
1037
+ ### cert-manager setup (prerequisite)
1038
+
1039
+ \`\`\`bash
1040
+ # Install cert-manager
1041
+ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
1042
+
1043
+ # Create ClusterIssuer for Let's Encrypt
1044
+ kubectl apply -f - <<EOF
1045
+ apiVersion: cert-manager.io/v1
1046
+ kind: ClusterIssuer
1047
+ metadata:
1048
+ name: letsencrypt-prod
1049
+ spec:
1050
+ acme:
1051
+ server: https://acme-v02.api.letsencrypt.org/directory
1052
+ email: admin@example.com
1053
+ privateKeySecretRef:
1054
+ name: letsencrypt-prod-key
1055
+ solvers:
1056
+ - http01:
1057
+ ingress:
1058
+ class: nginx
1059
+ EOF
1060
+ \`\`\`
1061
+
1062
+ ## Observability
1063
+
1064
+ ### MonitoredService — Prometheus monitoring
1065
+
1066
+ \`\`\`typescript
1067
+ import { MonitoredService } from "@intentius/chant-lexicon-k8s";
1068
+
1069
+ const { deployment, service, serviceMonitor, prometheusRule } = MonitoredService({
1070
+ name: "api",
1071
+ image: "api:1.0",
1072
+ port: 8080,
1073
+ metricsPort: 9090,
1074
+ metricsPath: "/metrics",
1075
+ scrapeInterval: "15s",
1076
+ alertRules: [
1077
+ {
1078
+ name: "HighErrorRate",
1079
+ expr: 'rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05',
1080
+ for: "5m",
1081
+ severity: "critical",
1082
+ annotations: { summary: "High error rate on {{ $labels.instance }}" },
1083
+ },
1084
+ {
1085
+ name: "HighLatency",
1086
+ expr: 'histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 1',
1087
+ for: "10m",
1088
+ severity: "warning",
1089
+ },
1090
+ ],
1091
+ });
1092
+ \`\`\`
1093
+
1094
+ ### Prerequisites
1095
+
1096
+ - Prometheus Operator installed (for ServiceMonitor/PrometheusRule CRDs)
1097
+ - Prometheus configured to discover ServiceMonitors
1098
+
1099
+ ## Network Isolation
1100
+
1101
+ ### NetworkIsolatedApp — per-app firewall rules
1102
+
1103
+ \`\`\`typescript
1104
+ import { NetworkIsolatedApp } from "@intentius/chant-lexicon-k8s";
1105
+
1106
+ const { deployment, service, networkPolicy } = NetworkIsolatedApp({
1107
+ name: "api",
1108
+ image: "api:1.0",
1109
+ port: 8080,
1110
+ allowIngressFrom: [
1111
+ { podSelector: { "app.kubernetes.io/name": "frontend" } },
1112
+ { namespaceSelector: { "kubernetes.io/metadata.name": "monitoring" } },
1113
+ ],
1114
+ allowEgressTo: [
1115
+ { podSelector: { "app.kubernetes.io/name": "postgres" }, ports: [{ port: 5432 }] },
1116
+ { podSelector: { "app.kubernetes.io/name": "redis" }, ports: [{ port: 6379 }] },
1117
+ ],
1118
+ });
1119
+ \`\`\`
1120
+
1121
+ ### Combining with NamespaceEnv
1122
+
1123
+ Use NamespaceEnv for namespace-level default-deny, then NetworkIsolatedApp for per-app allow rules:
1124
+
1125
+ \`\`\`typescript
1126
+ // Namespace: deny all by default
1127
+ const ns = NamespaceEnv({ name: "prod", defaultDenyIngress: true, defaultDenyEgress: true });
1128
+
1129
+ // App: allow specific traffic
1130
+ const app = NetworkIsolatedApp({
1131
+ name: "api",
1132
+ image: "api:1.0",
1133
+ namespace: "prod",
1134
+ allowIngressFrom: [{ podSelector: { "app.kubernetes.io/name": "gateway" } }],
1135
+ allowEgressTo: [{ podSelector: { "app.kubernetes.io/name": "db" }, ports: [{ port: 5432 }] }],
1136
+ });
1137
+ \`\`\`
1138
+
1139
+ ## Blue/Green and Canary
1140
+
1141
+ These patterns use standard K8s resources — no special composite needed.
1142
+
1143
+ ### Blue/Green
1144
+
1145
+ \`\`\`typescript
1146
+ // Two Deployments with different versions
1147
+ const blue = WebApp({ name: "app-blue", image: "app:1.0", labels: { version: "blue" } });
1148
+ const green = WebApp({ name: "app-green", image: "app:2.0", labels: { version: "green" } });
1149
+
1150
+ // Service points to active version — switch by changing selector
1151
+ // Active: blue → green (update the Service selector)
1152
+ \`\`\`
1153
+
1154
+ ### Canary
1155
+
1156
+ \`\`\`typescript
1157
+ // Main deployment (90% traffic)
1158
+ const main = AutoscaledService({ name: "app", image: "app:1.0", minReplicas: 9, maxReplicas: 20, ... });
1159
+
1160
+ // Canary deployment (10% traffic) — same app label, fewer replicas
1161
+ const canary = WebApp({ name: "app-canary", image: "app:2.0", replicas: 1, labels: { track: "canary" } });
1162
+ // Both share the same Service selector ("app.kubernetes.io/name": "app") for traffic splitting
1163
+ \`\`\`
1164
+
1165
+ ## Gateway API (future direction)
1166
+
1167
+ Gateway API is the successor to Ingress. Key differences:
1168
+ - **HTTPRoute** replaces Ingress rules
1169
+ - **Gateway** replaces IngressClass
1170
+ - Built-in traffic splitting, header matching, URL rewriting
1171
+ - Currently in beta — use Ingress/SecureIngress/AlbIngress for production today
1172
+
1173
+ When Gateway API reaches GA, new composites will be added. For now, use CRD import if you need Gateway API resources.
1174
+ `,
1175
+ triggers: [
1176
+ { type: "context", value: "sidecar" },
1177
+ { type: "context", value: "init-container" },
1178
+ { type: "context", value: "prometheus" },
1179
+ { type: "context", value: "cert-manager" },
1180
+ { type: "context", value: "tls" },
1181
+ { type: "context", value: "network-policy" },
1182
+ { type: "context", value: "canary" },
1183
+ { type: "context", value: "blue-green" },
1184
+ { type: "context", value: "configmap-mount" },
1185
+ { type: "context", value: "secret-mount" },
1186
+ ],
1187
+ preConditions: [
1188
+ "chant CLI is installed (chant --version succeeds)",
1189
+ "kubectl is configured and can access the cluster",
1190
+ ],
1191
+ postConditions: [
1192
+ "Pattern resources are deployed and functional",
1193
+ ],
1194
+ parameters: [],
1195
+ examples: [
1196
+ {
1197
+ title: "Sidecar with envoy proxy",
1198
+ description: "Deploy an app with an Envoy sidecar",
1199
+ input: "Add an envoy sidecar proxy to my API",
1200
+ output: `import { SidecarApp } from "@intentius/chant-lexicon-k8s";
1201
+
1202
+ const { deployment, service } = SidecarApp({
1203
+ name: "api",
1204
+ image: "api:1.0",
1205
+ port: 8080,
1206
+ sidecars: [{ name: "envoy", image: "envoyproxy/envoy:v1.28", ports: [{ containerPort: 9901 }] }],
1207
+ });`,
1208
+ },
1209
+ {
1210
+ title: "Monitored service with alerts",
1211
+ description: "Deploy a service with Prometheus monitoring and alerting",
1212
+ input: "Set up monitoring for my API with error rate alerts",
1213
+ output: `import { MonitoredService } from "@intentius/chant-lexicon-k8s";
1214
+
1215
+ const { deployment, service, serviceMonitor, prometheusRule } = MonitoredService({
1216
+ name: "api",
1217
+ image: "api:1.0",
1218
+ metricsPort: 9090,
1219
+ alertRules: [{ name: "HighErrorRate", expr: 'rate(http_errors[5m]) > 0.1', severity: "critical" }],
909
1220
  });`,
910
1221
  },
911
1222
  ],