---
title: Amazon EKS
description: "Install OpenLM Platform on Amazon EKS: ingress behind an NLB, gp3 storage, node groups, pod limits, and AWS data services."
product: OpenLM Platform
---

Read this page before [step 1](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/install/step-1-prepare-cluster). It covers what's specific to Amazon EKS. Everything else follows the standard installation steps.

## Before you start

Plan the cluster with these recommendations:

| Item | Recommendation |
|---|---|
| Kubernetes | A supported EKS version (1.29 or newer) |
| Nodes | Managed node groups or EKS Auto Mode. For the standard set: 3 × `m6i.2xlarge` (8 vCPU / 32 GiB), in private subnets. Larger sites: see [Sizing](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/before-you-start/sizing). |
| Networking | VPC with private subnets for nodes and data services, public subnets for the load balancer, a NAT gateway for outbound traffic |
| Add-ons | Amazon VPC CNI, CoreDNS, kube-proxy, **Amazon EBS CSI driver** (for managed node groups. Auto Mode has its own) |

### Pods per node

OpenLM Platform runs about 85 pods, so check how many pods your nodes can hold. With the Amazon VPC CNI, each pod takes an IP address from the node's network interfaces, so the number of pods per node depends on the instance type: 58 on an `m6i.xlarge`, for example. Use enough nodes, or turn on **prefix delegation** in the VPC CNI (`ENABLE_PREFIX_DELEGATION=true`) to raise the limit. Pods stuck in `Pending` with `Too many pods` mean the nodes have reached this limit.

## Ingress

Install **Traefik** or **ingress-nginx**, exposed through an AWS **Network Load Balancer**. The controller then serves the certificate from the `openlm-lb-cert` secret, as OpenLM Platform expects.

The following example installs Traefik with the `traefik/traefik` Helm chart:

```yaml
# traefik-values.yaml
service:
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: external          # needs the AWS Load Balancer Controller
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
    service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing   # or internal
ports:
  web:
    http:
      redirections:
        entryPoint: { to: websecure, scheme: https, permanent: true }
```

```bash
helm repo add traefik https://traefik.github.io/charts
helm install traefik traefik/traefik -n ingress --create-namespace -f traefik-values.yaml
kubectl -n ingress get service traefik    # EXTERNAL-IP is the NLB host name for your DNS CNAME
```

On **EKS Auto Mode**, the built-in load balancing creates the NLB, so keep only the `aws-load-balancer-scheme` annotation.

Then set `INGRESS_CLASS=traefik` in your worksheet.

:::warning[Not the ALB]
An Application Load Balancer created from an Ingress (`ingressClassName: alb`) terminates TLS with a certificate from AWS Certificate Manager, not with the cluster's secret, and needs its own annotations on the Ingress. The OpenLM Platform Ingress isn't built for it. Use the NLB with Traefik or ingress-nginx instead.
:::

If you restrict the NLB's allowed source ranges, include the NAT gateway's public IP, because pods in private subnets reach an internet-facing NLB through the NAT gateway. An **internal** NLB avoids this entirely.

## Storage

Set `STORAGE_CLASS` to the class that matches your node type:

| Cluster | `STORAGE_CLASS` | Notes |
|---|---|---|
| Managed node groups | `gp3` | Create it if it doesn't exist. EBS CSI provisioner `ebs.csi.aws.com`, `type: gp3`. |
| EKS Auto Mode | For example `auto-ebs-gp3` | Provisioner `ebs.csi.eks.amazonaws.com`. Auto Mode ships no default class: create one. |

The following manifest creates the `gp3` class:

```yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata: { name: gp3 }
provisioner: ebs.csi.aws.com             # Auto Mode: ebs.csi.eks.amazonaws.com
parameters: { type: gp3, encrypted: "true" }
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
```

## Node settings

Set the [file-watch limits](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/platforms/index#node-settings-that-apply-everywhere) in the node group's launch template (user data), or with the DaemonSet. On Auto Mode, check the value on a node first, because you can't change node settings there.

## Node groups

To use [node placement](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/concepts/node-placement), which is optional, give the node groups the label and, for exclusive nodes, the taint:

```hcl
# Terraform (aws_eks_node_group)
labels = { "openlm.com/role" = "main" }
taint {
  key    = "openlm.com/role"
  value  = "main"
  effect = "NO_SCHEDULE"
}
```

Add a second group with `spark` for the data-processing jobs. The values are exactly `main` and `spark`.

## Values

Amazon EKS needs no values beyond what step 4 gives you. If you use node groups with labels, also set `global.affinity.enabled: true` and `global.taints.enabled: true`.

## Data services

Use these AWS services, or your own, for the data services:

| Service | AWS option | Worksheet settings |
|---|---|---|
| SQL Server | **Amazon RDS for SQL Server** (Standard or Enterprise, Express only for tests), not publicly accessible | `SQL_HOST` = the RDS endpoint, `SQL_ENCRYPT=True` |
| Redis | **Amazon ElastiCache** for Redis or Valkey 7.x, with in-transit encryption and an auth token | `REDIS_TLS=true`, `REDIS_PASSWORD` = the auth token |
| Kafka | **Amazon MSK** or your own Kafka | Use a plaintext listener inside the VPC (port 9092). For MSK with only TLS or SASL/SCRAM listeners, contact OpenLM first. |
| MongoDB | **MongoDB Atlas** (VPC peering or PrivateLink), or MongoDB in the cluster | `MONGO_URI` from Atlas, with its options. **Amazon DocumentDB isn't supported.** |

To let the cluster reach the data services, allow inbound traffic from the **EKS cluster security group** on 1433 (SQL), 6379 (Redis), and 9092 (Kafka) in each service's security group.

Create the four databases on RDS as in [step 2](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/install/step-2-data-services), connected as the administrator user you set when you created the RDS instance (the AWS console calls it the **Master username**).

## Checks specific to EKS

Confirm the Amazon EKS settings with these commands:

- `kubectl get nodes -o wide`: all nodes `Ready`, in private subnets.
- `kubectl -n ingress get service`: the controller has an `EXTERNAL-IP` (a `…elb.amazonaws.com` name).
- `kubectl get storageclass`: your `STORAGE_CLASS` exists.
