@arthuroabrantes/maestro

中文文档
0.1.2发布于 2026/06/13ES Module近 30 天下载 1885

由单一的maestro.yaml(Pulumi + Ansible)提供数字海洋基础设施

中文使用文档
文档目录19 节
  1. 使用大师
  2. 1. 安装主机要求
  3. 2. 设置账户(一次)
  4. 3. 写你 maestro.yaml
  5. 运行它
  6. CLI 参考
  7. 配置参考
  8. 服务器角色
  9. 环境(垃圾)
  10. 数据库(管理中的邮政)
  11. 零下限后端部署迁移( M)
  12. 转发额外机密
  13. 如何运作
  14. 输油管
  15. Ansible 执行环境
  16. 软件包布局
  17. 释放
  18. 发展大师
  19. 路线图

大师

Maestro从一个单一的YAML文件中为生产部署一个网络应用程序. 指着一个 maestro.yaml 描述您的域名、 服务器和应用程序容器, 它提供云基础设施( DNS、 液滴、 隧道、 管理过的 Postgres) , 并配置服务器( nginx、 Docker、 您的后端) —— 以一个命令结束.

盖子下面是结合的 普鲁米 用于云资源及 可解药 用于服务器配置,所以你不必将两者连接在一起.

一个 maestro.yaml 让你:

  • DNS 和 TLS 数据 —— Cloudflare DNS 记录,区域 TLS 设置,以及您的域名的 Origin CA 证书.
  • 服务器 - 数字海洋液滴/环境(dev 编号 : staging 编号 : prod),每个环境在自己的子域上完全隔离.
  • 私人 SSH 访问 ——通过Cloudflare Zero Trust隧道到达服务器(ssh0.example.com),从未通过生IP.
  • 网络级别 —— nginx服务于您的静态网站或倒置的网络容器.
  • 后端分级 ——您应用的多克图像部署出蓝/绿色,并附有健康检查和可选的部署前数据库迁移,所以部署是零下架时间.
  • 数据库分级( 可选) – 数字海洋管理 Postgres 集成每条环境,仅能覆盖于一个私有的VPC上,拥有最不优惠的应用用户.

Maestro是一个有CLI的版本npm包. 您的应用程序仓库拥有 maestro.yaml (在文件描述的应用代码旁边) 并运行大师反对它—— bunx @arthuroabrantes/maestro,或被钉入 devDependency升级Maestro是一个版本 在您的Repo; 没有关于您的应用 住在Maestro的仓库.


使用大师

1. 安装主机要求

大师继续前进 阿宝 并管理一些主机工具( 所有工具在启动时都得到验证) :

工具用于
docker运行容器化的Ansible执行环境并提取图像源网站资产.
pulumi普鲁米CLI. Maestro通过自动化API在进程中驱动;你从未自己运行过. 州住普鲁米云(无) pulumi login 需要 -- -- PULUMI_ACCESS_TOKEN 认证).
bwsBitwarden Secrets Manager CLI——所有秘密的来源.
cloudflared通过Cloudflare SSH隧道到达服务器.
pip/Python大师自动安装 ansible-navigator (和 ansible-builder)通过 pip install --user 如果他们失踪了 PATH。 。 。 .

2. 设置账户(一次)

云浮华. 基础 domain 内 maestro.yaml 必须已经存在作为一个 活动区域 在您的 Cloudflare 账户中 : 在 Cloudflare 中添加域名, 并在 Cloudflare 指派的域名中标注您的注册员名服务员 。 大师在运行时按名称查看区域并失败 Cloudflare zone for <domain> not found. 如果它不见了——它从不创建区或验证所有权.

区域也必须是 没有相冲突的 DNS 记录大师创建自己的记录(apex) A, (中文(简体) ), www A,以及 api编号 :ssh* CNAME如果不同类型的记录已经占有其中之一,则Cloudflare以 A CNAME record with that host already exists (错误) 81054),运行部分失效. 删除( 或导入到 Pulumi) 顶端的任何相冲突记录, www, (中文(简体) ), api,以及 ssh* 名字第一个.

