Skip to content

Install

Reference architectures

What you provision and what the chart provisions, per cloud, before you run helm install

Provision a Kubernetes cluster, durable database storage, object storage, networking, and secrets before installing Sim. The Helm chart installs application workloads on that infrastructure; it does not provision cloud resources.

There is no official Terraform module or CloudFormation template. Call the chart from your infrastructure as code (IaC), for example with Terraform's helm_release or a Helm pipeline task.

The boundary

The chart bundles PostgreSQL and Redis for evaluation. For production, decide how each stateful dependency is backed up, restored, and made available.

ComponentChart defaultProduction
App, realtime, migrationsDeployedDeployed by the chart
Scheduled jobs (CronJobs)DeployedDeployed by the chart
PostgreSQLDeployed in-clusterReplace with managed Postgres — set externalDatabase.* and postgresql.enabled: false
RedisDeployed in-clusterReplace with a managed cache, or keep the bundled one — it holds no committed data
Object storageNone — local diskRequired. S3, Azure Blob, or GCS. Local disk is lost when a container is recreated and is not shared across replicas
IngressOffYou install the controller; the chart renders the Ingress
TLS certificatesOffYou provision them
Remote sandboxOffRequired for Python, Shell, and imported JavaScript — a provider and an immutable Function image. See Sandboxes
Pi executionOffA separate image from the Function one, set with E2B_PI_TEMPLATE_ID (a template name, an alias, or an immutable <template>:<build-id> ref) or DAYTONA_PI_SNAPSHOT_ID. Unlike the Function base these are not format-validated, but execution still fails closed when unset
PII redaction, Ollama, telemetry collectorOffOptional, off unless you enable them

The bundled Postgres uses a 10 Gi ReadWriteOnce volume and is intended for evaluation. Moving to managed Postgres is the single most important production change.

Per-cloud requirements

Use helm/sim/examples/values-aws.yaml as a starting point. It configures EBS GP3 storage, ALB ingress with AWS Certificate Manager, IRSA-style ServiceAccount annotations, and GPU tolerations for Ollama. Ollama itself ships disabled, and its node selectors are present but commented out.

You provision

ResourceNotes
EKS clusterA supported cloud-provider Kubernetes release compatible with the chart's >=1.25 minimum
EBS CSI driver add-onFor a standard EKS cluster using the EBS CSI provisioner, install aws-ebs-csi-driver with the cluster name and region. Match the StorageClass provisioner to the cluster's storage mode
gp3 StorageClassThe example selects gp3. Confirm that StorageClass exists and uses the provisioner installed in your cluster; create it or select an existing class before installing
AWS Load Balancer ControllerRequired for ALB ingress
ACM certificateALB discovers it from the ingress hosts, or pin it with alb.ingress.kubernetes.io/certificate-arn
RDS PostgreSQLWith the vector extension available. Reachable from the cluster subnets
S3 bucketsOne per file purpose — see Object storage
ElastiCacheOptional; the bundled Redis is a supported alternative

Identity. Bind an IAM role to the ServiceAccount with IRSA rather than issuing static keys. The role needs S3 access to the buckets you configured; grant nothing else unless you have enabled a feature that needs it.

Timeouts. ALB's default idle timeout will cut long-running executions and websockets. See Networking before you go live.

Secrets

The chart offers three strategies. Pick one before you write any IaC, because it decides what your pipeline has to create.

StrategyWhat your IaC createsWhen
Inline (app.env, or --set)NothingEvaluation. Values land in your values file, your shell history, and helm get values
app.secrets.existingSecret.enabled + .nameA Kubernetes Secret carrying every key the app needs, under the standard key names — it is consumed wholesale via envFrom, so key remapping is not supportedYou already manage secrets out of band
External Secrets OperatorThe operator itself, a ClusterSecretStore or SecretStore named in externalSecrets.secretStoreRef.name, entries in your cloud's secret manager, and externalSecrets.remoteRefs.app.<KEY> mappingsMost production deployments

Non-inline modes handle missing keys differently:

  • existingSecret fails quietly. The chart renders no Secret of its own, so a key absent from yours and from app.env is simply empty at runtime. A key you also set in app.env is inlined onto the pod spec, where it shadows the Secret — so the Secret is not always the source of truth.
  • External Secrets fails loudly. The chart refuses to render when a key is set in app.env but not mapped, on the grounds that a silently empty secret is worse than a failed install.

See Security for the full secret inventory, which keys are unrecoverable if lost, and what to back up.

Sizing

ComponentRequestsLimits
app4 Gi / 1000m8 Gi / 2000m
realtime512 Mi / 250m1 Gi / 500m
PostgreSQL (bundled)1 Gi / 500m2 Gi (no CPU limit)

These are chart defaults, not capacity benchmarks. Measure memory, CPU, execution concurrency, and database connections with representative workloads. See Scaling for pool budgets and sizing estimates. A node must fit an app pod plus system overhead.

Calling the chart from Terraform

If you already run Terraform, the chart is the resource to wrap — not something to reimplement. Point repository at the OCI registry and pin version; there is no need to vendor the repo.

Code
resource "helm_release" "sim" {
  name             = "sim"
  namespace        = "sim"
  create_namespace = true

  # Always pin `version`. Without it Terraform resolves the newest published
  # chart at apply time, which is how an unplanned apply moves Sim to a new
  # release with new migrations.
  repository = "oci://ghcr.io/simstudioai/charts"
  chart      = "sim"
  version    = "1.11.8"

  # Or the classic repository, if your tooling does not speak OCI:
  #   repository = "https://charts.sim.ai"

  # Your own values file. The examples under helm/sim/examples/ carry
  # placeholder secrets and are starting points, not deployable as-is.
  values = [file("${path.module}/values-aws.yaml")]

  # helm provider v3 syntax. On v2 each of these is a set_sensitive { } block.
  set_sensitive = [
    { name = "app.env.BETTER_AUTH_SECRET", value = var.better_auth_secret },
    { name = "app.env.ENCRYPTION_KEY", value = var.encryption_key },
    { name = "app.env.API_ENCRYPTION_KEY", value = var.api_encryption_key },
    { name = "app.env.INTERNAL_API_SECRET", value = var.internal_api_secret },
    { name = "app.env.CRON_SECRET", value = var.cron_secret },
    # Only when the bundled Postgres is in use. With managed Postgres, set
    # externalDatabase.* and postgresql.enabled=false instead.
    { name = "postgresql.auth.password", value = var.postgres_password },
  ]
}

Pin version above. Empty image tags use the selected chart's appVersion, so a pinned chart also selects that default app version. Explicit image tags or digests override it; pin them separately when you need that control, and keep app, realtime, and migrations aligned. Chart 1.11.8 was published with app version v0.9.17; local checkout metadata can differ. See Upgrades.

Was this helpful?
Suggest an edit