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

fleetly

module
v0.1.0-rc1 Latest Latest
Warning

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

Go to latest
Published: Sep 19, 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, snapshot-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 prints a bootstrap admin token once to the fleetlyd log. 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 rollout → observation window v0.1
Release safety Swarm failure-action=pause + platform snapshot 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 printed once to the fleetlyd log on first start, 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).

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 my-api --service web    # live stream (--json for JSONL)
fleetly env set my-api KEY value            # pending until next deploy
fleetly rollback my-api                     # snapshot 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 ~/.ssh/id_ed25519.pub --note laptop   # 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 rollout
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 my-api https://github.com/acme/web.git \
    --branch main --auth-kind none                          # 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: Go ≥ 1.26.6 (GOTOOLCHAIN=auto works), buf CLI, Docker (for e2e).

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

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.

License

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

Directories

Path Synopsis
cmd
fleetly command
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 平台事件名注册表(代码内唯一真源)。
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):
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