> ## Documentation Index
> Fetch the complete documentation index at: https://ai-kb.automationanywhere.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Terragrunt तैनाती गाइड

> Terragrunt का उपयोग करके संपूर्ण EKB EKS अवसंरचना तैनात करने के लिए चरण-दर-चरण कमांड्स, ड्राई रन सत्यापन और वास्तविक तैनाती सहित।

यह गाइड Terragrunt का उपयोग करके AWS पर EKB EKS अवसंरचना की पूर्ण तैनाती की व्याख्या करता है। इसमें उपकरण स्थापना, वातावरण सेटअप, और सभी अवसंरचना घटकों में उचित निर्भरता क्रम सुनिश्चित करने के लिए डिज़ाइन किए गए चरणबद्ध तैनाती क्रम शामिल हैं।

तैनातियाँ नौ चरणों में व्यवस्थित हैं:

1. **स्टेट प्रबंधन** — Terraform स्टेट संग्रहीत करने के लिए उपयोग किए जाने वाले S3 bucket को बूटस्ट्रैप करता है।
2. **EKS अवसंरचना** — VPC, सबनेट्स, NAT gateways, IAM भूमिकाएँ, और EKS क्लस्टर और managed node groups प्रोविज़न करता है।
3. **स्टोरेज और लोड बैलेंसिंग** — स्थायी volumes के लिए EBS CSI driver और ALB ingress के लिए AWS Load Balancer Controller तैनात करता है।
4. **Karpenter Autoscaling** — Spot instance समर्थन और SQS और EventBridge के माध्यम से interruption handling के साथ गतिशील node प्रोविज़निंग स्थापित करता है।
5. **KEDA Autoscaling** — CPU और मेमोरी सीमाओं के आधार पर pod-स्तरीय autoscaling के लिए KEDA तैनात करता है।
6. **डेटा सेवाएँ** — Supabase (सेल्फ़-होस्टेड या Cloud), ElastiCache Redis, और Amazon MQ RabbitMQ प्रोविज़न करता है।
7. **Odin सेवाएँ** — Helm के माध्यम से EKB एप्लिकेशन स्टैक (Web, FastAPI, Celery, Automator) तैनात करता है।
8. **SigNoz अवलोकन** — SigNoz और k8s-infra agent के माध्यम से वितरित tracing, मेट्रिक्स और लॉग एकत्रीकरण तैनात करता है।
9. **अंतिम तैनाती** — किसी भी शेष संसाधनों को समायोजित करने के लिए पूर्ण `terragrunt apply` चलाता है।

शुरू करने से पहले, ग्राहक के साथ पूर्व आवश्यकताएँ चेकलिस्ट पूरी करें और सुनिश्चित करें कि वातावरण टेम्पलेट में सभी `<YOUR_*>` placeholders भरे गए हैं। कई मान — जिनमें VPC ID, EKS क्लस्टर endpoint, और Redis और RabbitMQ endpoints शामिल हैं — केवल विशिष्ट चरण पूरे होने के बाद उपलब्ध हैं, इसलिए गाइड में ठीक बताया गया है कि उन्हें कब कैप्चर और लागू करना है।

***

## पूर्व आवश्यकताएँ

* उपयुक्त अनुमतियों के साथ कॉन्फ़िगर किया गया AWS CLI
* Terraform (>= 1.0)
* Terragrunt (नवीनतम संस्करण)
* Kubernetes प्रबंधन के लिए `kubectl`
* Helm chart प्रबंधन के लिए `helm`

***

## स्थापना गाइड

### Terragrunt स्थापित करें

**macOS (Homebrew)**

```bash theme={null}
brew install terragrunt
```

**Linux (apt)**

```bash theme={null}
# HashiCorp GPG कुंजी जोड़ें
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
 
# HashiCorp रिपॉज़िटरी जोड़ें
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
 
# अपडेट और स्थापित करें
sudo apt update
sudo apt install terragrunt
```

**Windows (Chocolatey)**

```bash theme={null}
choco install terragrunt
```

### kubectl स्थापित करें

**macOS (Homebrew)**

```bash theme={null}
brew install kubectl
```

**Linux**

```bash theme={null}
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
```

**Windows (Chocolatey)**

```bash theme={null}
choco install kubernetes-cli
```

### Helm स्थापित करें

**macOS (Homebrew)**

```bash theme={null}
brew install helm
```

**Linux**

```bash theme={null}
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
```

**Windows (Chocolatey)**

```bash theme={null}
choco install kubernetes-helm
```

### इंस्टॉलेशन सत्यापित करें

```bash theme={null}
terragrunt --version
terraform --version
kubectl version --client
helm version
```

### AWS CLI कॉन्फ़िगरेशन

```bash theme={null}
# AWS CLI स्थापित करें
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
 
# AWS credentials कॉन्फ़िगर करें
aws configure
 
# कॉन्फ़िगरेशन सत्यापित करें
aws sts get-caller-identity
```

***

## एक नया वातावरण बनाएँ

### चरण 1: वातावरण टेम्पलेट कॉपी करें

`env-template-folder` में `<YOUR_*>` placeholders के साथ पूर्व-संरचित फ़ाइलें हैं जो भरने के लिए तैयार हैं। अपना नया वातावरण फ़ोल्डर बनाने के लिए इसे पूरी तरह से कॉपी करें।

```bash theme={null}
# terragrunt environments निर्देशिका में नेविगेट करें
cd terragrunt/environments
 
# पूर्ण टेम्पलेट फ़ोल्डर को नए वातावरण में कॉपी करें ('your-env-name' बदलें)
cp -r env-template-folder your-env-name
 
# फ़ोल्डर संरचना तैयार है:
# your-env-name/
# ├── terragrunt.hcl               # मुख्य क्लस्टर कॉन्फ़िगरेशन
# ├── state/
# │   └── terragrunt.hcl           # S3 स्टेट bucket कॉन्फ़िगरेशन
# └── values/
#     ├── infrastructure.yaml      # AWS Load Balancer Controller
#     ├── karpenter-values.yaml    # Karpenter controller सेटिंग्स
#     ├── karpenter-nodeclasses.yaml  # EC2NodeClass परिभाषाएँ
#     ├── karpenter.yaml           # Karpenter NodePool परिभाषाएँ
#     ├── keda.yaml                # KEDA autoscaler
#     ├── aws-ebs-csi-driver.yaml  # EBS CSI driver
#     ├── odin-services.yaml       # Odin एप्लिकेशन सेवाएँ
#     ├── supabase.yaml            # Supabase (यदि सेल्फ़-होस्टिंग)
#     ├── ha-supabase-db.yaml      # Supabase HA DB (यदि सेल्फ़-होस्टिंग)
#     ├── cloudnative-pg.yaml      # CloudNativePG operator (यदि सेल्फ़-होस्टिंग)
#     ├── signoz.yaml              # SigNoz अवलोकन (वैकल्पिक)
#     └── signoz-k8s-infra.yaml    # SigNoz k8s मेट्रिक्स (वैकल्पिक)
```

### चरण 2: सत्यापित करें कि सभी Placeholders मौजूद हैं

```bash theme={null}
cd your-env-name
 
# भरे जाने वाले सभी placeholders सूचीबद्ध करें
grep -r "<YOUR_" . --include="*.hcl" --include="*.yaml" | sort
```

सभी placeholders `<YOUR_*>` परंपरा का पालन करते हैं। नीचे दिए गए चरण फ़ाइल-दर-फ़ाइल इन्हें भरने की व्याख्या करते हैं।

### चरण 3: SSL प्रमाणपत्र प्रोविज़न करें (AWS ACM)

वातावरण चर सेट करने से पहले आपको प्रमाणपत्र ARNs चाहिए। अपने वातावरण द्वारा सेव किए जाने वाले सभी डोमेन के लिए AWS Certificate Manager (ACM) में SSL प्रमाणपत्र अनुरोध करने के लिए AWS Console का उपयोग करें।

**विकल्प A: एकल वाइल्डकार्ड प्रमाणपत्र (अनुशंसित)**

एकल वाइल्डकार्ड प्रमाणपत्र एक ARN से सभी subdomains को कवर करता है। उदाहरण के लिए, यदि आपका आधार डोमेन `app.example.com` है, तो एकल `*.app.example.com` प्रमाणपत्र कवर करता है:

| सेवा      | डोमेन                         |
| --------- | ----------------------------- |
| Web       | `app.example.com`             |
| FastAPI   | `api-app.example.com`         |
| Automator | `automations-app.example.com` |
| Supabase  | `supabase-app.example.com`    |
| SigNoz    | `signoz-app.example.com`      |

**विकल्प B: प्रति-सेवा प्रमाणपत्र**

यदि आप वाइल्डकार्ड का उपयोग नहीं कर सकते तो प्रति डोमेन एक प्रमाणपत्र अनुरोध करें। प्रत्येक डोमेन के लिए नीचे दिए गए चरण दोहराएँ: `<YOUR_WEB_DOMAIN>`, `<YOUR_API_DOMAIN>`, `<YOUR_AUTOMATOR_DOMAIN>`, `<YOUR_SUPABASE_DOMAIN>` (केवल यदि `ENABLE_SUPABASE=true`), `<YOUR_SIGNOZ_DOMAIN>` (केवल यदि `ENABLE_SIGNOZ=true`)।

**AWS Console में प्रमाणपत्र अनुरोध करना**

1. AWS Certificate Manager console खोलें
2. सही क्षेत्र पर स्विच करें (ऊपरी-दाएँ) — `<YOUR_AWS_REGION>` से मेल खाना चाहिए
3. **Request a certificate** क्लिक करें → **Request a public certificate** → **Next**
4. **Fully qualified domain name** के अंतर्गत, वाइल्डकार्ड दर्ज करें (जैसे `*.app.example.com`) या एक विशिष्ट डोमेन
5. **Validation method** को **DNS validation** सेट करें
6. **Request** क्लिक करें — प्रमाणपत्र `Pending validation` स्थिति में बनाया जाता है

**DNS CNAME सत्यापन रिकॉर्ड जोड़ना**

ACM एक CNAME रिकॉर्ड बनाता है जिसे आपको डोमेन स्वामित्व साबित करने के लिए अपने DNS provider में जोड़ना होता है। ACM Console से मान प्राप्त करने के लिए प्रमाणपत्र खोलें और **Domains** के अंतर्गत डोमेन का विस्तार करें।

