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.

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(Link opens in a new window) 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 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 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 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 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 and Tableau Server Coordination Service.

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 secrets.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 and tsm topology.

  • 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:

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.

Additional Resources

Thanks for your feedback!Your feedback has been successfully submitted. Thank you!