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

compose

package
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 Imports: 18 Imported by: 0

Documentation

Overview

Package compose 实现 fleetly 的 Compose 应用描述处理:解析、受控子集 校验、稳定归一化与归一化差异(plan/diff 的地基)。

契约真源(本包行为逐条对齐,不发明清单外语义):

  • docs/design/2026-09-17-architecture.md §2.4(受控子集支持/拒绝清单、 平台 label 约定、受管字段、变量插值关闭、plan/apply 语义)
  • docs/design/2026-09-17-release-semantics.md §2.4(revisions 归一化 形态:env 按 key:sha256(value)+来源标注参与 spec_hash)与 §2.8 (受管字段政策:failure_action=pause、monitor≤5s、order 照用)
  • docs/design/2026-09-17-stateful-placement.md §2.3(placement label 语法、constraints 命名空间、replicas×卷校验、label 一致性)
  • docs/design/2026-09-17-state-model.md §2.4(fleetly.* 保留前缀 → E_LABEL_RESERVED)

解析器选型(关键决策):采用 github.com/compose-spec/compose-go/v2 官方 loader 作为 **schema 载体**(compose 语法合法性、类型换算:时长/字节/ 列表→映射 canonical 化),但 **受控子集校验完全自研**——受控子集是平台 契约而非 compose 全集,compose-go 的默认放行面远大于 §2.4 支持清单。 loader 选项与理由:

  • SkipInterpolation:`${VAR}`/`.env` 插值关闭(§2.4),归一化按字面;
  • SkipInclude / SkipExtends:include/extends 在拒绝清单内,必须保留 原始键让本包校验显式拒绝(默认 loader 会先解析消解掉这两个键);
  • ResolvePaths=false:路径保持书写形态,保证 spec_hash 跨机稳定;
  • SkipResolveEnvironment / SkipResolveLabels:env_file 与 label_file 不由 compose-go 合并——env 合并链(env_file < environment < 平台层) 需要保留 **来源标注**(release-semantics §2.4),本包自行解析 env_file(字面值、无插值,见 envfile.go);label_file 不在支持清单, 由白名单拒绝。
  • schema 校验保持开启:语法非法(未知键/类型错)→ 包装为 E_COMPOSE_UNSUPPORTED;其上再跑本包白名单/拒绝清单/受管字段校验。

归一化产物 Spec 是后续 revisions.compose_normalized 快照与 desired-hash 的地基:字段排序确定(服务/卷/域名/env 按字典序)、env 以 key+sha256 参与哈希(值永不落盘、永不输出)、spec_hash = sha256(canonical_json)。

本包不做的事(留待后续票,勿在此扩权):

  • apply 的真实执行(引擎层 T2.10);省略=删除的卷数据例外语义 (T2.10);平台 env_vars 合并层与 W_ENV_PLATFORM_OVERRIDE 告警 (env 票接入 DB 后);危险字段的 admin 显式旁路 + 审计(本期只 「拒绝+错误」,旁路留 TODO)。

Index

Constants

View Source
const (
	LabelDomains       = "fleetly.domains"
	LabelPlacementNode = "fleetly.placement.node"
	LabelCron          = "fleetly.cron"
	LabelCronTimezone  = "fleetly.cron.timezone"
	LabelCronTimeout   = "fleetly.cron.timeout"

	// LabelNamespace 是平台保留 label 命名空间前缀:用户占用约定键之外的
	// fleetly.* 键 → E_LABEL_RESERVED(422)。
	LabelNamespace = "fleetly."
)

平台 label 契约常量(架构 §2.4 平台约定表、state-model §2.4 保留前缀)。

View Source
const (
	EnvSourceEnvFile     = "env_file"
	EnvSourceEnvironment = "environment"
)

EnvSource 是归一化 env 条目的来源标注(release-semantics §2.4:三层合并 链 env_file < environment < 平台层;平台层随引擎/env 票接入,本包只产出 文件内两层)。值取稳定字符串,进快照与 plan/diff 输出。

