Help us shape the future of Go! Take the 2026 Go Developer Survey

fleetly

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 20, 2026 License: Apache-2.0

README

fleetly

ci nightly

English | 简体中文

Dokku's footprint, Railway's API, AI-Agent-first operations.

fleetly is an ultra-lightweight open-source PaaS for small teams. Deploy compose.yaml apps to a cluster of 1–10 servers with zero-downtime releases, revision-based rollback, drift detection, and an API surface designed for both humans and AI agents — no Kubernetes required.

Status: early development. Design is frozen and reviewed; the T0 foundation (repo, CI, proto contract chain, error-code registry, dind E2E skeleton) has landed. v0.1 is not released yet — see the roadmap. Formerly known as edgesets and edgefleet.

Install

One command on a clean Linux VPS (amd64/arm64, root) installs a running platform — engine gate (Docker ≥ 29.8.1, iptables backend), implicit docker swarm init, systemd autostart, and an install report with the port-exposure surface:

curl -fsSL https://fleetly.dev/install.sh | sudo sh -            # latest stable
curl -fsSL https://fleetly.dev/install.sh | sudo sh - --version v0.1.0
sudo sh install.sh --bin-dir ./dist                              # offline / dev form

The first start writes the bootstrap admin token once to <data-root>/bootstrap-token (0600, never logged; remove the file after the first successful login). Uninstall keeps application data (--purge removes it). Upgrading the control plane is one command with a pre-upgrade snapshot and automatic rollback (sudo sh upgrade.sh --version vX.Y.Z); Engine/host upgrades are a separate cold-backup procedure — see docs/runbooks/upgrade.md. Forms, gate list, port table, and dind verification: deploy/README.md. (Release artifacts land with the release pipeline — until then the offline --bin-dir form is the working path.)

Why fleetly

  • Built for teams without ops. ≤5 developers, no dedicated ops, 1–3 servers to start, a maintenance budget of 1–2 hours per week. Everything automatable (TLS, backups, upgrades, inspection) is automated and verifiable.
  • Compose is the only app model. No proprietary spec. A controlled subset of the Compose Specification with a minimal fleetly.* label convention; anything outside the subset is rejected with a structured error, never silently ignored.
  • Docker Swarm as the substrate. Membership, scheduling, and health-gated updates come from the engine itself — no self-built distributed core. Single-node v0.1 is already a (transparent) single-node Swarm, so adding the second server is a docker swarm join, not a re-architecture.
  • API-first, proto as the contract. gRPC + REST (grpc-gateway) derived from a single protobuf source; CLI, Console, and (in v0.2) MCP are all consumers of the same contract. No feature ships without an API.
  • Trust is the floor. Atomic self-upgrades (pre-pulled image + snapshot + auto-rollback), backups with read-back verification, error messages as a product (stable error codes + context + fix suggestions) — for humans and AI agents alike.

Feature map (planned)

Area Behavior Version
Deploy git push / webhook / API → Railpack or Dockerfile build → zero-downtime release → observation window v0.1
Release safety Swarm failure-action=pause + platform revision replay (last 5 verified revisions); never Swarm-native rollback v0.1
Routing / TLS Per-node Traefik with routes and certs pushed by the control plane; central ACME (HTTP-01), multi-SAN domain lists v0.1
State SQLite control-plane state, three-layer model (authoritative / observed cache / live read) v0.1
Drift detection Desired-state hash vs. reality; detection on by default, auto-converge opt-in per app v0.1
Multi-node docker swarm join, image registry (zot), stateful pinning, honest HA boundaries v0.2
AI agents MCP server with a curated toolset (≤30 tools), scoped tokens, two-step destructive confirmation v0.2
Data services Managed Postgres/Redis templates + per-engine backup adapters + connection-string injection v0.2
Extras Cron (Swarm jobs), metrics (VictoriaMetrics), Web terminal (exec relay, D19) v0.2+

Honest boundaries