数字海洋. 添加 SSH 公开 用于数字海洋账户的密钥。 大师的药水滴 但不为您注册钥匙.

Bitwarden 机密管理器 . 在您机器账户可读的 BWS 项目中创建下面的秘密 。 大师在启动时取出它们并注入它自己的环境——它们从未被写入你的Repo.

秘诀目的所需范围
VPS_SSH_KEYSSH 服务器 私营 键匹配在数字海洋注册的公钥.非 API 令牌; 不适用范围 .
GHCR_TOKENGitHub Control Register Register 标记用于调取您的应用图像的服务器 .GitHub 个人访问符( 经典) read:packages。不需要其他只读拉出.
GHCR_USERNAME拥有的 GitHub 用户名 GHCR_TOKEN。 。 。 .非 API 令牌; 不适用范围 .
PULUMI_ACCESS_TOKENPulumi Cloud 访问符 (基础设施状态所在).标准个人准入标志;需要进入正在部署的组织/仓库.
CLOUDFLARE_API_TOKENCloudflare API 代币.区 □ 区:读取, (中文(简体) ), 区设置: 编辑, (中文(简体) ), DNS: 编辑页:1 SSL 和证书: 编辑 (欧里金 CA 证书—— a) 用户级别 权限; 没有权限创建失败 401 / code 1016(c) 账户 云浮隧道: 编辑. 范围扩大到正在管理的账户/区.
DIGITALOCEAN_ACCESS_TOKENDigitalOcean API 代币.droplet:create/read/update/delete· ; ssh_key:read· ; tag:create/read/delete。一个完整的读出+写出符号也有效。 启用了数据库层级,另外 database:create/read/update/delete 和 VPC 读取/写入.

启用数据库级( E)pulumi.database.enabled: true),还需要两个秘密——您选择的稳定识别符,由Pulumi(创建用户/数据库)和您的后端阅读:

秘诀目的
POSTGRES_USER专用最不优惠的应用程序数据库用户名(由普鲁米创建).
POSTGRES_DB应用程序数据库名称(由Pulumi创建).

POSTGRES_HOST, (中文(简体) ), POSTGRES_PORT,以及 POSTGRES_PASSWORD 为: 没有 Bitwarden secrets——它们来源于 DigitalOcean,表面为 Pulumi 堆栈输出,并自动注入到您的后端. 永远不要犯法.

3. 写你 maestro.yaml

在您的应用程序仓库中创建 maestro.yaml。一个最小的完整实例:

domain: example.com

pulumi:
  enabled: true
  command: up
  projectName: example
  cloudflareAccountId: "<your-cloudflare-account-id>"
  sshPort: 22
  stacks:
    prod:
      servers:
        - roles: [backend, web]

ansible:
  enabled: true
  web:
    static:
      source: local
      dir: ./website # relative paths resolve against this file's directory
      dist: dist
  backend:
    image: ghcr.io/your-org/your-app
    tag: latest
    port: 3000

secrets:
  provider: bws

见 example.maestro.yaml 用于包含每个选项的完整文件模板,以及 配置参考 见下文.

运行它

export BWS_ACCESS_TOKEN="your_bws_machine_account_token"

bunx @arthuroabrantes/maestro --dry-run   # validate the config and preview settings
bunx @arthuroabrantes/maestro             # provision everything

BWS_ACCESS_TOKEN 是您手动设定的唯一环境变量—— Bitwarden 机账符 读取 进入拥有上述机密的项目。 其他一切从比特华登来.

或者,针大师作为一个 devDependency 并运行它通过 bun run maestro. 一个在合并上运行大师的瘦CI工作流程同样工作——CLI是非交互的.

CLI 参考

maestro [--config <path>] [--dry-run]
旗帜目的
--config <path>路径 maestro.yaml默认 : ./maestro.yaml 在当前工作目录中.
--dry-run验证配置并显示解析的设置, 不提供任何条件 .
--help显示用法 .

