---
schema_version: "1"
id: 8824a9eac88c1d0dca22545ca43e8f06b28bc06b42adde00d9218f82b55f901c
title: Helm Chart Deploy
collection: tableau
version: next
locale: en-us
portal_url: https://docs.salesforce.com/tableau/next/en-us/server-linux/server-helm-deploy.md
canonical_url: https://help.tableau.com/v0.0/server-linux/en-us/server-helm-deploy.htm
source_site: help.tableau.com
content_type: documentation
content_hash: dd8e86345369ff7c5d56ee02977ae60feaac1d6bfaccd229e5250c96778f1a33
description: "Important: This documentation assumes a knowledge of Helm and Helm charts and does not attempt to provide detailed, prescriptive examples"
---
[Skip to main content](#main-content)

# Tableau Server Helm Chart - Deploy

**Important**: This documentation assumes a knowledge of Helm and Helm charts and does not attempt to provide detailed, prescriptive examples. It is designed for customers who are familiar with both Tableau Server and Helm and Helm charts.

This topic walks you through the high level steps of deploying Tableau Server on Kubernetes using a Helm chart.

## Prerequisites

Before you begin, ensure you have met the prerequisites. For more information, see [Tableau Server Helm Chart - Prerequisites](https://help.tableau.com/v0.0/server-linux/en-us/server-helm-prerequisites.htm).

### Helm Chart Download

The Helm charts will be shipped as part of the Tableau Server in a Container setup tool (`tableau-server-container-setup-tool-<version>.tar.gz`) and can be downloaded from the [Tableau Server download](http://tableau.com/support/releases/server/latest) page.

After extraction, the required Helm chart files are located in the `helm/tableau` directory.

## Quick overview using a Helm chart to deploy Tableau Server

**Important**: This is a basic, high-level description of deploying Tableau Server using Helm charts. It is not intended to be a complete procedure. It assumes knowledge of Helm and Helm charts.

Before starting, make sure you have met the prerequisites for deploying Tableau Server using Helm charts. See [Tableau Server Helm Chart - Prerequisites](https://help.tableau.com/v0.0/server-linux/en-us/server-helm-prerequisites.htm) for details.

### Add your license key to values.yaml

Edit `values.yaml` and set your license key.

### Deploy a single-node Tableau Server

Deploy a single-node instance of Tableau Server by executing these commands at a prompt (substitute your release namespace for `<namespace>`, for example `tableau` or `default`):

helm install tableau-server ./helm/tableau-server \\  
  -n <namespace> \\  
  --create-namespace \\
  -f ./helm/tableau-server/values-single.yaml

### Deploy a multi-node Tableau Server

Deploy a multi-node instance of Server by executing these commands at a prompt, using the same namespace convention as above:

helm install tableau-server ./helm/tableau-server \\  
\-n <namespace> \\  
\--create-namespace \\
-f ./helm/tableau-server/values-multinode.yaml

## EKS multinode runbook (namespace + static bootstrap PV)

This section describes the order of operations for EKS: dedicated namespace, EFS CSI add-on, IAM on the node role, static bootstrap PV, and Helm.

1. Create a dedicated namespace.
    
    This must match `claimFef.namespace` on the bootstrap PV. This example uses `tableau`.
    
    kubectl create namespace tableau-server
    kubectl get namespace tableau
2. Confirm the EFS CSI add-on exists.
    
    If the add-on is missing, create it and wait until the status is `ACTIVE`:
    
    kubectl get csidriver efs.csi.aws.com
    aws eks describe-addon \\
      --cluster-name <cluster-name> \\  
      --addon-name aws-efs-csi-driver \\
      --region <region> \\
      --query 'addon.status'
3. Confirm the Storageclass:
    
    `efs-bootstrap` Storageclass — apply if not already present. See [Amazon Elastic Kubernetes Service (EKS) prerequisites](https://help.tableau.com/v0.0/server-linux/en-us/server-helm-prerequisites.htm#EKS-Prereq-storageclass) for details.
    
    kubectl get csidriver efs.csi.aws.com
    aws eks describe-addon \\
      --cluster-name <cluster-name> \\  
      --addon-name aws-efs-csi-driver \\
      --region <region> \\
      --query 'addon.status'
4. Confirm the Static bootstrap PV.
    
    `claimRef` must refer to the same namespace and PVC name the Helm chart creates (`tableau-server-bootstrap`). Replace `fs-...` with your EFS file system ID:
    
    cat > /tmp/tableau-bootstrap-pv.yaml <<'EOF'
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: tableau-bootstrap-pv
    spec:
      capacity:
        storage: 1Gi
      volumeMode: Filesystem
      accessModes:
        - ReadWriteMany
    persistentVolumeReclaimPolicy: Retain
    storageClassName: efs-bootstrap
    claimRef:
      namespace: tableau
      name: tableau-server-bootstrap
    csi:
      driver: efs.csi.aws.com
      volumeHandle: <fs-xxxxxxxxxxxxxxxxx>
    EOF
    kubectl apply -f /tmp/tableau-bootstrap-pv.yaml
    kubectl get pv tableau-bootstrap-pv
5. IAM on the node instance role.
    
    Attach EFS client and EC2 read-only policies. See [Amazon Elastic Kubernetes Service (EKS) prerequisites](https://help.tableau.com/v0.0/server-linux/en-us/server-helm-prerequisites.htm#EKS-Prereq-storageclass) for resolving `<your-node-instance-role>` from the node group.
    
    `efs-bootstrap` Storageclass — apply if not already present. See [Amazon Elastic Kubernetes Service (EKS) prerequisites](https://help.tableau.com/v0.0/server-linux/en-us/server-helm-prerequisites.htm#EKS-Prereq-storageclass) for details.
    
    kubectl get csidriver efs.csi.aws.com
    aws eks describe-addon \\
      --cluster-name <cluster-name> \\  
      --addon-name aws-efs-csi-driver \\
      --region <region> \\
      --query 'addon.status'
6. Values
    
    In `values-multinode.yaml` (or an overlay), set manual static PV mode
    
    persistence:
      bootstrap:  
        createPV: false  
        volumeName: tableau-bootstrap-pv  
        storageClass: efs-bootstrap
7. Ensure `image.repository`, `image.tag`, and secrets/license are set as required.
8. Install the Helm chart
    
    Install the chart into the same namespace as the PV `claimRef`:
    
    helm install tableau-server ./helm/tableau-server \\
      -n tableau \\  
      -f ./helm/tableau-server/values-multinode.yaml
9. Verify storage and pods:
    
    kubectl get pv,pvc -n tableau
    kubectl get pods -n tableau -w
10. Data PVC status
    
    Data PVCs may show `Pending` briefly until EBS volumes attach. All PVCs should transition to `Bound`, then `Running`, and eventually `READY 1/1`.
11. Topology (optional)
    
    If the post-install hook is disabled, you may need to set node `clustercontroller` and apply pending changes (see Post-Install Topology Automation (Hook) later in this document). The `tsm pending-changes apply` command may result in warnings about Index and Search Server distribution or the Coordination Service ensemble when you have multiple Tableau nodes. Address these warnings as documented in [Index and Search Server](https://help.tableau.com/v0.0/server-linux/en-us/server_process_index-and-search.htm) and [Tableau Server Coordination Service](https://help.tableau.com/v0.0/server-linux/en-us/server_process_coordination.htm).

### Custom installation

1. Customize values
    
    cp ./helm/tableau-server/values.yaml   
    ./helm/tableau-server/my-values.yaml  
    \# Edit ./helm/tableau-server/my-values.yaml with your configuration
2. Install with custom values
    
    helm install tableau-server ./helm/tableau-server -f ./helm/tableau-server/my-values.yaml

## Configuration

### Deployment modes

#### Single-node deployment

Single-node deployment runs Tableau Server as a monolithic container.

Use `values-single.yaml` or set:

deploymentMode: "single"  
primary:  
  replicaCount: 1  
worker:  
  replicaCount: 0

#### Multi-node deployment

Multi-node deployment runs one primary and one or more workers. Set the worker count with `worker.replicaCount` — use 1, 2, or any higher value your cluster capacity and Tableau topology allow. The chart creates `tableau-server-worker-0 … tableau-server-worker-(N-1)` for `replicaCount: N`.

Use `values-multinode.yaml` (default example uses two workers) or set explicitly:

deploymentMode: "multinode"  
primary:  
  replicaCount: 1  
worker:  
  replicaCount: 3    # example: three workers

Topology alignment: `values-multinode.yaml` ships with a sample `config.configJson` topology (node IDs such as `node1`, `node2`, `node3`). If you change `worker.replicaCount` or rearrange services, update that topology (and any related Tableau process assignments) so the number and roles of TSM nodes match your deployment — see Tableau Server help for clustering and process layout.

### Key configuration options

#### Image configuration

image:  
  repository: tableau\_server\_image  
  tag: "latest"  
  pullPolicy: IfNotPresent  
  pullSecrets: \[\]

#### License and secrets

secrets:
  licenseKey: "YOUR-LICENSE-KEY"  
  tsmRemotePassword: "password"  
  tableauUsername: "admin"  
  tableauPassword: "password"

Alternatively, you can set these using environment variables:

env:  
  LICENSE\_KEY: "YOUR-LICENSE-KEY"  
  TSM\_REMOTE\_PASSWORD: "password"  
  TABLEAU\_USERNAME: "admin"  
  TABLEAU\_PASSWORD: "password"

We recommend using a separate file (for example, `secrets.yaml`) and passing it with the `-f` switch.

`secrets.yaml`:

secrets:  
  licenseKey: "YOUR-LICENSE-KEY"  
  tsmRemotePassword: "YOUR-TSM-PASSWORD"  
  tableauUsername: "YOUR-ADMIN-USER"  
  tableauPassword: "YOUR-ADMIN-PASSWORD"

Install/upgrade example with `secrets.yaml`:

helm upgrade --install tableau-server ./helm/tableau-server \\  
  -n default \\  
  -f ./helm/tableau-server/values-multinode.yaml \\  
  -f ./helm/tableau-server/secrets.yaml

**Note:** Referencing a pre-existing Kubernetes Secret (for example s`ecrets.existingSecret`) is not currently supported. The only supported method is using chart values with a separate secrets value file.

#### External PostgreSQL Repository

The Helm chart does not enable an external repository by default using dedicated values keys.

We recommend you take these steps to enable an external repository:

1. Deploy the chart and confirm primary is healthy.
2. Run Tableau `tsm external repository` commands from the primary pod.
3. Apply pending changes.

Example workflow (command discovery and apply):

\# Discover command syntax for your Tableau version
kubectl exec -n default tableau-server-primary-0 -- sh -lc 'tsm topology external-services repository enable --help'  
\# After enabling external repository with Tableau-supported args/options:  
kubectl exec -n default tableau-server-primary-0 -- sh -lc 'tsm pending-changes apply -iw --ignore-prompt'  
kubectl exec -n default tableau-server-primary-0 -- sh -lc 'tsm status -v'

Notes:

- External repository configuration is Tableau version-specific (SSL mode, failover options, credentials fields). For more information, see [Tableau Server External Repository](https://help.tableau.com/v0.0/server-linux/en-us/server_external_repo.htm) and [tsm topology](https://help.tableau.com/v0.0/server-linux/en-us/cli_topology_tsm.htm).
- For customer deployments, store database credentials in Kubernetes Secrets and avoid plain text in shell history.

#### Persistent storage

persistence:  
  enabled: true  
  storageClass: "standard"  
  accessMode: ReadWriteOnce  
  size: 100Gi  
  
  # Bootstrap volume (required for multi-node)  
  bootstrap:  
    enabled: true  
    storageClass: "standard"  
    accessMode: ReadWriteMany  
    size: 1Gi  
    createPV: false

For clusters using static EFS CSI (for example with `mounttargetip`), Helm can manage both bootstrap PV and PVC:

persistence:  
  bootstrap:  
    enabled: true  
    storageClass: "efs-bootstrap"  
    accessMode: ReadWriteMany  
    size: 1Gi  
    createPV: true  
    permissionsFix:  
      enabled: true  
    pv:  
      name: "tableau-bootstrap-pv"  
      csi:  
        driver: efs.csi.aws.com  
        volumeHandle: "fs-xxxxxxxx"  
        volumeAttributes:  
          mounttargetip: "10.x.x.x"

`permissionsFix.enabled` adds an init container that `chown/chmods /docker/config/bootstrap` so the Tableau process (UID/GID 999:998) can write `bootstrap.json` on shared EFS mounts that default to `root:root`.

When `createPV: true`, the chart creates the bootstrap PV from values (for example `tableau-bootstrap-pv`) and binds `tableau-server-bootstrap` PVC to it.

If you manage bootstrap PV manually, create `tableau-bootstrap-pv` first, then install Helm with `createPV: false` and `volumeName: tableau-bootstrap-pv:`

apiVersion: v1
kind: PersistentVolume
metadata:
  name: tableau-bootstrap-pv
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: efs-bootstrap
  csi:
    driver: efs.csi.aws.com
    volumeHandle: fs-xxxxxxxx
    volumeAttributes:
      mounttargetip: 10.x.x.x

kubectl apply -f tableau-bootstrap-pv.yaml
kubectl get pv tableau-bootstrap-pv

#### Resource limits

primary:
  resources:
    limits:
      cpu: "4"
      memory: "8Gi"
    requests:
      cpu: "2"
      memory: "4Gi"

worker:
  resources:
    limits:
      cpu: "4"
      memory: "8Gi"
    requests:
      cpu: "2"
      memory: "4Gi"

#### Service configuration

service:
  primary:
    type: ClusterIP  # or NodePort, LoadBalancer
    ports:
      http: 80
      https: 8080
      tsm: 8850

#### Ingress

ingress:
  enabled: true
  className: "nginx"
  hosts:
    - host: tableau.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: tableau-tls
      hosts:
        - tableau.example.com

#### Ingress Setup Runbook (Example: NGINX Ingress Controller)

1. Install an ingress controller in the cluster (required before enabling chart ingress).
2. Set ingress values in your values file:
    
    ingress:  
      enabled: true  
      className: "nginx"  
      annotations:  
        nginx.ingress.kubernetes.io/proxy-body-size: "64m"  
        nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"  
        nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"  
      hosts:  
        - host: tableau.example.com  
          paths:  
            - path: /  
              pathType: Prefix  
      tls:  
        - secretName: tableau-tls  
          hosts:  
            - tableau.example.com
3. Create DNS record pointing tableau.example.com to your ingress/load balancer endpoint.
4. Create TLS secret (or use cert-manager) in the release namespace.
5. Deploy/upgrade chart and verify ingress:
    
    helm upgrade --install tableau-server ./helm/tableau-server -n default -f ./helm/tableau-server/values.yaml  
    kubectl get ingress -n default  
    kubectl describe ingress tableau-server

For more information, see:

- [Kubernetes Ingress Concept](https://kubernetes.io/docs/concepts/services-networking/ingress/)
- [ingress-nginx Deployment Guide](https://kubernetes.github.io/ingress-nginx/deploy/)
- [cert-manager Getting Started](https://cert-manager.io/docs/tutorials/getting-started-aks-letsencrypt/)

#### Health Checks

The chart supports startup, liveness, and readiness probes. The startup probe allows long first-time initialization (e.g. failureThreshold: 200 × periodSeconds) before liveness/readiness run:

healthChecks:
  startup:
    enabled: true
    initialDelaySeconds: 300
    periodSeconds: 15
    timeoutSeconds: 30
    failureThreshold: 200
  liveness:
    enabled: true
    initialDelaySeconds: 300
    periodSeconds: 30
    timeoutSeconds: 10
    failureThreshold: 3
  readiness:
    enabled: true
    initialDelaySeconds: 300
    periodSeconds: 10
    timeoutSeconds: 5
    failureThreshold: 3

For multinode worker pods, the chart defaults `worker.healthChecks.enabled: false` to avoid false probe failures when workers run limited process sets (for example admin agent + cluster controller only).

### Usage

#### Accessing Tableau Server

After installation, access Tableau Server based on your service configuration:

- **ClusterIP**: Use port-forwarding or Ingress
- **NodePort**: Access via `<node-ip>:<node-port>`
- **LoadBalancer**: Access via the external IP provided

#### Using TSM commands

\# Get pod name
POD\_NAME=$(kubectl get pods -l app.kubernetes.io/component=primary -o jsonpath='{.items\[0\].metadata.name}')

# Run tabcmd
kubectl exec -it $POD\_NAME -- tsm status
kubectl exec -it $POD\_NAME -- tsm configuration get

#### Using tabcmd

\# Get pod name
POD\_NAME=$(kubectl get pods -l app.kubernetes.io/component=primary -o jsonpath='{.items\[0\].metadata.name}')

# Run tabcmd
kubectl exec -it $POD\_NAME -- tabcmd login -u admin -p password
kubectl exec -it $POD\_NAME -- tabcmd sites

#### Viewing Tableau Server logs

\# Primary node logs
kubectl logs -l app.kubernetes.io/component=primary -f

# Worker node logs (multi-node)
kubectl logs -l app.kubernetes.io/component=worker -f

# All logs
kubectl logs -l app.kubernetes.io/instance=tableau-server -f

#### Shell access

\# Get pod name
POD\_NAME=$(kubectl get pods -l app.kubernetes.io/component=primary -o jsonpath='{.items\[0\].metadata.name}')

# Open shell
kubectl exec -it $POD\_NAME -- /bin/bash

### Upgrading

#### Upgrade the Tableau Server Helm chart

helm upgrade tableau-server ./helm/tableau-server -f ./helm/tableau-server/values.yaml

#### Upgrade with new values

helm upgrade tableau-server ./helm/tableau-server -f ./helm/tableau-server/new-values.yaml

### Post-install topology automation (hook)

For multinode installs, this chart can run a post-install/post-upgrade hook job that:

- waits for worker nodes to register in TSM
- sets worker `clustercontroller` process assignment
- runs `tsm pending-changes apply -iw --ignore-prompt` when changes are pending

Configuration:

hooks:
  autoApplyWorkerTopology:
    enabled: true
    kubectlImage: "bitnami/kubectl:latest"
    timeoutSeconds: 3600

Defaults:

- disabled in `values.yaml`
- in `values-multinode.yaml`, check `hooks.autoApplyWorkerTopology.enabled` (may be `true` or `false` depending on release; enable for hands-off worker `clustercontroller` setup)

Verify hook execution:

kubectl get jobs -n default
kubectl get pods -n default -l job-name=tableau-server-hook-topology
kubectl logs -n default job/tableau-server-hook-topology

Manual fallback if hook is disabled or fails — run `tsm topology set-process` for each worker TSM node (commonly node2 through node(1+N) when you have N workers; confirm IDs with `tsm topology list-nodes -v`):

kubectl exec -n default tableau-server-primary-0 -- sh -lc '
tsm topology set-process -n node2 -pr clustercontroller -c 1
tsm topology set-process -n node3 -pr clustercontroller -c 1
# Add one line per additional worker node, e.g. for four workers:
# tsm topology set-process -n node4 -pr clustercontroller -c 1
# tsm topology set-process -n node5 -pr clustercontroller -c 1
tsm pending-changes apply -iw --ignore-prompt
tsm topology list-nodes -v

tsm status -v

**Note**: Use `-iw` for `tsm pending-changes apply`. The `-ig` option is not valid in this environment.

### Uninstalling

helm uninstall tableau-server

**Warning**: This will delete all resources including persistent volumes. Make sure to backup your data before uninstalling.

#### Validation steps

Before release or when changing the chart, run:

1. Lint:
    
    helm lint helm/tableau-server -f helm/tableau-server/values-single.yaml  
    helm lint helm/tableau-server -f helm/tableau-server/values-multinode.yaml
2. Template (dry-run):
    
    helm template tableau-server helm/tableau-server -f helm/tableau-server/values-single.yaml  
    helm template tableau-server helm/tableau-server -f helm/tableau-server/values-multinode.yaml
3. Install test (optional):
    
    1. In a test namespace, run `helm install` with values-single or values-multinode.
    2. Run `kubectl rollout status` (for StatefulSet, wait for pod Ready) and basic smoke checks (e.g. `tsm status` or HTTP to the service).

For detailed troubleshooting, see [Tableau Server Helm Chart - Troubleshooting](https://help.tableau.com/v0.0/server-linux/en-us/server-helm-troubleshooting.htm).

## Additional Resources

- [Tableau Server Documentation](https://help.tableau.com/current/server-linux/en-us/)
- [Helm Documentation](https://helm.sh/docs/)
- [Helm Chart Upgrade](https://helm.sh/docs/helm/helm_upgrade/)