We say what we don't do: no cross-node shared storage (volumes are local; stateful services are pinned to a node and never auto-migrated — moving data goes through backup/restore); two nodes ≠ full HA (you get stateless process HA, not management-plane or stateful HA — the installer says so explicitly); no CI engine (your Git host runs CI; fleetly gates deploys on webhook status); no Kubernetes backend (k3s is reserved as an exit plan, not a feature).

Architecture

CLI (fleetly) / Console / MCP (v0.2) / gRPC / REST / git push (SSH) / Webhook
                 │
   fleetlyd — single Go binary on the Swarm manager
     API: gRPC + grpc-gateway (proto = single contract source)
     release state machine · reconciler · build pipeline (Railpack/BuildKit)
     state: SQLite (WAL) · secrets: envelope encryption (age) · TLS: central ACME
                 │  Docker API (local socket manages the whole cluster)
   Docker Engine (Swarm mode) — services · overlay networks · scheduling
   Traefik (global, per node) — routes & certs pushed by the control plane

Foundation stack: lynx + google/wire (D20), buf + grpc-gateway (D21). Domain code stays free of framework types — the core/adapter boundary is a hard rule (D13).

Repository layout

cmd/fleetlyd/   control-plane daemon
cmd/fleetly/    CLI
proto/            API contracts (fleetly.{server,client,console,shared}.v1)
genproto/         generated code + OpenAPI (openapiv2) — committed
sdk/go/           Go SDK (gRPC client)
internal/         errcode / eventcode registries, app error envelope
e2e/              dind smoke harness (reused by CI and Spikes)
docs/             design docs, research reports, implementation plan
console/          Console frontend (React + Vite + shadcn/ui, lands with T2.21)
deploy/           installer & systemd units (lands with T2.1)

CLI

The CLI talks to the daemon over gRPC only — no direct database or Docker access. Every verb that touches the platform takes --addr (default 127.0.0.1:8421, env FLEETLY_ADDR) and --token (env FLEETLY_TOKEN); the bootstrap admin token is written once to <data-root>/bootstrap-token on first start (never logged; delete after first login), further tokens come from fleetly tokens create. Every verb supports --json; exit codes are 0 success/no changes, 1 error, 2 changes detected (plan/diff only), 64 usage error (unknown verb, bad flags/arguments — EX_USAGE). Flags must precede positional arguments (Go std flag semantics). Unary RPCs carry a default 30s deadline; Ctrl-C on streaming verbs (logs follow, events watch) and wait verbs (deploy, build, rollback) exits cleanly with code 0.

fleetlyd &                                  # control plane (gRPC :8421, HTTP :8420, git SSH :8424)
export FLEETLY_ADDR=127.0.0.1:8421
export FLEETLY_TOKEN=<bootstrap admin token>

fleetly validate compose.yaml               # controlled-subset validation (local)
fleetly plan compose.yaml                   # diff vs latest revision via API; exit 2 = changes
fleetly deploy compose.yaml                 # enqueue and wait for the terminal state
fleetly apps list && fleetly deployments list my-api
fleetly logs follow --service web my-api    # live stream (--json for JSONL)
fleetly env set my-api KEY value            # pending until next deploy
fleetly rollback my-api                     # revision replay (last 5 revisions)
fleetly drift show my-api                   # desired vs. live
fleetly tokens create --scopes deploy --note CI   # plaintext shown once
Deploying via git push (SSH)

The daemon runs an embedded SSH git endpoint (default 127.0.0.1:8424 — loopback by default; expose it on a VPS by setting git.addr and firewalling accordingly). Register your public key, then push to the app's bare repo; compose.yaml/compose.yml at the repo root is the deploy unit, and pushes to the app's configured branch (default main) trigger a deployment.

fleetly git keys add --note laptop ~/.ssh/id_ed25519.pub   # admin scope; fingerprints at rest
git remote add fleetly ssh://git@127.0.0.1:8424/my-api.git
git push fleetly main                                      # → build → zero-downtime release
fleetly git keys list && fleetly git keys rm <id>
Deploying via webhook (GitHub / Gitea)

