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

# Install on an Existing EKS Cluster

You do not have to use the LILT Terraform module. If you provision AWS resources with your own tooling, or you already have an EKS cluster, the installer works against it as long as the cluster meets the requirements below and you name each resource explicitly in `install.env`.

This article lists what your cluster and account must provide, and how to configure the installer to use resources it did not create. For the Terraform path instead, see [Provision AWS infrastructure with Terraform](/kb/install-aws-terraform-module).

## What Your Cluster Must Provide

### Kubernetes

* Amazon EKS version 1.32 or later.

* The EBS CSI driver, with a StorageClass the installer can use. The installer creates `ebs-gp3` and `ebs-gp3-retain` by default. To use a class you already have, set `STORAGE_CLASS` and `STORAGE_CLASS_RETAIN`, and also set `ENABLE_CLUSTER_PREREQS=false`.

<Warning>
  Pointing `STORAGE_CLASS` at your own class without setting `ENABLE_CLUSTER_PREREQS=false` makes Helm take ownership of that class. A later uninstall then deletes it.
</Warning>

* The AWS Load Balancer Controller, or another controller that can provision a Network Load Balancer for the Istio ingress gateway.

* A node group for application workloads. Size it against [Self-managed hardware requirements](/kb/self-managed-hardware-requirements). Give each node at least 300 GB of disk: the neural services pull trained-data images that are tens of gigabytes compressed and roughly double that unpacked.

* Node kernel settings. A raised file-descriptor limit for Istio's ztunnel and `vm.max_map_count` for Elasticsearch are not part of the stock AMI baseline. If you build your own AMI, the Kubernetes baseline is yours to provide too. See [Node kernel settings](/kb/install-system-aws-eks#node-kernel-settings).

* GPU nodes labelled `capability=gpu`, if you run the translation, OCR, review, or speech models. Each GPU node group needs the `nvidia.com/gpu` taint so that only GPU workloads land on it.

### AWS Resources

| Resource            | Purpose                                                       | Configured with                    |
| ------------------- | ------------------------------------------------------------- | ---------------------------------- |
| RDS MySQL instance  | The application database                                      | `RDS_IDENTIFIER`, `DB_NAME`        |
| S3 bucket           | Object storage for documents and memories                     | `S3_BUCKET`                        |
| SQS queue           | Asynchronous work, subscribed to bucket events                | `SQS_QUEUE_URL`                    |
| Container registry  | Every LILT image. The node role must be able to pull from it. | `REGISTRY_BASE`, `REGISTRY_PATH_*` |
| Route53 hosted zone | The hostnames LILT serves                                     | `HOSTED_ZONE_ID`, `DNS_DOMAIN`     |

The installer reads the RDS master credentials from the AWS Secrets Manager secret that RDS created with the instance. Create your database with a managed master password so that this works without further configuration.

### Registry Access from the Nodes

LILT relies on node-level authentication to pull images, not on per-namespace pull secrets. Attach `AmazonEC2ContainerRegistryReadOnly`, or an equivalent scoped policy, to your node group's IAM role. The LILT Terraform module does this for you; a cluster you built yourself may not have it.

Without it, pods sit in `ImagePullBackOff` with an error that names the image but not the missing permission.

### Workload Identity

Two service-facing roles must exist before you install:

* An **application workload role** with read and write access to your S3 bucket and SQS queue. Set `APP_WORKLOAD_ROLE_NAME` to its name.

* A **Cluster Autoscaler role**, if you run Cluster Autoscaler. Set `CLUSTER_AUTOSCALER_ROLE_NAME` to its name.

Bind each role to its Kubernetes service account with either EKS Pod Identity or IAM Roles for Service Accounts. Pod Identity is the better choice for a new cluster.

Then tell the installer which one you used. `IAM_AUTH_METHOD` defaults to `irsa`:

```bash theme={null}
# install.env
IAM_AUTH_METHOD=pod_identity   # or irsa
```

<Note>
  The install scripts find these roles by a substring match on the role **name**, not the ARN. Set the variables to the name only, without the `arn:aws:iam::...:role/` prefix.
</Note>

<Warning>
  Under EKS Pod Identity, leave the service accounts unannotated. An `eks.amazonaws.com/role-arn` annotation overrides the Pod Identity association, and the pod then fails to reach S3 with a credentials error that does not name the annotation.
</Warning>

## Tools on the Install Host

