自建Supabase:创业出海的首选数据库

如何在本地/云端物理机/裸金属/虚拟机上使用 Pigsty 自建企业级 Supabase?

Supabase 非常棒,拥有你自己的 Supabase 那就是棒上加棒!本文介绍了如何在本地/云端物理机/裸金属/虚拟机上自建企业级 Supabase。


目录


简短版本

curl -fsSL https://repo.pigsty.io/get | bash; && cd ~/pigsty
./bootstrap               # 准备 Pigsty 依赖
./configure -c app/supa   # 使用 Supabase 应用模板
./install.yml             # 安装 Pigsty,以及各种数据库
./docker.yml              # 安装 Docker 与 Docker Compose
./app.yml                 # 使用 Docker 拉起 Supabase 无状态部分

Supabase是什么?

Supabase 是一个开源的 Firebase,是一个 BaaS (Backend as Service)。 Supabase 对 PostgreSQL 进行了封装,并提供了身份认证,消息传递,边缘函数,对象存储,以及基于 PG 数据库模式自动生成的 REST API 与 GraphQL API。

Supabase 旨在为开发者提供一站式的后端解决方案,减少开发和维护后端基础设施的复杂性,使开发者专注于前端开发和用户体验。 用大白话来说就是:让开发者告别绝大部分后端开发的工作,只需要懂数据库设计与前端即可快速出活!

目前,Supabase 是 PostgreSQL 生态 人气最高的开源项目,在 GitHub 上已经有高达 7万4千 的Star数。 并且和 Neon,Cloudflare 一起并称为赛博菩萨 —— 因为他们都提供了非常不错的云服务免费计划。 目前,Supabase 和 Neon 已经成为许多初创企业的首选数据库 —— 用起来非常方便,起步还是免费的。


为什么要自建Supabase?

小微规模(4c8g)内的 Supabase 云服务极富性价比,人称赛博菩萨。那么 Supabase 云服务这么香,为什么要自建呢?

最直观的原因是是我们在《云数据库是智商税吗?》中提到过的:当你的规模超出云计算适用光谱,成本很容易出现爆炸式增长。 而且在当下,足够可靠的本地企业级 NVMe SSD在性价比上与云端存储有着三到四个数量级的优势,而自建能更好地利用这一点。

另一个重要的原因是功能, Supabase 云服务的功能受限 —— 出于与RDS相同的逻辑, 很多 强力PG扩展 因为多租户安全挑战与许可证的原因无法作为云服务提供。 故而尽管PG扩展是 Supabase 的一个核心特色,在云服务上也依然只有 64 个可用扩展,而 Pigsty 提供了多达 404 个开箱即用的 PG 扩展。

此外,尽管 Supabase 虽然旨在提供一个无供应商锁定的 Google Firebase 开源替代,但实际上自建高标准企业级的 Supabase 门槛并不低: Supabase 内置了一系列由他们自己开发维护的 PG 扩展插件,而这些扩展在 PGDG 官方仓库中并没有提供。 这实际上是某种隐性的供应商锁定,阻止了用户使用除了 supabase/postgres Docker 镜像之外的方式自建。

Pigsty 解决了这些问题,我们将所有 Supabase 自研与用到的 10 个缺失的扩展打成开箱即用的 RPM/DEB 包,确保它们在所有主流Linux操作系统发行版上都可用:

  • pg_graphql:提供PG内的GraphQL支持 (RUST),Rust扩展,由PIGSTY提供
  • pg_jsonschema:提供JSON Schema校验能力,Rust扩展,由PIGSTY提供
  • wrappers:Supabase提供的外部数据源包装器捆绑包,,Rust扩展,由PIGSTY提供
  • index_advisor:查询索引建议器,SQL扩展,由PIGSTY提供
  • pg_net:用 SQL 进行异步非阻塞HTTP/HTTPS 请求的扩展 (supabase),C扩展,由PIGSTY提供
  • vault:在 Vault 中存储加密凭证的扩展 (supabase),C扩展,由PIGSTY提供
  • pgjwt:JSON Web Token API 的PG实现 (supabase),SQL扩展,由PIGSTY提供
  • pgsodium:表数据加密存储 TDE,扩展,由PIGSTY提供
  • supautils:用于在云环境中确保数据库集群的安全,C扩展,由PIGSTY提供
  • pg_plan_filter:使用执行计划代价过滤阻止特定查询语句,C扩展,由PIGSTY提供

