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

# Kubernetes eks

# EKS Kubernetes provisioner backend

> Provision Nora agents into Amazon EKS using Nora's generic Kubernetes adapter and Admin cluster registry.

EKS uses the same Kubernetes adapter as every Kubernetes provider. Nora stores provider, namespace, exposure, and load-balancer settings on the Admin cluster row; `docker-compose.kubernetes.yml` only mounts kubeconfig files into the control-plane containers.

## Step-by-step setup

### 1. Prerequisites

* AWS account with permission to call the EKS API and create LoadBalancer services in your VPC.
* `aws` CLI installed and configured (`aws configure` or env vars / SSO profile).
* An existing EKS cluster (or create one — AWS Console → **EKS → Add cluster**).
* **AWS Load Balancer Controller** installed in the cluster, OR EKS **Auto Mode** enabled — without one, Service provisioning hangs at `EXTERNAL-IP: <pending>`.
* `kubectl` installed on the host that runs Nora.

Use the EKS cluster overview page to confirm the cluster name and AWS region before creating
the kubeconfig.

<Frame caption="AWS Console — EKS cluster overview">
  <img src="https://mintcdn.com/sttechnologyllc/A_pk5LchBKKfnyIr/images/provisioner-backends/k8s/eks/cluster-overview.png?fit=max&auto=format&n=A_pk5LchBKKfnyIr&q=85&s=d12a1864a758274e6cf97be76f8bbccf" alt="EKS cluster overview" width="1512" height="382" data-path="images/provisioner-backends/k8s/eks/cluster-overview.png" />
</Frame>

### 2. Create the kubeconfig

```bash theme={null} theme={null}
mkdir -p .secrets
aws eks update-kubeconfig \
  --name <cluster-name> \
  --region <region> \
  --kubeconfig ./.secrets/eks-kubeconfig
```

### 3. Verify access from the host

```bash theme={null} theme={null}
kubectl --kubeconfig ./.secrets/eks-kubeconfig get nodes
```

Confirm the node group reports `Ready` in the Console's **Compute** tab.

<Frame caption="AWS Console — EKS dashboard with managed node groups tab">
  <img src="https://mintcdn.com/sttechnologyllc/A_pk5LchBKKfnyIr/images/provisioner-backends/k8s/eks/compute-tab.png?fit=max&auto=format&n=A_pk5LchBKKfnyIr&q=85&s=27402b56719776a926a7c070dac7eb4e" alt="EKS managed node groups dashboard" width="2870" height="2144" data-path="images/provisioner-backends/k8s/eks/compute-tab.png" />
</Frame>

### 4. Configure Nora

Set the generic Kubernetes mount variable in `.env`:

```bash theme={null} theme={null}
mkdir -p ./.secrets/kubeconfigs
cp ./.secrets/eks-kubeconfig ./.secrets/kubeconfigs/eks-us-east-1
NORA_KUBECONFIGS_DIR=./.secrets/kubeconfigs
```

For two or more EKS clusters, put each kubeconfig under `NORA_KUBECONFIGS_DIR` and use Admin paths such as `/kubeconfigs/eks-us-east-1` and `/kubeconfigs/eks-us-west-2`.

Confirm the LB-creating add-on is present under **Add-ons** before continuing.

<Frame caption="AWS Console — Cluster → Add-ons (Amazon VPC CNI active)">
  <img src="https://mintcdn.com/sttechnologyllc/A_pk5LchBKKfnyIr/images/provisioner-backends/k8s/eks/add-ons.png?fit=max&auto=format&n=A_pk5LchBKKfnyIr&q=85&s=46659939c7e38a69b344ecb053f199ef" alt="EKS Amazon VPC CNI add-on" width="890" height="1024" data-path="images/provisioner-backends/k8s/eks/add-ons.png" />
</Frame>

### 5. Start the stack

```bash theme={null} theme={null}
docker compose -f docker-compose.yml -f docker-compose.kubernetes.yml up -d --build
```