| DNS फ़ील्ड       | मान                                                                       |
| ---------------- | ------------------------------------------------------------------------- |
| रिकॉर्ड प्रकार   | `CNAME`                                                                   |
| नाम / होस्ट      | उदा., `_fa187f22ac17bce6f508bf3c56439c61.signoz-app.example.com.`         |
| मान / पॉइंट्स टू | उदा., `_c7c97325fe38061e168e232d122c7ff3.jkddzztszm.acm-validations.aws.` |

<Info>
  यदि आपका DNS provider आवश्यकता रखता है तो CNAME मानों के अंत में trailing dot (`.`) शामिल करें।
</Info>

**Cloudflare**

1. Cloudflare में लॉग इन करें → अपना डोमेन चुनें → **DNS** पर जाएँ → **Records** → **Add record**
2. **Type** को `CNAME` सेट करें
3. ACM CNAME नाम को **Name** में और ACM CNAME मान को **Target** में पेस्ट करें
4. **Proxy status** को **DNS only** (ग्रे क्लाउड आइकन) सेट करें — प्रमाणपत्र Cloudflare प्रॉक्सी के माध्यम से सत्यापित नहीं होगा
5. **Save** क्लिक करें

**Route 53**

1. Route 53 console खोलें → **Hosted zones** → अपना ज़ोन चुनें → **Create record**
2. **Record type** को `CNAME` सेट करें
3. ACM CNAME नाम को **Record name** (केवल subdomain भाग) में और मान को **Value** में पेस्ट करें
4. TTL को `300` सेट करें और **Create records** क्लिक करें

<Tip>
  ACM में आप **Create records in Route 53** भी क्लिक कर सकते हैं ताकि यदि hosted zone उसी खाते में है तो ACM स्वचालित रूप से रिकॉर्ड जोड़ दे।
</Tip>

जब DNS propagation हो जाता है (आमतौर पर 1–5 मिनट), तो प्रमाणपत्र स्थिति **Issued** में बदल जाती है। प्रमाणपत्र के शीर्ष से ARN कॉपी करें — यह `arn:aws:acm:<region>:<account-id>:certificate/<uuid>` जैसा दिखता है। अगले चरण के लिए ARN(s) सुरक्षित रखें।

### चरण 4: वातावरण चर सेट करें

कोई भी Terragrunt कमांड चलाने से पहले ये shell वातावरण चर सेट करें। इन्हें `terragrunt.hcl` में `get_env()` कॉल्स द्वारा सीधे पढ़ा जाता है।

```bash theme={null}
export AWS_REGION="<YOUR_AWS_REGION>"          # उदा., "eu-west-2", "us-east-2"
export CLUSTER_NAME="<env_folder_name>"          # उदा., "env-template-folder"
 
# डोमेन कॉन्फ़िगरेशन
export WEB_DOMAIN="<YOUR_WEB_DOMAIN>"                    # उदा., "app.example.com"
export FASTAPI_DOMAIN="<YOUR_API_DOMAIN>"                # उदा., "api-app.example.com"
export AUTOMATOR_DOMAIN="<YOUR_AUTOMATOR_DOMAIN>"        # उदा., "automations-app.example.com"
export SUPABASE_DOMAIN="<YOUR_SUPABASE_DOMAIN>"          # उदा., "supabase-app.example.com"
export SIGNOZ_DOMAIN="<YOUR_SIGNOZ_DOMAIN>"              # उदा., "signoz-app.example.com"
 
# SSL प्रमाणपत्र ARNs — विकल्प A: एकल वाइल्डकार्ड प्रमाणपत्र (अनुशंसित)
export WILDCARD_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_WILDCARD_CERT_ID>"
 
# SSL प्रमाणपत्र ARNs — विकल्प B: प्रति-सेवा प्रमाणपत्र
export WEB_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_WEB_CERT_ID>"
export FASTAPI_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_API_CERT_ID>"
export AUTOMATOR_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_AUTOMATOR_CERT_ID>"
export SUPABASE_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_SUPABASE_CERT_ID>"
export SIGNOZ_CERTIFICATE_ARN="arn:aws:acm:<YOUR_AWS_REGION>:<YOUR_AWS_ACCOUNT_ID>:certificate/<YOUR_SIGNOZ_CERT_ID>"
 
# सेवा सक्षम करने के फ़्लैग्स
export ENABLE_ALB_CONTROLLER="true"
export ENABLE_AWS_SERVICES="true"      # ElastiCache और AmazonMQ सक्षम करने के लिए "true" सेट करें
 
# Supabase स्टैक (सेल्फ़-होस्टेड) — यदि Supabase सेल्फ़-होस्ट कर रहे हैं तो तीनों को एक साथ सक्षम करें
export ENABLE_CNPG="true"             # CloudNativePG operator  (namespace: cnpg-system)
export ENABLE_HA_SUPABASE_DB="true"   # Supabase HA database    (namespace: ha-supabase-db)
export ENABLE_SUPABASE="true"         # Supabase एप्लिकेशन    (namespace: supabase)
 
export ENABLE_SIGNOZ="true"           # SigNoz अवलोकन सक्षम करने के लिए "true" सेट करें
export SSL_TERMINATION="alb"
```

#### Spot Instances और स्टेटफुल वर्कलोड

Spot instances को पर्यावरण चरों के माध्यम से नहीं, बल्कि `values/karpenter.yaml` में प्रति NodePool कॉन्फ़िगर किया जाता है। प्रत्येक NodePool अपनी क्षमता रणनीति घोषित करता है:

| NodePool            | `workload-type` लेबल                         | क्षमता प्रकार             | तर्क                                                                                 |
| ------------------- | -------------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------ |
| `general`           | `general`                                    | Spot → On-Demand fallback | रहित batch/पृष्ठभूमि वर्कलोड के लिए लागत-अनुकूलित                                    |
| `compute-intensive` | `compute-intensive`                          | Spot → On-Demand fallback | CPU-बाउंड वर्कलोड के लिए लागत-अनुकूलित                                               |
| `memory-intensive`  | `memory-intensive`                           | On-Demand → Spot fallback | उच्च-मेमोरी pods के लिए स्थिरता प्राथमिकता                                           |
| `gpu`               | `gpu`                                        | Spot → On-Demand fallback | AI/ML batch वर्कलोड के लिए लागत-अनुकूलित                                             |
| `application`       | `application`                                | केवल On-Demand            | स्थिर उपयोगकर्ता-सामने की सेवाएँ (Supabase, Kong, आदि) — कोई Spot interruptions नहीं |
| `database`          | `database` / `node-type: database-dedicated` | केवल On-Demand            | स्टेटफुल — databases के लिए Spot interruption असुरक्षित                              |

`application` NodePool m/c instance families (पीढ़ी 5+) का उपयोग केवल On-Demand के साथ करता है। Supabase सेवा pods `nodeSelector: workload-type: "application"` के माध्यम से यहाँ पिन किए जाते हैं ताकि यह गारंटी दी जा सके कि उन्हें कभी Spot पुनःप्राप्ति घटना से बाधित नहीं किया जाएगा।

`database-dedicated` NodePool कभी Spot का उपयोग नहीं करता। यह `consolidationPolicy: WhenEmpty` का उपयोग करता है ताकि Karpenter उस node को निकाले नहीं जिस पर अभी भी एक चलता हुआ pod है, जिससे PostgreSQL और CloudNativePG replicas जैसे स्टेटफुल वर्कलोड के लिए सुरक्षित हो।

**Spot पर स्टेटफुल एप्लिकेशन के लिए दिशानिर्देश:**

* Spot NodePools पर databases, स्थायी queues, या `PersistentVolumeClaim` वाले किसी भी pod को शेड्यूल न करें।
* `node-type: database-dedicated` को लक्षित करने वाले `nodeSelector` और मिलान `database-workload: "true"` toleration का उपयोग database pods के लिए करें।
* उन उपयोगकर्ता-सामने की रहित सेवाओं के लिए `nodeSelector: workload-type: "application"` का उपयोग करें जिन्हें बिना बाधा के उपलब्ध रहना चाहिए।
* पृष्ठभूमि वर्कलोड (Web, API, Celery, Automator) के लिए, `general` Spot NodePool उपयुक्त है — Karpenter का SQS interruption handler AWS द्वारा पुनःप्राप्ति से पहले Spot nodes को सुरक्षित रूप से drain करता है, और KEDA की न्यूनतम रेप्लिका गणना (≥ 2) node प्रतिस्थापन के दौरान उपलब्धता सुनिश्चित करती है।
* Spot को वैश्विक रूप से अक्षम करने के लिए, `values/karpenter.yaml` में प्रत्येक NodePool के values list से `"spot"` हटा दें।

**Karpenter Spot interruption चेतावनियों को कैसे संभालता है:**

AWS Spot instance को समाप्त करने से पहले 2-मिनट का interruption notice देता है। Karpenter इस पर स्वचालित रूप से कार्य करने के लिए EventBridge और SQS का उपयोग करता है:

```
AWS Spot Interruption Event
        │
        ▼
Amazon EventBridge (CloudWatch Events)
  Rule: EC2 Spot Instance Interruption Warning
        │
        ▼
   SQS Queue (Karpenter interruption queue)
        │
        ▼
  Karpenter Controller (SQS को लगातार poll करता है)
        │
        ├── Node को cordons करता है (नए pods शेड्यूल नहीं होते)
        ├── मौजूदा pods को drain करता है (PodDisruptionBudgets का सम्मान करता है)
        ├── समानांतर में प्रतिस्थापन node प्रोविज़न करता है
        └── 2-मिनट की विंडो बंद होने से पहले pods नए node पर पुनः शेड्यूल हो जाते हैं
```

यह `terragrunt.hcl` में `karpenter` ब्लॉक में कॉन्फ़िगर किया गया है:

```hcl theme={null}
karpenter = {
  spot_interruption_handling = true   # SQS queue और EventBridge rule बनाता है
  enable_spot_instances       = true   # NodePool क्षमता आवश्यकताओं में Spot की अनुमति देता है
}
```

### चरण 5: वातावरण-विशिष्ट फ़ाइल मान अपडेट करें