我们还在 Supabase 中默认安装了以下扩展,您可以参考可用扩展列表启用更多。

- timescaledb postgis pg_graphql pg_jsonschema wrappers pg_search pg_analytics pg_parquet plv8 duckdb_fdw pg_cron pg_timetable pgqr
- supautils pg_plan_filter passwordcheck plpgsql_check pgaudit pgsodium pg_vault pgjwt pg_ecdsa pg_session_jwt index_advisor
- pgvector pgvectorscale pg_summarize pg_tiktoken pg_tle pg_stat_monitor hypopg pg_hint_plan pg_http pg_net pg_smtp_client pg_idkit

同时,Pigsty 还会负责好底层 高可用 PostgreSQL 数据库集群,高可用 MinIO 对象存储集群的自动搭建,甚至是 Docker 容器底座的部署与 Nginx 域名配置与证书签发。 最终,您可以使用 Docker Compose 拉起任意数量的无状态 Supabase 容器集群,并使用外部由 Pigsty 托管的企业级 PostgreSQL 数据库与 MinIO 对象存储,甚至连反向代理的 Nginx 等都已经为您配置准备完毕!

在这一自建部署架构中,您获得了使用不同内核的自由(PG 14-17),加装 404 个扩展的自由,扩容与伸缩 Supabase/Postgres/MinIO 的自由,免于数据库运维的自由,以及告别供应商锁定的自由。 而相比于使用 Supabase 云服务需要付出的代价,不过是准备一(几)台物理机/虚拟机 + 敲几行命令,等候十几分钟的区别。


单节点自建快速上手

让我们先从单节点 Supabase 部署开始,我们会在后面进一步介绍多节点高可用部署的方法。

首先,使用 Pigsty 标准安装流程 安装 Supabase 所需的 MinIO 与 PostgreSQL 实例; 然后额外运行 docker.ymlapp.yml 完成剩余的工作, 拉起无状态部分的 Supabase 容器,Supabase 就可以使用了(默认端口 8000/8433)。

curl -fsSL https://repo.pigsty.io/get | bash; && cd ~/pigsty
./bootstrap               # 准备 Pigsty 依赖
./configure -c app/supa   # 使用 Supabase 应用模板
./install.yml             # 安装 Pigsty,以及各种数据库
./docker.yml              # 安装 Docker 与 Docker Compose
./app.yml                 # 使用 Docker 拉起 Supabase 无状态部分

请在部署 Supabase 前,根据您的实际情况,修改自动生成的 pigsty.yml 配置文件中的参数(主要是密码!) 如果您只是将其用于本地开发测试,可以先不管这些,我们将在后面介绍如何通过修改配置文件来定制您的 Supabase。

如果您的配置没有问题,那么大约在 10 分钟后,您就可以在本地网络通过 http://<your_ip_address>:8000 访问到 Supabase Studio 管理界面了。 默认的用户名与密码分别是: supabasepigsty

asciicast


检查清单

  • 硬件/软件:准备所需的机器资源:Linux x86_64/arm64 服务器一台,全新安装主流 Linux 操作系统
  • 网络/权限:有 ssh 免密登陆权限,所用用户有免密 sudo 权限
  • 确保机器有内网静态IPv4网络地址,并可以访问互联网。中国地区 DockerHub 需要翻墙,需要有可用的代理或镜像站点
    • configure 过程中,请输入节点的内网首要 IP 地址,或直接通过 -i <primary_ip> 命令行参数指定
    • 如果您的网络环境无法访问 DockerHub,请通过 docker_registry_mirrors 使用镜像站 或 proxy_env 绕过防火墙。
  • 确保使用了 app/supa 配置模板,并按需修改了参数
    • 您是否修改了所有与密码有关的配置参数?【可选】
    • 您是否需要使用外部 SMTP 服务器?是否配置了 apps.<supabase>.conf 中的 SMTP 相关参数?【可选】