View Source
const (
	// WarningKindCronLabelPending:fleetly.cron* label 在 v0.1 不生效
	// (定时任务为 v0.2 契约),服务按长驻部署。
	WarningKindCronLabelPending = "cron_label_v02_pending"
)

警告 Kind 常量(无注册码提示的稳定标识)。

Variables

This section is empty.

Functions

func Load

func Load(ctx context.Context, path string) (*Spec, []Warning, error)

Load 读取并解析 compose 文件,执行受控子集校验后返回归一化 Spec 与 警告标注(警告不阻断校验:W_DEPLOY_NO_HEALTHCHECK、cron label 的 v0.2 生效提示等)。任何失败都经 apperr 携带注册表错误码(suggestion/docs 由 注册表默认带出)。

Types

type Build

type Build struct {
	Context    string `json:"context"`
	Dockerfile string `json:"dockerfile,omitempty"`
}

Build 是归一化后的构建声明(仅保留平台消费的子键;构建引擎参数不在 §2.4 支持清单,白名单拒绝)。

type Deploy

type Deploy struct {
	Mode          string         `json:"mode,omitempty"`
	Replicas      int64          `json:"replicas,omitempty"`
	UpdateConfig  *UpdateConfig  `json:"update_config,omitempty"`
	RestartPolicy *RestartPolicy `json:"restart_policy,omitempty"`
	Resources     *Resources     `json:"resources,omitempty"`
	Placement     *Placement     `json:"placement,omitempty"`
}

Deploy 是归一化后的 deploy 段(受管字段 failure_action/monitor 校验通过 后不进快照——值恒为 pause/5s 平台常量,写进快照只会放大噪音;order 及 其余字段照用)。

type EnvVar

type EnvVar struct {
	Key    string `json:"key"`
	Hash   string `json:"hash"`
	Source string `json:"source"`
}

EnvVar 是一条 env 合并结果:值只以 sha256 hex 表示(spec_hash 参与; 明文与明文长度都不泄露),Source 标注三层合并链中的文件内层级。

type FieldChange

type FieldChange struct {
	Path string `json:"path"`
	From any    `json:"from,omitempty"`
	To   any    `json:"to,omitempty"`
}

FieldChange 是一条字段级变更:Path 为归一化形态内的稳定路径 (如 environment.FOO、deploy.replicas、healthcheck.test);From/To 为 该路径上的 JSON 值(env 路径只含 hash/source,无明文)。

type Healthcheck

type Healthcheck struct {
	Test        []string `json:"test,omitempty"`
	Interval    string   `json:"interval,omitempty"`
	Timeout     string   `json:"timeout,omitempty"`
	Retries     uint64   `json:"retries,omitempty"`
	StartPeriod string   `json:"start_period,omitempty"`
}

Healthcheck 是按书写形态归一化的健康检查(平台默认 5s/3s/3/10s 只补 运行态缺省,不烘焙进快照——治理参数取当前平台配置,release-semantics §2.4)。时长为归一化字符串(time.Duration.String() 形态,如 10s)。

type Mount

type Mount struct {
	Volume   string `json:"volume"`
	Target   string `json:"target"`
	ReadOnly bool   `json:"read_only,omitempty"`
}

Mount 是一次命名卷挂载。

type Placement

type Placement struct {
	Constraints []string `json:"constraints,omitempty"`
}

Placement 归一化放置约束(constraints 仅允许 node.labels.fleetly.* 命名空间,stateful-placement §2.3)。

type Plan

type Plan struct {
	// Name 是目标 Spec 的应用名(基线与目标名不一致时取目标侧)。
	Name string `json:"name,omitempty"`
	// SpecHash 是目标归一化形态哈希(= etag)。
	SpecHash string `json:"spec_hash"`
	// BaseSpecHash 是基线归一化形态哈希(空基线为空串)。
	BaseSpecHash string `json:"base_spec_hash,omitempty"`
	HasChanges   bool   `json:"has_changes"`
	// Destructive 表示变更集含破坏性操作(服务删除/卷解绑——省略=删除;
	// 卷数据不随声明删除的例外语义由执行层 T2.10 兑现,本期只解析标记)。
	Destructive bool `json:"destructive"`
	// RequiresConfirmDestructive 是执行侧 --confirm-destructive 的门控位
	// (v0.1 恒等于 Destructive;独立成字段以便引擎层引入非破坏性降级后
	// 二者分叉)。
	RequiresConfirmDestructive bool         `json:"requires_confirm_destructive"`
	Services                   ServicesPlan `json:"services"`
	Volumes                    VolumesPlan  `json:"volumes,omitempty"`
	Warnings                   []Warning    `json:"warnings,omitempty"`
}