Helm 4, `kubectl`, `aws` CLI v2, and `jq`. Add [crane](https://github.com/google/go-containerregistry) if you populate your registry with `seed-registry.sh`. None of these are installed for you.

Confirm Helm 4 with `helm version --short` before you start. Helm 3 fails partway through the install rather than at the beginning.

## Configure the Install

Copy the template and fill it in. With no `PREFIX` set, the installer takes each identifier from the value you give it and derives nothing.

```bash theme={null}
cp install.env.example install.env
chmod 0600 install.env
```

A minimal bring-your-own configuration:

```bash theme={null}
# Identity and location
SUBDOMAIN=myenv
DNS_DOMAIN=example.com
AWS_REGION=us-east-1

# Pre-existing resources, named explicitly
CLUSTER_NAME=my-eks-cluster
RDS_IDENTIFIER=my-rds-instance
DB_NAME=lilt_dev
S3_BUCKET=my-lilt-bucket
SQS_QUEUE_URL=https://sqs.us-east-1.amazonaws.com/111122223333/my-lilt-queue
SA_NAME=lilt-s3-workload
APP_WORKLOAD_ROLE_NAME=my-app-workload-role
CLUSTER_AUTOSCALER_ROLE_NAME=my-cluster-autoscaler-role

# Registry
REGISTRY_BASE=111122223333.dkr.ecr.us-east-1.amazonaws.com
REGISTRY_PATH_APP=
REGISTRY_PATH_GAR=
REGISTRY_PATH_INFRA=

# TLS, supplied by you
TLS_CRT_FILE=/opt/lilt/certs/lilt.crt
TLS_KEY_FILE=/opt/lilt/certs/lilt.key

# Required. The /connectors-admin console login.
CONNECTORS_ADMIN_PASSWORD=<choose one>
```

### Registry Paths

A full image reference is `<REGISTRY_BASE>/<REGISTRY_PATH_*>/<image>`. The three path variables exist because LILT's own registry proxies three upstreams, and a mirror of it keeps that layout.

For a plain Amazon ECR registry there is no proxy path. Set all three `REGISTRY_PATH_*` variables to an empty value, as shown above. An empty value is honoured, not replaced with the default, and the reference collapses to `<REGISTRY_BASE>/<image>` with no double slash.

### TLS Certificate

Without the Terraform module and without cert-manager, you supply the certificate. Set `TLS_CRT_FILE` and `TLS_KEY_FILE`, and the installer seeds the `lilt-com-tls` secret once.

<Warning>
  The certificate must cover all of these names. They are siblings, not subdomains, so a single `*.<SUBDOMAIN>.<DNS_DOMAIN>` wildcard is not enough:

  ```
  *.<SUBDOMAIN>.<DNS_DOMAIN>
  <SUBDOMAIN>.<DNS_DOMAIN>
  core-api-<SUBDOMAIN>.<DNS_DOMAIN>
  connectors-api-<SUBDOMAIN>.<DNS_DOMAIN>
  wso2-<SUBDOMAIN>.<DNS_DOMAIN>
  ```

  If `ENABLE_VAULT_UI=true`, add the Vault UI host as well. Miss one and browsers look correct while API clients fail hostname verification, which reads as a TLS bug rather than as a missing name.
</Warning>

Do not set `TLS_CRT_FILE` together with `ENABLE_CERT_MANAGER=true`. The installer skips the file-seed step when cert-manager is on, to keep two owners off the same secret.

### DNS Records

Set `ENABLE_DNS=false` if you create DNS records with your own tooling. Point each LILT hostname at the Network Load Balancer that the Istio ingress gateway provisions. Read its address after the install with:

```bash theme={null}
kubectl get svc -n istio-ingressgateway
```

## Turn Off What the Cluster Already Has

The EKS entrypoint never installs the self-hosted infrastructure that the on-premises flavor brings, so there is nothing to disable for networking, storage, or load balancing.

Set these to `false` for anything your cluster already runs, so that the installer does not install a second copy:

| Variable                     | Component                    |
| ---------------------------- | ---------------------------- |
| `ENABLE_CLUSTER_AUTOSCALER`  | Cluster Autoscaler           |
| `ENABLE_METRICS_SERVER`      | metrics-server               |
| `ENABLE_PROMETHEUS`          | Prometheus                   |
| `ENABLE_CERT_MANAGER`        | cert-manager                 |
| `ENABLE_NVIDIA_GPU_OPERATOR` | NVIDIA GPU Operator          |
| `ENABLE_CLUSTER_PREREQS`     | The `ebs-gp3` StorageClasses |

<Warning>
  The `enable_cloudwatch_observability` EKS add-on injects OpenTelemetry auto-instrumentation into every pod through `NODE_OPTIONS`. MongoDB's health probes shell out to `mongosh`, which is a Node.js program, so each probe loads the agent, exceeds its 5-second timeout, and pushes the container past its memory limit into a restart loop. If you run that add-on, raise the MongoDB container's memory limit or exclude the `lilt` namespace from injection.
</Warning>

## Install

```bash theme={null}
sh install-lilt-eks.sh 2>&1 | tee /var/log/lilt-install.log
```

If your cluster's API endpoint is private, run this from inside the VPC. See [Install from a bastion](/kb/install-from-a-bastion).

The rest of the process, including phased bring-up, secrets, verification, and recovering from a failed component, is the same on both paths. See [Install System (AWS EKS)](/kb/install-system-aws-eks).