中国地区的用户请注意,如果您没有配置好 Docker 镜像站点或代理服务器,那么会有极大概率会翻车在 ./supabase 最后一步的镜像拉取上。我们建议您掌握科学上网技巧,参考 Docker 模块 FAQ 的说明配置镜像站代理服务器。 请注意,我们提供 Supabase 自建专门咨询服务,¥2000 / 例·半小时,购买附赠预制离线安装包,可以无需互联网(自然也无需翻墙)安装,将您的企业级自建 Supabase 安稳扶上马!

修改后的配置文件,应该如下所示:

对默认生成的配置文件进行修改
all:
  children:

    # supabase 无状态部分的定义 (默认用户名密码: supabase/pigsty)
    supa:
      hosts:
        10.10.10.10: {}
      vars:
        app: supabase # 指定默认安装等应用名称(supabase)
        apps:         # 定义应用列表,这里只有 supabase
          supabase:   # Supabase 应用定义
            conf:     # 下面的 Supabase 配置项会自动覆盖或追加到 /opt/supabase/.env 文件中(模板路径:app/supabase/.env ,内容详见:https://github.com/Vonng/pigsty/blob/main/app/supabase/.env)

              # 【非常重要】: 请修改下面的 JWT_SECRET 以及 ANON_KEY 与 SERVICE_ROLE_KEY : https://supabase.com/docs/guides/self-hosting/docker#securing-your-services
              JWT_SECRET: your-super-secret-jwt-token-with-at-least-32-characters-long
              ANON_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
              SERVICE_ROLE_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
              DASHBOARD_USERNAME: supabase
              DASHBOARD_PASSWORD: pigsty

              # postgres connection string (use the correct ip and port)
              POSTGRES_HOST: 10.10.10.10
              POSTGRES_PORT: 5436             # access via the 'default' service, which always route to the primary postgres
              POSTGRES_DB: postgres
              POSTGRES_PASSWORD: DBUser.Supa  # password for supabase_admin and multiple supabase users

              # expose supabase via domain name
              SITE_URL: http://supa.pigsty                # <------- Change This to your external domain name
              API_EXTERNAL_URL: http://supa.pigsty        # <------- Otherwise the storage api may not work!
              SUPABASE_PUBLIC_URL: http://supa.pigsty     # <------- Do not forget!

              # if using s3/minio as file storage
              S3_BUCKET: supa
              S3_ENDPOINT: https://sss.pigsty:9000
              S3_ACCESS_KEY: supabase
              S3_SECRET_KEY: S3User.Supabase
              S3_FORCE_PATH_STYLE: true
              S3_PROTOCOL: https
              S3_REGION: stub
              MINIO_DOMAIN_IP: 10.10.10.10  # sss.pigsty domain name will resolve to this ip statically

              # if using SMTP (optional)
              #SMTP_ADMIN_EMAIL: admin@example.com
              #SMTP_HOST: supabase-mail
              #SMTP_PORT: 2500
              #SMTP_USER: fake_mail_user
              #SMTP_PASS: fake_mail_password
              #SMTP_SENDER_NAME: fake_sender
              #ENABLE_ANONYMOUS_USERS: false


    # infra 集群,包含 Prometheus & Grafana 监控基础设施
    infra: { hosts: { 10.10.10.10: { infra_seq: 1 } } }

    # etcd 集群,本例为单节点 Etcd,用于提供 PG 高可用
    etcd: { hosts: { 10.10.10.10: { etcd_seq: 1 } }, vars: { etcd_cluster: etcd } }

    # minio 集群,单节点 SNSD 的 S3 兼容对象存储
    minio: { hosts: { 10.10.10.10: { minio_seq: 1 } }, vars: { minio_cluster: minio } }

    # pg-meta, Supabase 底层实际的 PostgreSQL 数据库
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta
        pg_users:
          # supabase roles: anon, authenticated, dashboard_user
          - { name: anon           ,login: false }
          - { name: authenticated  ,login: false }
          - { name: dashboard_user ,login: false ,replication: true ,createdb: true ,createrole: true }
          - { name: service_role   ,login: false ,bypassrls: true }
          # 【注意】如果你要修改 Supabase 业务用户的密码,请在这里统一修改所有用户的密码
          - { name: supabase_admin             ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: true   ,roles: [ dbrole_admin ] ,superuser: true ,replication: true ,createdb: true ,createrole: true ,bypassrls: true }
          - { name: authenticator              ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: false  ,roles: [ dbrole_admin, authenticated ,anon ,service_role ] }
          - { name: supabase_auth_admin        ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: false  ,roles: [ dbrole_admin ] ,createrole: true }
          - { name: supabase_storage_admin     ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: false  ,roles: [ dbrole_admin, authenticated ,anon ,service_role ] ,createrole: true }
          - { name: supabase_functions_admin   ,password: 'DBUser.Supa' ,pgbouncer: true ,inherit: false  ,roles: [ dbrole_admin ] ,createrole: true }
          - { name: supabase_replication_admin ,password: 'DBUser.Supa' ,replication: true ,roles: [ dbrole_admin ]}
          - { name: supabase_read_only_user    ,password: 'DBUser.Supa' ,bypassrls: true ,roles: [ dbrole_readonly, pg_read_all_data ] }
        # 【注意】 这里定义了 Supabase 使用的底层 Postgres 业务数据库,
        pg_databases:
          - name: postgres
            baseline: supabase.sql  # 这里的 files/supabase.sql 文件包含了初始化 Supabase 所必需的模式迁移脚本,非常重要!
            owner: supabase_admin   # 这里的数据库所有者,必须是上面定义的 supabase_admin,我们建议使用此用户进行模式变更。
            comment: supabase postgres database
            schemas: [ extensions ,auth ,realtime ,storage ,graphql_public ,supabase_functions ,_analytics ,_realtime ]
            extensions:             # 定义在这里的扩展会默认在数据库中 “创建并启用”
              - { name: pgcrypto  ,schema: extensions } # cryptographic functions
              - { name: pg_net    ,schema: extensions } # async HTTP
              - { name: pgjwt     ,schema: extensions } # json web token API for postgres
              - { name: uuid-ossp ,schema: extensions } # generate universally unique identifiers (UUIDs)
              - { name: pgsodium        }               # pgsodium is a modern cryptography library for Postgres.
              - { name: supabase_vault  }               # Supabase Vault Extension
              - { name: pg_graphql      }               # pg_graphql: GraphQL support
              - { name: pg_jsonschema   }               # pg_jsonschema: Validate json schema
              - { name: wrappers        }               # wrappers: FDW collections
              - { name: http            }               # http: allows web page retrieval inside the database.
              - { name: pg_cron         }               # pg_cron: Job scheduler for PostgreSQL
              - { name: timescaledb     }               # timescaledb: Enables scalable inserts and complex queries for time-series data
              - { name: pg_tle          }               # pg_tle: Trusted Language Extensions for PostgreSQL
              - { name: vector          }               # pgvector: the vector similarity search
              - { name: pgmq            }               # pgmq: A lightweight message queue like AWS SQS and RSMQ
        # supabase required extensions
        pg_libs: 'timescaledb, plpgsql, plpgsql_check, pg_cron, pg_net, pg_stat_statements, auto_explain, pg_tle, plan_filter'
        pg_parameters:
          cron.database_name: postgres
          pgsodium.enable_event_trigger: off
        pg_hba_rules: # supabase hba rules, require access from docker network
          - { user: all ,db: postgres  ,addr: intra         ,auth: pwd ,title: 'allow supabase access from intranet'    }
          - { user: all ,db: postgres  ,addr: 172.17.0.0/16 ,auth: pwd ,title: 'allow access from local docker network' }
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ] # make a full backup every 1am



  #==============================================================#
  # Global Parameters
  #==============================================================#
  vars:
    version: v3.3.0                   # pigsty version string
    admin_ip: 10.10.10.10             # admin node ip address
    region: default                   # upstream mirror region: default|china|europe
    node_tune: oltp                   # node tuning specs: oltp,olap,tiny,crit
    pg_conf: oltp.yml                 # pgsql tuning specs: {oltp,olap,tiny,crit}.yml
    docker_enabled: true              # enable docker on app group

    # WARNING: YOU MAY HAVE
    #docker_registry_mirrors: ["https://docker.m.daocloud.io"] # use dao cloud mirror in mainland china
    proxy_env:                        # global proxy env when downloading packages & pull docker images
      no_proxy: "localhost,127.0.0.1,10.0.0.0/8,192.168.0.0/16,*.pigsty,*.aliyun.com,mirrors.*,*.tsinghua.edu.cn"
      #http_proxy:  127.0.0.1:12345 # add your proxy env here for downloading packages or pull images
      #https_proxy: 127.0.0.1:12345 # usually the proxy is format as http://user:pass@proxy.xxx.com
      #all_proxy:   127.0.0.1:12345

    infra_portal:                     # domain names and upstream servers
      home         : { domain: h.pigsty }
      grafana      : { domain: g.pigsty ,endpoint: "${admin_ip}:3000" , websocket: true }
      prometheus   : { domain: p.pigsty ,endpoint: "${admin_ip}:9090" }
      alertmanager : { domain: a.pigsty ,endpoint: "${admin_ip}:9093" }
      minio        : { domain: m.pigsty ,endpoint: "10.10.10.10:9001", https: true, websocket: true }
      blackbox     : { endpoint: "${admin_ip}:9115" }
      loki         : { endpoint: "${admin_ip}:3100" }  # expose supa studio UI and API via nginx
      supa         : { domain: supa.pigsty ,endpoint: "10.10.10.10:8000", websocket: true }
      # certbot --nginx --agree-tos --email your@email.com -n -d supa.your.domain    # replace with your email & supa domain

    #----------------------------------#
    # Credential: CHANGE THESE PASSWORDS
    #----------------------------------#
    #grafana_admin_username: admin
    grafana_admin_password: pigsty
    #pg_admin_username: dbuser_dba
    pg_admin_password: DBUser.DBA
    #pg_monitor_username: dbuser_monitor
    pg_monitor_password: DBUser.Monitor
    #pg_replication_username: replicator
    pg_replication_password: DBUser.Replicator
    #patroni_username: postgres
    patroni_password: Patroni.API
    #haproxy_admin_username: admin
    haproxy_admin_password: pigsty
    #minio_access_key: minioadmin
    minio_secret_key: minioadmin      # minio root secret key, `minioadmin` by default

    # use minio as supabase file storage, single node single driver mode for demonstration purpose
    minio_buckets: [ { name: pgsql }, { name: supa } ]
    minio_users:
      - { access_key: dba , secret_key: S3User.DBA, policy: consoleAdmin }
      - { access_key: pgbackrest , secret_key: S3User.Backup,   policy: readwrite }
      - { access_key: supabase   , secret_key: S3User.Supabase, policy: readwrite }
    minio_endpoint: https://sss.pigsty:9000    # explicit overwrite minio endpoint with haproxy port
    node_etc_hosts: ["10.10.10.10 sss.pigsty"] # domain name to access minio from all nodes (required)

    # use minio as default backup repo for PostgreSQL
    pgbackrest_method: minio          # pgbackrest repo method: local,minio,[user-defined...]
    pgbackrest_repo:                  # pgbackrest repo: https://pgbackrest.org/configuration.html#section-repository
      local:                          # default pgbackrest repo with local posix fs
        path: /pg/backup              # local backup directory, `/pg/backup` by default
        retention_full_type: count    # retention full backups by count
        retention_full: 2             # keep 2, at most 3 full backup when using local fs repo
      minio:                          # optional minio repo for pgbackrest
        type: s3                      # minio is s3-compatible, so s3 is used
        s3_endpoint: sss.pigsty       # minio endpoint domain name, `sss.pigsty` by default
        s3_region: us-east-1          # minio region, us-east-1 by default, useless for minio
        s3_bucket: pgsql              # minio bucket name, `pgsql` by default
        s3_key: pgbackrest            # minio user access key for pgbackrest
        s3_key_secret: S3User.Backup  # minio user secret key for pgbackrest
        s3_uri_style: path            # use path style uri for minio rather than host style
        path: /pgbackrest             # minio backup path, default is `/pgbackrest`
        storage_port: 9000            # minio port, 9000 by default
        storage_ca_file: /pg/cert/ca.crt  # minio ca file path, `/pg/cert/ca.crt` by default
        bundle: y                     # bundle small files into a single file
        cipher_type: aes-256-cbc      # enable AES encryption for remote backup repo
        cipher_pass: pgBackRest       # AES encryption password, default is 'pgBackRest'
        retention_full_type: time     # retention full backup by time on minio repo
        retention_full: 14            # keep full backup for last 14 days

    # download docker and all available extensions
    pg_version: 17
    repo_modules: node,pgsql,infra,docker
    repo_packages: [node-bootstrap, infra-package, infra-addons, node-package1, node-package2, pgsql-utility, docker ]
    repo_extra_packages: [pg17-core ,pg17-time ,pg17-gis ,pg17-rag ,pg17-fts ,pg17-olap ,pg17-feat ,pg17-lang ,pg17-type ,pg17-util ,pg17-func ,pg17-admin ,pg17-stat ,pg17-sec ,pg17-fdw ,pg17-sim ,pg17-etl ]
    pg_extensions:                  [pg17-time ,pg17-gis ,pg17-rag ,pg17-fts ,pg17-feat ,pg17-lang ,pg17-type ,pg17-util ,pg17-func ,pg17-admin ,pg17-stat ,pg17-sec ,pg17-fdw ,pg17-sim ,pg17-etl ] #,pg17-olap]