नए env फ़ोल्डर में सभी फ़ाइलों में निम्नलिखित placeholders के लिए ढूँढें और बदलें:

| Placeholder             | विवरण                       | उदाहरण                   |
| ----------------------- | --------------------------- | ------------------------ |
| `<YOUR_ENV_NAME>`       | अद्वितीय वातावरण पहचानकर्ता | `app-eks-prod`           |
| `<YOUR_AWS_REGION>`     | क्लस्टर का AWS क्षेत्र      | `eu-west-2`, `us-east-2` |
| `<YOUR_AWS_ACCOUNT_ID>` | 12-अंकों का AWS खाता ID     | `123456789012`           |
| `<YOUR_ENVIRONMENT>`    | वातावरण टैग मान             | `prod`, `staging`, `dev` |
| `<YOUR_PROJECT>`        | प्रोजेक्ट टैग मान           | `odin`, `ekb`            |

```bash theme={null}
# सभी शेष placeholders खोजने के लिए अपने नए env फ़ोल्डर से चलाएँ
grep -r "<YOUR_" .
```

#### 5.1 `terragrunt.hcl` — मुख्य क्लस्टर कॉन्फ़िगरेशन

```bash theme={null}
nano terragrunt.hcl
```

| फ़ील्ड                                     | Placeholder                | नोट्स                                                                    |
| ------------------------------------------ | -------------------------- | ------------------------------------------------------------------------ |
| `cluster_name`                             | `<YOUR_ENV_NAME>`          | EKS क्लस्टर नाम से मेल खाना चाहिए                                        |
| `cluster_region`                           | `<YOUR_AWS_REGION>`        | AWS क्षेत्र                                                              |
| `aws_account_id`                           | `<YOUR_AWS_ACCOUNT_ID>`    | 12-अंकों का खाता ID                                                      |
| `vpc_cidr`                                 | `<YOUR_VPC_CIDR>`          | उदा., `192.168.0.0/16`                                                   |
| `availability_zones`                       | `<YOUR_REGION>a/b/c`       | आपके क्षेत्र में 3 AZs                                                   |
| `tags.Environment`                         | `<YOUR_ENVIRONMENT>`       | उदा., `prod`                                                             |
| `tags.Project`                             | `<YOUR_PROJECT>`           | उदा., `odin`                                                             |
| `aws_services.amazon_mq.rabbitmq.username` | `<YOUR_RABBITMQ_USERNAME>` | RabbitMQ admin उपयोगकर्ता नाम (केवल जब `ENABLE_AWS_SERVICES=true`)       |
| `aws_services.amazon_mq.rabbitmq.password` | `<YOUR_RABBITMQ_PASSWORD>` | न्यूनतम 12 अक्षर; अपरकेस, लोअरकेस, डिजिट और विशेष अक्षर शामिल होने चाहिए |

#### 5.2 `state/terragrunt.hcl` — S3 स्टेट bucket

```bash theme={null}
nano state/terragrunt.hcl
```

| फ़ील्ड        | Placeholder                            | नोट्स                              |
| ------------- | -------------------------------------- | ---------------------------------- |
| `bucket_name` | `odin-terraform-state-<YOUR_ENV_NAME>` | वैश्विक रूप से अद्वितीय होना चाहिए |
| `region`      | `<YOUR_AWS_REGION>`                    | क्लस्टर के समान क्षेत्र            |

#### 5.3 `values/infrastructure.yaml` — AWS Load Balancer Controller

<Warning>
  AWS Load Balancer Controller तैनात करने से पहले EKS क्लस्टर बनाने के **बाद** VPC ID प्राप्त करें।
</Warning>

```bash theme={null}
# EKS क्लस्टर बनाने के बाद VPC ID प्राप्त करें
aws eks describe-cluster --name <YOUR_ENV_NAME> \
  --query "cluster.resourcesVpcConfig.vpcId" --output text
```

```bash theme={null}
nano values/infrastructure.yaml
```

| फ़ील्ड                                                  | Placeholder                                | नोट्स                            |
| ------------------------------------------------------- | ------------------------------------------ | -------------------------------- |
| `clusterName`                                           | `<YOUR_ENV_NAME>`                          | EKS क्लस्टर नाम                  |
| `region`                                                | `<YOUR_AWS_REGION>`                        | AWS क्षेत्र                      |
| `vpcId`                                                 | `<YOUR_VPC_ID>`                            | ALB तैनाती से पहले आवश्यक        |
| `serviceAccount.annotations.eks.amazonaws.com/role-arn` | `<YOUR_AWS_ACCOUNT_ID>`, `<YOUR_ENV_NAME>` | ALB controller के लिए IAM भूमिका |

#### 5.4 `values/karpenter-values.yaml` — Karpenter controller

<Warning>
  Karpenter तैनात करने से पहले EKS क्लस्टर बनाने के **बाद** और Karpenter तैनात करने से पहले EKS क्लस्टर endpoint प्राप्त करें।
</Warning>

```bash theme={null}
# EKS क्लस्टर बनाने के बाद क्लस्टर endpoint प्राप्त करें
aws eks describe-cluster --name <YOUR_ENV_NAME> \
  --query "cluster.endpoint" --output text
```

```bash theme={null}
nano values/karpenter-values.yaml
```

| फ़ील्ड                                                  | Placeholder                                | नोट्स                           |
| ------------------------------------------------------- | ------------------------------------------ | ------------------------------- |
| `serviceAccount.annotations.eks.amazonaws.com/role-arn` | `<YOUR_AWS_ACCOUNT_ID>`, `<YOUR_ENV_NAME>` | Karpenter के लिए IAM भूमिका     |
| `env.CLUSTER_NAME`                                      | `<YOUR_ENV_NAME>`                          | EKS क्लस्टर नाम                 |
| `env.CLUSTER_ENDPOINT`                                  | `<YOUR_EKS_CLUSTER_ENDPOINT>`              | Karpenter तैनाती से पहले आवश्यक |
| `settings.aws.defaultInstanceProfile`                   | `<YOUR_ENV_NAME>`                          | Karpenter node instance profile |

#### 5.5 `values/karpenter-nodeclasses.yaml` — Karpenter node classes

```bash theme={null}
nano values/karpenter-nodeclasses.yaml
```

| फ़ील्ड                                            | Placeholder          | नोट्स                                 |
| ------------------------------------------------- | -------------------- | ------------------------------------- |
| सभी `kubernetes.io/cluster/<YOUR_ENV_NAME>` टैग्स | `<YOUR_ENV_NAME>`    | सबनेट/SG selectors के लिए cluster टैग |
| `user_data` बूटस्ट्रैप cluster नाम                | `<YOUR_ENV_NAME>`    | Node बूटस्ट्रैप स्क्रिप्ट             |
| `tags.Environment`                                | `<YOUR_ENVIRONMENT>` | उदा., `prod`                          |
| `tags.Project`                                    | `<YOUR_PROJECT>`     | उदा., `odin`                          |

#### 5.6 `values/aws-ebs-csi-driver.yaml` — EBS CSI Driver

```bash theme={null}
nano values/aws-ebs-csi-driver.yaml
```

| फ़ील्ड                                                             | Placeholder                                | नोट्स                                |
| ------------------------------------------------------------------ | ------------------------------------------ | ------------------------------------ |
| `controller.serviceAccount.annotations.eks.amazonaws.com/role-arn` | `<YOUR_AWS_ACCOUNT_ID>`, `<YOUR_ENV_NAME>` | EBS CSI controller के लिए IAM भूमिका |
| `node.serviceAccount.annotations.eks.amazonaws.com/role-arn`       | `<YOUR_AWS_ACCOUNT_ID>`, `<YOUR_ENV_NAME>` | EBS CSI node के लिए IAM भूमिका       |
| `controller.env.AWS_DEFAULT_REGION`                                | `<YOUR_AWS_REGION>`                        | AWS क्षेत्र                          |
| `controller.env.AWS_REGION`                                        | `<YOUR_AWS_REGION>`                        | AWS क्षेत्र                          |
| `node.env.AWS_DEFAULT_REGION`                                      | `<YOUR_AWS_REGION>`                        | AWS क्षेत्र                          |
| `node.env.AWS_REGION`                                              | `<YOUR_AWS_REGION>`                        | AWS क्षेत्र                          |

#### 5.7 `values/karpenter.yaml` — Karpenter NodePools

```bash theme={null}
nano values/karpenter.yaml
```

| फ़ील्ड                                       | Placeholder                                              | नोट्स                       |
| -------------------------------------------- | -------------------------------------------------------- | --------------------------- |
| `*.labels.Environment`                       | `<YOUR_ENVIRONMENT>`                                     | सभी NodePool लेबल्स पर लागू |
| `*.requirements topology.kubernetes.io/zone` | `["<YOUR_REGION>a", "<YOUR_REGION>b", "<YOUR_REGION>c"]` | सभी NodePools के लिए AZs    |

Node class names (`general`, `compute-intensive`, `memory-intensive`, `gpu`, `database`) `karpenter-nodeclasses.yaml` में entries से मेल खाने चाहिए।

#### 5.8 `values/keda.yaml` — KEDA Autoscaler

कोई वातावरण-विशिष्ट placeholders आवश्यक नहीं। संसाधन सीमाएँ और रेप्लिका गणनाएँ उचित डिफ़ॉल्ट्स के साथ पूर्व-कॉन्फ़िगर की गई हैं। समीक्षा करें और आवश्यकतानुसार समायोजित करें।

#### 5.9 `values/supabase.yaml` — Supabase एप्लिकेशन (केवल यदि `ENABLE_SUPABASE=true`)

<Warning>
  नीचे दी गई सभी कुंजियाँ लगातार उत्पन्न होनी चाहिए और `ha-supabase-db.yaml` के साथ साझा की जानी चाहिए। इन्हें एक बार उत्पन्न करें और दोनों फ़ाइलों में एक ही मानों का उपयोग करें।
</Warning>

```bash theme={null}
# JWT secret उत्पन्न करें
openssl rand -hex 32
 
# anon/service role JWTs उत्पन्न करें (Supabase CLI आवश्यक)
brew install supabase/tap/supabase
supabase gen-keys
 
# पासवर्ड और tokens उत्पन्न करें
openssl rand -hex 24       # पासवर्ड के लिए
openssl rand -base64 64    # secretKeyBase के लिए
```