Plan 是 plan/diff 的产物:两份归一化 Spec 的变更集(架构 §2.4 plan/apply 语义——面向 AI Agent 的一等接口)。JSON 形态即 plan artifact:

  • spec_hash 即 etag(apply 前校验防 stale 并发,落盘 artifact 的机制位);
  • requires_confirm_destructive 置位时,执行侧(T2.10 引擎层)必须持有 --confirm-destructive 才允许继续;
  • 脱敏结构性成立:env 只以 key+sha256+source 表示,明文值无从泄露。

func Diff

func Diff(base, target *Spec) (*Plan, error)

Diff 计算两份归一化 Spec 的变更集:base(如上一 revision 快照/基线 compose)→ target(本次目标)。nil 参数视为空 Spec(首部署语义)。 数据来源接口化:真实 DB 基线(revisions.compose_normalized)随引擎票接入, 本期 CLI 用 --baseline 另一份 compose 文件或空基线。

func (*Plan) RenderText

func (p *Plan) RenderText() string

RenderText 渲染人读 plan/diff 报告(非 --json 形态;顺序确定)。

type ResourceLimits

type ResourceLimits struct {
	CPUS        float64 `json:"cpus,omitempty"`
	MemoryBytes int64   `json:"memory_bytes,omitempty"`
}

ResourceLimits 是 limits 的平台消费子集。

type Resources

type Resources struct {
	Limits *ResourceLimits `json:"limits,omitempty"`
}

Resources 归一化资源限额(仅 limits;reservations 不在支持清单)。

type RestartPolicy

type RestartPolicy struct {
	Condition   string `json:"condition,omitempty"`
	Delay       string `json:"delay,omitempty"`
	MaxAttempts uint64 `json:"max_attempts,omitempty"`
	Window      string `json:"window,omitempty"`
}

RestartPolicy 归一化重启策略(release-semantics §2.8:restart_policy 照用)。

type Service

type Service struct {
	Name string `json:"name"`
	// Build/Image 互斥或同现均可(compose 允许 image+build;构建模式裁决
	// 随构建票:无 dockerfile → Railpack,有 build.dockerfile → Dockerfile)。
	Build   *Build   `json:"build,omitempty"`
	Image   string   `json:"image,omitempty"`
	Command []string `json:"command,omitempty"`
	// Expose 保持原序(路由目标端口取首个,架构 §2.4)。
	Expose []string `json:"expose,omitempty"`
	// Domains 是 fleetly.domains label 解析后的域名列表(trim/小写/
	// IDN→punycode 归一化后排序)。有该 label 的服务即入口。
	Domains []string `json:"domains,omitempty"`
	// PlacementNode 是 fleetly.placement.node label 的字面值(放置意图;
	// 名或 n_<ULID> 的解析/绑定校验属放置层,语法校验见 validate.go)。
	PlacementNode string `json:"placement_node,omitempty"`

	Healthcheck *Healthcheck `json:"healthcheck,omitempty"`
	// Environment 是 env 合并结果(env_file < environment),按 key 排序;
	// 只含 key+hash+source,值永不进归一化形态(脱敏结构性成立)。
	Environment []EnvVar `json:"environment,omitempty"`
	Secrets     []string `json:"secrets,omitempty"`
	// Volumes 是命名卷挂载(v0.1 受控子集:仅命名卷;bind/tmpfs 拒绝),
	// 保持声明顺序(挂载点集合有语义)。
	Volumes  []Mount  `json:"volumes,omitempty"`
	Networks []string `json:"networks,omitempty"`

	Deploy          *Deploy `json:"deploy,omitempty"`
	StopSignal      string  `json:"stop_signal,omitempty"`
	StopGracePeriod string  `json:"stop_grace_period,omitempty"`
}