自建关键技术决策

以下是一些自建 Supabase 会涉及到的关键技术决策,供您参考:

使用默认的单节点部署 Supabase 无法享受到 PostgreSQL / MinIO 的高可用能力。 尽管如此,单节点部署相比官方纯 Docker Compose 方案依然要有显著优势: 例如开箱即用的监控系统,自由安装扩展的能力,各个组件的扩缩容能力,以及数据库时间点恢复能力等。

如果您只有一台服务器,Pigsty 建议您直接使用外部的 S3 作为对象存储,存放 PostgreSQL 的备份,并承载 Supabase Storage 服务。 这样的部署在故障时可以提供一个最低标准的 RTO (小时级恢复时长)/ RPO (MB级数据损失)兜底容灾水平。 此外,如果您选择在云上自建,我们也建议您直接使用 S3,而非默认使用的本体 MinIO ,单纯在本地 EBS 上再套一层 MinIO 转发,除了便于开发测试外,对生产实用并没有意义。

在严肃的生产部署中,Pigsty 建议使用至少3~4个节点的部署策略,确保 MinIO 与 PostgreSQL 都使用满足企业级高可用要求的多节点部署。 在这种情况下,您需要相应准备更多节点与磁盘,并相应调整 pigsty.yml 配置清单中的集群配置,以及 supabase 集群配置中的接入信息。