```bash theme={null}
nano values/supabase.yaml
```

| फ़ील्ड                                | Placeholder                                | नोट्स                                                              |
| ------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------ |
| `secret.jwt.anonKey`                  | `<YOUR_SUPABASE_ANON_KEY>`                 | `ha-supabase-db.yaml` `anonKey` से मेल खाना चाहिए                  |
| `secret.jwt.serviceKey`               | `<YOUR_SUPABASE_SERVICE_ROLE_KEY>`         | `ha-supabase-db.yaml` `serviceRoleKey` से मेल खाना चाहिए           |
| `secret.jwt.secret`                   | `<YOUR_SUPABASE_JWT_SECRET>`               | `ha-supabase-db.yaml` `jwtSecret` से मेल खाना चाहिए                |
| `secret.db.password`                  | `<YOUR_SUPABASE_DB_PASSWORD>`              | `ha-supabase-db.yaml` `postgresPassword` से मेल खाना चाहिए         |
| `secret.analytics.publicAccessToken`  | `<YOUR_SUPABASE_ANALYTICS_PUBLIC_TOKEN>`   | आंतरिक Logflare token                                              |
| `secret.analytics.privateAccessToken` | `<YOUR_SUPABASE_ANALYTICS_PRIVATE_TOKEN>`  | आंतरिक Logflare token                                              |
| `secret.dashboard.username`           | `<YOUR_SUPABASE_DASHBOARD_USERNAME>`       | Studio UI लॉगिन                                                    |
| `secret.dashboard.password`           | `<YOUR_SUPABASE_DASHBOARD_PASSWORD>`       | Studio UI लॉगिन                                                    |
| `secret.realtime.secretKeyBase`       | `<YOUR_SUPABASE_REALTIME_SECRET_KEY_BASE>` | Phoenix secret key                                                 |
| `secret.meta.cryptoKey`               | `<YOUR_SUPABASE_META_CRYPTO_KEY>`          | `openssl rand -hex 32`                                             |
| `secret.s3.keyId`                     | `<YOUR_MINIO_KEY_ID>`                      | `secret.minio.user` (`openssl rand -hex 16`) से मेल खाना चाहिए     |
| `secret.s3.accessKey`                 | `<YOUR_MINIO_ACCESS_KEY>`                  | `secret.minio.password` (`openssl rand -hex 32`) से मेल खाना चाहिए |
| `secret.minio.user`                   | `<YOUR_MINIO_KEY_ID>`                      | `secret.s3.keyId` जैसा ही मान                                      |
| `secret.minio.password`               | `<YOUR_MINIO_ACCESS_KEY>`                  | `secret.s3.accessKey` जैसा ही मान                                  |

#### 5.10 `values/ha-supabase-db.yaml` — Supabase HA Database (केवल यदि `ENABLE_HA_SUPABASE_DB=true`)

<Warning>
  यहाँ के secrets को `supabase.yaml` से मेल खाना चाहिए। `postgresPassword`, `jwtSecret`, `anonKey`, और `serviceRoleKey` के लिए एक ही उत्पन्न मानों का उपयोग करें।
</Warning>

```bash theme={null}
nano values/ha-supabase-db.yaml
```

| फ़ील्ड                                 | Placeholder                        | नोट्स                                                     |
| -------------------------------------- | ---------------------------------- | --------------------------------------------------------- |
| `secrets.inline.postgresPassword`      | `<YOUR_SUPABASE_DB_PASSWORD>`      | `supabase.yaml` `secret.db.password` से मेल खाना चाहिए    |
| `secrets.inline.authenticatorPassword` | `<YOUR_SUPABASE_DB_PASSWORD>`      | `postgresPassword` के समान होना चाहिए                     |
| `secrets.inline.pgbouncerPassword`     | `<YOUR_SUPABASE_DB_PASSWORD>`      | `postgresPassword` के समान होना चाहिए                     |
| `secrets.inline.jwtSecret`             | `<YOUR_SUPABASE_JWT_SECRET>`       | `supabase.yaml` `secret.jwt.secret` से मेल खाना चाहिए     |
| `secrets.inline.anonKey`               | `<YOUR_SUPABASE_ANON_KEY>`         | `supabase.yaml` `secret.jwt.anonKey` से मेल खाना चाहिए    |
| `secrets.inline.serviceRoleKey`        | `<YOUR_SUPABASE_SERVICE_ROLE_KEY>` | `supabase.yaml` `secret.jwt.serviceKey` से मेल खाना चाहिए |

Storage class (`ebs-csi-gp2`), instance गणनाएँ, और संसाधन सीमाएँ पूर्व-कॉन्फ़िगर हैं। अपनी अपेक्षित डेटा मात्रा के अनुसार `postgres.storage.size` और `postgres.walStorage.size` समायोजित करें।

#### 5.11 `values/cloudnative-pg.yaml` — CloudNativePG Operator (केवल यदि `ENABLE_CNPG=true`)

कोई वातावरण-विशिष्ट placeholders आवश्यक नहीं। यह केवल CNPG operator controller तैनात करता है। डिफ़ॉल्ट सेटिंग्स (3 रेप्लिकास, संसाधन सीमाएँ) अधिकांश वातावरण के लिए उपयुक्त हैं।

#### 5.12 `values/odin-services.yaml` — Odin एप्लिकेशन सेवाएँ

<Warning>
  Redis और RabbitMQ endpoints केवल Terraform द्वारा उन AWS संसाधनों को बनाने के बाद उपलब्ध हैं। प्रमाणपत्र ARNs तैनाती से पहले ACM में प्रोविज़न किए जाने चाहिए।
</Warning>

```bash theme={null}
nano values/odin-services.yaml
```

**सामान्य सेटिंग्स:**

| फ़ील्ड                 | Placeholder                     | नोट्स                                                                                                     |
| ---------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `server`               | `<YOUR_WEB_DOMAIN>`             | मुख्य वेब डोमेन                                                                                           |
| `toolkitEncryptionKey` | `<YOUR_TOOLKIT_ENCRYPTION_KEY>` | उत्पन्न करें: `python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"` |

**Supabase (`dataServiceConfig`) — सेल्फ़-होस्टेड (`ENABLE_SUPABASE=true`):**

| फ़ील्ड                       | Placeholder                                                          | स्रोत                                               |
| ---------------------------- | -------------------------------------------------------------------- | --------------------------------------------------- |
| `supabase.projectUrl`        | `http://supabase-kong:8000`                                          | स्थिर — आंतरिक Supabase Kong                        |
| `supabase.key`               | `<YOUR_SUPABASE_SERVICE_ROLE_KEY>`                                   | `supabase.yaml` में `secret.jwt.serviceKey` जैसा ही |
| `supabase.postgres.user`     | `postgres`                                                           | सेल्फ़-होस्टेड के लिए स्थिर                         |
| `supabase.postgres.host`     | `ha-supabase-db-postgres-pooler-rw.ha-supabase-db.svc.cluster.local` | स्थिर — क्लस्टर के भीतर DB Pool सेवा                |
| `supabase.postgres.password` | `<YOUR_SUPABASE_DB_PASSWORD>`                                        | `supabase.yaml` में `secret.db.password` जैसा ही    |
| `supabase.projectId`         | *(खाली छोड़ें)*                                                      | सेल्फ़-होस्टेड मोड में उपयोग नहीं                   |

**Supabase (`dataServiceConfig`) — Supabase Cloud (`ENABLE_SUPABASE=false`):**

| फ़ील्ड                       | Placeholder                        | स्रोत                                                                       |
| ---------------------------- | ---------------------------------- | --------------------------------------------------------------------------- |
| `supabase.projectUrl`        | `<YOUR_SUPABASE_PROJECT_URL>`      | Supabase dashboard → Project Settings → API                                 |
| `supabase.key`               | `<YOUR_SUPABASE_SERVICE_ROLE_KEY>` | Supabase dashboard → API → `service_role` कुंजी                             |
| `supabase.postgres.user`     | `<YOUR_SUPABASE_DB_USER>`          | Supabase dashboard → Project Settings → Database                            |
| `supabase.postgres.host`     | `<YOUR_SUPABASE_DB_HOST>`          | Supabase dashboard → Database (उदा., `aws-0-eu-west-2.pooler.supabase.com`) |
| `supabase.postgres.password` | `<YOUR_SUPABASE_DB_PASSWORD>`      | Supabase dashboard → Project Settings → Database                            |
| `supabase.projectId`         | `<YOUR_SUPABASE_PROJECT_ID>`       | आपके Supabase प्रोजेक्ट URL से                                              |

**Redis:**

| फ़ील्ड       | Placeholder                                          | नोट्स                                     |
| ------------ | ---------------------------------------------------- | ----------------------------------------- |
| `redis.url`  | `rediss://<YOUR_REDIS_HOST>:6379?ssl_cert_reqs=none` | Terraform द्वारा ElastiCache बनाने के बाद |
| `redis.host` | `<YOUR_REDIS_HOST>`                                  | ElastiCache primary endpoint              |

```bash theme={null}
# Terraform apply के बाद Redis endpoint प्राप्त करें
aws elasticache describe-cache-clusters \
  --show-cache-node-info \
  --query "CacheClusters[?starts_with(CacheClusterId,'<YOUR_ENV_NAME>')].CacheNodes[0].Endpoint.Address" \
  --output text
```

**RabbitMQ:**

| फ़ील्ड              | Placeholder                                                                           | नोट्स                                  |
| ------------------- | ------------------------------------------------------------------------------------- | -------------------------------------- |
| `rabbitmq.url`      | `amqps://<YOUR_RABBITMQ_USERNAME>:<YOUR_RABBITMQ_PASSWORD>@<YOUR_RABBITMQ_HOST>:5671` | Terraform द्वारा AmazonMQ बनाने के बाद |
| `rabbitmq.host`     | `<YOUR_RABBITMQ_HOST>`                                                                | AmazonMQ broker endpoint               |
| `rabbitmq.username` | `<YOUR_RABBITMQ_USERNAME>`                                                            | `terragrunt.hcl` में सेट               |
| `rabbitmq.password` | `<YOUR_RABBITMQ_PASSWORD>`                                                            | `terragrunt.hcl` में सेट               |