Service 是归一化后的服务定义。只承载受控子集字段;平台管理项(镜像 digest、secret 值、路由绑定、节点绑定)不进文件、不进快照。

type ServiceUpdate

type ServiceUpdate struct {
	Name   string        `json:"name"`
	Fields []FieldChange `json:"fields"`
}

ServiceUpdate 是单个服务的字段级变更报告。

type ServicesPlan

type ServicesPlan struct {
	Added   []string        `json:"added,omitempty"`
	Removed []string        `json:"removed,omitempty"`
	Updated []ServiceUpdate `json:"updated,omitempty"`
}

ServicesPlan 是服务维度的变更集。

type Spec

type Spec struct {
	Name     string    `json:"name,omitempty"`
	Services []Service `json:"services"`
	Volumes  []Volume  `json:"volumes,omitempty"`
	Networks []string  `json:"networks,omitempty"`
	Secrets  []string  `json:"secrets,omitempty"`
	// SpecHash 是 CanonicalJSON 的 sha256 hex(载入时填定)。
	SpecHash string `json:"spec_hash"`
}

Spec 是 compose 文件经受控子集校验后的稳定归一化形态(架构 §2.4、 release-semantics §2.4):受控子集内的服务与卷定义;env 以 key:sha256(value)+来源标注表示(值本身不进归一化结果);无插值、字面值。 该形态即 revisions.compose_normalized 快照与 desired-hash 的地基。

稳定性纪律:所有切片输出前排序(服务/卷/网络/secret/域名/env 按名称或 字典序;expose/volumes 挂载顺序语义保留原序),canonical JSON 由 CanonicalJSON 确定性编码,spec_hash = sha256(canonical_json)。

func LoadEmpty

func LoadEmpty(name string) *Spec

LoadEmpty 返回空基线 Spec(首部署语义:一切服务视为新增)。plan 在未 提供 --baseline 时使用;DB 基线(上一 revision 快照)随引擎票接入。

func (*Spec) CanonicalJSON

func (s *Spec) CanonicalJSON() ([]byte, error)

CanonicalJSON 输出确定性 JSON(键排序由 encoding/json 保证、HTML 转义 关闭、无尾部换行),作为 spec_hash 的哈希输入。

type UpdateConfig

type UpdateConfig struct {
	Order       string `json:"order,omitempty"`
	Parallelism uint64 `json:"parallelism,omitempty"`
	Delay       string `json:"delay,omitempty"`
}

UpdateConfig 归一化更新策略(order 照用;有卷服务显式 start-first 在 校验层拒绝 → E_COMPOSE_UNSAFE_STRATEGY)。

type Volume

type Volume struct {
	Key    string `json:"key"`
	Driver string `json:"driver,omitempty"`
}

Volume 是顶层命名卷声明(卷数据生命周期归平台卷注册表,声明仅承载 driver 等卷级参数;external/name 拒绝)。

type VolumesPlan

type VolumesPlan struct {
	Added   []string `json:"added,omitempty"`
	Removed []string `json:"removed,omitempty"`
}

VolumesPlan 是顶层卷维度的变更集(新增=声明卷;移除=解绑标记,数据 不随声明删除)。

type Warning

type Warning struct {
	Code    string `json:"code,omitempty"`
	Kind    string `json:"kind,omitempty"`
	Service string `json:"service,omitempty"`
	Message string `json:"message"`
}

Warning 是校验/计划产物上的非阻断标注。Code 为注册表 W_ 码(如 W_DEPLOY_NO_HEALTHCHECK);无注册码的提示(如 cron label 的 v0.2 生效 提示——v0.1 冻结注册表不含对应码,不发明新码)Code 留空、以 Kind 给出 稳定标识。

Jump to

Keyboard shortcuts

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