
## Install SDR Orchestrator on Kubernetes

URL: https://docs.atlan.com/product/connections/self-deployed-runtime/how-tos/install-orchestrator-on-kubernetes

> Install Self-Deployed Runtime Orchestrator on Kubernetes for automated app lifecycle management

# Install SDR orchestrator on Kubernetes

:::warning Use the guided install wizard instead
**New Self-Deployed Runtime setups are encouraged to use the [guided install wizard](https://docs.atlan.com/llms/platform/self-deployed-runtime/install-guided/llms.txt).** It assembles a complete guide tailored to your lifecycle mode, platform, and image procurement on a single page—and it's where new setup options (for example, HTTP proxy and custom CA trust) are documented going forward.

This page is kept for existing users who already reference it and may not include the latest steps.
:::

:::warning Important!
Some capabilities shown here may require additional enablement or licensing. Contact your Atlan representative for details.
:::

This guide walks you through deploying the SDR Orchestrator on a Kubernetes cluster. You download the SDR package, fill in a single configuration file, install via Helm, and verify the connection in the Atlan UI. The SDR Orchestrator then automatically manages the full lifecycle of Atlan apps—installation, upgrades, health checks, and self-updates—without any manual intervention.

For Docker or Podman-based installations, see [Install SDR Orchestrator on Docker/Podman](https://docs.atlan.com/llms/platform/self-deployed-runtime/install-with-orchestrator/llms.txt).

## System requirements

- **Kubernetes cluster**: EKS, GKE, AKS, k3s, OpenShift, RKE2, or any CNCF-conformant distribution. See [supported distributions](https://docs.atlan.com/product/connections/self-deployed-runtime/references/sdr-orchestrator?platform=kubernetes).
- **Kubernetes version**: 1.24+
- **CLI tools**: `kubectl` and `helm` (v3+) configured with access to the target cluster
- **SDR Orchestrator resources**:
 - CPU: 100m request, 500m limit
 - Memory: 256Mi request, 512Mi limit
- **Per app resources**: 0.5–1 vCPU, 512 MB–1 GB memory (varies by app)

## Prerequisites

Setup takes 10–15 minutes. Gather credentials from your infrastructure team beforehand.

Before you begin, verify you have:
- **kubectl** and **helm** (v3+) configured with administrative access to the target cluster (ability to create namespaces, roles, deployments)
- A **Docker Hub Personal Access Token (PAT)** from your Atlan representative (required to pull private app images)
 - The PAT is regenerated periodically—contact your Atlan representative for the latest token.
- **Object storage**: AWS S3, Google Cloud Storage, or Azure Blob Storage. See [Dapr object store docs](https://docs.dapr.io/reference/components-reference/supported-bindings/).
- **Secret store**: AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, or HashiCorp Vault. See [Dapr secret store docs](https://docs.dapr.io/reference/components-reference/supported-secret-stores/).
- **Outbound network connectivity** (HTTPS) from the cluster to:
 - `<tenant>.atlan.com`:Atlan API, auth, event ingress
 - `<tenant>-temporal.atlan.com:443`:Temporal workflow server
 - `docker.io`:pull app container images

## Download SDR package

Download the SDR package from Atlan. This archive contains the Helm chart, a pre-filled `values.yaml` template, and a README.

```bash
curl -fSL -o sdr-orchestrator-k8s.tar.gz \
 https://atlan-public.s3.eu-west-1.amazonaws.com/sdr-orchestrator-k8s-app/sdr-orchestrator-k8s.tar.gz
tar -xzf sdr-orchestrator-k8s.tar.gz
cd sdr-orchestrator-k8s
```

The extracted directory contains the following files:

```
sdr-orchestrator-k8s/
├── chart/ # Helm chart (do not modify)
├── values.yaml # Configuration file (edit this)
└── README.md # Quick reference
```

## Create namespace and registry credentials

Create the `atlan` namespace and a secret for pulling private app images from Docker Hub.

```bash
kubectl create namespace atlan

kubectl create secret docker-registry atlan-registry-creds \
 --namespace atlan \
 --docker-server=docker.io \
 --docker-username=YOUR_DOCKERHUB_USERNAME \
 --docker-password=YOUR_DOCKERHUB_PAT
```

Replace `YOUR_DOCKERHUB_USERNAME` and `YOUR_DOCKERHUB_PAT` with the credentials provided by your Atlan representative.

:::warning PAT rotation
The Docker Hub PAT is regenerated periodically. If pulls start failing, contact your Atlan representative for the latest token.
:::

## Generate OAuth credentials

SDR uses per-deployment OAuth credentials to authenticate with Atlan. Generate them before filling in `values.yaml`.

1. **Obtain an API token**: [Create an API token](https://docs.atlan.com/get-started/references/api-access#create-api-token) from the Atlan UI.

2. **Register your SDR deployment**: Using the API token from the previous step, run the following command:

 ```bash
 curl --location 'https://<tenant>.atlan.com/api/service/oauth-clients' \
 --header 'Content-Type: application/json' \
 --header 'Authorization: Bearer YOUR_API_TOKEN' \
 --data '{
 "displayName": "sdr-orchestrator",
 "description": "OAuth client for SDR Orchestrator",
 "scopes": ["events-app-permissions-scope","temporal-app-permissions-scope"]
 }'
 ```

 Replace `<tenant>` with your Atlan tenant name and `YOUR_API_TOKEN` with the token from step 1.

3. Save the `clientId` and `clientSecret` from the response—you'll need them in the next step.

## Configure values.yaml

Open `values.yaml` and fill in the required values. The SDR image tag is already pre-filled. **Don't change it.**

### Atlan identity

- **deploymentName**: A unique identifier for this SDR installation (for example, `mycompany-eks`). Lowercase letters, numbers, and hyphens only. Must start and end with a letter or number.
- **domain**: Your Atlan tenant domain (for example, `mycompany.atlan.com`). Don't include `https://`.

```yaml
sdr:
 enabled: true
 deploymentName: "mycompany-eks"

 credentials:
 clientId: "oauth-client-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
 clientSecret: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

 config:
 domain: "mycompany.atlan.com"
```

### Object storage

Self-Deployed Runtime needs a store for reading or writing files. Configure the object storage under `sdr.config.components`.

:::tip Don't see your preferred object store?
If your preferred object store isn't listed here, [reach out to Atlan support](https://docs.atlan.com/support/submit-request). Support for additional object stores may be available.
:::

### AWS S3

Add AWS S3 configuration. For more information, see [AWS S3 Binding Spec](https://docs.dapr.io/reference/components-reference/supported-bindings/s3/).

```yaml
sdr:
 config:
 components:
 objectstore:
 type: bindings.aws.s3
 version: v1
 metadata:
 - name: accessKey # optional, leave empty for IAM / IRSA authentication
 value: ""
 - name: secretKey # optional, leave empty for IAM / IRSA authentication
 value: ""
 - name: bucket # required
 value: "<bucket-name>"
 - name: region # required
 value: "<bucket-region>"
 - name: forcePathStyle
 value: "true"
```

#### IAM permissions for instance role or IRSA authentication

When `accessKey` and `secretKey` are empty, the SDR uses the node's IAM role (or IRSA) to access S3. Attach the following minimum policy to the role:

```json
{
 "Version": "2012-10-17",
 "Statement": [
 {
 "Effect": "Allow",
 "Action": ["s3:ListBucket"],
 "Resource": "arn:aws:s3:::<bucket-name>"
 },
 {
 "Effect": "Allow",
 "Action": [
 "s3:PutObject",
 "s3:GetObject",
 "s3:DeleteObject"
 ],
 "Resource": "arn:aws:s3:::<bucket-name>/*"
 }
 ]
}
```

- Replace `<bucket-name>` with your objectstore bucket name.
- If the bucket uses SSE-KMS encryption, also grant `kms:GenerateDataKey` and `kms:Decrypt` on the KMS key used to encrypt the bucket.

:::caution
Connection checks pass without these permissions. Extraction activities fail with `AccessDenied` only when the SDR writes metadata to the bucket during a crawl.
:::

### Google Cloud Storage

Add Google Cloud Storage configuration. For more information, see [GCP Storage Bucket binding spec](https://docs.dapr.io/reference/components-reference/supported-bindings/gcpbucket/).

```yaml
sdr:
 config:
 components:
 objectstore:
 type: bindings.gcp.bucket
 version: v1
 metadata:
 - name: bucket
 value: "<your-gcs-bucket-name>"
 - name: type
 value: "service_account"
 - name: project_id
 value: "<your-gcp-project-id>"
```

### Azure Blob Storage

Add Azure Blob Storage configuration. For more information, see [Azure Blob Storage binding spec](https://docs.dapr.io/reference/components-reference/supported-bindings/blobstorage/).

```yaml
sdr:
 config:
 components:
 objectstore:
 type: bindings.azure.blobstorage
 version: v1
 metadata:
 - name: accountName
 value: "<your-storage-account-name>"
 - name: accountKey
 value: "<your-storage-account-key>"
 - name: containerName
 value: "<your-container-name>"
```

### Secret store

Self-Deployed Runtime fetches secrets from a secret store to connect to source systems. Configure the secret store under the same `sdr.config.components` section.

:::info Did you know?
Dapr supports additional secret stores. For more information, see [Dapr secret store documentation](https://docs.dapr.io/reference/components-reference/supported-secret-stores/).
:::

### AWS Secrets Manager

Add AWS Secrets Manager configuration. For more information, see [AWS Secrets Manager](https://docs.dapr.io/reference/components-reference/supported-secret-stores/aws-secret-manager/).

```yaml
sdr:
 config:
 components:
 secretstore:
 type: secretstores.aws.secretmanager
 version: v1
 metadata:
 - name: region # required
 value: "<secret-region>"
 - name: accessKey # optional, leave empty for IAM / IRSA
 value: ""
 - name: secretKey # optional, leave empty for IAM / IRSA
 value: ""
```

If you are using IAM role / IRSA authentication, leave `accessKey` and `secretKey` empty.

If you are using an IAM user instead, set:
- `accessKey` to the IAM user's access key ID
- `secretKey` to the IAM user's secret access key

That IAM user must have permission to read the target secret from AWS Secrets Manager:

```json
{
 "Version": "2012-10-17",
 "Statement": [
 {
 "Effect": "Allow",
 "Action": [
 "secretsmanager:GetSecretValue",
 "secretsmanager:DescribeSecret"
 ],
 "Resource": "arn:aws:secretsmanager:<region>:<account-id>:secret:<secret-name>*"
 }
 ]
}
```

:::note
Include the trailing `*` in the secret ARN. AWS appends a random suffix to secret names in the ARN, so omitting it can cause access failures.
:::

### Azure Key Vault

Add Azure Key Vault configuration. For more information, see [Azure Key Vault secret store](https://docs.dapr.io/reference/components-reference/supported-secret-stores/azure-keyvault/).

```yaml
sdr:
 config:
 components:
 secretstore:
 type: secretstores.azure.keyvault
 version: v1
 metadata:
 - name: vaultName
 value: "<your-keyvault-name>"
 - name: azureTenantId
 value: "<your-tenant-id>"
 - name: azureClientId
 value: "<your-client-id>"
 - name: azureClientSecret
 value: "<your-client-secret>"
```

### GCP Secret Manager

Add Google Cloud Secret Manager configuration. For more information, see [GCP Secret Manager](https://docs.dapr.io/reference/components-reference/supported-secret-stores/gcp-secret-manager/).

```yaml
sdr:
 config:
 components:
 secretstore:
 type: secretstores.gcp.secretmanager
 version: v1
 metadata:
 - name: type
 value: "service_account"
 - name: project_id
 value: "<project-id>"
 - name: private_key_id
 value: "<private-key-id>"
 - name: private_key
 value: "<private-key>"
 - name: client_email
 value: "<client-email>"
 - name: client_id
 value: "<client-id>"
 - name: auth_uri
 value: "https://accounts.google.com/o/oauth2/auth"
 - name: token_uri
 value: "https://oauth2.googleapis.com/token"
 - name: auth_provider_x509_cert_url
 value: "https://www.googleapis.com/oauth2/v1/certs"
 - name: client_x509_cert_url
 value: "https://www.googleapis.com/robot/v1/metadata/x509/<client-email>"
```

### HashiCorp Vault

Add HashiCorp Vault configuration. For more information, see [HashiCorp Vault](https://docs.dapr.io/reference/components-reference/supported-secret-stores/hashicorp-vault/).

```yaml
sdr:
 config:
 components:
 secretstore:
 type: secretstores.hashicorp.vault
 version: v1
 metadata:
 - name: vaultAddr
 value: "[vault_address]"
 - name: vaultToken
 value: "[vault_token]"
 - name: vaultKVPrefix
 value: "dapr"
 - name: enginePath
 value: "secret"
```

### Private container registry (optional)

If you mirror Atlan app images to your own registry, set `containerRegistryBase` in `values.yaml` to rewrite image URLs at deploy time. For example, `atlanhq/atlan-oracle-app:main-ec46120` becomes `myregistry.io/atlan/atlan-oracle-app:main-ec46120`.

```yaml
sdr:
 config:
 containerRegistryBase: "myregistry.io/atlan"
```

Leave this empty (or omit it) if pulling directly from Docker Hub.

:::tip Renamed images or a pollable workflow?
The `containerRegistryBase` rewrite assumes your registry keeps the same image names and tags. If your registry renames images or tags during replication—or you want a machine-readable source of truth for which images to mirror—use an image map in object storage instead. See [Keep a private registry in sync](https://docs.atlan.com/llms/platform/self-deployed-runtime/mirror-images-to-private-registry/llms.txt).
:::

### Sample values.yaml files

Below are complete, copy-paste-ready `values.yaml` snippets for common infrastructure combinations. Replace placeholder values with your actual credentials.

### AWS (EKS)

```yaml
image:
 repository: atlanhq/atlan-sdr-orchestrator-k8s
 tag: "<tag>" # pre-filled by the Marketplace download
 pullPolicy: Always

sdr:
 enabled: true
 deploymentName: "mycompany-eks"

 credentials:
 clientId: "oauth-client-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
 clientSecret: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

 imagePullSecrets:
 - name: atlan-registry-creds

 config:
 domain: "mycompany.atlan.com"
 components:
 objectstore:
 type: bindings.aws.s3
 version: v1
 metadata:
 - name: bucket
 value: "<your-bucket-name>"
 - name: region
 value: "us-east-1"
 - name: forcePathStyle
 value: "true"

 secretstore:
 type: secretstores.aws.secretmanager
 version: v1
 metadata:
 - name: region
 value: "us-east-1"
```

### GCP (GKE)

```yaml
image:
 repository: atlanhq/atlan-sdr-orchestrator-k8s
 tag: "<tag>" # pre-filled by the Marketplace download
 pullPolicy: Always

sdr:
 enabled: true
 deploymentName: "mycompany-gke"

 credentials:
 clientId: "oauth-client-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
 clientSecret: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

 imagePullSecrets:
 - name: atlan-registry-creds

 config:
 domain: "mycompany.atlan.com"
 components:
 objectstore:
 type: bindings.gcp.bucket
 version: v1
 metadata:
 - name: bucket
 value: "<your-gcs-bucket-name>"
 - name: type
 value: "service_account"
 - name: project_id
 value: "<your-gcp-project-id>"

 secretstore:
 type: secretstores.gcp.secretmanager
 version: v1
 metadata:
 - name: type
 value: "service_account"
 - name: project_id
 value: "<your-gcp-project-id>"
```

### Azure (AKS)

```yaml
image:
 repository: atlanhq/atlan-sdr-orchestrator-k8s
 tag: "<tag>" # pre-filled by the Marketplace download
 pullPolicy: Always

sdr:
 enabled: true
 deploymentName: "mycompany-aks"

 credentials:
 clientId: "oauth-client-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
 clientSecret: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

 imagePullSecrets:
 - name: atlan-registry-creds

 config:
 domain: "mycompany.atlan.com"
 components:
 objectstore:
 type: bindings.azure.blobstorage
 version: v1
 metadata:
 - name: accountName
 value: "<your-storage-account-name>"
 - name: accountKey
 value: "<your-storage-account-key>"
 - name: containerName
 value: "<your-container-name>"

 secretstore:
 type: secretstores.azure.keyvault
 version: v1
 metadata:
 - name: vaultName
 value: "<your-keyvault-name>"
 - name: azureTenantId
 value: "<your-tenant-id>"
 - name: azureClientId
 value: "<your-client-id>"
 - name: azureClientSecret
 value: "<your-client-secret>"
```

## Install SDR Orchestrator

Run `helm install` with the release name `atlan-sdr-<deployment_name>`. The release name **must** follow this pattern—it's required for the automatic self-update mechanism.

```bash
helm install atlan-sdr- ./chart \
 --namespace atlan \
 -f values.yaml
```

Replace `` with the value you set in `sdr.deploymentName`. For example:

```bash
helm install atlan-sdr-mycompany-eks ./chart \
 --namespace atlan \
 -f values.yaml
```

Helm creates all required resources in one command:

| Resource | Name | Purpose |
|----------|------|---------|
| Deployment | `atlan-sdr-<name>` | SDR orchestrator pod |
| Secret | `atlan-sdr-<name>-credentials` | OAuth + deployment credentials |
| ConfigMap | `atlan-sdr-<name>-config` | Domain, Dapr component specs |
| ServiceAccount | `atlan-sdr-<name>-serviceaccount` | K8s API identity |
| Role | `atlan-sdr-<name>-role` | Namespace-scoped permissions |
| RoleBinding | `atlan-sdr-<name>-rolebinding` | Binds role to service account |

For full details on what each resource does, see [SDR Orchestrator on Kubernetes](https://docs.atlan.com/product/connections/self-deployed-runtime/references/sdr-orchestrator?platform=kubernetes).

## Verify installation

1. **Check the SDR pod is running:**

 ```bash
 kubectl get pods -n atlan -l app=atlan-sdr
 ```

 Expected output:

 ```
 NAME READY STATUS RESTARTS AGE
 atlan-sdr-mycompany-eks-xxxxx-xxxxx 1/1 Running 0 2m
 ```

2. **Check logs** for "K8s SDR worker listening on task_queue" which confirms Temporal connectivity:

 ```bash
 kubectl logs -n atlan -l app=atlan-sdr --tail=50
 ```

 You can see:

 ```
 [entrypoint] Starting K8s SDR agent...
 [entrypoint] deployment_name=mycompany-eks
 [entrypoint] Generating SDR Dapr components from config.yaml...
 ...
 K8s SDR worker listening on task_queue=atlan-sdr-mycompany-eks
 ```

3. **Verify in Atlan UI:** Go to **Settings** > **Self-Deployed Runtimes**. Your deployment appears as "Connected."

4. **Install apps:** From the Atlan UI, navigate to the Marketplace, select an app, and choose your SDR as the deployment target. The SDR automatically creates the app Deployment with all necessary configurations.

## Automatic updates

The SDR Orchestrator manages two types of automatic updates:

- **App updates**: When a new app version is published to the marketplace, the reconciler detects the version mismatch and triggers an update via the SDR (checked every 60 minutes). The SDR runs `helm upgrade --install` with the new image tag, and K8s performs a rolling update.

- **SDR self-updates**: The SDR Orchestrator itself is also a marketplace app. When a new SDR version is published, the same reconciler triggers a self-update. The SDR runs `helm upgrade --reuse-values` with the new image tag, and K8s rolls the SDR pod to the new version.

No manual intervention is required for either type of update.

## Uninstall

To remove the SDR orchestrator and all managed apps:

```bash

# List all Helm releases in the atlan namespace

helm list -n atlan

# Uninstall each app first

helm uninstall oracle -n atlan
helm uninstall redshift -n atlan

# ... uninstall other apps

# Uninstall the SDR

helm uninstall atlan-sdr- -n atlan

# Clean up remaining resources

kubectl delete secret atlan-registry-creds -n atlan
kubectl delete namespace atlan
```

:::warning
Deleting the namespace removes all resources in it, including any app Deployments managed by the SDR.
:::

## Need help

If the SDR pod isn't starting or apps aren't deploying, check the logs:

```bash
kubectl logs -n atlan -l app=atlan-sdr --tail=100
```

Common issues:
- **"IP address not allowed"**: Your cluster's egress IP needs to be allowlisted on the Atlan tenant. Contact your Atlan representative.
- **"Authentication token refresh failed"**: Check OAuth credentials in `values.yaml` (`sdr.credentials.clientId` and `sdr.credentials.clientSecret`).
- **"ImagePullBackOff"**: Check registry credentials (`atlan-registry-creds` Secret). The Docker Hub PAT may need rotation.
- **Pod stuck in Pending**: Check cluster resource availability with `kubectl describe pod -n atlan`.
- **App pod CrashLoopBackOff**: Check the app pod logs. Common causes: misconfigured object storage or secret store in `values.yaml`.

For additional troubleshooting, see the [SDR Orchestrator FAQ](https://docs.atlan.com/product/connections/self-deployed-runtime/faq/sdr-orchestrator-faq).

## Next steps

Once the SDR shows as **Connected** in Atlan UI:

1. Navigate to the **Marketplace** and pick an app (for example, Oracle connector).
2. Click **Install** and select your SDR as the deployment target.
3. The SDR handles everything—creating the Deployment, configuring Dapr components, health checking, and reporting success back to Atlan. No terminal commands are needed.

## See also

- [Install SDR Orchestrator on Docker/Podman](https://docs.atlan.com/llms/platform/self-deployed-runtime/install-with-orchestrator/llms.txt): For VM-based installations using Docker or Podman.
- [SDR Orchestrator](https://docs.atlan.com/product/connections/self-deployed-runtime/references/sdr-orchestrator): Components, communication model, and how deployment management works.
- [SDR Orchestrator on Kubernetes](https://docs.atlan.com/product/connections/self-deployed-runtime/references/sdr-orchestrator?platform=kubernetes): RBAC, Helm charts, environment variables, and K8s-specific operational details.
- [SDR Orchestrator FAQ](https://docs.atlan.com/product/connections/self-deployed-runtime/faq/sdr-orchestrator-faq): Troubleshooting, monitoring, and common issues.
- [Configure network security](https://docs.atlan.com/llms/platform/self-deployed-runtime/configure-network-security/llms.txt): Firewall rules for outbound-only communication.

---