```bash theme={null}
# Terraform apply के बाद RabbitMQ endpoint प्राप्त करें
aws mq list-brokers \
  --query "BrokerSummaries[?BrokerName=='odin-rabbitmq'].BrokerId" --output text | \
  xargs -I{} aws mq describe-broker --broker-id {} \
  --query "BrokerInstances[0].Endpoints[0]" --output text
```

**SSL / प्रमाणपत्र ARNs:**

| फ़ील्ड                                       | Placeholder                        | नोट्स                               |
| -------------------------------------------- | ---------------------------------- | ----------------------------------- |
| `ssl.services.web.domain`                    | `<YOUR_WEB_DOMAIN>`                | उदा., `app.example.com`             |
| `ssl.services.web.certificateArn`            | `<YOUR_WEB_CERTIFICATE_ARN>`       | ACM प्रमाणपत्र ARN                  |
| `ssl.services.fastapiBackend.domain`         | `<YOUR_API_DOMAIN>`                | उदा., `api-app.example.com`         |
| `ssl.services.fastapiBackend.certificateArn` | `<YOUR_API_CERTIFICATE_ARN>`       | ACM प्रमाणपत्र ARN                  |
| `ssl.services.automator.domain`              | `<YOUR_AUTOMATOR_DOMAIN>`          | उदा., `automations-app.example.com` |
| `ssl.services.automator.certificateArn`      | `<YOUR_AUTOMATOR_CERTIFICATE_ARN>` | ACM प्रमाणपत्र ARN                  |
| `ssl.services.supabase.domain`               | `<YOUR_SUPABASE_DOMAIN>`           | उदा., `supabase-app.example.com`    |
| `ssl.services.supabase.certificateArn`       | `<YOUR_SUPABASE_CERTIFICATE_ARN>`  | ACM प्रमाणपत्र ARN                  |

```bash theme={null}
# अपने क्षेत्र में ACM प्रमाणपत्र सूचीबद्ध करें
aws acm list-certificates --region <YOUR_AWS_REGION> \
  --query "CertificateSummaryList[*].[DomainName,CertificateArn]" --output table
```

**वेब फ़्रंटएंड Supabase keys — सेल्फ़-होस्टेड (`ENABLE_SUPABASE=true`):**

| फ़ील्ड                        | Placeholder                        | स्रोत                                               |
| ----------------------------- | ---------------------------------- | --------------------------------------------------- |
| `web.supabase.url`            | `https://<YOUR_SUPABASE_DOMAIN>`   | ALB ingress के माध्यम से रूट किया गया बाहरी URL     |
| `web.supabase.anonKey`        | `<YOUR_SUPABASE_ANON_KEY>`         | `supabase.yaml` में `secret.jwt.anonKey` जैसा ही    |
| `web.supabase.serviceRoleKey` | `<YOUR_SUPABASE_SERVICE_ROLE_KEY>` | `supabase.yaml` में `secret.jwt.serviceKey` जैसा ही |
| `web.supabase.clientanonKey`  | `<YOUR_SUPABASE_SERVICE_ROLE_KEY>` | `supabase.yaml` में `secret.jwt.serviceKey` जैसा ही |

**वेब फ़्रंटएंड Supabase keys — Supabase Cloud (`ENABLE_SUPABASE=false`):**

| फ़ील्ड                        | Placeholder                        | स्रोत                                           |
| ----------------------------- | ---------------------------------- | ----------------------------------------------- |
| `web.supabase.url`            | `<YOUR_SUPABASE_PROJECT_URL>`      | Supabase dashboard → Project Settings → API     |
| `web.supabase.anonKey`        | `<YOUR_SUPABASE_ANON_KEY>`         | Supabase dashboard → API → `anon` कुंजी         |
| `web.supabase.serviceRoleKey` | `<YOUR_SUPABASE_SERVICE_ROLE_KEY>` | Supabase dashboard → API → `service_role` कुंजी |
| `web.supabase.clientanonKey`  | `<YOUR_SUPABASE_CLIENT_ANON_KEY>`  | `service_role` कुंजी जैसा ही                    |

#### 5.13 `values/signoz.yaml` — SigNoz अवलोकन (केवल यदि `ENABLE_SIGNOZ=true`)

```bash theme={null}
nano values/signoz.yaml
```

| फ़ील्ड                                                                 | Placeholder                                                                  | नोट्स                          |
| ---------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------ |
| `global.clusterName`                                                   | `<YOUR_ENV_NAME>`                                                            | EKS क्लस्टर नाम                |
| `signoz.ingress.annotations.alb.ingress.kubernetes.io/certificate-arn` | `<YOUR_AWS_REGION>`, `<YOUR_AWS_ACCOUNT_ID>`, `<YOUR_SIGNOZ_CERTIFICATE_ID>` | SigNoz के लिए ACM प्रमाणपत्र   |
| `signoz.ingress.hosts[0].host`                                         | `<YOUR_SIGNOZ_DOMAIN>`                                                       | उदा., `signoz-app.example.com` |

#### 5.14 `values/signoz-k8s-infra.yaml` — SigNoz K8s मेट्रिक्स (केवल यदि `ENABLE_SIGNOZ=true`)

```bash theme={null}
nano values/signoz-k8s-infra.yaml
```

| फ़ील्ड               | Placeholder       | नोट्स                                  |
| -------------------- | ----------------- | -------------------------------------- |
| `global.clusterName` | `<YOUR_ENV_NAME>` | मेट्रिक लेबलिंग के लिए EKS क्लस्टर नाम |

OTel collector endpoint (`signoz-otel-collector.monitoring.svc.cluster.local:4317`) यह मानकर पूर्व-कॉन्फ़िगर किया गया है कि SigNoz और k8s-infra दोनों `monitoring` namespace में तैनात हैं। जब तक आप कस्टम release name का उपयोग नहीं करते, कोई बदलाव आवश्यक नहीं।

#### तैनाती क्रम अनुस्मारक

कुछ मान केवल कुछ अवसंरचना के तैनात होने के बाद उपलब्ध हैं। इस क्रम का पालन करें:

1. **किसी भी तैनाती से पहले** — सेट करें: `<YOUR_ENV_NAME>`, `<YOUR_AWS_REGION>`, `<YOUR_AWS_ACCOUNT_ID>`, `<YOUR_ENVIRONMENT>`, `<YOUR_PROJECT>`, `<YOUR_VPC_CIDR>`, सभी डोमेन नाम, सभी प्रमाणपत्र ARNs, सभी Supabase मान, `<YOUR_TOOLKIT_ENCRYPTION_KEY>`, RabbitMQ username/password
2. **EKS क्लस्टर बनाने के बाद** — सेट करें: `<YOUR_VPC_ID>` (`infrastructure.yaml`), `<YOUR_EKS_CLUSTER_ENDPOINT>` (`karpenter-values.yaml`)
3. **AWS सेवाओं के लिए `terraform apply` के बाद** — सेट करें: `<YOUR_REDIS_HOST>`, `<YOUR_RABBITMQ_HOST>` (`odin-services.yaml`)

### चरण 6: सत्यापित करें कि कोई Placeholders शेष नहीं हैं

```bash theme={null}
grep -r "<YOUR_" . --include="*.hcl" --include="*.yaml"
```

अपेक्षित आउटपुट खाली होना चाहिए, या केवल उन संसाधनों के संदर्भ शामिल होने चाहिए जो बनाए जाने वाले हैं (VPC, Redis, MQ, EKS)। यदि कोई placeholders शेष हैं, तो ऊपर दिए गए चरण 5 उप-अनुभागों का संदर्भ लें।

**फ़ाइलें चेकलिस्ट:**

| फ़ाइल                               | चरण  | आवश्यक                                |
| ----------------------------------- | ---- | ------------------------------------- |
| `terragrunt.hcl`                    | 5.1  | हमेशा                                 |
| `state/terragrunt.hcl`              | 5.2  | हमेशा                                 |
| `values/infrastructure.yaml`        | 5.3  | हमेशा                                 |
| `values/karpenter-values.yaml`      | 5.4  | हमेशा                                 |
| `values/karpenter-nodeclasses.yaml` | 5.5  | हमेशा                                 |
| `values/karpenter.yaml`             | 5.7  | हमेशा                                 |
| `values/keda.yaml`                  | 5.8  | हमेशा                                 |
| `values/aws-ebs-csi-driver.yaml`    | 5.6  | हमेशा                                 |
| `values/odin-services.yaml`         | 5.12 | हमेशा                                 |
| `values/cloudnative-pg.yaml`        | 5.11 | केवल यदि `ENABLE_CNPG=true`           |
| `values/ha-supabase-db.yaml`        | 5.10 | केवल यदि `ENABLE_HA_SUPABASE_DB=true` |
| `values/supabase.yaml`              | 5.9  | केवल यदि `ENABLE_SUPABASE=true`       |
| `values/signoz.yaml`                | 5.13 | केवल यदि `ENABLE_SIGNOZ=true`         |
| `values/signoz-k8s-infra.yaml`      | 5.14 | केवल यदि `ENABLE_SIGNOZ=true`         |

***

## चरण 1: स्टेट प्रबंधन सेटअप

**उद्देश्य:** Terraform स्टेट के लिए S3 bucket निर्माण।

प्रत्येक वातावरण का स्टेट प्रबंधन मॉड्यूल `odin-terraform-state-{environment-name}` पैटर्न के साथ S3 bucket बनाता है, एन्क्रिप्शन, वर्शनिंग और पब्लिक एक्सेस ब्लॉकिंग कॉन्फ़िगर करता है, और स्टेट मॉड्यूल के लिए स्थानीय स्टेट का उपयोग करता है (बूटस्ट्रैप पैटर्न)।

```bash theme={null}
cd terragrunt/environments/{your-env-name}/state
terragrunt init
terragrunt plan
terragrunt apply
```

***

## चरण 2: EKS अवसंरचना तैनाती

**उद्देश्य:** मुख्य नेटवर्किंग (VPC, सबनेट्स, NAT gateway), IAM भूमिकाएँ और नीतियाँ, EKS क्लस्टर और managed node groups।

### 2.1 ड्राई रन — EKS अवसंरचना