Configure the per-app signing secret (never echoed again), point the webhook at the control plane (POST /v1/apps/<app>/webhooks/github or /gitea, JSON body), and the daemon verifies the HMAC-SHA256 signature, rejects replayed delivery IDs (15-min TTL), dedups by commit, fetches the source, and enqueues the deploy.

fleetly apps webhook set-secret my-api <secret>            # ≥16 chars; admin scope
fleetly apps webhook set-source --branch main --auth-kind none \
    my-api https://github.com/acme/web.git                  # or https_token / ssh_key
fleetly apps webhook show my-api                           # no sensitive projection

See fleetly help <verb> for the full flag list.

Console (web UI)

A React SPA (Vite + Tailwind + shadcn/ui) that consumes only the authenticated REST API. Build it and point the daemon at the output to get it served at /ui/ (static assets are unauthenticated; all data still goes through the Bearer-authenticated /v1 API):

cd console && pnpm install && pnpm build      # → console/dist
fleetlyd -c config.yaml                       # with console.static_dir: "./console/dist"
# open http://127.0.0.1:8420/ui/  → paste an API token to sign in

The console covers app list/detail (derived-state badges), deploys with live terminal-state tracking, rollback, streaming logs (NDJSON follow + history search), env management (pending changes grouped as "takes effect on next deploy"), domains with verify, system health, and the platform event stream. See console/README.md.

Documentation

All docs live in docs/ (Chinese, design-first workflow):

Roadmap

Stage Scope Status
T0 foundation repo, CI gates, proto contract chain, error/event registries, dind E2E skeleton ✅ done
Spike A/B/C build, release+routing, substrate risk validation (V1–V7) next
v0.1 single-node GA of the 8-item scope (deploy loop, TLS, rollback, trust drill) in development
v0.2 multi-node, MCP, S3 endpoints, managed databases, cron, metrics, Web terminal planned
v0.3 preview environments, template catalog, RBAC, Compose subset expansion, tunnel access planned

Development

Prerequisites: mise — mise install provisions Go, Node, pnpm, buf and golangci-lint at the versions pinned in mise.toml (aligned with the CI gates); Docker is only needed for e2e (dind) and a full local loop. Without mise, install the same tools yourself (Go ≥ 1.26.6, GOTOOLCHAIN=auto works; buf CLI).

go build ./...
go test ./... ./sdk/go/... -race   # or: mise run test
buf lint && buf generate          # generated artifacts are committed; must not drift; mise run generate:proto
golangci-lint run                 # or: mise run lint

Smoke E2E (runs fleetlyd inside docker:29.8.1-dind): see e2e/README.md.

Contribution discipline: this project is design-first — behavior changes start as doc changes (review rounds), then land as vertical slices tracked in the task breakdown. Error codes and events are append-only registries. Remediation acceptance must include a write-back check of related docs/comments: grep the changed keyword across docs/, deploy/, and code comments to confirm runbooks, scripts, and help text no longer describe the pre-fix behavior (drift is a defect, not a style issue).

License

Apache-2.0 — see LICENSE. The default distribution contains no AGPL/DSAL components.

Directories