配置内部的相对路径( 如 . ansible.web.static.dir: ./website总是决心反对 配置文件目录,而不是引用目录的maestro 从,所以同样的配置在本地,在CI,并通过 --config 从任何地方.


配置参考

所有配置都生活在一个YAML文件中. 整个结构:

domain: example.com # Base domain for DNS and nginx

pulumi:
  enabled: true # Enable/disable cloud provisioning
  command: up # up | refresh | cancel | output | destroy (destroy skips Ansible)
  projectName: your-project-name # Pulumi project name
  cloudflareAccountId: "" # Your Cloudflare account ID
  sshPort: 22 # SSH port for tunnels
  database: # Optional: Managed Postgres tier (global defaults)
    enabled: false # Provision a DigitalOcean Managed Postgres cluster per stack
    version: "16" # Postgres major version: "15", "16", or "17"
    size: db-s-1vcpu-1gb # DigitalOcean DB node size
    nodeCount: 1 # Node count (region always co-locates with the stack's droplets)
  stacks: # One or more environments: dev, staging, prod
    prod:
      servers:
        - roles: [backend, web] # Roles determine what gets provisioned/configured
          # groups: [devops]    # Optional: override global ansible.groups
          # size: s-1vcpu-1gb   # Optional: DigitalOcean droplet size
          # region: nyc1        # Optional: DigitalOcean region
      # database:               # Optional: per-stack sizing override (override wins)
      #   size: db-s-2vcpu-4gb

ansible:
  enabled: true # Enable/disable all server configuration
  groups: [devops] # System groups (can be overridden per-server)
  web: # Required if any server has the "web" role
    static: # ...serve static files with nginx, or:
      source: local # local | image
      dir: ./website # Website source (relative to this config file)
      build: bun run build # Optional build command
      dist: dist # Subdirectory with built assets
    # docker:               # ...or reverse-proxy a web container
    #   image: ghcr.io/org/web
    #   tag: latest
    #   port: 3000
  backend: # Required if any server has the "backend" role
    image: ghcr.io/org/app # Container image
    tag: latest # Image tag
    port: 3000 # Backend port
    env: # Non-sensitive environment variables for the container
      SOME_VAR: value
    secretEnv: # Sensitive vars: names of Bitwarden secrets, values injected at runtime
      - STRIPE_SECRET_KEY # container var STRIPE_SECRET_KEY ← BWS secret of the same name
      - BWS_ACCESS_TOKEN: APP_BWS_ACCESS_TOKEN # rename on inject: container var ← BWS secret
    migrate: # Optional: DB migration before each deploy (omit = none)
      command: ["npm", "run", "migrate"] # argv run inside the backend image
    healthCheck: # Optional: blue/green readiness probe
      path: /health # Polled for 200 before cutover (default: /health)

secrets:
  provider: bws # Secrets provider (bws = Bitwarden Secrets Manager)
  projectId: "" # Optional BWS project ID to scope the fetch
  requiredVars: [] # Extra secrets to validate and forward to Ansible

服务器角色

供给是 基于角色:每个 Ansible 游戏本只运行在持有相应角色的服务器上,并且在没有服务器时完全跳过.

作用游戏本目的
backendbackend.ymlDocker + 后端容器部署
webweb.ymlnginx( 静态文件或反向代理)

加强安全 (单位:千美元)security.yml) 总是运行在所有服务器上: UFW 防火墙规则(默认接收次数少,允许SSH,特定角色的开口)和系统组管理(英语:ansible.groups) (中文(简体) ).

环境(垃圾)

每个堆放在下面 pulumi.stacks 是一个孤立的环境,有自己的Pulumi状态、服务器和(可选的)数据库。 Maestro提供每个被定义的堆栈相继,然后为Ansible相位汇总所有主机. 服务器同时被标记为堆栈名和角色,因此游戏本可以根据环境瞄准. 见 ansible/README.md 用于主机目标细节.

非生产堆栈活在基部的前缀子域上 domain,用于每种资源:

资源devstagingprod
网络域dev.example.comstaging.example.comexample.com
WWW 域名www.dev.example.comwww.staging.example.comwww.example.com
API 终点api.dev.example.comapi.staging.example.comapi.example.com
SSH 隧道ssh0.dev.example.comssh0.staging.example.comssh0.example.com

DNS记录是在基域Cloudflare区下创建的;TLS证书是每个有效域签发的.