**मुख्य अवसंरचना**

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt plan -target="aws_vpc.main" \
  -target="aws_internet_gateway.main" \
  -target="aws_subnet.public" \
  -target="aws_subnet.private" \
  -target="aws_eip.nat" \
  -target="aws_nat_gateway.main" \
  -target="aws_route_table.public" \
  -target="aws_route_table.private" \
  -target="aws_route_table_association.public" \
  -target="aws_route_table_association.private"
```

**IAM भूमिकाएँ और नीतियाँ**

```bash theme={null}
terragrunt plan -target="aws_iam_role.cluster" \
  -target="aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy" \
  -target="aws_iam_openid_connect_provider.eks" \
  -target="aws_iam_role.node" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly"
```

**EKS क्लस्टर और Node Groups**

```bash theme={null}
terragrunt plan -target="aws_eks_cluster.main" \
  -target="aws_eks_node_group.main" \
  -target="kubernetes_secret.regcred"
```

#### कस्टम / निजी Docker Registry का उपयोग करना

डिफ़ॉल्ट रूप से, EKB images `regcred` नामक secret का उपयोग करके Docker Hub से पुल किए जाते हैं। यदि ग्राहक अलग registry में images होस्ट करता है, तो `odin-services` तैनात करने से पहले इन चरणों का पालन करें।

**चरण 1 — लक्षित namespace में `imagePullSecret` बनाएँ**

```bash theme={null}
# जेनेरिक निजी registry (Docker Hub, Quay, सेल्फ़-होस्टेड, आदि)
kubectl create secret docker-registry regcred \
  --namespace default \
  --docker-server=<YOUR_REGISTRY_HOST> \
  --docker-username=<YOUR_REGISTRY_USERNAME> \
  --docker-password=<YOUR_REGISTRY_PASSWORD> \
  --docker-email=<YOUR_EMAIL>
 
# AWS ECR — टोकन हर 12h में समाप्त होता है; CronJob या ECR pull-through cache के माध्यम से रीफ्रेश करें
aws ecr get-login-password --region <YOUR_AWS_REGION> | \
  kubectl create secret docker-registry regcred \
    --namespace default \
    --docker-server=<YOUR_AWS_ACCOUNT_ID>.dkr.ecr.<YOUR_AWS_REGION>.amazonaws.com \
    --docker-username=AWS \
    --docker-password-stdin
```

**चरण 2 — `values/odin-services.yaml` में secret नाम सेट करें**

```yaml theme={null}
# values/odin-services.yaml
imagePullSecrets:
  - name: regcred          # ऊपर बनाए गए secret नाम से मेल खाना चाहिए
  # - name: customer-registry-secret  # आवश्यकतानुसार अतिरिक्त registries जोड़ें
```

**चरण 3 — image संदर्भ अपडेट करें**

```yaml theme={null}
web:
  image: <YOUR_REGISTRY_HOST>/<YOUR_ORG>/web:<TAG>
 
fastapiBackend:
  image: <YOUR_REGISTRY_HOST>/<YOUR_ORG>/server:<TAG>
```

**चरण 4 — पूर्ण तैनाती से पहले पुल पहुँच सत्यापित करें**

```bash theme={null}
kubectl run registry-test \
  --image=<YOUR_REGISTRY_HOST>/<YOUR_ORG>/web:<TAG> \
  --overrides='{"spec":{"imagePullSecrets":[{"name":"regcred"}]}}' \
  --restart=Never --rm -it -- echo "Pull successful"
```

### 2.2 EKS अवसंरचना तैनात करें

**चरण 1: मुख्य अवसंरचना**

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt apply -target="aws_vpc.main" \
  -target="aws_internet_gateway.main" \
  -target="aws_subnet.public" \
  -target="aws_subnet.private" \
  -target="aws_eip.nat" \
  -target="aws_nat_gateway.main" \
  -target="aws_route_table.public" \
  -target="aws_route_table.private" \
  -target="aws_route_table_association.public" \
  -target="aws_route_table_association.private"
```

<Warning>
  इस चरण के बाद, AWS Load Balancer Controller तैनात करने से पहले `values/infrastructure.yaml` में `vpcId` अपडेट करें।
</Warning>

**चरण 2: EKS क्लस्टर और IAM भूमिकाएँ और नीतियाँ**

```bash theme={null}
terragrunt apply -target="aws_iam_role.cluster" \
  -target="aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy" \
  -target="aws_iam_openid_connect_provider.eks" \
  -target="aws_iam_role.node" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly"
```

**चरण 3: Node Groups और Addons**

```bash theme={null}
terragrunt apply -target="aws_eks_cluster.main" \
  -target="aws_eks_node_group.main" \
  -target="kubernetes_secret.regcred"
```

<Warning>
  इस चरण के बाद, Karpenter तैनात करने से पहले `values/karpenter-values.yaml` में `CLUSTER_ENDPOINT` अपडेट करें।
</Warning>

**EKS क्लस्टर कनेक्टिविटी जाँचें**

```bash theme={null}
aws eks update-kubeconfig --region $AWS_REGION --name $CLUSTER_NAME
 
kubectl cluster-info
kubectl get nodes
kubectl get secret regcred -n default
```

***

## चरण 3: स्टोरेज और लोड बैलेंसिंग

**उद्देश्य:** स्थायी volumes के लिए EBS CSI driver, managed node group पर चलने वाला AWS Load Balancer Controller।

### 3.1 ड्राई रन — स्टोरेज और लोड बैलेंसिंग

**EBS CSI Driver**

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt plan -target="aws_iam_role.ebs_csi_driver" \
  -target="aws_iam_role_policy_attachment.ebs_csi_driver" \
  -target="helm_release.ebs_csi_driver"
```

**AWS Load Balancer Controller**

```bash theme={null}
terragrunt plan -target="aws_iam_role.aws_load_balancer_controller" \
  -target="aws_iam_role_policy_attachment.aws_load_balancer_controller" \
  -target="aws_iam_policy.aws_load_balancer_controller" \
  -target="helm_release.infrastructure"
```

### 3.2 स्टोरेज और लोड बैलेंसिंग तैनात करें

**चरण 1: EBS CSI Driver**

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt apply -target="aws_iam_role.ebs_csi_driver" \
  -target="aws_iam_role_policy_attachment.ebs_csi_driver" \
  -target="helm_release.ebs_csi_driver"
```

**सत्यापन**

```bash theme={null}
helm list -n kube-system | grep ebs
kubectl get pods -n kube-system | grep ebs-csi
kubectl get storageclass
aws iam get-role --role-name $CLUSTER_NAME-ebs-csi-driver-role --region $AWS_REGION
kubectl get sa -n kube-system | grep ebs-csi
kubectl describe sa ebs-csi-controller-sa -n kube-system
```

**चरण 2: AWS Load Balancer Controller**

```bash theme={null}
terragrunt apply -target="aws_iam_role.aws_load_balancer_controller" \
  -target="aws_iam_role_policy_attachment.aws_load_balancer_controller" \
  -target="aws_iam_policy.aws_load_balancer_controller" \
  -target="helm_release.infrastructure"
```

**सत्यापन**

```bash theme={null}
helm list -n infrastructure
kubectl get pods -n infrastructure | grep aws-load-balancer-controller
kubectl get sa -n infrastructure
kubectl describe sa aws-load-balancer-controller -n infrastructure
aws iam get-role --role-name $CLUSTER_NAME-aws-load-balancer-controller --region $AWS_REGION
kubectl logs -n infrastructure -l app.kubernetes.io/name=aws-load-balancer-controller
kubectl get ingressclass
```

***

## चरण 4: Karpenter Autoscaling

**उद्देश्य:** Karpenter के लिए IAM भूमिकाएँ, Spot interruption handling, Karpenter controller और node pools।

### 4.1 ड्राई रन — Karpenter

**Karpenter IAM संसाधन**

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt plan -target="aws_iam_role.karpenter_controller" \
  -target="aws_iam_policy.karpenter_controller" \
  -target="aws_iam_role_policy_attachment.karpenter_controller" \
  -target="aws_iam_role.karpenter_node" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEC2ContainerRegistryReadOnly" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEBSCSIDriverPolicy" \
  -target="aws_iam_instance_profile.karpenter_node"
```

**EC2 Spot Service-Linked Role (यदि spot instances सक्षम हैं)**

```bash theme={null}
terragrunt plan -target="aws_iam_service_linked_role.ec2_spot[0]"
```

**Karpenter Spot Interruption (यदि `terragrunt.hcl` में सक्षम)**

```bash theme={null}
terragrunt plan -target="aws_sqs_queue.karpenter_interruption_queue" \
  -target="aws_sqs_queue_policy.karpenter_interruption_queue" \
  -target="aws_cloudwatch_event_rule.karpenter_interruption" \
  -target="aws_cloudwatch_event_target.karpenter_interruption"
```

**Karpenter Helm Charts**

```bash theme={null}
terragrunt plan -target="helm_release.karpenter"
```

**Karpenter NodePools और EC2NodeClasses**

```bash theme={null}
terragrunt plan -target="kubernetes_manifest.karpenter_nodepool" \
  -target="kubernetes_manifest.karpenter_nodeclass" \
  -target="kubernetes_config_map.aws_auth"
```

<Info>
  Plan के दौरान एक अपेक्षित त्रुटि दिखाई दे सकती है: `API did not recognize GroupVersionKind from manifest (CRD may not be installed)`. इसे अनदेखा करना सुरक्षित है — Kubernetes CRDs स्थापित होने से पहले plan समय पर लाइव API के विरुद्ध संसाधनों को सत्यापित करता है।
</Info>

### 4.2 Karpenter तैनात करें

**चरण 1: Karpenter IAM संसाधन**

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt apply -target="aws_iam_role.karpenter_controller" \
  -target="aws_iam_policy.karpenter_controller" \
  -target="aws_iam_role_policy_attachment.karpenter_controller" \
  -target="aws_iam_role.karpenter_node" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEC2ContainerRegistryReadOnly" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEBSCSIDriverPolicy" \
  -target="aws_iam_instance_profile.karpenter_node"
```

**सत्यापन**

```bash theme={null}
aws iam get-role --role-name $CLUSTER_NAME-karpenter-controller --region $AWS_REGION
aws iam get-role --role-name $CLUSTER_NAME-karpenter-node --region $AWS_REGION
aws iam get-instance-profile --instance-profile-name $CLUSTER_NAME-karpenter-node --region $AWS_REGION
aws iam list-attached-role-policies --role-name $CLUSTER_NAME-karpenter-node --region $AWS_REGION
```

