尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Openship 平台架构深度解析:`@repo/adapters` 抽象层的三目标部署设计

Openship 平台架构深度解析:`@repo/adapters` 抽象层的三目标部署设计 Openship 平台架构深度解析repo/adapters抽象层的三目标部署设计【免费下载链接】openshipSelf-hosted deployment platform项目地址: https://gitcode.com/GitHub_Trending/ope/openshipOpenship 的自托管部署平台在 cloudOblien 云、selfhostedDocker / 裸金属与 desktop桌面端三种完全不同的运行环境中复用同一套代码。核心答案就在packages/adapters包中一个createPlatform()工厂 三个分层Runtime / Infra / System的适配器组合让同一份 API 代码面对云 API、Docker Engine 与裸机进程时无需任何业务分支。本文将基于 packages/adapters/docs/ARCHITECTURE.md 展开结合源码逐层拆解其抽象接口、工厂装配逻辑、环境变量解析与单例生命周期帮助你理解并扩展这套适配层。为什么需要一层平台适配Openship 的 APIapps/api本身只关心业务构建、部署、注册路由、签发证书。至于构建命令跑在哪里、路由配置写到哪里、证书由谁签发完全是基础设施问题。如果业务代码直接调用dockerode、certbot或云厂商 SDK那么每接入一种运行环境就要改写一次业务逻辑且 cloud 模式下业务代码会持有本机远程执行RCE能力是严重的安全隐患。repo/adapters把平台抽象成三层的组合业务侧永远只拿到一个统一入口const { runtime, routing, ssl, system } getPlatform(); await runtime.build(config, onLog); await routing.registerRoute({ domain, targetUrl, tls: true }); await ssl.provisionCert(domain); if (system) await system.requireFeature(deploy);上述用法直接出现在 platform.ts 的头部文档注释 中createPlatform()只在服务器启动时调用一次之后所有服务代码都通过同步的getPlatform()拿到已缓存的实例。三个部署目标同一份代码三种环境PlatformTarget cloud | selfhosted | desktop见 platform.ts。createPlatform(config)根据config.target三选一其中selfhosted再根据config.runtime二选一docker/bare。下表是各目标下每一层的具体实现与传输方式目标RuntimeRouting / SSLSystemExecutorssh2 是否加载cloud (Oblien)CloudRuntime纯 API 调用CloudInfraProvider纯 API 调用null无任何 RCEnull不执行任何东西否selfhosted (docker)DockerRuntimedockerodeNginxProvider经 executor 写配置 certbot ACMESystemManager检查 安装器LocalExecutor或SshExecutor仅配置了 SSH 时selfhosted (bare)BareRuntime共享 executorNginxProvider同上SystemManagerLocalExecutor或SshExecutor仅配置了 SSH 时desktopBareRuntime自有 executorNoopInfraProvider静默 no-opnull无需安装null否源码侧的分支实现位于 createCloudPlatform / createDesktopPlatform / createSelfHostedPlatformcloud构造单一 Oblien 客户端优先cloudToken否则clientId/clientSecret后两者可回退到环境变量OBLIEN_CLIENT_ID/OBLIEN_CLIENT_SECRETCloudRuntime与CloudInfraProvider共享该客户端system与executor均为nulllocalHost: false——工作负载永远运行在 Oblien 的基础设施上不在本机。desktopBareRuntime配NoopInfraProvider无 system、无 executorlocalHost: true——桌面应用部署的目标就是其自身所在的机器。selfhosted最复杂的分支见下文。三个分层单一职责只由 Platform 组合每层只做一件事且从不被业务代码直接实例化只通过Platform暴露。对应接口分别定义在 runtime/types.ts、infra/types.ts 与 system/setup.ts。1. Runtime构建 / 部署 / 停止的生命周期RuntimeAdapter接口runtime/types.ts统一了build、deploy、stop/start/restart/destroy、getContainerInfo、日志与资源用量等全部生命周期操作。三种实现DockerRuntimeruntime/docker.ts基于 dockerode 调用 Docker Engine API支持三种连接方式——本地 socket默认零配置、经 SSH streamlocal 转发的远程 socket、TCP 双向 TLS无明文 TCP见文件头部安全模型注释。Docker 拥有自己独立的 SSH 传输与下文共享的 executor 完全分离。构建时若仓库自带 Dockerfile 则以其为准否则 Openship 生成最小构建器 Dockerfile。BareRuntimeruntime/bare.ts不使用 Docker直接在目标服务器上以 shell 命令管理进程。所有操作git、npm、nohup、kill、PID 文件都走共享 executor因此本地与 SSH 远端行为完全一致。部署阶段委托给ProcessSupervisorLinux 自动检测 systemdmacOS 回退 nohup支持 Capistrano 风格硬链接 release 目录previousDeploymentId让多版本回滚的磁盘成本从 O(N × 全量) 降到 O(全量 增量 × N)。CloudRuntimeruntime/cloud.ts对 Oblien SDK 的纯 API 桩本地零调用。一个关键机制是能力声明RuntimeAdapter.capabilities: ReadonlySetRuntimeCapabilitysupports(cap)。例如stabilityProbe重启历史/健康读数仅 Docker 实现、unitRestore可原地重启的持久化部署单元Bare/Cloud 有而 Docker 没有、serviceShell容器内交互式 PTY、projectContainerSweep按openship.project标签枚举容器以回收孤儿等。调用方必须先supports()再调用配套的 assertCapability 会在不支持时抛出带完整能力清单的报错——调用者永远不会命中一个静默桩。2. Infra路由 SSLRoutingProvider与SslProviderinfra/types.ts之所以从 runtime 中拆出是因为Docker 是运行时而非反向代理路由由 Nginx/OpenResty 负责SSL 由 certbot/ACME 负责云环境则走完全不同的 API 机制桌面/开发环境则根本不需要。NginxProviderinfra/nginx.ts向 OpenRestyinclude的sites-enabled目录写入 server block 配置后重载SSL 由 certbot 以独立进程处理OpenResty 只负责读证书文件。所有文件写入都经 executor因此同一套 provider 既能在本机写配置也能经 SSH 写远程服务器。典型接入形如http { include /usr/local/openresty/nginx/conf/sites-enabled/*; }该 provider 同时服务于 Docker 与 Bare 两种 runtime。需要留意的是实际实现远比Nginx命名宽泛在 compose 的 docker-edge 模式下路由能力来自容器化的openship-edgeOpenResty Lua certbot镜像provider 的构造路径由 createInfraProvider 中的localContainerEdgeProvider/containerEdgeProvider决定platform.ts的 ASCII 图里写 Nginx 是历史命名真正的装配优先级是本机容器边缘 → 远程容器边缘 → 裸机 OpenResty → no-op 降级。CloudInfraProviderOblien API 桩无本地操作。NoopInfraProvider静默 no-op用于桌面/开发。SSL 侧除provisionCert/renewCertcertbot支持http-01/dns-01、force强制续期外还有installCert安装操作员自备证书如 Cloudflare Origin CA绕过 ACME、verifyCert只读校验驱动Recheck SSL。证书结果通过SslResult.verifiedreason区分尚无证书missing与证书在盘但不可用invalid过期/密钥不匹配/签发给了别的域名与按设计不由本机签发not_local避免状态层把正确状态写成 provisioning。3. System前置检查 服务器初始化SystemManagersystem/setup.ts仅存在于 selfhostedcloud 与 desktop 为null。其设计要点所有检查与安装都经 executorcheckAll检测 git、docker、edge 等组件安装器以预收集的InstallerConfigACME email、域名等运行无交互式提示日志实时回流。状态缓存结果写入SetupStateStore接口抽象默认FileStateStore写到/etc/openship/setup-state.jsonAPI 层可注入 DB 实现见 system/state.ts。缓存 TTL 为 24 小时CACHE_TTL_MS过期后在请求背后异步重验kickBackgroundVerify做了去重避免同一部署对多个 feature 依次 gate 时叠满 sshd 的 MaxSessions绝不阻塞热路径。功能门控requireFeature(deploy)读取缓存状态热路径上近乎免费。docker模式的前置规则是build → git docker、deploy → docker、routing/ssl → edgebare模式为build → git、routing/ssl → edge。注意Node/Go/Python 等语言运行时不是系统前置——它们由 toolchain 层按各栈需求按需安装。assumeInstalledcompose 容器化部署时 docker 是挂载的 socket、edge 是openship-edge镜像API 容器绝不能在自己容器/宿主机上安装任何东西此标志让ensureFeature/ensureComponents直接短路。ProvisionLock将 check→install→revalidate 整段串行化如 apt/dpkg、systemd 单元、80 端口、/etc 配置、状态文件保证并发部署不会互相踩踏API 侧注入进程内 mutex Postgres advisory lock的实现。executor 三兄弟system/executor.tscreateExecutor(ssh?)无 SSH 配置时返回单例LocalExecutorchild_process fs有 SSH 时返回SshExecutor进程内 ssh2 客户端密码/私钥/agent 认证。SshConfigtypes.ts还支持useSystemSsh走系统ssh二进制与~/.ssh/config、keychain、agent、sshJumpHost跳板机-J、readyTimeoutMs容器→宿主机一跳场景建议缩短避免 20s 默认值读起来像挂起等。此外createHostExecutor()处理容器化部署中容器→宿主机的 host channel经host.docker.internal走 SSH 控制宿主unavailableExecutor(reason)则返回一个每个方法都拒绝并附上原因的占位执行器——把宿主不可达从使用时的匿名故障提前到带补救提示的分类错误。装配逻辑如何连成一条线createSelfHostedPlatformplatform.ts的装配顺序如下判定目标机器targetIsThisMachine !config.ssh (config.localHost ?? !config.executor)——ssh 配置明确为远端且优先级最高否则信任显式localHost标志最后才回退到旧推断!executor。该结论通过Platform.localHost暴露给消费者如sharedMountExecutor决定哪些路径走本机 executor 而非 host channel。创建 executor优先用注入的托管/连接池 executor否则createExecutor(config.ssh)。创建 SystemManagernew SystemManager(runtimeMode, { executor, stateStore, installerConfig, provisionLock, assumeInstalled })。创建 runtimebare分支用new BareRuntime({ ...config.bare, executor, systemManager })否则DockerRuntime.create(config.docker, system, config.provisionLock)。创建 infracreateInfraProvider依次探测本机容器边缘OPENSHIP_EDGE_MODEdocker且目标为本机时经挂载的 Docker socket 操作openship-edge容器、远程容器边缘经共享 executor 探测目标机上的openship-edge、裸机 OpenRestydetectOpenRestyPaths探测真实路径写入 root 属主路径前经rootOrDegrade提权或降级。关键不变量路由缺口永远不导致部署失败——探测失败时降级为 no-op 并打日志应用照常构建运行只是路由可能不完整。整个包还强调构建期分离所有代码存在于同一代码库但工厂用动态import()按目标懒加载依赖zero bleed构建时 tree-shaking 可剔除未使用的适配器见 runtime/index.ts 的createRuntime与注释。例如 cloud 模式永远不会把 dockerode、ssh2 拉进最终产物。环境变量与解析优先级架构文档给出的两个核心变量在 API 层的 resolvePlatformConfig 中有完整实现变量取值作用CLOUD_MODEtrue/falseSaaS 托管模式与DEPLOY_MODEcloud均触发 cloud 目标鉴权/计费另由CLOUD_MODE单独门控DEPLOY_MODEdocker/bare/cloud/desktop选择 runtime 与目标解析优先级resolveConfig()/resolvePlatformConfig()CLOUD_MODEtrue或DEPLOY_MODEcloud或检测到 Oblien 凭据已配置→target: cloudDEPLOY_MODEdesktop→target: desktop其余情况 →target: selfhostedruntime: DEPLOY_MODEbare→ BareRuntime否则docker全部未设置 →target: selfhostedruntime: docker。值得注意的细节在云目标下allowHostBuild默认取!env.CLOUD_MODE——即本地/桌面实例允许 CloudRuntime 在本机执行本地构建、上传产物策略而 SaaS 实例默认拒绝因为宽松默认正是多租户控制面被租户构建命令攻破的方式platform.ts 中allowHostBuild的注释 明确写道此字段是一道边界缺省即拒绝。此外 selfhosted 还可选OPENSHIP_EDGE_MODEdocker/OPENSHIP_EDGE_CONTAINER控制边缘容器模式与容器名。单例生命周期一次启动全程同步platform.ts 维护模块级单例initPlatform(config)启动时调用一次内部await createPlatform(config)并缓存getPlatform()此后所有服务代码同步读取缓存实例未初始化即调用会抛出明确错误Platform not initialized. Call initPlatform() at server startup.peekPlatform()无单例时返回null而非抛错——专供该对象是否进程级平台这类归属判断如销毁逻辑抛错会把归属检查变成一次事故resetPlatform()测试用重置。API 侧的接线对应文档 How Its Wired 一节为app.ts: bootstrapPlatform()→controller-helpers.ts: resolveConfig() → initPlatform()→ 服务代码const { runtime, routing, ssl } platform()。getPlatform()的同步性保证热路径上零异步开销。从源码看演进中的架构事实对照文档与当前源码有三处值得补充的现状均为可验证的源码事实文档中的TraefikProvider已演化为 OpenResty/OpenResty-Lua 体系infra/nginx.ts实际面向 OpenResty certbot路由配置写入sites-enabled目录在 docker-edge 模式下由openship-edge容器承载。NoopInfraProvider在非 Linux 本机如 macOS 驱动 compose作为降级路径仍然存在。路由模型远超domain → containerRouteConfig支持proxyLocationsvercel.jsonrewrites 驱动的前缀代理、redirects、headerRules、cleanUrls、trailingSlash、redirectHost整站 canonical 跳转、staticRoot静态目录直出等见 types.ts 的 BaseRouteConfig。多服务与回滚是第一公民MultiServiceRuntimeAdaptercompose 语义的ensureServiceGroup/deployServiceWorkload/finalizeServiceGroup与archive/purge/makeActive回滚原语都定义在 runtime 层且不同 runtime 对制品是什么给出了不同答案——Bare/Cloud 是可原地重启的持久化单元Docker 则是镜像容器可弃、回滚时按保留镜像重走 deploy 流程。继续深入仓库packages/adapters/docs/ARCHITECTURE.md本文的母文档含 File Map 与装配 ASCII 图packages/adapters/src/platform.ts工厂、单例与全部装配逻辑packages/adapters/src/types.tsCommandExecutor、SshConfig、BuildConfig/DeployConfig/RouteConfig等全部共享类型packages/adapters/src/runtime/types.tsRuntimeAdapter接口与RuntimeCapability能力集packages/adapters/src/system/setup.tsSystemManager的检查/安装/缓存/门控实现apps/api/src/lib/controller-helpers.tsresolvePlatformConfig的环境变量解析测试佐证platform-local-edge.test.ts、platform-local-host-edge.test.ts 覆盖了本机边缘与本地宿主边缘两条装配路径。【免费下载链接】openshipSelf-hosted deployment platform项目地址: https://gitcode.com/GitHub_Trending/ope/openship创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表