---
title: Cluster types compared
description: Compare Amazon EKS, Azure Kubernetes Service (AKS), Red Hat OpenShift, and K3s before you install OpenLM Platform on one of them.
product: OpenLM Platform
---

OpenLM Platform installs the same way on every cluster type: same chart, same images, same steps. What changes is the cluster around it: how traffic comes in, which storage class you use, how you configure the nodes, and which managed data services you can use.

## At a glance

The following table compares the four cluster types:

| | Amazon EKS | AKS | Red Hat OpenShift | K3s |
|---|---|---|---|---|
| **Ingress** | Traefik or ingress-nginx behind an NLB | ingress-nginx or Traefik behind the Azure LB | OpenShift Routes (router) | Built-in Traefik |
| **`INGRESS_CLASS`** | `traefik` / `nginx` | `nginx` / `traefik` | (not used) | `traefik` |
| **`STORAGE_CLASS`** | `gp3` (EBS CSI) | `managed-csi` (Azure Disk) | cluster's block class, for example `gp3-csi`, `managed-csi`, `thin-csi` | `local-path` |
| **TLS terminated at** | Ingress controller | Ingress controller | Router (edge) | Traefik |
| **Pod user IDs** | Set by the chart | Set by the chart | **Assigned by OpenShift** (`useOpenShift: true`) | Set by the chart |
| **Node placement** | Optional (node group labels) | Optional (node pool labels) | Usually off (you can't label nodes) | Usually off (one or few nodes) |
| **SQL Server** | RDS for SQL Server, or your own | Azure SQL Database / Elastic Pool, or your own | Any reachable SQL Server | Your own |
| **Redis** | ElastiCache (Redis/Valkey) | Azure Managed Redis / Azure Cache | Any | Your own |
| **Kafka** | Amazon MSK or your own | Your own or Confluent Cloud | Your own (an operator, for example Strimzi) | Your own |
| **MongoDB** | MongoDB Atlas or your own (not DocumentDB) | MongoDB Atlas or your own (not Cosmos DB) | Atlas or your own | Your own |
| **Extra steps** | NLB, node file-watch limit | Firewall rules for the NAT IP | OpenShift values file, extra Routes, certificate | Redirect, DNS rewrite |

Each platform page covers the same topics in the same order: before you start, ingress, storage, node settings, values, data services, and platform-specific checks. Open the page for your cluster type:

- [Amazon EKS](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/eks)
- [Azure Kubernetes Service (AKS)](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/aks)
- [Red Hat OpenShift](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/openshift) (including ROSA and ARO)
- [K3s](https://www.openlm.com/documentation/cloud/deployment-operations/on-premise/deployment-guide/kubernetes/k3s)

## Node settings that apply everywhere

OpenLM Platform starts about 100 .NET services, so set two Linux file-watch limits on every node that runs them:

| Setting | Minimum | Why |
|---|---|---|
| `fs.inotify.max_user_instances` | 8192 | Each service watches its configuration files. The common default of 128 runs out, and pods fail with `too many open files`. |
| `fs.inotify.max_user_watches` | 524288 | Same reason |

If you manage the nodes, set the limits in `/etc/sysctl.d/`. If you can't, set them on every node with a small DaemonSet. The DaemonSet runs privileged, which your cluster policy might forbid:

```yaml
apiVersion: apps/v1
kind: DaemonSet
metadata: { name: openlm-node-sysctl, namespace: kube-system }
spec:
  selector: { matchLabels: { app: openlm-node-sysctl } }
  template:
    metadata: { labels: { app: openlm-node-sysctl } }
    spec:
      initContainers:
        - name: sysctl
          image: public.ecr.aws/docker/library/busybox:stable
          securityContext: { privileged: true }
          command: ["sh", "-c", "sysctl -w fs.inotify.max_user_instances=8192 fs.inotify.max_user_watches=524288"]
      containers:
        - name: wait
          image: public.ecr.aws/docker/library/busybox:stable
          command: ["sleep", "2147483647"]
          resources: { requests: { cpu: 1m, memory: 8Mi }, limits: { memory: 16Mi } }
      tolerations: [{ operator: Exists }]
```

To check the value, run this command on a node or from a debug pod:

```bash
kubectl debug node/<node> -it --image=public.ecr.aws/docker/library/busybox:stable -- cat /proc/sys/fs/inotify/max_user_instances
```