**चरण 2: EC2 Spot Service-Linked Role (यदि spot instances सक्षम हैं)**

<Warning>
  EC2 Spot service-linked role खाता-व्यापी (प्रत्येक AWS खाते में केवल एक) है और Karpenter द्वारा Spot instances लॉन्च करने से पहले मौजूद होना चाहिए।
</Warning>

**विकल्प A: Terraform को इसे बनाने दें (नई तैनातियों के लिए अनुशंसित)**

```bash theme={null}
terragrunt apply -target="aws_iam_service_linked_role.ec2_spot[0]"
```

**विकल्प B: यदि भूमिका पहले से मौजूद है तो आयात करें**

```bash theme={null}
# जाँचें कि भूमिका मौजूद है
aws iam get-role --role-name AWSServiceRoleForEC2Spot --region $AWS_REGION
 
# यदि मौजूद नहीं है, तो मैनुअल रूप से बनाएँ
aws iam create-service-linked-role --aws-service-name spot.amazonaws.com --region $AWS_REGION
 
# Terraform में आयात करें (ACCOUNT_ID को अपने 12-अंकों के AWS खाता ID से बदलें)
terragrunt import 'aws_iam_service_linked_role.ec2_spot[0]' \
  arn:aws:iam::ACCOUNT_ID:role/aws-service-role/spot.amazonaws.com/AWSServiceRoleForEC2Spot
```

<details>
  <summary>Spot Instance निर्माण समस्याओं का निवारण</summary>

  **Spot-संबंधित त्रुटियों के लिए Karpenter लॉग्स जाँचें:**

  ```bash theme={null}
  kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter -f | grep -i spot
  ```

  सामान्य त्रुटियाँ: `AuthFailure.ServiceLinkedRoleCreationNotPermitted`, `UnfulfillableCapacity`, `InsufficientInstanceCapacity`।

  **सत्यापित करें कि service-linked role मौजूद है:**

  ```bash theme={null}
  aws iam get-role --role-name AWSServiceRoleForEC2Spot --region $AWS_REGION
  ```

  **सत्यापित करें कि IAM नीति में Spot अनुमति शामिल है:**

  ```bash theme={null}
  aws iam get-policy-version \
    --policy-arn $(aws iam list-policies --query 'Policies[?PolicyName==`YOUR_CLUSTER_NAME-karpenter-controller`].Arn' --output text) \
    --version-id $(aws iam get-policy --policy-arn $(aws iam list-policies --query 'Policies[?PolicyName==`YOUR_CLUSTER_NAME-karpenter-controller`].Arn' --output text) --query 'Policy.DefaultVersionId' --output text) \
    --region $AWS_REGION | grep -i "CreateServiceLinkedRole"
  ```

  **Spot instance उपलब्धता जाँचें:**

  ```bash theme={null}
  aws ec2 describe-spot-price-history \
    --instance-types r6a.4xlarge r6a.large \
    --product-descriptions "Linux/UNIX" \
    --region $AWS_REGION \
    --max-items 10
  ```

  **NodePool क्षमता प्रकार जाँचें:**

  ```bash theme={null}
  kubectl get nodepool -o yaml | grep -A 5 "capacity-type"
  ```

  **Spot vs On-Demand नोड्स सत्यापित करें:**

  ```bash theme={null}
  kubectl get nodes -o json | jq -r '.items[] | "\(.metadata.name)\t\(.metadata.labels."karpenter.sh/capacity-type")\t\(.metadata.labels."node.kubernetes.io/instance-type")"'
  ```
</details>

**चरण 3: Karpenter Spot Interruption (यदि `terragrunt.hcl` में सक्षम)**

```bash theme={null}
terragrunt apply -target="aws_sqs_queue.karpenter_interruption_queue" \
  -target="aws_sqs_queue_policy.karpenter_interruption_queue" \
  -target="aws_cloudwatch_event_rule.karpenter_interruption" \
  -target="aws_cloudwatch_event_target.karpenter_interruption"
```

**सत्यापन**

```bash theme={null}
aws events describe-rule --name $CLUSTER_NAME-karpenter-interruption --region $AWS_REGION
aws events list-targets-by-rule --rule $CLUSTER_NAME-karpenter-interruption --region $AWS_REGION
aws sqs get-queue-url --queue-name $CLUSTER_NAME-karpenter-interruption-queue --region $AWS_REGION
```

**चरण 4: Karpenter Helm Chart**

```bash theme={null}
terragrunt apply -target="helm_release.karpenter"
```

**सत्यापन**

```bash theme={null}
helm list -n kube-system | grep karpenter
kubectl get pods -n kube-system | grep karpenter
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter
kubectl describe sa karpenter -n kube-system
```

**चरण 5: Karpenter Kubernetes Manifests**

```bash theme={null}
terragrunt apply -target="kubernetes_manifest.karpenter_nodepool" \
  -target="kubernetes_manifest.karpenter_nodeclass"
 
# मौजूदा aws-auth ConfigMap आयात करें
# नोट: zsh द्वारा brackets को glob patterns के रूप में interpret करने से रोकने के लिए quotes का उपयोग करें
terragrunt import 'kubernetes_config_map.aws_auth[0]' kube-system/aws-auth
 
# फिर लागू करें
terragrunt apply -target='kubernetes_config_map.aws_auth[0]'
```

**सत्यापन**

```bash theme={null}
kubectl get nodepools -o wide
kubectl describe nodepool general
kubectl describe nodepool application
kubectl describe nodepool database
kubectl get ec2nodeclasses -o wide
kubectl get configmap aws-auth -n kube-system -o jsonpath='{.data.mapRoles}' | grep karpenter-node
kubectl get nodepools -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}'
kubectl get nodes -l karpenter.sh/nodepool --show-labels
kubectl get events -n kube-system --field-selector involvedObject.name=karpenter --sort-by='.lastTimestamp'
```

***

## चरण 5: KEDA Autoscaling

**उद्देश्य:** एप्लिकेशन-स्तरीय autoscaling के लिए KEDA।

### 5.1 ड्राई रन — KEDA

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt plan -target="helm_release.keda"
```

### 5.2 KEDA तैनात करें

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt apply -target="helm_release.keda"
```

**सत्यापन**

```bash theme={null}
helm list -n keda
kubectl get pods -n keda
kubectl get deployment -n keda
kubectl get crd | grep keda
kubectl get validatingwebhookconfigurations | grep keda
kubectl get svc -n keda
```

***

## चरण 6: डेटा सेवाएँ

**उद्देश्य:** Supabase (डेटाबेस), ElastiCache (Redis), RabbitMQ (मैसेज क्यू)।

<Info>
  पहले CloudNativePG operator तैनात करें, फिर HA Supabase DB क्लस्टर, फिर Supabase एप्लिकेशन। DB क्लस्टर Supabase शुरू होने से पहले तैयार होना चाहिए।
</Info>

### 6.1 ड्राई रन — डेटा सेवाएँ

**चरण 1: CloudNativePG operator (यदि सक्षम)**

```bash theme={null}
cd terragrunt/environments/your-env-name
ENABLE_CNPG=true terragrunt plan \
  --target='helm_release.additional_charts["cloudnative-pg"]'
```

**चरण 2: HA Supabase DB (यदि सक्षम)**

```bash theme={null}
ENABLE_HA_SUPABASE_DB=true terragrunt plan \
  --target='helm_release.additional_charts["ha-supabase-db"]'
```

**चरण 3: Supabase एप्लिकेशन (यदि सक्षम)**

```bash theme={null}
if [ "${ENABLE_SUPABASE:-false}" = "true" ]; then
  ENABLE_SUPABASE=true terragrunt plan \
    --target='helm_release.supabase[0]'
fi
```

**चरण 4: AWS सेवाएँ — ElastiCache और RabbitMQ (यदि सक्षम)**

```bash theme={null}
if [ "${ENABLE_AWS_SERVICES:-false}" = "true" ]; then
  terragrunt plan -target="aws_elasticache_subnet_group.redis" \
    -target="aws_security_group.redis" \
    -target="aws_elasticache_replication_group.redis" \
    -target="aws_security_group.rabbitmq" \
    -target="aws_mq_broker.rabbitmq"
fi
```

### 6.2 डेटा सेवाएँ तैनात करें

**चरण 1: CloudNativePG operator (यदि सक्षम)**

```bash theme={null}
cd terragrunt/environments/your-env-name
ENABLE_CNPG=true terragrunt apply --auto-approve \
  --target='helm_release.additional_charts["cloudnative-pg"]'
```

**चरण 2: HA Supabase DB (यदि सक्षम)**

```bash theme={null}
ENABLE_HA_SUPABASE_DB=true terragrunt apply --auto-approve \
  --target='helm_release.additional_charts["ha-supabase-db"]'
```

**तैनाती के बाद PgBouncer pooler और credentials की सत्यापन:**

```bash theme={null}
kubectl get svc -n ha-supabase-db | grep pooler
kubectl get secrets -n ha-supabase-db
kubectl get secret ha-supabase-db-authenticator-credentials -n ha-supabase-db \
  -o jsonpath='{.data.username}' | base64 -d && echo ""
```

`values/odin-services.yaml` में `SUPABASE_POSTGRES_HOST` मान और `values/supabase.yaml` में `secret.db.postgresHost` के रूप में pooler ClusterIP (या यदि LoadBalancer हो तो `EXTERNAL-IP`) का उपयोग करें।

**चरण 3: Supabase एप्लिकेशन (यदि सक्षम)**

सभी Supabase सेवा pods Spot interruptions को रोकने के लिए केवल Karpenter `application` NodePool (केवल On-Demand) पर चलते हैं।

```bash theme={null}
if [ "${ENABLE_SUPABASE:-false}" = "true" ]; then
  ENABLE_SUPABASE=true terragrunt apply --auto-approve \
    --target='helm_release.supabase[0]'
fi
```

**चरण 4: AWS सेवाएँ — ElastiCache और RabbitMQ (यदि सक्षम)**

```bash theme={null}
if [ "${ENABLE_AWS_SERVICES:-false}" = "true" ]; then
  terragrunt apply \
    -target="aws_elasticache_subnet_group.redis" \
    -target="aws_security_group.redis" \
    -target="aws_elasticache_replication_group.redis" \
    -target="aws_security_group.rabbitmq" \
    -target="aws_mq_broker.rabbitmq"
fi
```

