ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Devenv 声明式配置 PostgreSQL 服务:services.postgres 模块配置与源码级解析

Devenv 声明式配置 PostgreSQL 服务:services.postgres 模块配置与源码级解析 开发工具CLI【免费下载链接】devenvFast, Declarative, Reproducible, and Composable Developer Environments using Nix项目地址https://gitcode.com/gh_mirrors/de/devenv点击查看免费下载devenv 通过services.postgres模块提供开箱即用的 PostgreSQL 开发环境一行enable true即可启动数据库进程并通过 Nix 声明式地完成建库、建用户、初始化 SQL、扩展安装与postgresql.conf调优。本文以 docs/src/content/docs/services/postgres.md 的选项文档为骨架结合 src/modules/services/postgres.nix 的实现与仓库内真实测试用例逐项讲解每个配置项的语义、默认值与运行机制帮助你写出可复现、可迁移的 PostgreSQL 开发环境配置。快速开始从零启动一个 PostgreSQLdevenv 将服务抽象在processes之上processes 提供运行任意命令的底层控制而 services如 PostgreSQL为数据库这类既有软件提供预配置接口。services 与 processes 一样通过devenv up启动$ devenv up Starting processes ...如果希望服务在后台运行传入-d标志$ devenv up -d一个最小的 PostgreSQL 配置如下参考 docs/src/content/docs/services/index.md 中的官方示例{ pkgs, ... }: { services.postgres { enable true; package pkgs.postgresql_15; initialDatabases [{ name mydb; }]; extensions extensions: [ extensions.postgis extensions.timescaledb ]; settings.shared_preload_libraries timescaledb; initialScript CREATE EXTENSION IF NOT EXISTS timescaledb;; }; }这份配置会安装 PostgreSQL 15 与 postgis、timescaledb 两个扩展在首次启动时创建名为mydb的数据库加载timescaledb共享库并执行initialScript。服务状态持久化在$DEVENV_STATE下的目录中——当你调整了initialScript这类只在首次启动生效的选项后需要删除服务对应的状态目录改动才能在下次devenv up时生效。核心开关与版本选择services.postgres.enable属性值类型boolean默认值false示例true启用 PostgreSQL 进程。注意 devenv 同时提供了一个重命名兼容机制postgres.enable这一旧路径会被自动迁移到services.postgres.enable见 src/modules/services/postgres.nix 中的mkRenamedOptionModule导入。services.postgres.package属性值类型package默认值pkgs.postgresql示例pkgs.postgresql_15指定使用的 PostgreSQL 包用于覆盖默认版本例如锁定到postgresql_15或postgresql_16。在模块内部package的取值决定了 shell 中可用的二进制packages [ (lib.getBin postgresPkg) startScript ];这里有一个值得注意的实现细节从 2026 年起的版本行为看模块只把package中存放服务端与客户端二进制postgres、psql、pg_ctl等的binoutput 加入 shell而不是整个包。这样做避免了把 PostgreSQL 构建期依赖约 2.4 GB 的 LLVM、Perl、Python、Tcl以及 libpq 头文件和libpq.pc污染 shell 的 include 与 pkg-config 路径。如果你的应用需要链接或加载 libpq 客户端库例如 Ruby 的pggem、从源码构建的psycopg2或纯 Python 的psycopg需要自行将pkgs.libpq加入packages需要pg_config的构建可以使用pkgs.libpq.pg_config。services.postgres.createDatabase属性值类型boolean默认值true在启动时创建一个与当前用户名同名的数据库。该选项仅在initialDatabases为空列表时生效。对应实现位于setupInitialDatabases的 else 分支psql --dbname postgres EOF CREATE DATABASE ${USER:-$(id -nu)}; EOF网络监听listen_addresses 与 portservices.postgres.listen_addresses属性值类型string默认值示例127.0.0.1以逗号分隔的 TCP/IP 地址列表指定服务端监听的网络接口。默认情况下服务只接受 Unix socket 连接不会暴露任何 TCP 端口。该选项同时被解析用来设置PGHOST环境变量支持的特殊值*监听所有可用网络接口对应实现会将其映射为127.0.0.1用于PGHOST0.0.0.0监听所有可用 IPv4 接口映射为127.0.0.1::监听所有可用 IPv6 接口映射为::1localhost仅监听回环接口空字符串禁用 TCP/IP仅监听 Unix socket默认行为实现上parseListenAddresses会把输入按逗号拆分、trim、将*/0.0.0.0/::转换为回环地址再取第一个元素作为PGHOST若listen_addresses为空则PGHOST指向运行时 socket 目录$DEVENV_RUNTIME/postgresenv.PGHOST let parsedAddress headWithDefault null (parseListenAddresses cfg.listen_addresses); host if cfg.listen_addresses ! then parsedAddress else runtimeDir; in lib.mkDefault host;services.postgres.port属性值类型16 位无符号整数0–65535默认值5432TCP 监听端口。启用网络监听listen_addresses ! 后模块会通过processes.postgres.ports.main为5432basePort申请端口分配并将实际分配结果写入settings.port与PGPORT环境变量未开启网络监听时该端口仅用于初始化阶段临时启动实例。仓库中的 tests/postgres-localhost/devenv.nix 展示了指定listen_addresses localhost与port 2345的写法tests/postgres-pghost/devenv.nix 则演示了listen_addresses *的场景。postgresql.conf 调优settings属性值类型属性集attribute set of boolean/float/int/string默认值{}直接对应 PostgreSQL 的postgresql.conf配置项。字符串值会被自动包裹在单引号中且单引号会按上游文档规则转义为两个单引号。模块会将settings序列化为一份独立的postgresql.conf文件并覆盖到数据目录configFile pkgs.writeText postgresql.conf (lib.concatStringsSep \n (lib.mapAttrsToList (n: v: ${n} ${toStr v}) cfg.settings));toStr的转换规则为true→yes、false→no、字符串 → 单引号包裹、其余 →toString。官方示例settings { log_connections true; log_statement all; logging_collector true; log_disconnections true; log_destination lib.mkForce syslog; };另外模块会在settings中强制注入三个键listen_addresses取自对应选项、port取自分配结果以及默认值unix_socket_directories $DEVENV_RUNTIME/postgres保证 Unix socket 落在运行时目录。多进程场景下注意同名 socket 目录会导致所有 PostgreSQL 实例共用 socket 路径这在仓库的 postgres 相关测试中已被显式验证。initdb 与客户端认证initdbArgs、hbaConfservices.postgres.initdbArgs属性值类型字符串列表行拼接默认值[--localeC --encodingUTF8]示例[--data-checksums --allow-group-access]数据目录初始化时额外传给initdb的参数。默认的--localeC --encodingUTF8保证了可复现的默认排序规则需要数据校验和或允许组访问时可追加示例中的参数。services.postgres.hbaConf属性值类型null or string默认值null示例builtins.readFile ./my-custom/directory/to/pg_hba.conf自定义pg_hba.conf文件内容会被拷贝进 PostgreSQL 安装目录用于建立自定义的连接认证规则。实现中若该选项非空会在初始化脚本里执行cp ${file} $PGDATA/pg_hba.conf。典型用途是从项目目录读取一份受版本控制的认证配置文件例如services.postgres.hbaConf builtins.readFile ./pg_hba.conf;扩展管理extensions属性值类型null 或(extensions - list of package)函数默认值null示例extensions: [ extensions.pg_cron extensions.postgis extensions.timescaledb ]声明式安装 PostgreSQL 扩展。可用扩展来自当前 nixpkgs 中postgresql.pkgs的属性集合涵盖age、citus、hypopg、pg_cron、pg_net、pg_partman、pg_uuidv7、pgaudit、pgjwt、pgvector、pgvecto-rs、postgis、timescaledb、timescaledb_toolkit、sqlite_fdw、wal2json等 70 余项完整清单以devenv eval求值结果为准。实现上扩展通过package.withPackages机制注入postgresPkg if cfg.extensions ! null then if builtins.hasAttr withPackages cfg.package then cfg.package.withPackages cfg.extensions else builtins.throw Cannot add extensions to the PostgreSQL package. services.postgres.package is missing the withPackages attribute. Did you already add extensions to the package? else cfg.package;也就是说当你同时指定了自定义package时该包必须带withPackages属性否则会直接抛错。仓库示例 examples/postgres/devenv.nix 给出了“postgis 建库 initialScript 建扩展”的完整组合{ pkgs, ... }: { packages [ pkgs.coreutils ]; services.postgres { enable true; extensions extensions: [ extensions.postgis ]; initialDatabases [ { name mydb; } ]; initialScript CREATE EXTENSION IF NOT EXISTS postgis; ; }; }首次启动初始化initialDatabases 与 initialScriptservices.postgres.initialDatabases属性值类型list of submodule默认值[]首次启动 PostgreSQL 时创建的数据库列表及其初始 schema。列表为空时退化为createDatabase行为。官方示例initialDatabases [ { name foodatabase; schema ./foodatabase.sql; } { name bardatabase; } ];每个数据库条目包含以下子选项initialDatabases.*.name类型string说明要创建的数据库名称。initialDatabases.*.schema类型null or absolute pathtypes.path默认值null说明数据库的初始 schema为null默认时创建空数据库。schema的实现支持两种形态均由setupInitialDatabases处理单个.sql文件awk NF file | psql --dbname ${database.name}逐条执行目录按版本顺序ls -1v读取目录下所有*.sql文件逐个应用——这解决了“文件最后一条语句不以;结尾”时的执行问题。仓库测试 tests/postgres-customdbuser/devenv.nix 正是使用了schema ./.;当前目录下的 SQL 文件按版本序应用。initialDatabases.*.user类型null or string默认值null说明数据库属主用户名。若设置会创建同名角色并使数据库归其所有为null时默认使用$USER。initialDatabases.*.pass类型null or string默认值null说明数据库属主角色的密码要求必须同时设置user。实现中CREATE ROLE ${user} WITH LOGIN PASSWORD ${pass}通过DO $$ ... EXCEPTION WHEN duplicate_object THEN RAISE NOTICE ...保证角色已存在时不报错并且模块在assertions中做了硬性校验pass非空而user为空时抛错该行为是 2026 年起的变更此前pass无user会被静默忽略。另一个相关行为变更当在initialDatabases中指定user时建库语句会带上OWNER即CREATE DATABASE name OWNER user数据库不再一律归$USER所有。initialDatabases.*.initialSQL类型null or string默认值null说明在该数据库初始化期间运行的 SQL 命令多条语句可用分号分隔。示例initialSQL CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT); INSERT INTO users (name) VALUES (admin); CREATE EXTENSION IF NOT EXISTS pg_uuidv7; ;仓库测试 tests/postgres-customperdbinit/devenv.nix 展示了 per-database 初始化的完整形态第一个库testdb指定了user、pass与initialSQL建扩展、建表、改属主第二个库testdb2仅创建空库initialDatabases [ { name testdb; user testuser; pass testuserpass; initialSQL CREATE EXTENSION IF NOT EXISTS pg_uuidv7; CREATE TABLE user_owned_table (id SERIAL PRIMARY KEY, name TEXT); ALTER TABLE user_owned_table OWNER TO testuser; ; } { name testdb2; } ];services.postgres.initialScript属性值类型null or string默认值null示例CREATE ROLE postgres SUPERUSER; CREATE ROLE bar;初始化期间运行的服务器级 SQL 命令可分号分隔多条。适用场景区分initialScript用于服务器级初始化例如创建角色、配置全局设置initialSQL在initialDatabases内用于数据库级初始化initialScript在initialDatabases全部建库完成后执行。实现中的执行顺序见setupScript首次启动 →initdb→ 拷贝配置文件与pg_hba.conf→ 临时用 Unix socket 启动实例pg_ctl -w start→ 执行setupInitialDatabases→ 执行runInitialScript→pg_ctl -m fast -w stop。由于initialDatabases与initialScript只在首次初始化$PGDATA不存在时运行后续重启不会重复执行。环境变量、数据目录与进程生命周期启用services.postgres后模块自动注入以下环境变量环境变量取值PGDATA$DEVENV_STATE/postgres数据目录PGHOST网络监听地址未监听时为$DEVENV_RUNTIME/postgressocket 目录PGPORT分配后的端口数据目录固定在$DEVENV_STATE/postgres。由于所有初始化逻辑都以$PGDATA是否已存在为判断条件初始化完成后还会写入$PGDATA/.devenv_initialized标记文件想重新执行初始化时需要删除该状态目录例如通过devenv gc或手动清理$DEVENV_STATE/postgres再执行devenv up。进程本身的定义位于processes.postgresexecstartScript内部先执行setupScript完成初始化与配置再exec postgresready探针检查.devenv_initialized标记随后用pg_isready -d template1与psql -c SELECT 1 template1双重验证实例可用initial_delay 2、probe_timeout 4、failure_threshold 5shutdown.signal 2SIGINT对应 PostgreSQL 文档中的快速关停fast shutdown语义。实战组合与常见注意事项1. 本地开发 TCP 访问参考 tests/postgres-localhost/devenv.nixservices.postgres { enable true; listen_addresses localhost; port 2345; initialScript CREATE USER postgres SUPERUSER; ; };此时应用可通过psql -h localhost -p 2345或$PGHOST/$PGPORT连接同时仍保留 Unix socket 访问路径。2. 容器/远程场景开放全网监听参考 tests/postgres-pghost/devenv.nixservices.postgres.listen_addresses *;注意*会让PGHOST解析为127.0.0.1而服务端实际监听所有接口如需限制访问请配合hbaConf定制认证规则。3. 数据校验与多实例可通过initdbArgs [--data-checksums]开启数据页校验和。如果需要在同一devenv up中运行多个 PostgreSQL 实例留意它们共享$DEVENV_STATE/postgres与运行时 socket 目录需自行调整settings与端口分配策略这在当前模块中是已知约束。4. 状态清理调整initialScript、initialDatabases、hbaConf、settings等仅在初始化/启动阶段生效的选项后服务状态不会自动重建。请删除$DEVENV_STATE/postgres目录后重新devenv up确保配置变更真正生效详见 docs/src/content/docs/services/index.md 的说明。5. 版本与扩展联动指定非默认package如pkgs.postgresql_15时扩展集合也来自同一 nixpkgs 的postgresql.pkgs二者版本需相互匹配若package缺少withPackages属性启用extensions会在求值时直接抛错错误信息见 src/modules/services/postgres.nix。如需在模块化/多项目场景中复用这些配置可以结合 devenv 的模块与 profile 机制见 docs/src/content/docs/blog/2025/09/17/devenv-19-scaling-nix-projects-using-modules-and-profiles.md 中lib.mkIf config.myteam.services.database.enable的条件启用写法把services.postgres封装成团队级可开关的数据库能力。赞分享开发工具CLI【免费下载链接】devenvFast, Declarative, Reproducible, and Composable Developer Environments using Nix项目地址https://gitcode.com/gh_mirrors/de/devenv点击查看免费下载相关推荐Node.js v7 升级 V8 5.4新 ECMAScript 特性与性能优化解读Node.js v7 升级 V8 5.4新 ECMAScript 特性与性能优化解读 本文以 nodejs.org 仓库中的官方公告 update v8 5.开发工具CLI革命性Go插件系统go-plugin基于WebAssembly打造安全高效的插件生态革命性Go插件系统go plugin基于WebAssembly打造安全高效的插件生态 go plugin是一款基于WebAssembly技术的Go插件系统它开发工具CLIAgentMesh Kubernetes 部署实战独立信任代理与 Sidecar 双模式接入指南Agent Governance ToolkitAgentMesh Kubernetes 部署实战独立信任代理与 Sidecar 双模式接入指南Agent Governance Toolkit 本文为开发工具CLI上一篇探索未来之路2025年夏季实习宝典 —— Ouckah CSCareers 携手启航下一篇CVAT 标注平台一条命令部署覆盖图像、视频与 3D 点云标注创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表