<Warning>
  This smoke-mode command is for the local nginx config (`NGINX_CONFIG_FILE=nginx.conf`, usually
  `NGINX_HTTP_PORT=8080`). If your `.env` already points to the public TLS config
  (`NGINX_CONFIG_FILE=nginx.public.conf`), include the tracked `infra/docker-compose.public-tls.yml`
  layer as shown in [Promote to production](#promote-to-production); otherwise nginx will not mount
  `/etc/letsencrypt` and Cloudflare can return 521 because the origin web server is down.
</Warning>

### 6. Register this cluster in Admin

Open **Admin -> Kubernetes**, click **Add cluster**, and use these values:

| Field                    | Value                                                                                                      |
| ------------------------ | ---------------------------------------------------------------------------------------------------------- |
| Cluster id               | `eks-us-east-1`                                                                                            |
| Label                    | `EKS US East 1`                                                                                            |
| Provider                 | `EKS`                                                                                                      |
| Actual cluster name      | The EKS cluster name from the AWS Console                                                                  |
| Credential mode          | `Mounted kubeconfig path`                                                                                  |
| Kubeconfig path          | `/kubeconfigs/eks-us-east-1`                                                                               |
| Fallback namespace       | `nora-openclaw-agents`                                                                                     |
| OpenClaw namespace       | `nora-openclaw-agents`                                                                                     |
| Hermes namespace         | `nora-hermes-agents`                                                                                       |
| Exposure mode            | `LoadBalancer`                                                                                             |
| Service annotations JSON | Leave empty for EKS Auto Mode, or use the AWS Load Balancer Controller annotations that match your cluster |
| Source ranges            | Your Nora control-plane egress CIDR when you can restrict access                                           |
| Load balancer class      | `eks.amazonaws.com/nlb` for EKS Auto Mode NLB, otherwise leave empty if you use annotations                |

Do not put `./.secrets/eks-kubeconfig` in the Admin Kubeconfig path when Nora runs in Docker Compose. That is the host-side path; the containers see files from `NORA_KUBECONFIGS_DIR` under `/kubeconfigs`.

### 7. Deploy a test agent

Open the dashboard at `http://127.0.0.1:8080`, sign in, and create an agent with the EKS cluster label you registered.

<Frame caption="Nora deploy wizard — Backend dropdown showing Kubernetes on EKS">
  <img
    src="https://mintcdn.com/sttechnologyllc/hES1KHpUWDvLb_Wr/images/provisioner-backends/k8s/_nora/nora-deploy-backend-picker.png?fit=max&auto=format&n=hES1KHpUWDvLb_Wr&q=85&s=9788405d5b29b781c069611db393e696"
    alt="Deploy wizard backend
picker"
    width="1512"
    height="1080"
    data-path="images/provisioner-backends/k8s/_nora/nora-deploy-backend-picker.png"
  />
</Frame>

<Frame caption="Nora deploy wizard — Kubernetes on EKS selected">
  <img
    src="https://mintcdn.com/sttechnologyllc/hES1KHpUWDvLb_Wr/images/provisioner-backends/k8s/_nora/nora-deploy-k8s-selected.png?fit=max&auto=format&n=hES1KHpUWDvLb_Wr&q=85&s=83ffffd500bc21cd168808e522eec88c"
    alt="Deploy wizard Kubernetes
selected"
    width="1512"
    height="1080"
    data-path="images/provisioner-backends/k8s/_nora/nora-deploy-k8s-selected.png"
  />
</Frame>

<Frame caption="Agent detail — status running with the EKS NLB address">
  <img src="https://mintcdn.com/sttechnologyllc/A_pk5LchBKKfnyIr/images/provisioner-backends/k8s/_nora/nora-agent-running-k8s.png?fit=max&auto=format&n=A_pk5LchBKKfnyIr&q=85&s=9c6d98571b77e4680faf11697341729e" alt="Agent detail K8s" width="1512" height="1080" data-path="images/provisioner-backends/k8s/_nora/nora-agent-running-k8s.png" />
</Frame>

## EKS Service options

For EKS Auto Mode NLB:

Set the Admin **Load balancer class** field to `eks.amazonaws.com/nlb`.

For AWS Load Balancer Controller / NLB annotations:

```json theme={null} theme={null}
{
  "service.beta.kubernetes.io/aws-load-balancer-scheme": "internet-facing",
  "service.beta.kubernetes.io/aws-load-balancer-nlb-target-type": "ip"
}
```

Your cluster must have the AWS load-balancing path you choose installed and configured. If Services stay pending, check the EKS controller events and IAM permissions for load balancer creation.

## Verification

```bash theme={null} theme={null}
kubectl --kubeconfig ./.secrets/eks-kubeconfig -n nora-openclaw-agents get deploy,svc,pods
# If Hermes is enabled and deployed:
kubectl --kubeconfig ./.secrets/eks-kubeconfig -n nora-hermes-agents get deploy,svc,pods
docker compose -f docker-compose.yml -f docker-compose.kubernetes.yml logs worker-provisioner
```

For real e2e, enable the Kubernetes matrix cell:

```bash theme={null} theme={null}
cd e2e
REAL_ENABLE_OPENCLAW_DOCKER=0 REAL_ENABLE_OPENCLAW_K8S=1 \
  BASE_URL=http://localhost:8080 npm run test:real:matrix
```

<Frame caption="Logs tab — worker-provisioner output during a successful EKS deploy">
  <img src="https://mintcdn.com/sttechnologyllc/A_pk5LchBKKfnyIr/images/provisioner-backends/k8s/_nora/nora-agent-logs-k8s.png?fit=max&auto=format&n=A_pk5LchBKKfnyIr&q=85&s=fed94088a03606a531285305b6e64662" alt="Agent logs K8s" width="1512" height="1080" data-path="images/provisioner-backends/k8s/_nora/nora-agent-logs-k8s.png" />
</Frame>

## Automated smoke

Once your EKS kubeconfig is in place, run the shared lifecycle smoke:

```bash theme={null} theme={null}
cd e2e
KUBECONFIG_PATH=$PWD/../.secrets/eks-kubeconfig npm run smoke:k8s-eks
```

This script is operator-run only — it provisions real workloads against a live EKS cluster and is not part of CI. Set `KEEP_ENV=true` to leave the stack running after the script finishes.

## Promote to production

Once the smoke is green, switch from the dev-mode stack to the prod-mode stack. The only changes vs the testing setup are nginx (public config + TLS) and Compose mode (`infra/docker-compose.public-tls.yml` for prod Dockerfiles, TLS mounts, public ports, and restart policies).

### 1. Tighten the LoadBalancer source ranges

Replace the smoke-time `<nora-control-plane-egress-cidr>` placeholder with your production control plane's egress CIDR. For internal-only NLBs, add the `aws-load-balancer-scheme: internal` annotation.

### 2. Switch nginx to public + TLS

In `.env`:

```bash theme={null} theme={null}
NGINX_CONFIG_FILE=nginx.public.conf
NGINX_HTTP_PORT=80
```

Provision Let's Encrypt certs once:

```bash theme={null} theme={null}
sudo ./infra/setup-tls.sh <your-domain>
```

### 3. Stop the smoke-mode stack

```bash theme={null} theme={null}
docker compose -f docker-compose.yml -f docker-compose.kubernetes.yml down
```

### 4. Start the prod-mode stack

```bash theme={null} theme={null}
docker compose \
  -f docker-compose.yml \
  -f infra/docker-compose.public-tls.yml \
  -f docker-compose.kubernetes.yml \
  up -d --build
```

### 5. Confirm

```bash theme={null} theme={null}
docker compose ps
curl -fsS https://<your-domain>/api/health
docker compose logs worker-provisioner | tail -50
```

Deploy a real agent from the UI and confirm it reaches `running` and the EKS NLB assigns a hostname.

## See also

* [Kind](/configuration/provisioner-backends/kubernetes-kind) — local Kubernetes for development
* [K3s](/configuration/provisioner-backends/kubernetes-k3s) — self-hosted production K8s
* [AKS](/configuration/provisioner-backends/kubernetes-aks) — Azure Kubernetes Service
* [GKE](/configuration/provisioner-backends/kubernetes-gke) — Google Kubernetes Engine
