> ## Documentation Index
> Fetch the complete documentation index at: https://help.teable.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# K8s 部署

<Callout type="info">
  **推荐场景**：50+ 用户的生产环境
</Callout>

<Tip>
  配置建议（CPU、内存、副本数）请参考 [私有化部署概览 → 配置建议](/zh/deploy/production-overview#配置建议)。
</Tip>

## 前置条件

### Teable 镜像

* 应用镜像: `registry.cn-shenzhen.aliyuncs.com/teable/teable:latest`

### 运行环境

* 运行中的 Kubernetes 集群

### 已配置的外部服务

#### 数据库服务

* PostgreSQL 数据库: postgres:15.4（版本号大于 12）
  * PostgreSQL 镜像: `registry.cn-shenzhen.aliyuncs.com/teable/postgres:15.4`

#### 缓存服务

* Redis 缓存服务: redis:7.2.4（版本号大于 5）
  * Redis 镜像: `registry.cn-shenzhen.aliyuncs.com/teable/redis:7.2.4`

#### 对象存储服务

* MinIO 对象存储服务: minio:RELEASE.2024-10-13T13-34-11Z-cpuv1
  * MinIO 镜像: `registry.cn-shenzhen.aliyuncs.com/teable/minio:RELEASE.2024-10-13T13-34-11Z-cpuv1`
  * 注意: 可以直接使用最新版本，或者使用云存储，配置参考，下方示例使用 minio 来做例子。

### 必要工具

* kubectl 命令行工具

## 依赖组件配置

### 文件存储 MinIO

<Note>文件存储服务需要支持外网访问（即终端用户可直接访问到）</Note>

文件存储需要预先创建好两个 bucket：

| Bucket | 环境变量                                        | 权限                 |
| ------ | ------------------------------------------- | ------------------ |
| 公共桶    | `BACKEND_STORAGE_PUBLIC_BUCKET=teable-pub`  | **公共可读（必须开启匿名访问）** |
| 私有桶    | `BACKEND_STORAGE_PRIVATE_BUCKET=teable-pvt` | 私有（默认）             |

<Warning>
  公共桶**必须**开启匿名读取权限。否则用户将无法查看共享图片、头像等公开文件。
</Warning>

#### 使用 MinIO Client (mc) 创建 Bucket

在部署 Teable 之前，请先创建所需的 bucket：

```sh theme={null}
# 设置 MinIO 客户端别名
mc alias set teable-minio https://minio.example.com YOUR_ACCESS_KEY YOUR_SECRET_KEY

# 创建公共桶并设置匿名读取权限
mc mb --ignore-existing teable-minio/teable-pub
mc anonymous set public teable-minio/teable-pub

# 创建私有桶
mc mb --ignore-existing teable-minio/teable-pvt

# 验证 bucket 是否创建成功
mc ls teable-minio
# 预期输出：
# [2024-01-01 00:00:00 UTC]     0B teable-pub/
# [2024-01-01 00:00:00 UTC]     0B teable-pvt/
```

#### Teable MinIO 环境变量总览

```sh theme={null}
# 固定值
BACKEND_STORAGE_PROVIDER=minio
# 公共桶
BACKEND_STORAGE_PUBLIC_BUCKET=teable-pub
# 私有桶
BACKEND_STORAGE_PRIVATE_BUCKET=teable-pvt
# 外网端点，重要！需要终端用户可以直接访问到
BACKEND_STORAGE_MINIO_ENDPOINT=minio.example.com
# 与前面的值保持一样，但是要加个协议名称
STORAGE_PREFIX=https://minio.example.com
# 内网端点（Kubernetes DNS 格式：<service>.<namespace>.svc.cluster.local）
# ⚠️ 请将 <namespace> 替换为实际的命名空间，例如：minio.teable.svc.cluster.local
BACKEND_STORAGE_MINIO_INTERNAL_ENDPOINT=minio.teable.svc.cluster.local
# 外网端口，一般为 443 或者 9000
BACKEND_STORAGE_MINIO_PORT=443
# 内网端口，一般为 80 或者 9000
BACKEND_STORAGE_MINIO_INTERNAL_PORT=80
# 是否启用 HTTPS, 注意如果 Teable 启用了 https 则 minio 也必须启用 https 否则有跨域问题
BACKEND_STORAGE_MINIO_USE_SSL="true"
# 管理员账号
BACKEND_STORAGE_MINIO_ACCESS_KEY=root
# 管理员密码
BACKEND_STORAGE_MINIO_SECRET_KEY=rootPassword
```

### 数据库

需要创建一个具有管理员权限的数据库账户，以及一个数据库，并且设置密码。
对应环境变量示例:

* 数据库名称: teable
* 密码：your-password
* 账号: postgres
* 端口: 5432

```sh theme={null}
PRISMA_DATABASE_URL="postgresql://postgres:your-password@your-postgres-host:5432/teable"
```

### 缓存 Redis

Teable 配置 redis 缓存只需要提供内网连接地址即可。（注意 Redis 不仅管理缓存还管理队列，不可或缺。数据需要定时备份）
对应环境变量示例

```sh theme={null}
BACKEND_CACHE_REDIS_URI="redis://username:password@your-redis-host:6379/0"
```

## 创建配置文件

```yaml teable-config.yaml（非敏感配置） theme={null}
apiVersion: v1
kind: ConfigMap
metadata:
  name: teable-config
  namespace: teable  # 请替换为你的命名空间
data:
  # 应用基础配置，对外访问的域名
  PUBLIC_ORIGIN: "https://your-domain.com"
  
  # 存储配置
  BACKEND_STORAGE_PROVIDER: "minio"
  # Bucket 名称（需要在部署前于 MinIO 中创建）
  BACKEND_STORAGE_PUBLIC_BUCKET: "teable-pub"
  BACKEND_STORAGE_PRIVATE_BUCKET: "teable-pvt"
  # 外网端点，重要！需要终端用户可以直接访问到
  BACKEND_STORAGE_MINIO_ENDPOINT: "minio.example.com"
  # 与前面的值保持一样，但是要加个协议名称
  STORAGE_PREFIX: "https://minio.example.com"
  # 内网端点（Kubernetes DNS 格式：<service>.<namespace>.svc.cluster.local）
  # ⚠️ 请将 'teable' 替换为实际的命名空间
  BACKEND_STORAGE_MINIO_INTERNAL_ENDPOINT: "minio.teable.svc.cluster.local"
  # 外网端口，一般为 443 或者 9000
  BACKEND_STORAGE_MINIO_PORT: "443"
  # 内网端口，一般为 80 或者 9000
  BACKEND_STORAGE_MINIO_INTERNAL_PORT: "80"
  # 是否启用 HTTPS, 注意如果 Teable 启用了 https 则 minio 也必须启用 https 否则有跨域问题
  BACKEND_STORAGE_MINIO_USE_SSL: "true"
  
  # 缓存配置, 固定值
  BACKEND_CACHE_PROVIDER: "redis"
  
  # 其他配置，固定值
  NEXT_ENV_IMAGES_ALL_REMOTE: "true"
  PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING: "1"
  # 使用自签发证书需要保留这个
  NODE_TLS_REJECT_UNAUTHORIZED: '0'
```

```yaml teable-secrets.yaml（敏感信息） theme={null}
apiVersion: v1
kind: Secret
metadata:
  name: teable-secrets
  namespace: teable  # 请替换为你的命名空间
type: Opaque
stringData:
  # 数据库敏感信息
  PRISMA_DATABASE_URL: "postgresql://postgres:your-password@your-postgres-host:5432/teable"
  
  # 应用密钥
  BACKEND_JWT_SECRET: "your-jwt-secret"
  BACKEND_SESSION_SECRET: "your-session-secret"
  
  # MinIO 认证信息
  BACKEND_STORAGE_MINIO_ACCESS_KEY: "your-minio-access-key"
  BACKEND_STORAGE_MINIO_SECRET_KEY: "your-minio-secret-key"
  
  # Redis 认证信息
  BACKEND_CACHE_REDIS_URI: "redis://username:password@your-redis-host:6379/0"
```

```yaml teable-deployment.yaml theme={null}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: teable
  namespace: teable  # 请替换为你的命名空间
spec:
  replicas: 1 # 根据需要配置
  selector:
    matchLabels:
      app: teable
  template:
    metadata:
      labels:
        app: teable
    spec:
      # Add initContainers for database migration
      initContainers:
        - name: db-migrate
          image: registry.cn-shenzhen.aliyuncs.com/teable/teable:latest
          args:
            - migrate-only
          envFrom:
            - configMapRef:
                name: teable-config
            - secretRef:
                name: teable-secrets
          resources:
            requests:
              cpu: 100m
              memory: 102Mi
            limits:
              cpu: 1000m
              memory: 1024Mi
      containers:
        - name: teable
          image: registry.cn-shenzhen.aliyuncs.com/teable/teable:latest
          args:
            - skip-migrate
          ports:
            - containerPort: 3000
          envFrom:
            - configMapRef:
                name: teable-config
            - secretRef:
                name: teable-secrets
          resources:
            requests:
              cpu: 200m
              memory: 400Mi
            limits:
              cpu: 2000m
              memory: 4096Mi
          startupProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 10
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 30
            successThreshold: 1
          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 30
            periodSeconds: 30
            timeoutSeconds: 5
            failureThreshold: 3
            successThreshold: 1
          readinessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 15
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 3
            successThreshold: 1
```

```yaml teable-service.yaml theme={null}
apiVersion: v1
kind: Service
metadata:
  name: teable
  namespace: teable  # 请替换为你的命名空间
spec:
  ports:
    - port: 3000
      targetPort: 3000
  selector:
    app: teable
```

```yaml teable-ingress.yaml (可选) theme={null}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: teable
  namespace: teable  # 请替换为你的命名空间
  # 以 nginx 做示例，如果使用其他的 ingress class 请替换
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "100m"
    nginx.ingress.kubernetes.io/proxy-buffer-size: "128k"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
spec:
  ingressClassName: nginx  # 如果使用其他 ingress class 请修改
  rules:
    - host: your-domain.com  # 请替换为你的域名
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: teable
                port:
                  number: 3000
  tls:
    - hosts:
        - your-domain.com  # 请替换为你的域名
      secretName: your-tls-secret 
```

<Warning>
  **请勿**添加 `nginx.ingress.kubernetes.io/rewrite-target` 注解，这会破坏 Teable 的内部路由。
</Warning>

## 部署步骤

<Warning>
  在部署 Teable 之前，请确保：

  1. MinIO bucket（`teable-pub` 和 `teable-pvt`）已创建
  2. 公共桶已开启匿名读取权限
  3. PostgreSQL 数据库 `teable` 已存在
  4. Redis 服务可访问
</Warning>

1. 创建命名空间（如果不存在）：

```sh theme={null}
kubectl create namespace teable
```

2. 创建配置和密钥：

```sh theme={null}
kubectl apply -f teable-config.yaml
kubectl apply -f teable-secrets.yaml
```

3. 部署应用：

```sh theme={null}
kubectl apply -f teable-deployment.yaml
kubectl apply -f teable-service.yaml
kubectl apply -f teable-ingress.yaml  # 可选，如果使用 Ingress
```

4. 验证部署：

```sh theme={null}
# 检查 Pod 状态
kubectl get pods -n teable -l app=teable

# 等待 Pod 就绪
kubectl rollout status deployment/teable -n teable

# 查看应用日志
kubectl logs -n teable -l app=teable
```

### 配置注意事项

1. 敏感信息管理

* 所有密码、密钥类信息应通过 Secrets 管理

2. 数据库配置

* 确保数据库已创建 teable 数据库
* 数据库用户需要具备适当权限
* 建议使用连接池管理数据库连接

3. MinIO 配置

* 确保存储桶已创建且权限正确, 一个公共桶，一个私有桶
* 公共桶需要完全公开读
* 内外部访问地址配置正确

4. Redis 配置

* 建议启用 Redis 持久化
* 配置适当的内存限制
* 考虑使用 Redis 集群提高可用性

5. 安全建议

* 使用强密码和密钥
* 启用 TLS/SSL 加密
* 定期更新证书
* 限制网络访问范围

6. 资源配置

* 根据实际负载调整资源限制
* 监控资源使用情况
* 配置适当的健康检查参数

### 故障排查

#### 常见问题

| 错误信息                         | 原因                           | 解决方案                                                                                          |
| ---------------------------- | ---------------------------- | --------------------------------------------------------------------------------------------- |
| `ECONNREFUSED` 连接 MinIO 失败   | MinIO 内网端点配置错误或不可达           | 检查 `BACKEND_STORAGE_MINIO_INTERNAL_ENDPOINT` 格式是否正确：`<service>.<namespace>.svc.cluster.local` |
| `Bucket not found`           | MinIO bucket 未创建             | 在部署前使用 `mc mb` 命令创建 bucket                                                                    |
| `Access Denied` 文件上传失败       | MinIO 凭证错误                   | 检查 `BACKEND_STORAGE_MINIO_ACCESS_KEY` 和 `SECRET_KEY`                                          |
| 访问页面显示 `Page not found`      | Ingress 配置了 `rewrite-target` | 移除 Ingress 中的 `rewrite-target` 注解                                                             |
| Pod 处于 `CrashLoopBackOff` 状态 | 后端启动失败                       | 检查日志，确认 MinIO、数据库、Redis 连接是否正常                                                                |

#### 诊断命令

1. 检查 Pod 状态：

```sh theme={null}
kubectl describe pod -n teable -l app=teable
```

2. 查看应用日志：

```sh theme={null}
kubectl logs -n teable -l app=teable
kubectl logs -n teable -l app=teable --previous  # 如果 Pod 崩溃
```

3. 验证配置：

```sh theme={null}
kubectl describe configmap teable-config -n teable
kubectl describe secret teable-secrets -n teable
```

4. 检查网络连接：

```sh theme={null}
kubectl exec -it <pod-name> -n teable -- curl -v localhost:3000/health
```

5. 测试 MinIO 集群内部连接：

```sh theme={null}
kubectl run test-minio --rm -it --image=curlimages/curl --restart=Never -n teable -- \
  curl -v http://minio.teable.svc.cluster.local/minio/health/live
```