数据库(管理中的邮政)

何时 pulumi.database.enabled 实值 true,硕士规定a 数字海洋管理邮政 分组作为专门的数据库级别。 指导原则: 后端是牛; 数据库是皇冠珠宝 ——数据库存在于自有管理的故障域中,与可支配后端滴入相分离.

  • 环境相互隔离. 每个启用的堆栈设置 拥有 集群、应用程序数据库和应用程序用户。 A 类 dev 部署绝不触及 prod 数据库.
  • 私人 VPC 端点 + TLS. 每个堆栈都得到一个由后端滴入和集群组成的专用VPC. 后端连接到数据库的 私营 终点——交通从不穿越公共互联网——仍然使用 sslmode=require (单位:千美元) PGSSLMODE=require 为libpq客户端服务.
  • 起码的特权. Pulumi 创建专用数据库用户(来自 POSTGRES_USER和数据库(来自 POSTGRES_DB) (中文(简体) ). 应用程序从不使用集群管理员( E)doadmin) (中文(简体) ).
  • 防火墙通过标签. A 类 DatabaseFirewall 相信后端的小滴 以他们的每桶 标签,不是"滴"ID,所以它能活过"滴"重建. 没有 0.0.0.0/0 规则.
  • 生命周期保障. 组装 retainOnDelete: true 财务报告和审定财务报表 protect: true; 应用程序数据库、用户和 VPC 携带 retainOnDeleteA级 pulumi destroy 可支配后端在离开云数据库及其数据完好无损的情况下成功; 故意撕毁需要故意不保护并移除资源.
  • 杜尔比特. DigitalOcean的内置日备份外加点入时恢复(PITR)覆盖耐久性——PITR防止操作员/应用程序出错(不良迁移,意外) DELETE不仅仅是基础设施的损失.

一次性地更换水滴. VPC成员在一款"数字海洋"(DigitalOcean droplet)上是不可改变的,因此允许数据库在首次应用时替换了已存在的后端droplet. 后端为牛;Ansible重接替换.

连接线. POSTGRES_USER编号 :POSTGRES_DB 来源于 Bitwarden(您选择的稳定值); POSTGRES_HOST, (中文(简体) ), POSTGRES_PORT,以及 POSTGRES_PASSWORD 来源于 DigitalOcean并读取已键入的 Pulumi 堆栈输出(密码为 Pulumi 密件)。 Maestro在堆栈后端主机上线程显示每个堆栈的值,因此多堆部署从不交叉连接一个堆栈后端到另一个堆栈的数据库. 后端容器最后会 POSTGRES_HOST, (中文(简体) ), POSTGRES_PORT, (中文(简体) ), POSTGRES_USER, (中文(简体) ), POSTGRES_DB, (中文(简体) ), POSTGRES_PASSWORD,以及 POSTGRES_SSLMODE=require 在环境.

零下限后端部署迁移( M)

后端部署为 零关闭时间 默认情况下:nginx作为稳定的倒置代理保持上行,而Maestro将容器取而代之的是蓝色/绿色.

后端作为两个集装箱之一运行—— backend-blue 联 合 国 ansible.backend.port和 backend-green 联 合 国 port + 1——两者都有义务 127.0.0.1。每次部署在闲置的端口启动新图像,而活的端口则继续服务,等待其通过健康检查,在新端口点出nginx并重新装入(nginx -s reload (b) 飞行中排水请求)。 直到那时,旧集装箱才停止。 如果新容器永远没有健康,老容器继续服务,部署失败——没有半部署状态.

  • ansible.backend.healthCheck.path (可选): HTTP 路径为 200 在新容器上,在切换前。 默认为 /health。重试/超时预算是固定的.
  • ansible.backend.migrate.command (可选):一个 argv 阵列(例如. ["npm", "run", "migrate"],而不是外壳行)在后端图像中运行一次 在新容器开始前,基于实时数据库,环境与应用程序相同(包括每集) POSTGRES_* 页:1 非零退出在应用容器被触碰前中止部署. 关闭块 跳过迁移。 DB 密码和其他机密都保留在 no_log- 守护的路径,从来没有印刷.

