连接字符串
sh0 不会替你把数据库接入应用。你需要读取连接信息,为应用创建数据库和用户,并自行设置 DATABASE_URL。本页列出每一步,命令均为实际执行结果。
DATABASE_URL、REDIS_URL 或其他任何变量,无论应用属于哪个项目。期待 DATABASE_URL 的应用在你设置之前什么也拿不到。查找连接信息
在控制台中打开 Databases,再打开服务器:Connection Info 显示 Internal Host、端口、Root Password 以及可复制的 Connection URL。
使用 CLI 时,sh0 db connection-info 需要服务器 ID(创建时输出,或通过 sh0 db list 查看):
$ sh0 db create --name my-pg --engine postgres
Database server 'my-pg' created (id: e8afafa4-2ff1-4088-8276-fccb839734a8, engine: postgres 16)
$ sh0 db connection-info e8afafa4-2ff1-4088-8276-fccb839734a8
Connection Info:
Host: my-pg.internal
Port: 32962
Username: postgres
Password: <password>
Internal: postgresql://postgres:<password>@my-pg.internal:5432/
External: postgresql://postgres:<password>@localhost:32962/应用中请使用 Internal URL。External URL 指向服务器上绑定在 127.0.0.1 的端口,只能从服务器本机访问(见“从你的电脑连接”)。
每个应用一个数据库和一个用户
新建的服务器没有任何数据库,只有管理员账户。请为每个应用创建独立的数据库和用户,而不是使用管理员密码。控制台中依次点击 Create Database、Create User、Grant Access。使用 CLI:
$ sh0 db create-database e8afafa4-2ff1-4088-8276-fccb839734a8 --name appdb
Database 'appdb' created (id: 503a447c-f9f5-44b8-87cf-22c0905f075c).
$ sh0 db create-user e8afafa4-2ff1-4088-8276-fccb839734a8 --username appuser --password '<password>'
User 'appuser' created (id: 86de6179-7e97-463a-93d8-dfd89b1da6e2).
$ sh0 db grant e8afafa4-2ff1-4088-8276-fccb839734a8 \
--user 86de6179-7e97-463a-93d8-dfd89b1da6e2 \
--database 503a447c-f9f5-44b8-87cf-22c0905f075c --privileges all
Access granted.- 密码规则 -- 至少包含一个大写字母和一个符号等;不符合的密码会被拒绝,并提示违反的规则。控制台的 Generate 按钮可生成合规密码;请立即保存,之后不会再显示。
- 权限 --
all或readonly,其他值会被拒绝。
在应用上设置 DATABASE_URL
用内部主机名、引擎端口、用户和数据库拼出 URL,保存为应用的环境变量。变量在部署时生效,因此需要重新部署:
$ sh0 env my-api set "DATABASE_URL=postgresql://appuser:<password>@my-pg.internal:5432/appdb"
[ok] Set DATABASE_URL for 'my-api'
$ sh0 deploy my-api
[*] Deploying my-api...
Deployment ID: 64492c39-dad0-409f-ad6d-29b71f79bab3
Status: queued各引擎的 URL 格式(把名称换成你自己的;内部端口是引擎默认端口,而不是 Port 下显示的端口):
- PostgreSQL --
postgresql://appuser:<password>@my-pg.internal:5432/appdb - MySQL 和 MariaDB --
mysql://appuser:<password>@my-mysql.internal:3306/appdb - Redis --
redis://:<password>@my-redis.internal:6379
@、:、/、#…)在 URL 中必须进行百分号编码。定时任务不会收到这些变量 -- 见定时任务。内部网络
应用和数据库服务器共享 sh0 的 Docker 网络。应用通过 <服务器名>.internal 加引擎端口访问服务器 -- 在应用容器中实测:到 my-pg.internal:5432 的 TCP 连接成功建立,appuser 使用上述 URL 登录 appdb。
从你的电脑连接
要从工作站(pgAdmin、TablePlus、DBeaver、psql)访问数据库,有两种方式,优先使用第一种。
SSH 隧道(推荐)
Port 下显示的端口(此处为 32962)在服务器上绑定于 127.0.0.1。通过 SSH 转发即可:不会向互联网暴露任何端口,访问权限即你的 SSH 密钥权限。
ssh -N -L 5432:127.0.0.1:32962 root@your-server
# in another terminal
psql "postgresql://appuser:<password>@127.0.0.1:5432/appdb"外部访问
在服务器上点击 Enable External Access 会通过 sh0 的代理开放一个公网端口。已发布版本的代码强制执行以下规则:
- 必须填写允许的 IP -- 单个地址或 CIDR 段;
0.0.0.0/0和::/0会被拒绝。 - 默认要求 TLS。
- 有效期 -- 1 小时、6 小时、24 小时、7 天、30 天或永久。
- 端口 -- 10000-10999 范围内第一个空闲端口;你的防火墙需要放行它。
连接池
每个数据库都有连接数上限(PostgreSQL 默认 100)。请调整连接池大小,使所有副本加起来低于该上限。
- 使用框架自带的连接池 -- 大多数 ORM 和驱动都提供。
- 在副本之间分配上限 -- 应用有 3 个副本、上限为 100 时,每个副本约 30 个连接,再减去其他应用的占用。
- 设置空闲超时,让闲置连接释放名额。
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20, // Maximum connections in the pool
idleTimeoutMillis: 30000, // Close idle connections after 30s
connectionTimeoutMillis: 5000, // Fail if connection takes > 5s
});常见框架示例
下面的每个示例都读取你在应用上设置的 DATABASE_URL。
production:
url: <%= ENV['DATABASE_URL'] %>import dj_database_url
DATABASES = {"default": dj_database_url.config(conn_max_age=600)}let pool = PgPoolOptions::new()
.max_connections(20)
.connect(&std::env::var("DATABASE_URL")?)
.await?;pool, err := pgxpool.New(ctx, os.Getenv("DATABASE_URL"))