部分 Supabase 的功能需要发送邮件,所以要用到 SMTP。除非单纯用于内网,否则对于严肃的生产部署,我们建议您考虑使用外部的 SMTP 服务。 自建的邮件服务器发送的邮件可能会被对方邮件服务器拒收,或者被标记为垃圾邮件。

如果您的服务直接向公网暴露,我们建议您使用 Nginx 进行反向代理,使用真正的域名与 HTTPS 证书,并通过不同的域名区分不同的多个实例。

接下来,我们会依次讨论这几个主题:

  • 进阶主题:安全加固
  • 高可用的 PostgreSQL 集群部署与接入
  • 高可用的 MinIO 集群部署与接入
  • 使用 S3 服务替代 MinIO
  • 使用外部 SMTP 服务发送邮件
  • 使用真实域名,证书,通过 Nginx 反向代理

进阶主题:安全加固

Pigsty基础组件

对于严肃的生产部署,我们强烈建议您修改 Pigsty 基础组件的密码。因为这些默认值是公开且众所周知的,不改密码上生产无异于裸奔:

以上密码为 Pigsty 组件模块的密码,强烈建议在安装部署前就设置完毕。

Supabase密钥

除了 Pigsty 组件的密码,你还需要 修改 Supabase 的密钥,包括

这里请您务必参照 Supabase教程:保护你的服务 里的说明:

  • 生成一个长度超过 40 个字符的 jwt_secret,并使用教程中的工具签发 anon_keyservice_role_key 两个 JWT。
  • 使用教程中提供的工具,根据 jwt_secret 以及过期时间等属性,生成一个 anon_key JWT,这是匿名用户的身份凭据。
  • 使用教程中提供的工具,根据 jwt_secret 以及过期时间等属性,生成一个 service_role_key,这是权限更高服务角色的身份凭据。
  • 如果您使用的 PostgreSQL 业务用户使用了不同于默认值的密码,请相应修改 `postgres_password`` 的值
  • 如果您的对象存储使用了不同于默认值的密码,请相应修改 s3_access_key``](https://github.com/Vonng/pigsty/blob/main/conf/app/supa.yml#136) 与 [s3_secret_key`` 的值

Supabase 部分的凭据修改后,您可以重启 Docker Compose 容器以应用新的配置:

cd /opt/supabase; docker compose up

进阶主题:域名接入

如果你在本机或局域网内使用 Supabase,那么可以选择 IP:Port 直连 Kong 对外暴露的 HTTP 8000 端口,当然这样并不好,我们建议您使用域名与 HTTPS 来访问。

使用默认的本地域名 supa.pigsty 时,您可以在浏览器本机的 /etc/hosts 或局域网 DNS 里来配置它的解析,将其指向安装节点的【对外】IP地址。 Pigsty 管理节点上的 Nginx 会为此域名申请自签名的证书(浏览器显示《不安全》),并将请求转发到 8000 端口的 Kong,由 Supabase 处理。

不过,更为实用与常见的用例是:Supabase 通过公网队外提供服务。在这种情况下,通常您需要进行以下准备:

  • 您的服务器应当有一个公网 IP 地址
  • 购买域名,使用 云/DNS/CDN 供应商提供的 DNS 解析服务,将其指向安装节点的公网 IP(下位替代:本地 /etc/hosts
  • 申请证书,使用 Let’s Encrypt 等证书颁发机构签发的免费 HTTPS 证书,用于加密通信(下位替代:默认自签名证书,手工信任)

您可以 参考certbot教程 ,申请免费的 HTTPS 证书,这里我们假设您使用的自定义域名是:supa.pigsty.cc

certbot --nginx --agree-tos --email your@email.com -n -d supa.pigsty.cc

申请证书后,请修改 pigsty.yml 配置文件中 Nginx 与 Supabase 的配置:

  • all.vars.infra_portal 部分的 supa 域名(domain,然后填入生成证书的 certkey 文件路径)
  • 修改 supabase 中的三个域名字段。
all:
  vars:     # 全局配置 
    #.....
    infra_portal:                     # domain names and upstream servers
      home         : { domain: h.pigsty }
      grafana      : { domain: g.pigsty ,endpoint: "${admin_ip}:3000" , websocket: true }
      prometheus   : { domain: p.pigsty ,endpoint: "${admin_ip}:9090" }
      alertmanager : { domain: a.pigsty ,endpoint: "${admin_ip}:9093" }
      minio        : { domain: m.pigsty ,endpoint: "10.10.10.10:9001", https: true, websocket: true }
      blackbox     : { endpoint: "${admin_ip}:9115" }
      loki         : { endpoint: "${admin_ip}:3100" }
      
      #supa        : { domain: supa.pigsty ,endpoint: "10.10.10.10:8000", websocket: true }  # 如果使用申请的 HTTPS 证书,请在这里指定证书的存放路径
      supa         : { domain: supa.pigsty.cc ,endpoint: "10.10.10.10:8000", websocket: true ,cert: /etc/cert/suap.pigsty.cc.crt ,key: /etc/cert/supa.pigsty.cc.key }

    # the supabase stateless (default username & password: supabase/pigsty)
    supa:
      hosts:
        10.10.10.10: {}
      vars:
        app: supabase # specify app name (supa) to be installed (in the apps)
        apps:         # define all applications
          supabase:   # the definition of supabase app
            conf:     # override /opt/supabase/.env
              
              # 请在这里更新 Supabase 使用的域名 (换成了真实 HTTPS 域名)
              site_url: https://supa.pigsty.cc
              api_external_url: https://supa.pigsty.cc
              supabase_public_url: https://supa.pigsty.cc

然后更新 Nginx 与 Supabase App 的配置后应用生效:

./infra.yml    -t nginx_config,nginx_launch
./app.yml      -t app_config,app_launch

使用以上命令重新加载 Nginx 和 Supabase 的配置。


进阶主题:外部对象存储

您可以使用 S3 或 S3 兼容的服务,来作为 PGSQL 备份与 Supabase 使用的对象存储。这里我们使用一个 阿里云 OSS 对象存储作为例子。

Pigsty 提供了一个 terraform/spec/aliyun-meta-s3.tf 模板,用于在阿里云上拉起一台服务器,以及一个 OSS 存储桶。

首先,我们修改 all.children.supa.vars.apps.[supabase].conf 中 S3 相关的配置,将其指向阿里云 OSS 存储桶:

# if using s3/minio as file storage
S3_BUCKET: supa
S3_ENDPOINT: https://sss.pigsty:9000
S3_ACCESS_KEY: supabase
S3_SECRET_KEY: S3User.Supabase
S3_FORCE_PATH_STYLE: true
S3_PROTOCOL: https
S3_REGION: stub
MINIO_DOMAIN_IP: 10.10.10.10  # sss.pigsty domain name will resolve to this ip statically

同样使用以下命令重载 Supabase 配置:

./app.yml -t app_config,app_launch

您同样可以使用 S3 作为 PostgreSQL 的备份仓库,在 all.vars.pgbackrest_repo 新增一个 aliyun 备份仓库的定义:

all:
  vars:
    pgbackrest_method: aliyun          # pgbackrest 备份方法:local,minio,[其他用户定义的仓库...],本例中将备份存储到 MinIO 上
    pgbackrest_repo:                   # pgbackrest 备份仓库: https://pgbackrest.org/configuration.html#section-repository
      aliyun:                          # 定义一个新的备份仓库 aliyun
        type: s3                       # 阿里云 oss 是 s3-兼容的对象存储
        s3_endpoint: oss-cn-beijing-internal.aliyuncs.com
        s3_region: oss-cn-beijing 
        s3_bucket: pigsty-oss
        s3_key: xxxxxxxxxxxxxx
        s3_key_secret: xxxxxxxx
        s3_uri_style: host
        
        path: /pgbackrest
        bundle: y
        cipher_type: aes-256-cbc
        cipher_pass: PG.${pg_cluster}   # 设置一个与集群名称绑定的加密密码
        retention_full_type: time 
        retention_full: 14

然后在 all.vars.pgbackrest_mehod 中指定使用 aliyun 备份仓库,重置 pgBackrest 备份:

./pgsql.yml -t pgbackrest

Pigsty 会将备份仓库切换到外部对象存储上。


进阶主题:备份策略

你可以使用操作系统的 Crontab 来设置定时备份策略,例如,向默认的 all.children.pg-meta.vars 中添加 node_crontab 参数:

all:
  children:
    pg-meta:
      hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
      vars:
        pg_cluster: pg-meta  # 每天凌晨一点做个全量备份
        node_crontab: [ '00 01 * * * postgres /pg/bin/pg-backup full' ]

然后执行以下命令,将 Crontab 配置应用到节点上:

./node.yml -t node_crontab

更多关于备份策略的主题,请参考 备份策略


进阶主题:使用SMTP

你可以使用 SMTP 来发送邮件,修改 supabase 配置,添加 SMTP 信息:

all:
  children:
    supabase:
      vars:
        supa_config:
          smtp_host: smtpdm.aliyun.com:80
          smtp_port: 80
          smtp_user: no_reply@mail.your.domain.com
          smtp_pass: your_email_user_password
          smtp_sender_name: MySupabase
          smtp_admin_email: adminxxx@mail.your.domain.com
          enable_anonymous_users: false

不要忘了使用 app.yml -t app_config,app_launch 来重载配置


进阶主题:真·高可用

经过上面的配置,您已经可以使用一个带有公网域名,HTTPS 证书,SMTP 邮件服务器,备份的 Supabase 了。

如果您的这个节点挂了,起码外部 S3 存储中保留了备份,您可以在新的节点上重新部署 Supabase,然后从备份中恢复。 这样的部署在故障时可以提供一个最低标准的 RTO (小时级恢复时长)/ RPO (MB级数据损失)兜底容灾水平 兜底。

但如果您想要达到 RTO < 30s ,零数据丢失,那么就需要用到多节点高可用集群了。多节点部署有三个维度:

  • ETCD: DCS 需要使用三个节点或以上,才能容忍一个节点的故障。
  • PGSQL: PGSQL 同步提交不丢数据模式,建议使用至少三个节点。
  • INFRA:监控基础设施故障影响稍小,但我们建议生产环境使用三副本
  • Supabase 本身也可以是多节点的副本,实现高可用

我们建议您参考 triosafe 中的集群配置,将您的集群配置升级到三节点或以上。

在这种情况下,您还需要修改 PostgreSQL 与 MinIO 的接入点,使用 DNS / L2 VIP / HAProxy 等 高可用接入点





最后修改 2025-02-27: update release note (bf999b0)