转发额外机密

大师从来不在其中存储秘密值 maestro.yaml ——此文件意在被版本控制. 通过敏感度和目的地,有三种方式使配置进入系统:

  • ansible.backend.env ——非敏感的后端-容器变量,作为字形键/值对(例如. NODE_ENV: production) (中文(简体) ).
  • ansible.backend.secretEnv —— 说 敏感 后端- 容器变量 。 列出 名称 b. 存储在 Bitwarden 中的秘密; 要以不同的名称注入,请使用绘图条目—— CONTAINER_VAR: BWS_SECRET_NAME (例如:. BWS_ACCESS_TOKEN: APP_BWS_ACCESS_TOKEN 手持应用程序在一个不相冲突的 Bitwarden 名下存储的令牌。 启动时验证源代码密钥( 一个缺失的秘密在任何云调时前失败运行), 值运行相同 no_log- 守护路径作为数据库密码 - 它们永远不会被写入您的 repo 或打印 。 集装箱 var 可能也不出现在 env,以及 PORT 保留(自动从 ansible.backend.port) (中文(简体) ).
  • secrets.requiredVars - Ansible公司需要的秘密 游戏本 (不是应用容器). 它们在启动时被验证,并被传送到Ansible执行环境,游戏本通过该环境读取 lookup('env', 'VAR_NAME')。 。 。 .

永远不要向前 BWS_ACCESS_TOKEN 给您的应用程序. Maestro的部署符可以读取所有部署的秘密(Cloudflare, DigitalOcean, Pulumi);一个受损后端容器会继承你的全部基础设施. 大师拒绝它 secretEnv 来源。 如果您的应用程序本身需要 Bitwarden 访问, 请创建一个单独的机器账户符号, 范围为应用程序机密项目, 在 Bitwarden 中以不同的名称存储( 例如 。). APP_BWS_ACCESS_TOKEN),并使用映射表将其以所期望的名称交给应用程序: BWS_ACCESS_TOKEN: APP_BWS_ACCESS_TOKEN。 。 。 .


如何运作

输油管

index.ts (单位:千美元) maestro bin) 管线管线:

  1. 解析 CLI 旗 并对照当前工作目录解决配置路径.
  2. 校验 maestro.yaml 对照一个打入的计数器(io-ts codecs外加语义检查:角色/web一致性,区域混合,数据库先决条件,路径存在). --dry-run 在此停止并打印解析的设置 .
  3. 获取机密 从 Bitwarden 保密管理器( R)bws secret list)并注入过程环境;要求的秘密在前面被断言,因此在任何云调之前都会发生故障.
  4. 写入 SSH 密钥 改为 0600 临时文件(stable path ——它被插入了普鲁米资源,因此每个运行的随机路径都会在每次部署时将它们抖出).
  5. 运行 Pulumi 每堆 正在通过 自动化 API没有Pulumi Docker的形象,也没有炮击到 pulumi up下方的类型脚本程序 pulumi/ 提供 Cloudflare DNS 记录、 区 TLS 设置、 Origin CA 证书、 Zero Trust SSH 隧道、 Digital Ocean 液滴和(可选) VPC + 管理 Postgres 级。 州住普贤云.
  6. 总主机 从所有堆栈的打出输出——主机名,角色,堆栈标记,以及每个堆栈的数据库端点.
  7. 等待隧道准备 ——民意调查 SSH-over-cloudflailed 直到每个主机接受连接.
  8. 运行解析器 与主敌: web.yml, (中文(简体) ), backend.yml,则 security.yml 最后(它可能会收紧防火墙规则,从而阻碍早先的剧情).

Ansible 执行环境

游戏本不运行在你的主人的Ansible上——它们运行在一个集装箱内 执行环境 (EE) 驱动由 ansible-navigator。大师用 ansible-builder 从装有货包的船舶的定义(ansible/execution_environment/) (中文(简体) ). 已建图像被标记为定义的内容散列,因此之后运行再使用并完全跳过该构建,直到定义发生变化(比如在maestro升级上).

