---
schema_version: "1"
id: a1bcdd5f3224fa0f6a5befc7e8d68c67d893c1d397a8e27c75e41a9230b2af0e
title: 容器中的动态扩展 - Tableau Server 后台程序
collection: tableau
version: next
locale: zh-cn
portal_url: https://docs.salesforce.com/tableau/next/zh-cn/server-linux/server-backgrounder-autoscaling.md
canonical_url: https://help.tableau.com/v0.0/server-linux/zh-cn/server-backgrounder-autoscaling.htm
source_site: help.tableau.com
content_type: documentation
content_hash: 040c2d233af597e007c32d7242ee8f1365e3379cae4a18cb493bcff75189348e
description: Configure dynamic scaling of Backgrounders for Tableau Server in a container.
---
[跳转到主要内容](#main-content)

# 容器中的动态扩展 - Tableau Server 后台程序

## 简介

容器中后台程序的动态扩展允许将各种扩展策略应用于 Tableau Server 中的后台程序和计划作业。在这种情况下，自动扩展意味着服务可以独立扩展，以处理可变的任务负载，而不需要人工干预或影响其他服务器系统的正常运行时间。包含 Tableau Server 进程的完整节点的 Tableau Server 容器将继续作为整体系统运行。相反，包含“后台程序”服务角色的较小的一组分离的独立容器服务将是动态可扩展的，并处理通常由 Tableau Server 容器处理的计算负载。后台程序服务负责处理系统任务，包括刷新/创建数据提取、发送订阅、检查数据通知以及许多维护作业。举例来说，如果有时刷新大量数据集或计算大量计算成本高昂的数据通知是有利的，那么您现在可以利用 Kubernetes 来提升计算能力，以便高效地完成这些任务。本指南涵盖了 Kubernetes 中自动扩展后台程序的配置和部署要求。本文档是对[容器中的 Tableau Server](https://help.tableau.com/v0.0/server-linux/zh-cn/server-in-container.htm)文档的补充。

## 先决条件

自动扩展后台程序仅在 Kubernetes 中可用，并且基于容器中的 Tableau Server。为了使用自动扩展后台程序功能，您必须满足某些先决条件：

- Tableau Server 必须具有 Advanced Management 功能。有关详细信息，请参见[关于 Tableau Server 上的 Tableau Advanced Management](https://help.tableau.com/v0.0/server-linux/zh-cn/itm_intro.htm)。
- 您必须使用基于角色的许可。不支持内核许可证。有关许可的详细信息，请参见[了解许可证模式和产品密钥](https://help.tableau.com/v0.0/server-linux/zh-cn/license_product_keys.htm)。
- 必须启用以下 Advanced Management 功能：
    - [Tableau Server 外部文件存储](https://help.tableau.com/v0.0/server-linux/zh-cn/server_external_filestore_storage.htm)
    - [Tableau Server 外部存储库](https://help.tableau.com/v0.0/server-linux/zh-cn/server_external_repo.htm)
- 您必须拥有 Kubernetes 群集版本 1.20 或更高版本，并了解如何使用和管理它。

## 限制

- 该功能仅作为基于 Linux 的部署的一部分。
- 自动扩展后台程序不支持流程作业。流程作业将由继续在 Tableau Server 容器中运行的后台程序服务处理。

## 创建 Tableau Server 和后台程序 Pod 映像

在容器中使用自动扩展后台程序的第一步是创建包含 Tableau Server 安装的服务映像。这些映像将包括 Tableau Server 映像，以及单独的后台程序和支持服务的映像。您使用与创建全面的一体化 Tableau Server 容器映像相同的构建工具，但该工具必须是版本 2022.3.0 或更高版本，您必须拥有 Advanced Management 许可证，并且在构建映像时需要使用特殊标志。

1. 若要创建服务映像，请运行以下命令：
    
    build-image --accepteula -i <installer> --backgrounder-images
    
    这将创建 Tableau Server 和四个新映像。这些附加映像包含构成新的可自动扩展后台程序 pod 的单独服务。
    
    `docker images` 命令列出了在本地 docker 存储库中创建的映像：
    
    hyper                          20214.21.1117.1006             52fd9843c178   10 seconds ago
    gateway                        20214.21.1117.1006             2308e602a2a3   11 seconds ago
    backgrounder                   20214.21.1117.1006             4540e459cf23   12 seconds ago
    dataserver                     20214.21.1117.1006             c5345ed47f51   12 seconds ago
    tableau\_server\_image           20214.21.1117.1006             b27817047dd1   7 minutes ago
    
    hyper、gateway、backgrounder 和 dataserver 映像构成了新的后台程序 pod。自定义驱动程序、安装脚本和属性将在所有这五个映像之间共享。有关详细信息，请参见[自定义映像](https://help.tableau.com/v0.0/server-linux/zh-cn/server-in-container_setup-tool.htm#CustomizingImage)。
2. 将所有这些映像发布到您的内部映像存储库进行部署。

## 部署指南

以下信息提供了有关如何在容器中部署 Tableau Server 并使用自动扩展后台程序的上下文。这些信息假设您已经理解并知道如何在自容式容器中部署 Tableau Server。有关详细信息，请参见[容器中的 Tableau Server](https://help.tableau.com/v0.0/server-linux/zh-cn/server-in-container.htm)。“Kubernetes 配置”部分中的三个 Kubernetes 配置文件是可以用来设置部署的模板。本指南中的其他部分介绍了部署的要求和详细信息。

Tableau Server 和自动扩展后台程序的部署应该与部署指南底部的已填充 Kubernetes 配置文件一样简单：

kubectl apply -f <tableau-kubeconfig-dir>

### 后台程序作业

后台程序 pod 帮助容器中的 Tableau Server 并行计算额外的计划工作负荷。后台程序处理提取刷新、订阅、通知、流程和系统工作负载。在后台程序 pod 之间分发作业意味着将有更多的计算资源可供 Tableau Server 处理其他任务，比如呈现工作簿和仪表板等交互式用户活动。流程作业是唯一不在后台运行的后台程序作业类型。有关后台程序作业的详细信息，请参见[在 Tableau Server 中管理后台作业](https://help.tableau.com/v0.0/server-linux/zh-cn/server_backgrounder_job_management.htm)。

除了必须在主 Tableau Server 容器中运行的流程作业之外，后台程序 pod 可以处理任何类型的负载，主 Tableau Server 容器继续运行后台程序服务。

“节点角色”功能使用户可以灵活地为特定类型的作业指定专用的后台程序 pod。此功能是 Tableau Server 上“节点角色”功能的扩展。关于不同节点角色的详细描述可以在这里找到。请注意，默认情况下，由于后台程序 pod 无法运行流程作业，因此在后台程序 pod 上禁用流程作业（即角色设置为“无流程”）。

若要为后台程序设置节点角色，您需要为运行后台程序服务的容器设置环境变量 `NODE_ROLES`，作为 kubeconfig 的一部分。例如，若要将后台程序设置为仅运行数据提取刷新作业，请将 `NODE_ROLES` 环境变量设置为 extract-refreshes，如下所示：

#### NODE\_ROLE\_CONFIG

containers:  
      - name: backgrounder  
        image: <backgrounder\_image> # Backgrounder Image  
        ports:  
        - containerPort: 8600  
        volumeMounts:  
        - name: logmount  
          mountPath: /var/log/tableau  
        - name: clone-volume  
          mountPath: /docker/clone  
        - name: dataengine-volume  
          mountPath: /docker/dataengine  
        - name: temp  
          mountPath: /var/opt/tableau/tableau\_server/data/tabsvc/temp  
        env:  
          - name: ROOT\_LOG\_DIR  
            value: /var/log/tableau  
          - name: CLONE\_ARTIFACT\_DIR  
            value: /docker/clone/clone-artifacts  
          - name: FILESTORE\_MOUNT\_PATH  
            value: /docker/dataengine  
          - name: NODE\_ROLES  
            value: extract-refreshes

Tableau Server pod 将在其拓扑中至少配置一个后台程序，这是确保始终有一个运行后台程序作业的位置所必需的。默认情况下，TSM 将要求必须有一个后台程序能够处理后台作业的每个角色。在某些情况下，您可能希望让后台程序 pod 处理特定类型的所有作业。为此，必须将 Server 配置键 `topology.roles_handle_all_jobs_constraint_disabled` 设置为 `true`，这将禁用 TSM 拓扑处理所有作业类型的要求。通过设置该参数，Tableau Server 后台程序实例的后台程序角色可设置为 `no-extract-refreshes`，而后台程序 pod 的角色可设置为 `extract-refreshes`，这将确保所有数据提取刷新作业仅在后台程序 pod 上运行。

**注意：**禁用此约束允许您配置角色，以便从不计划某些作业类型。必须仔细设置 TSM 后台程序和后台程序作业的角色配置，因为 TSM 将不再验证是否可以计划所有的后台程序作业类型。

### “容器中的 Tableau Server”Pod

对于将 Tableau Server 作为自动扩展后台程序 pod 一部分的容器，其部署方式与现有“容器中的 Tableau Server”几乎相同。有几个关键的要求更改：

- 在 Tableau Server 容器和后台程序 pod 间传输配置_需要_网络文件共享。
- 您必须启用并使用“外部文件存储”功能。这也需要一个专用的网络文件共享。

### 后台程序 Pod

后台程序 pod 由四个独立的服务容器组成，它们协同工作：**gateway**、**hyper**、**dataserver** 和 **backgrounder**。您可以像部署典型的独立 Kubernetes 容器 pod 一样部署这些 pod。pod 有以下要求：

- 后台程序 pod 必须能够使用主机名 DNS 解析到达 Tableau Server 节点。
- 必须提供外部文件存储和克隆网络文件共享。

**注意：**后台程序 pod 配置有一个初始化容器，在继续运行之前，它会一直等待，直到 Tableau Server 容器成功生成克隆配置输出。

#### 日志

后台程序 pod 服务（如 Tableau Server）仍然主要将日志写入磁盘。由于后台程序 pod 可以缩放，因此它们是短暂的，所以必须确保日志存储在 pod 之外。许多拥有现有 K8s 环境的客户已经在使用某种类型的日志聚合服务从他们部署的 pod 收集日志。日志聚合服务的示例有 Splunk 和 fluentd。我们强烈建议客户使用某种日志聚合服务从他们的后台程序 pod 中收集日志。为了使日志管理更容易，我们提供的 kubeconfig 将 pod 中的每个服务配置为写入共享日志卷。每个服务容器中的目录路径由 `ROOT_LOG_DIR` 环境变量指定。

如果您需要开立支持案例并提供日志，您将提供两组日志：从主服务器容器收集的 ziplog，以及从后台程序 pod（通过日志聚合服务检索，或使用下面的手动流程）收集的日志。

对于无法使用日志聚合服务的客户，可以从 pod 中手动检索日志。

**注意：**当 pod 缩小时，任何没有对包含日志的卷使用持久卷声明的 pod 中的日志都将丢失！

所有相关的日志都可以在后台程序 pod 中的 `/var/log/tableau` 目录（可通过 `ROOT_LOG_DIR` 环境变量配置）下找到。我们强烈建议您在此位置装载一个 PersistantVolumeClaim，以便在 pod 终止时有日志可用。

##### 在后台程序 pod 运行时收集日志：

在容器内创建日志的 tar 文件：

kubectl exec -it <backgrounder-pod-name> -- bash -c "tar -czf /docker/user/backgrounder-pod-logs.tar.gz /var/log/tableau"

将 tar 文件复制到容器外部：

kubectl cp <backgrounder-pod-name>:docker/user/backgrounder-pod-logs.tar.gz ./backgrounder-pod-logs.tar.gz

##### 在后台程序 pod 退出（或无法启动）时收集日志

使用 PersistantVolumeClaim 挂载附加任何长期运行的 pod，该挂载用于后台程序 pod 部署日志。一个示例配置：

apiVersion: v1  
kind: Pod  
metadata:  
  name: <name>  
  namespace: <namespace>  
spec:  
  containers:  
  - name: get-logs-pod  
    image: busybox:1.28  
    securityContext:  
      runAsUser: 0  
      allowPrivilegeEscalation: true  
    command: \['sh', '-c', "while :; do sleep 5; done"\]  
    volumeMounts:  
    - name: logmount  
      mountPath: /var/log/tableau
restartPolicy: Never  
volumes:  
  - name: logmount  
    persistentVolumeClaim:  
      claimName: logvolume

在容器内创建日志的 tar 文件：

kubectl exec -it <backgrounder-pod-name> -- bash -c "tar -czf /backgrounder-pod-logs.tar.gz /var/log/tableau"

将 tar 文件复制到容器外部：

kubectl cp <backgrounder-pod-name>:/backgrounder-pod-logs.tar.gz ./backgrounder-pod-logs.tar.gz

#### 实时配置更改

如果您在“容器中的 Tableau Server”中进行配置更改（例如使用 tsm 命令行），并希望这些配置更改在后台程序 pod 中显示，则需要运行 `[tsm settings clone](https://help.tableau.com/v0.0/server-linux/zh-cn/cli_settings_tsm.htm#TSMSettingsClone)` 命令来生成一组新的克隆配置文件（“克隆有效负载”）。

1. 使用 TSM 在“容器中的 Tableau Server”pod 中进行配置更改，并将配置更改应用到服务器。
2. 在“容器中的 Tableau Server”pod 中运行以下命令：
    
    \## Run this command in the Tableau Server in a Container pod.
    tsm settings clone -d $CLONE\_ARTIFACT\_DIR
    
    此命令创建一组新的配置文件，并将其写入克隆 NFS 驱动器位置。
3. 重新部署您的后台程序 pod。pod 应配置为使用克隆 NFS 驱动器，并将采用新配置。

### 扩展策略

可以使用各种技术和策略在 Kubernetes 中扩展后台程序 pod。我们提供了一个根据时间表更改后台程序 pod 池大小的示例扩展策略。

请注意，CPU 和内存利用率并**不是**扩展后台程序 pod 的好指标。内存和 CPU 利用率不能准确反映群集的整体负载需求。例如，后台程序 pod 可能处于刷新数据提取的最大利用率，但是在后台程序作业队列中没有其他作业在等待。在这种情况下，自动扩展不会提高作业吞吐量。

#### 计划的扩展

使用 cron 作业的标准 Kubernetes 机制允许您计划扩展解决方案。

下面的“Kubernetes 配置”部分针对此情况提供了一个 Kubernetes 配置示例。

## Kubernetes 配置

### 新的环境变量

除了标准的 Tableau Server 容器环境变量（请参见[初始配置选项](https://help.tableau.com/v0.0/server-linux/zh-cn/server-in-container_image.htm#InitialConfigOptions-container)），还有一些新的必需环境变量必须在 Kubernetes 配置中设置。

<table style="width: 100%;mc-table-style: url('Resources/TableStyles/Basic-Border-Light.css');" class="TableStyle-Basic-Border" cellspacing="0"><colgroup><col class="TableStyle-Basic-Border-Column-Column1" style="width: 25%;"><col class="TableStyle-Basic-Border-Column-Column1" style="width: 25%;"><col class="TableStyle-Basic-Border-Column-Column1" style="width: 50%;"></colgroup><thead><tr class="TableStyle-Basic-Border-Head-Header1"><th class="TableStyle-Basic-Border-HeadE-Column1-Header1">环境变量</th><th class="TableStyle-Basic-Border-HeadE-Column1-Header1">建议值</th><th class="TableStyle-Basic-Border-HeadD-Column1-Header1">描述</th></tr></thead><tbody><tr class="TableStyle-Basic-Border-Body-Body1"><td class="TableStyle-Basic-Border-BodyE-Column1-Body1"><code>FILESTORE_MOUNT_PATH</code></td><td class="TableStyle-Basic-Border-BodyE-Column1-Body1"><code>/docker/dataengine</code></td><td class="TableStyle-Basic-Border-BodyD-Column1-Body1">外部文件存储目录装载位置。此目录应该指向装载在每个已部署的 Tableau 容器中的数据引擎 NFS 目录。有关外部文件存储的详细信息，请参见<a href="https://help.tableau.com/v0.0/server-linux/zh-cn/server_external_filestore_storage.htm" class="xref">Tableau Server 外部文件存储</a>。对于“容器中 Tableau Server”pod 和“后台程序”pod，该值应该相同。</td></tr><tr class="TableStyle-Basic-Border-Body-Body1"><td class="TableStyle-Basic-Border-BodyE-Column1-Body1"><code>CLONE_ARTIFACT_DIR</code></td><td class="TableStyle-Basic-Border-BodyE-Column1-Body1"><code>/docker/clone/clone-artifacts</code></td><td class="TableStyle-Basic-Border-BodyD-Column1-Body1">克隆配置目录装载位置。此目录应该指向装载在每个 Tableau 容器内的 NFS 目录。Tableau Server 将输出配置数据，后台程序 Pod 使用这些数据成为群集成员。</td></tr><tr class="TableStyle-Basic-Border-Body-Body1"><td class="TableStyle-Basic-Border-BodyB-Column1-Body1"><code>ROOT_LOG_DIR</code></td><td class="TableStyle-Basic-Border-BodyB-Column1-Body1"><code>/var/log/tableau</code></td><td class="TableStyle-Basic-Border-BodyA-Column1-Body1">（仅限后台程序 pod）<p>在后台程序 pod 中运行的所有服务的通用日志目录位置。</p></td></tr></tbody></table>

### 后台程序 Pod 端口

后台程序 pod 由四个服务组成，每个服务默认设置为在指定的端口上运行。如果您想在容器内部更改服务附加的端口，您需要提供与服务的端口分配相对应的键。在大多数情况下，这种类型的配置是不必要的，除非有一个边车容器或一些其他附加组件被添加到 pod，并且与服务的端口冲突。

| 端口环境变量 | 默认 |
| --- | --- |
| `BACKGROUNDER_PORT` | `8600` |
| `DATASERVER_PORT` | `8400` |
| `HYPER_PORT` | `8200` |
| `GATEWAY_PORT` | `8080` |

Dataserver 还使用端口 8300，该端口不能重新配置。

### 共享网络目录

Tableau Server 的这种部署需要两个网络共享才能正常工作。注意，在所有 Tableau Server 和后台程序 pod Kubernetes 配置模板中，这些网络目录都存在：

- **数据引擎目录** (`FILESTORE_MOUNT_PATH`)：后台程序 pod 需要“外部文件存储”功能。此网络共享包含将在 Tableau Server 和后台程序 pod 之间共享的数据提取和其他基于文件的项目。
- **克隆目录** (`CLONE_ARTIFACT_DIR`)：Tableau Server 将静态连接和配置信息写入网络共享。后台程序 pod 将使用这些信息成为 Tableau Server 群集的成员。在未来的预发布版本中，该配置将被纳入 Kubernetes 配置的标准生命周期中。

**重要信息：**如果您想要重新部署整个群集（包括新的 Tableau Server 容器），您必须清除克隆 NFS 装载的内容（否则后台程序 pod 将尝试连接到旧服务器）。

### Kubernetes 配置示例

**注意：** 配置示例包括准备情况探测器的使用。当您的 Tableau Server 容器部署是单节点 TSM 部署（部署可以包括多个后台程序 pod）时，您可以使用准备情况探测器。您不能在容器部署中对多节点 Tableau Server 使用准备情况探测器。

#### Tableau Server 容器配置

\---  
apiVersion: v1  
kind: Service  
metadata:  
  name: <service\_name>  
  namespace: <namespace>  
spec:  
  selector:  
    app: <service\_name>  
  ports:  
    - protocol: TCP  
      port: 8080  
      nodePort: <nodeport-number>  
      name: http  
    - protocol: TCP  
      port: 8443  
      nodePort: <nodeport-number>  
      name: https  
  type: NodePort  
\---  
apiVersion: v1  
kind: ConfigMap  
metadata:  
  name: configfile  
  namespace: <namespace>  
data:  
  config.json: |-  
    {  
      "configEntities": {  
      "identityStore": {  
        "\_type": "identityStoreType",  
        "type": "local"  
      }  
    },  
    "configKeys" : {  
      "tabadmincontroller.init.smart\_defaults.enable" : "false",  
      "wgserver.domain.ldap.starttls.enabled" : "false"  
    },  
    "daysLeftForMaintenanceExpiring" : 0  
  }  
\---  
apiVersion: v1  
kind: ConfigMap  
metadata:  
  name: extrepojsonfile  
  namespace: <namespace>  
data:  
  config.json: |-  
    {  
      "flavor":"generic",  
      "masterUsername":"<admin-name>",  
      "masterPassword":"<password>",  
      "host":"<hostname>",  
      "port":5432,  
      "prerequisiteCheckEnabled":false,  
      "requireSsl":false  
    }  
\---  
apiVersion: v1  
kind: PersistentVolumeClaim  
metadata:  
  name: datadir1  
  namespace: <namespace>  
spec:  
  accessModes:  
  - ReadWriteOnce  
  resources:  
    requests:  
    storage: 50Gi  
\---  
\# This is required for multi-node tableau server in container  
apiVersion: v1  
kind: PersistentVolume  
metadata:  
  name: bootstrapnfs  
  namespace: <namespace>  
spec:  
  accessModes:  
    - ReadWriteMany  
  capacity:  
    storage: 1Gi  
  nfs:  
    server: <nfs-ip>  
    path: <mount-path>  
\---  
\# This is required for multi-node tableau server in container  
apiVersion: v1  
kind: PersistentVolumeClaim  
metadata:  
  name: bootstrapnfs  
  namespace: <namespace>  
spec:  
  accessModes:  
    - ReadWriteMany  
  storageClassName: ""  
  resources:  
    requests:  
      storage: 1Mi  
\---  
apiVersion: v1  
kind: PersistentVolumn  
metadata:  
  name: clonenfs  
  namespace: <namespace>  
spec:  
  accessModes:  
    - ReadWriteMany  
capacity:  
  storage: 1Gi  
nfs:  
  server: <nfs-ip>  
  path: <mount-path>  
\---  
apiVersion: v1  
kind: PersistentVolumeClaim  
metadata:  
  name: clonenfs  
  namespace: <namespace>  
spec:  
  accessModes:  
    - ReadWriteMany  
  storageClassName: ""  
  resources:  
    requests:  
      storage: 1Mi  
\---  
apiVersion: v1  
kind: PersistentVolume  
metadata:  
    name: dataenginenfs  
    namespace: <namespace>  
spec:  
  accessModes:  
    - ReadWriteMany  
  capacity:  
    storage: 1Gi  
  nfs:  
    server: <nfs-ip>  
    path: <namespace>  
\---  
apiVersion: v1  
kind: PersistentVolumeClaim  
metadata:  
  name: dataenginenfs  
  namespace: <namespace>  
spec:  
  accessModes:  
    - ReadWriteMany  
  storageClassName: ""  
  resources:  
    requests:  
      storage: 1Mi  
\---  
apiVersion: v1  
kind: Secret  
type: Opaque  
metadata:
  name: tableau-server-in-a-container-secrets  
  namespace: <namespace>  
stringData:  
  license\_key: <license\_key> # Tableau License Key String  
  tableau\_username: <tableau\_username> # Initial admin username in Tableau Server  
  tableau\_password: <tableau\_password> # Initial admin password  
\---  
apiVersion: apps/v1  
kind: StatefulSet  
metadata:  
  name: tableau-server  
  namespace: <namespace>  
  labels:  
    app: <service\_name>  
spec:  
  selector:  
    matchLabels:  
      app: <service\_name>  
  replicas: 1  
  serviceName: <service\_name>  
  template:  
    metadata:  
      labels:  
        app: <service\_name>  
    spec:  
      securityContext:  
        runAsUser: 999  
        fsGroup: 998  
        fsGroupChangePolicy: "OnRootMismatch"  
      terminationGracePeriodSeconds: 120  
      dnsPolicy: "None"  
      dnsConfig:  
        nameservers:  
          - <dns\_ip> # DNS IP for resolving container hostnames  
        searches:  
          - <service\_name>.<namespace>.svc.<cluster\_domain>.<example> # SRV Record  
          - <namespace>.svc.<cluster\_domain>.<example> # SRV Record  
          - svc.<cluster\_domain>.<example> # SRV Record  
          - <cluster\_domain>.<example> # SRV Record  
        options:  
          - name: ndots  
            value: "5"  
      initContainers: # init containers are optional, to clear directory content if already exists  
        - name: clean-bootstrap-dir  
          image: busybox:1.28  
          securityContext:  
            runAsUser: 0  
            allowPrivilegeEscalation: true  
          volumeMounts:  
          - name: bootstrap  
            mountPath: /docker/config/bootstrap  
          command: \['sh', '-c', 'rm -rf /docker/config/bootstrap/\* || true'\]  
        - name: clean-clone-artifacts-dir  
          image: busybox:1.28  
          securityContext:  
            runAsUser: 0  
            allowPrivilegeEscalation: true  
          volumeMounts:  
          - name: clone  
            mountPath: /docker/clone  
          command: \['sh', '-c', 'rm -rf /docker/clone/clone-artifacts || true'\]  
      containers:  
      - name: <container\_name> # Name of container  
        image: <tableau\_server\_image> # Tableau Server in Container Image  
        env:  
        - name: LICENSE\_KEY  
          valueFrom:  
            secretKeyRef:  
              name: tableau-server-in-a-container-secrets  
              key: license\_key  
        - name: FILESTORE\_MOUNT\_PATH  
          value: /docker/dataengine  
        - name: CLONE\_ARTIFACT\_DIR\_FOR\_INDEPENDENT\_CONTAINERS  
          value: /docker/clone/clone-artifacts  
        - name: SERVER\_FOR\_INDEPENDENT\_SERVICE\_CONTAINERS  
          value: "1"  
        - name: EXT\_REP\_JSON\_FILE  
          value: /docker/external-repository/config.json  
        - name: TABLEAU\_USERNAME  
          valueFrom:  
            secretKeyRef:  
              name: tableau-server-in-a-container-secrets  
              key: tableau\_username  
        - name: TABLEAU\_PASSWORD  
          valueFrom:  
            secretKeyRef:  
              name: tableau-server-in-a-container-secrets  
              key: tableau\_password  
        resources:  
          requests:  
            memory: 40Gi  
            cpu: 15  
          limits:  
            memory: 40Gi  
            cpu: 15  
        ports:  
        - containerPort: 8080  
        volumeMounts:  
        - name: configmount  
          mountPath: /docker/config/config.json  
          subPath: config.json  
        - name: externalrepomount  
          mountPath: /docker/external-repository  
        - name: datadir1  
          mountPath: /var/opt/tableau  
        - name: bootstrap  
          mountPath: /docker/config/bootstrap  
        - name: clone  
          mountPath: /docker/clone  
        - name: dataengine  
          mountPath: /docker/dataengine  
        imagePullPolicy: IfNotPresent  
        startupProbe:  
          exec:  
            command:  
            - /bin/sh  
            - -c  
            - /docker/server-ready-check  
          initialDelaySeconds: 300  
          periodSeconds: 15  
          timeoutSeconds: 30  
          failureThreshold: 200  
        readinessProbe:  
          exec:  
            command:  
            - /bin/sh  
            - -c  
            - /docker/server-ready-check  
          periodSeconds: 30  
          timeoutSeconds: 60  
        livenessProbe:  
          exec:  
            command:  
            - /bin/sh  
            - -c  
            - /docker/alive-check  
          initialDelaySeconds: 600  
          periodSeconds: 60  
          timeoutSeconds: 60  
      volumes:  
      - name: configmount  
        configMap:  
          name: configfile  
      - name: externalrepomount  
        configMap:  
          name: extrepojsonfile  
      - name: datadir1  
        persistentVolumeClaim:  
          claimName: datadir1  
      - name: bootstrap  
        persistentVolumeClaim:  
          claimName: bootstrapnfs  
      - name: clone  
        persistentVolumeClaim:  
          claimName: clonenfs  
      - name: dataengine  
        persistentVolumeClaim:  
          claimName: dataenginenfs

#### 后台程序 Pod 配置

\---  
apiVersion: v1  
kind: PersistentVolumeClaim  
metadata:  
  name: logvolume  
  namespace: <namespace>  
spec:  
  accessModes:  
  - ReadWriteOnce  
  resources:  
    requests:  
      storage: 20Gi  
\---  
apiVersion: apps/v1  
kind: Deployment  
metadata:  
  name: backgrounder  
  labels:  
    app: backgrounder  
  namespace: <namespace>   
spec:  
  replicas: 2  
  selector:  
    matchLabels:  
      app: backgrounder  
  template:  
    metadata:  
      labels:  
        app: backgrounder  
    spec:  
      securityContext:  
        runAsUser: 999  
        runAsGroup: 998  
        fsGroup: 998
        fsGroupChangePolicy: "OnRootMismatch"  
      hostname: backgrounder  
      dnsPolicy: "None"  
      dnsConfig:  
        nameservers:  
          - <dns\_ip> # DNS IP for resolving container hostnames  
        searches:  
          - <service\_name>.<namespace>.svc.<cluster\_domain>.<example> # SRV Record  
          - <namespace>.svc.<cluster\_domain>.<example> # SRV Record  
          - svc.<cluster\_domain>.<example> # SRV Record  
          - <cluster\_domain>.<example> # SRV Record  
        options:  
          - name: ndots  
            value: "5"
      initContainers:  
        - name: init-myservice  
          image: busybox # This init-container is optional (as long as there is a mechanism to set the log volume directory permissions and the pod waits for clone artifacts)  
          securityContext:  
            runAsUser: 0  
            allowPrivilegeEscalation: true  
          env:  
            - name: CLONE\_ARTIFACT\_DIR\_FOR\_INDEPENDENT\_CONTAINERS  
            value: /docker/clone/clone-artifacts  
          volumeMounts:  
          - name: logmount  
            mountPath: /var/log/tableau  
          - name: clone-volume  
            mountPath: /docker/clone  
          command: \['sh', '-c', "chmod 777 /var/log/tableau && while \[ ! -d ${CLONE\_ARTIFACT\_DIR\_FOR\_INDEPENDENT\_CONTAINERS} \]; do sleep 5; done"\]  
      containers:  
      - name: backgrounder  
        image: <backgrounder\_image> # Backgrounder Image  
        ports:  
        - containerPort: 8600
        imagePullPolicy: IfNotPresent
        readinessProbe:  
          exec:  
            command:  
              - /bin/sh  
              - -c  
              - /tsm\_docker\_utils/status\_check.sh | grep -E 'ACTIVE|BUSY'  
          periodSeconds: 30  
          timeoutSeconds: 60  
        livenessProbe:  
          exec:  
            command:  
              - /bin/sh  
              - -c  
              - /tsm\_docker\_utils/status\_check.sh | grep -E 'ACTIVE|BUSY'  
          initialDelaySeconds: 600  
          periodSeconds: 60  
          timeoutSeconds: 60
        volumeMounts:  
        - name: logmount  
          mountPath: /var/log/tableau  
        - name: clone-volume  
          mountPath: /docker/clone  
        - name: dataengine-volume  
          mountPath: /docker/dataengine  
        - name: temp  
          mountPath: /var/opt/tableau/tableau\_server/data/tabsvc/temp  
        env:  
          - name: ROOT\_LOG\_DIR  
            value: /var/log/tableau  
          - name: CLONE\_ARTIFACT\_DIR\_FOR\_INDEPENDENT\_CONTAINERS  
            value: /docker/clone/clone-artifacts  
          - name: FILESTORE\_MOUNT\_PATH  
            value: /docker/dataengine  
      - name: dataserver  
        image: <dataserver\_image> # Dataserver Image  
        ports:  
        - containerPort: 8400
        imagePullPolicy: IfNotPresent
        readinessProbe:  
          exec:  
            command:  
              - /bin/sh  
              - -c  
              - /tsm\_docker\_utils/status\_check.sh | grep -E 'ACTIVE|BUSY'  
          periodSeconds: 30  
          timeoutSeconds: 60  
        livenessProbe:  
          exec:  
            command:  
              - /bin/sh  
              - -c  
              - /tsm\_docker\_utils/status\_check.sh | grep -E 'ACTIVE|BUSY'  
          initialDelaySeconds: 600  
          periodSeconds: 60  
          timeoutSeconds: 60  
        volumeMounts:  
        - name: logmount  
          mountPath: /var/log/tableau  
        - name: clone-volume  
          mountPath: /docker/clone  
        - name: dataengine-volume  
          mountPath: /docker/dataengine  
        - name: temp  
          mountPath: /var/opt/tableau/tableau\_server/data/tabsvc/temp  
        env:  
          - name: ROOT\_LOG\_DIR  
            value: /var/log/tableau  
          - name: CLONE\_ARTIFACT\_DIR\_FOR\_INDEPENDENT\_CONTAINERS  
            value: /docker/clone/clone-artifacts  
          - name: FILESTORE\_MOUNT\_PATH  
            value: /docker/dataengine  
      - name: gateway  
        image: <gateway\_image> # Gateway Image  
        ports:  
        - containerPort: 8080
        imagePullPolicy: IfNotPresent
        readinessProbe:  
          exec:  
            command:  
              - /bin/sh  
              - -c  
              - /tsm\_docker\_utils/status\_check.sh | grep -E 'ACTIVE|BUSY'  
          periodSeconds: 30  
          timeoutSeconds: 60  
        livenessProbe:  
          exec:  
            command:  
              - /bin/sh  
              - -c  
              - /tsm\_docker\_utils/status\_check.sh | grep -E 'ACTIVE|BUSY'  
          initialDelaySeconds: 600  
          periodSeconds: 60  
          timeoutSeconds: 60
        volumeMounts:  
        - name: logmount  
          mountPath: /var/log/tableau  
        - name: clone-volume  
          mountPath: /docker/clone  
        - name: dataengine-volume  
          mountPath: /docker/dataengine  
        - name: temp  
          mountPath: /var/opt/tableau/tableau\_server/data/tabsvc/temp  
        env:  
          - name: ROOT\_LOG\_DIR  
            value: /var/log/tableau  
          - name: CLONE\_ARTIFACT\_DIR\_FOR\_INDEPENDENT\_CONTAINERS  
            value: /docker/clone/clone-artifacts  
          - name: FILESTORE\_MOUNT\_PATH  
            value: /docker/dataengine  
    - name: hyper  
      image: <hyper\_image> # Hyper Image  
      ports:
      - containerPort: 8200
      imagePullPolicy: IfNotPresent
      readinessProbe:  
        exec:  
          command:  
            - /bin/sh  
            - -c  
            - /tsm\_docker\_utils/status\_check.sh | grep -E 'ACTIVE|BUSY'  
        periodSeconds: 30  
        timeoutSeconds: 60  
      livenessProbe:  
        exec:  
          command:  
          - /bin/sh  
          - -c
          - /tsm\_docker\_utils/status\_check.sh | grep -E 'ACTIVE|BUSY'  
        initialDelaySeconds: 600  
        periodSeconds: 60  
        timeoutSeconds: 60
      volumeMounts:  
        - name: logmount  
          mountPath: /var/log/tableau  
        - name: clone-volume  
          mountPath: /docker/clone  
        - name: dataengine-volume  
          mountPath: /docker/dataengine  
        - name: temp  
          mountPath: /var/opt/tableau/tableau\_server/data/tabsvc/temp  
      env:  
        - name: ROOT\_LOG\_DIR  
          value: /var/log/tableau  
        - name: CLONE\_ARTIFACT\_DIR\_FOR\_INDEPENDENT\_CONTAINERS  
          value: /docker/clone/clone-artifacts  
        - name: FILESTORE\_MOUNT\_PATH  
          value: /docker/dataengine  
    volumes:  
      - name: clone-volume  
        nfs:  
          server: <nfs\_ip>   
          path: <mount\_path>  
      - name: dataengine-volume  
        nfs:  
          server: <nfs\_ip>   
          path: /dataengine  
      - name: logmount  
        persistentVolumeClaim:  
          claimName: logvolume  
      - name: temp  
        emptyDir: {}

#### 计划的扩展配置

apiVersion: v1  
kind: ServiceAccount  
metadata:  
name: backgrounder-scaler-service-account  
namespace: <namespace> # Namespace  
\---  
apiVersion: rbac.authorization.k8s.io/v1  
kind: RoleBinding  
metadata:  
name: scale-backgrounder-pods  
namespace: <namespace> # Namespace  
subjects:  
\- kind: ServiceAccount  
name: backgrounder-scaler-service-account  
roleRef:  
kind: ClusterRole  
name: cluster-admin  
apiGroup: rbac.authorization.k8s.io  
\---  
apiVersion: batch/v1beta1  
kind: CronJob  
metadata:  
name: scale-up-job  
namespace: <namespace> # Namespace  
spec:  
schedule: "0 7 \* \* \*" # Cron Job timing to scale up deployment replicas  
jobTemplate:  
spec:  
template:  
spec:  
serviceAccountName: backgrounder-scaler-service-account  
restartPolicy: OnFailure  
containers:  
\- name: scale  
image: bitnami/kubectl:1.21  
imagePullPolicy: IfNotPresent  
args:  
\- scale  
\- --replicas=4  
\- deployment/backgrounder  
\---  
apiVersion: batch/v1beta1  
kind: CronJob  
metadata:  
name: scale-down-job  
namespace: <namespace>  
spec:  
schedule: "0 9 \* \* \*" # Cron Job timing to scale down deployment replicas  
jobTemplate:  
spec:  
template:  
spec:  
serviceAccountName: backgrounder-scaler-service-account  
restartPolicy: OnFailure  
containers:  
\- name: scale  
image: bitnami/kubectl:1.21  
imagePullPolicy: IfNotPresent  
args:  
\- scale  
\- --replicas=2  
\- deployment/backgrounder

#### 用于清理克隆配置的 Kubernetes 作业（可选）

这是一个方便的 Kubernetes 作业，您可以在测试期间使用。如果您希望在不同的部署运行之间清除由“容器中的 Tableau Server”生成的克隆配置，您可以运行这样的作业来清理 NFS。

apiVersion: batch/v1  
kind: Job  
metadata:  
name: delete-clone-artifacts-job  
namespace: manatee-cluster  
spec:  
template:  
spec:  
containers:  
\- name: delete-clone-artifacts  
image: busybox:1.28  
command: \['sh', '-c', "rm -rf ${CLONE\_ARTIFACT\_DIR}"\]  
env:  
\- name: CLONE\_ARTIFACT\_DIR  
value: /docker/clone/clone-artifacts  
securityContext:  
runAsUser: 0  
allowPrivilegeEscalation: true  
volumeMounts:  
\- name: clone-volume  
mountPath: /docker/clone  
restartPolicy: Never  
volumes:  
\- name: clone-volume  
nfs:  
server: <nfs\_ip> # IP for shared NFS directory for clone output  
path: /clone