**सत्यापन**

```bash theme={null}
# Terraform outputs से कनेक्शन विवरण प्राप्त करें
terragrunt output elasticache_endpoint
terragrunt output elasticache_port
terragrunt output rabbitmq_endpoint
terragrunt output rabbitmq_port
 
# EKS क्लस्टर से Redis कनेक्टिविटी परीक्षण करें
kubectl run redis-test --image=redis:7-alpine --restart=Never -- \
  sh -c "redis-cli -h <redis-endpoint> -p 6379 --tls --insecure ping && echo 'Redis connection successful'"
kubectl logs redis-test
kubectl delete pod redis-test
 
# Redis एन्क्रिप्शन स्थिति जाँचें
aws elasticache describe-replication-groups \
  --replication-group-id $CLUSTER_NAME-redis \
  --region $AWS_REGION \
  --query 'ReplicationGroups[0].{AtRestEncryption:AtRestEncryptionEnabled,TransitEncryption:TransitEncryptionEnabled}'
```

<Warning>
  Odin सेवाएँ तैनात करने से पहले, इस चरण में प्राप्त Redis endpoint, RabbitMQ endpoint और सभी प्रमाणपत्र ARNs के साथ `values/odin-services.yaml` अपडेट करें।
</Warning>

***

## चरण 7: Odin सेवाएँ

**उद्देश्य:** Helm के माध्यम से एप्लिकेशन तैनाती।

<Info>
  तैनात करने से पहले, प्रारंभिक डेटाबेस माइग्रेशन रन के लिए `fastapiBackend` को अस्थायी रूप से एकल रेप्लिका तक स्केल-डाउन करें — `replicaCount: 1`, `workers: 1`, और `keda.minReplicas: 1` सेट करें। एक बार माइग्रेशन सफलतापूर्वक पूरा हो जाने पर, पुनः-तैनाती से पहले इन मानों को उनके उत्पादन डिफ़ॉल्ट्स में वापस करें।
</Info>

### 7.1 ड्राई रन — Odin सेवाएँ

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt plan -target="helm_release.odin_services"
```

### 7.2 Odin सेवाएँ तैनात करें

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt apply -target="helm_release.odin_services"
```

**सत्यापन**

```bash theme={null}
kubectl get pods
kubectl get ingress  # ALB endpoints को अपने DNS provider में जोड़ें
```

***

## चरण 8: SigNoz अवलोकन

**उद्देश्य:** लॉग्स और मेट्रिक्स निगरानी।

### 8.1 ड्राई रन — SigNoz Charts

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt plan -target='helm_release.additional_charts["signoz"]'
terragrunt plan -target='helm_release.additional_charts["k8s-infra"]'
```

### 8.2 SigNoz Charts तैनात करें

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt apply -target='helm_release.additional_charts["signoz"]'
terragrunt apply -target='helm_release.additional_charts["k8s-infra"]'
```

**सत्यापन**

```bash theme={null}
kubectl get pods -n monitoring
kubectl get ingress -n monitoring  # ALB endpoints को अपने DNS provider में जोड़ें
```

***

## चरण 9: अंतिम तैनाती

### 9.1 पूर्ण तैनाती

```bash theme={null}
cd terragrunt/environments/your-env-name
terragrunt apply
```

यह अंतिम apply पिछले चरणों में स्पष्ट रूप से लक्षित नहीं किए गए किसी भी शेष संसाधनों को संभालता है।

### 9.2 तैनाती सत्यापित करें

```bash theme={null}
# kubeconfig अपडेट करें
aws eks update-kubeconfig --region us-east-2 --name your-env-name
 
# क्लस्टर स्थिति जाँचें
kubectl get nodes
kubectl get pods --all-namespaces
 
# Karpenter जाँचें
kubectl get pods -n kube-system -l app.kubernetes.io/name=karpenter
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter
 
# AWS Load Balancer Controller जाँचें
kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller
 
# KEDA जाँचें
kubectl get pods -n keda
 
# Odin सेवाएँ जाँचें
kubectl get pods -n default
kubectl get services -n default
kubectl get ingress -n default
 
# सभी Helm releases जाँचें
helm list --all-namespaces
```

***

## समस्या निवारण

**स्टेट लॉक समस्याएँ**

```bash theme={null}
terragrunt force-unlock <lock-id>
```

**Karpenter काम नहीं कर रहा**

```bash theme={null}
kubectl describe nodes
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter
```

**लोड बैलेंसर समस्याएँ**

```bash theme={null}
kubectl describe ingress -n default
kubectl logs -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller
```

**Helm chart समस्याएँ**

```bash theme={null}
helm status <release-name> -n <namespace>
helm rollback <release-name> <revision> -n <namespace>
```

***

## सफ़ाई

```bash theme={null}
# अवसंरचना नष्ट करें
cd terragrunt/environments/your-env-name
terragrunt destroy -auto-approve
 
# स्टेट bucket नष्ट करें (सावधानी से उपयोग करें)
cd terragrunt/environments/your-env-name/state
terragrunt destroy -auto-approve
```

***

## निगरानी और लॉगिंग

```bash theme={null}
# AWS संसाधन
aws eks describe-cluster --name your-env-name --region us-east-2
aws ec2 describe-instances --filters "Name=tag:kubernetes.io/cluster/your-env-name,Values=owned"
 
# Kubernetes संसाधन
kubectl top nodes
kubectl top pods --all-namespaces
kubectl get events --sort-by=.metadata.creationTimestamp
```

***

## क्विक रेफ़रेंस — सभी तैनाती कमांड्स

```bash theme={null}
# चरण 1: स्टेट प्रबंधन
cd terragrunt/environments/your-env-name/state
terragrunt apply
 
# चरण 2: EKS अवसंरचना
cd terragrunt/environments/your-env-name
 
terragrunt apply -target="aws_vpc.main" -target="aws_internet_gateway.main" \
  -target="aws_subnet.public" -target="aws_subnet.private" -target="aws_eip.nat" \
  -target="aws_nat_gateway.main" -target="aws_route_table.public" \
  -target="aws_route_table.private" -target="aws_route_table_association.public" \
  -target="aws_route_table_association.private" -auto-approve
 
terragrunt apply -target="aws_iam_role.cluster" \
  -target="aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy" \
  -target="aws_iam_openid_connect_provider.eks" -target="aws_iam_role.node" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly" \
  -auto-approve
 
terragrunt apply -target="aws_eks_cluster.main" \
  -target="aws_eks_node_group.main" -target="kubernetes_secret.regcred" -auto-approve
 
# चरण 3: स्टोरेज और लोड बैलेंसिंग
terragrunt apply -target="aws_iam_role.ebs_csi_driver" \
  -target="aws_iam_role_policy_attachment.ebs_csi_driver" \
  -target="helm_release.ebs_csi_driver" -auto-approve
 
terragrunt apply -target="aws_iam_role.aws_load_balancer_controller" \
  -target="aws_iam_role_policy_attachment.aws_load_balancer_controller" \
  -target="aws_iam_policy.aws_load_balancer_controller" \
  -target="helm_release.infrastructure" -auto-approve
 
# चरण 4: Karpenter Autoscaling
terragrunt apply -target="aws_iam_role.karpenter_controller" \
  -target="aws_iam_policy.karpenter_controller" \
  -target="aws_iam_role_policy_attachment.karpenter_controller" \
  -target="aws_iam_role.karpenter_node" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKSWorkerNodePolicy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEKS_CNI_Policy" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEC2ContainerRegistryReadOnly" \
  -target="aws_iam_role_policy_attachment.karpenter_node_AmazonEBSCSIDriverPolicy" \
  -target="aws_iam_instance_profile.karpenter_node" -auto-approve
 
# Spot interruption handling (यदि spot_interruption_handling = true)
terragrunt apply -target="aws_sqs_queue.karpenter_interruption_queue" \
  -target="aws_sqs_queue_policy.karpenter_interruption_queue" \
  -target="aws_cloudwatch_event_rule.karpenter_interruption" \
  -target="aws_cloudwatch_event_target.karpenter_interruption" -auto-approve
 
terragrunt apply -target="helm_release.karpenter" -auto-approve
 
terragrunt apply -target="kubernetes_manifest.karpenter_nodepool" \
  -target="kubernetes_manifest.karpenter_nodeclass" \
  -target='kubernetes_config_map.aws_auth[0]' -auto-approve
 
# चरण 5: KEDA Autoscaling
terragrunt apply -target="helm_release.keda" -auto-approve
 
# चरण 6: डेटा सेवाएँ
ENABLE_CNPG=true terragrunt apply --target='helm_release.additional_charts["cloudnative-pg"]' -auto-approve
ENABLE_HA_SUPABASE_DB=true terragrunt apply --target='helm_release.additional_charts["ha-supabase-db"]' -auto-approve
 
if [ "${ENABLE_SUPABASE:-false}" = "true" ]; then
  ENABLE_SUPABASE=true terragrunt apply --target='helm_release.supabase[0]' -auto-approve
fi
 
if [ "${ENABLE_AWS_SERVICES:-false}" = "true" ]; then
  terragrunt apply -target="aws_elasticache_subnet_group.redis" \
    -target="aws_security_group.redis" \
    -target="aws_elasticache_replication_group.redis" \
    -target="aws_security_group.rabbitmq" \
    -target="aws_mq_broker.rabbitmq" -auto-approve
fi
 
# चरण 7: Odin सेवाएँ
terragrunt apply -target="helm_release.odin_services" -auto-approve
 
# चरण 8: SigNoz (यदि सक्षम)
terragrunt apply -target='helm_release.additional_charts["signoz"]' -auto-approve
terragrunt apply -target='helm_release.additional_charts["k8s-infra"]' -auto-approve
 
# चरण 9: अंतिम तैनाती
terragrunt apply -auto-approve
```

<Info>
  अपने वास्तविक वातावरण नाम से `your-env-name` को पूरी तरह से बदलें। हमेशा बदलाव लागू करने से पहले अपनी कॉन्फ़िगरेशन सत्यापित करने के लिए ड्राई रन्स (`terragrunt plan`) पहले चलाएँ।
</Info>