图像是 应用不可知论 ——所有特定应用程序在运行时到达容器,在图像构建时从不:

  • 网站资产 编成临时目录(从 ansible.web.static.dir,或从容器图像中取出)和卷载只读于 /opt/website。 。 。 .
  • SSH 密钥 临时文件是卷载只读的 .
  • 配置和秘密 作为环境变量转发(--penv),包括主机列表(SSH_HOSTS),这是一个动态目录脚本(ansible/inventory/hosts.py)变为Ansible主机,按角色和堆栈分组.

这就是让一个EE图像服务于每一个消耗性应用.

Maestro的安装目录在运行时被作为只读处理:网站中转,EE构建上下文,导航日志,以及秘密文件都活在系统临时目录中(带有 maestro_ 前缀, 0600 机密文件, 并清理出口, 加上启动时的 stale 扫描 .

软件包布局

路径这是什么
index.tsCLI 切入点bin),上面的输油管.
lib/管弦乐团:配置装入/验证,秘密,普鲁米司机,Ansible司机,隧道准备.
pulumi/Pulumi方案(进口入厂):DNS,证书,地道,液滴,VPC,管理Postgres.
ansible/执行环境定义,动态库存,以及用于nginx, Docker,UFW,蓝色/绿色部署的游戏本/角色.

释放

重放大师版是 version 突然间 package.json 加号 npm publish ——EE图像定义,游戏本,普鲁米程序都在包内出行,所以没有第二件文物可以保持同步.

发展大师

这个寄存器本身只是另一个消耗性应用 maestro.yaml 恰好坐在工具旁边:

bun index.ts --dry-run   # or: bun run maestro:dry-run
bun index.ts             # full run against the repo's own maestro.yaml
bun test                 # unit tests

路线图

  • 独立逻辑备份流到数字海洋空间:除了DO的日常备份+PITR,一个自有的 pg_dump- 系统备份在日程安排上的空间桶,有寿命周期/保留规则和经过测试的恢复钻头——针对账户或提供者一级的问题进行深入的防御,以及便携式副本.
  • 数据库赠款紧缩: 应用程序用户为非超级用户且从未 doadmin,但将其权限范围限定为自身数据库(超越了DigitalOcean的默认值)内仅需要的,是后续.
  • 多云提供者支持: DigitalOcean是目前唯一的提供商;AWS/GCP/Azure可能跟随.
  • 自动SSH 密钥提供:今天的公用密钥必须在第一次运行前手动添加到 DigitalOcean.
  • 每个环境有多个网络/后端服务器 包含负载平衡;今天每个角色映射到每个堆栈的单个服务器.
  • 通过 SDK 可解析:通过库界面驱动 Ansible ,而不是炮击到 ansible-navigator (Pulumi已经运行在进程中).
  • 强化安保后续行动:避免在主机文件系统中实现SSH密钥,从Pulumi输出中隐藏服务器IP地址.

版本与发布记录

@arthuroabrantes/maestro 共发布 3 个版本,首次发布于 2026/06/13;过去 12 个月发布了 3 个版本。

版本发布日期距今
0.1.2latest2026/06/134 个月前
0.1.12026/06/134 个月前
0.1.02026/06/134 个月前

关于 @arthuroabrantes/maestro 的常见问题

@arthuroabrantes/maestro 是什么?

由单一的maestro.yaml(Pulumi + Ansible)提供数字海洋基础设施

如何安装 @arthuroabrantes/maestro?

在项目目录运行 npm install @arthuroabrantes/maestro,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 maestro,可以用 npx maestro 直接运行。

@arthuroabrantes/maestro 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/arthuroabrantes__maestro 是否存在。

@arthuroabrantes/maestro 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@arthuroabrantes/maestro 可以商用吗?

@arthuroabrantes/maestro 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@arthuroabrantes/maestro 的下载量有多少?

根据 npm 官方下载统计,@arthuroabrantes/maestro 在 2026/10/07 – 2026/11/05 这 30 天内被下载 1,885 次,日均约 63 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@arthuroabrantes/maestro 还在维护吗?

最新版本 0.1.2 发布于 2026/06/13(4 个月前);至今共发布 3 个版本,其中过去 12 个月发布了 3 个;首次发布于 2026/06/13。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。