Path Synopsis
cmd
fleetly command
fleetly CLI 进程入口:只保留信号挂接与版本注入(-ldflags "-X main.version=...")。
fleetly CLI 进程入口:只保留信号挂接与版本注入(-ldflags "-X main.version=...")。
fleetly/cmd
fleetly CLI:fleetly 平台命令行(lynx-go/commands 动词注册,D21)。
fleetly CLI:fleetly 平台命令行(lynx-go/commands 动词注册,D21)。
fleetlyd command
fleetlyd 是 fleetly 控制面守护进程。
fleetlyd 是 fleetly 控制面守护进程。
genproto module
internal
api
Package api 是 fleetly 控制面 v0.1 API 服务实现与拦截器链(T2.17; 架构 D21:proto 唯一真源,鉴权/限流在 gRPC 拦截器链)。
Package api 是 fleetly 控制面 v0.1 API 服务实现与拦截器链(T2.17; 架构 D21:proto 唯一真源,鉴权/限流在 gRPC 拦截器链)。
apitest
Package apitest 是 CLI/SDK 侧集成测试的进程内服务装配夹具:真实 internal/api 服务实现 + 独立临时目录 sqlite + 生产同构拦截链(auth)的 bufconn gRPC server。
Package apitest 是 CLI/SDK 侧集成测试的进程内服务装配夹具:真实 internal/api 服务实现 + 独立临时目录 sqlite + 生产同构拦截链(auth)的 bufconn gRPC server。
apperr
Package apperr 是携带 fleetly 错误信封的应用错误类型。
Package apperr 是携带 fleetly 错误信封的应用错误类型。
build
Package build 是构建管线(task-breakdown T2.8 构建管线产品化 + T2.9 镜像身份 v0.1 免 registry):compose 服务的 build/image 两模式到本机 镜像 digest 的生产链——Builder 端口 + Railpack/Dockerfile 双实现 + 构建队列(并发 ≤2、资源限额)+ plan/日志归档 + 本机镜像登记与 preflight(供发布引擎消费)。
Package build 是构建管线(task-breakdown T2.8 构建管线产品化 + T2.9 镜像身份 v0.1 免 registry):compose 服务的 build/image 两模式到本机 镜像 digest 的生产链——Builder 端口 + Railpack/Dockerfile 双实现 + 构建队列(并发 ≤2、资源限额)+ plan/日志归档 + 本机镜像登记与 preflight(供发布引擎消费)。
compose
Package compose 实现 fleetly 的 Compose 应用描述处理:解析、受控子集 校验、稳定归一化与归一化差异(plan/diff 的地基)。
Package compose 实现 fleetly 的 Compose 应用描述处理:解析、受控子集 校验、稳定归一化与归一化差异(plan/diff 的地基)。
engine
Package engine 是 fleetly 发布引擎(task-breakdown T2.10 发布状态机与 对账核心 + T2.11 窗口与失败语义):compose → 放置/env/镜像/secret 准备 → Swarm service 对账(新增/更新/删除)→ 健康门 → 观察窗 → 版本固化,以及 失败分流(归位/首发 scale=0/已切流告警)、L2 看门狗与 L3 观察窗、控制面 重启分类恢复、cancel 与 app 派生状态。
Package engine 是 fleetly 发布引擎(task-breakdown T2.10 发布状态机与 对账核心 + T2.11 窗口与失败语义):compose → 放置/env/镜像/secret 准备 → Swarm service 对账(新增/更新/删除)→ 健康门 → 观察窗 → 版本固化,以及 失败分流(归位/首发 scale=0/已切流告警)、L2 看门狗与 L3 观察窗、控制面 重启分类恢复、cancel 与 app 派生状态。
envlayer
Package envlayer 是变量三层合并链(architecture §2.4 变量合并行, 2026-09-17 审核裁决):
Package envlayer 是变量三层合并链(architecture §2.4 变量合并行, 2026-09-17 审核裁决):
errcode
Package errcode 是 fleetly 错误码注册表(代码内唯一真源)。
Package errcode 是 fleetly 错误码注册表(代码内唯一真源)。
eventcode
Package eventcode 是 fleetly 平台事件名注册表(代码内唯一真源)。
Package eventcode 是 fleetly 平台事件名注册表(代码内唯一真源)。
execrun
Package execrun 是平台对外部子进程的统一生命周期封装(MG-1:外部 进程/会话生命周期统一封装——架构评审结论:逐点修留漏网即缺机制)。
Package execrun 是平台对外部子进程的统一生命周期封装(MG-1:外部 进程/会话生命周期统一封装——架构评审结论:逐点修留漏网即缺机制)。
gitserver
Package gitserver 是 git push(SSH) 与 webhook 两条部署触发入口的 daemon 侧实现(T2.19):
Package gitserver 是 git push(SSH) 与 webhook 两条部署触发入口的 daemon 侧实现(T2.19):
ingress
Package ingress 是入口与证书适配器(T2.15/T2.16;架构 §2.6 入口真源): 平台自管 Traefik(global service 每节点,v0.1 单机 1 实例)、路由与证书 经 HTTP provider 由控制面集中下发、控制面内嵌 ACME(lego)集中签发。
Package ingress 是入口与证书适配器(T2.15/T2.16;架构 §2.6 入口真源): 平台自管 Traefik(global service 每节点,v0.1 单机 1 实例)、路由与证书 经 HTTP provider 由控制面集中下发、控制面内嵌 ACME(lego)集中签发。
logs
Package logs 是应用日志管线(T2.20;architecture §4.2 第 5 项「实时流 + 历史落盘检索」):
Package logs 是应用日志管线(T2.20;architecture §4.2 第 5 项「实时流 + 历史落盘检索」):
naming
Package naming 是 fleetly 平台对象命名与最小 label 集的唯一定义点 (state-model §2.4 对象标记契约 + architecture §2.4 服务命名与网络行)。
Package naming 是 fleetly 平台对象命名与最小 label 集的唯一定义点 (state-model §2.4 对象标记契约 + architecture §2.4 服务命名与网络行)。
placement
Package placement 是放置解析与绑定生命周期(stateful-placement 专项的 v0.1 单机切面,T2.14):
Package placement 是放置解析与绑定生命周期(stateful-placement 专项的 v0.1 单机切面,T2.14):
runtime
Package runtime 是 fleetlyd 的服务组装层(composition root):在 lynx App 之上,Wire 编译期装配出 boot.Bootstrap——配置解析与缺省回落 (config.go)、资源构造与释放(provides.go 的 provider 集)、入口面 (HTTP gateway/gRPC/git SSH)、写入者与资源层的服务壳(*_service.go, 注册序即停止序的三段不变量见 NewServices 注释),以及 schema-version 之外的全部守护进程形态。
Package runtime 是 fleetlyd 的服务组装层(composition root):在 lynx App 之上,Wire 编译期装配出 boot.Bootstrap——配置解析与缺省回落 (config.go)、资源构造与释放(provides.go 的 provider 集)、入口面 (HTTP gateway/gRPC/git SSH)、写入者与资源层的服务壳(*_service.go, 注册序即停止序的三段不变量见 NewServices 注释),以及 schema-version 之外的全部守护进程形态。
secrets
Package secrets 是平台密钥方案的 envelope 加密实现(architecture §2.3 密钥方案 + §2.4 密钥行):
Package secrets 是平台密钥方案的 envelope 加密实现(architecture §2.3 密钥方案 + §2.4 密钥行):
state
Package state 是 fleetly 控制面状态层(SQLite 权威态 + 底座观测缓存 + 写前直读端口)。
Package state 是 fleetly 控制面状态层(SQLite 权威态 + 底座观测缓存 + 写前直读端口)。
statebackup
Package statebackup 是控制面状态热备(T2.22,备份基线与信任闭环): SQLite 一致性快照(VACUUM INTO)→ 回读校验(integrity_check + 关键表 行数抽查 + schema 版本)→ sha256 落 manifest → state_backups 台账(与 审计同事务)。
Package statebackup 是控制面状态热备(T2.22,备份基线与信任闭环): SQLite 一致性快照(VACUUM INTO)→ 回读校验(integrity_check + 关键表 行数抽查 + schema 版本)→ sha256 落 manifest → state_backups 台账(与 审计同事务)。
substrate
Package substrate 是 Docker/Swarm 底座的 moby/client 适配器:把 state.DockerClient 端口翻译为 Docker Engine API 调用。
Package substrate 是 Docker/Swarm 底座的 moby/client 适配器:把 state.DockerClient 端口翻译为 Docker Engine API 调用。
pkg
api
Package api 预留为 fleetly API 契约的 Go 侧挂载点:proto 契约与 生成链(gRPC + grpc-gateway,torchwood 范式)随 T0.3 落地;本阶段 仅占位,保证 monorepo 目录结构(架构 §2.7)就位。
Package api 预留为 fleetly API 契约的 Go 侧挂载点:proto 契约与 生成链(gRPC + grpc-gateway,torchwood 范式)随 T0.3 落地;本阶段 仅占位,保证 monorepo 目录结构(架构 §2.7)就位。
sdk
go module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL