文档/运维操作

运维操作#

资源历史、可恢复日志、磁盘采样、告警和认证 Prometheus 抓取见可观测。单 Manager SQLite、历史保留、备份和恢复见控制面存储与恢复

Luma Control 是 Manager 上的自托管 API,管理令牌、节点注册、DNS、job 渲染和 Nomad 部署调用。luma deploy 与 Control 通信,不通过 SSH 部署。底层使用 HashiCorp Nomad,部署单位为 Nomad job。

默认流程:

service.yaml -> luma deploy -> Luma Control -> render jobspec -> sync DNS -> Nomad API (/v1/jobs) -> docker driver

Luma 通过 Nomad HTTP API 部署。

添加服务#

luma service new
luma deploy <service>.yaml --dry-run
luma login https://luma.example.com --token <management-token>
luma deploy <service>.yaml
luma doctor

手写清单使用相同字段:

name: api
image: ghcr.io/me/api:2026-05-29-1
region: cn
exposure: cn-edge
domain: api.example.com
port: 3000
replicas: 2

多服务应用保持标准 docker-compose.yml,另加 Luma sidecar:

luma compose init --compose docker-compose.yml --output luma.compose.yml
luma compose validate luma.compose.yml
luma compose deploy luma.compose.yml --dry-run
luma compose deploy luma.compose.yml

新的持久化 Compose 和原生服务使用部署节点本地存储。在 luma.compose.yml 里用 volumes.<name>.local.path;原生服务用 named volume 或 bind mount。不要为新应用注册 NFS 或 storage class。迁移期间仍可使用旧的 storageClass 引用;Control 仍拒绝 sidecar 里的非空 storageClasses,切换后端需要已验证的 adopted: trueinitialize: empty。详见 compose-storage.md

更新镜像标签#

修改清单:

image: ghcr.io/me/api:2026-05-29-2

然后部署:

luma deploy api.yaml

调整副本#

修改清单:

replicas: 3

然后部署:

luma deploy api.yaml

从 Manager 临时扩缩容:

nomad job scale api 3

临时命令不更新 Git。需要持久保留时,随后提交清单变更。

固定到一个节点#

仅在服务依赖本地磁盘、硬件或特定家庭/工作机器时使用:

region: home
node: home-mac-mini

node 必须是 luma node join --name 的节点名。Luma 渲染 ${node.unique.name}(或 meta.luma_node_name)约束,并保留 ${meta.region} 约束,因此目标节点必须属于该区域。Nomad 节点身份跨重新加入保持稳定,无需刷新固定放置。

查看状态#

从客户端:

luma status
luma context list
luma context use <cluster-id>

luma status 显示 Nomad、server leader 和 role=client 节点。

从 Manager:

nomad job status <service>
nomad job status -verbose <service>
nomad alloc logs -f <alloc-id>

回滚#

Nomad 为每个 job 保留版本历史,Luma 在控制台和 CLI 都提供运行时回滚。

控制台打开 https://<control-domain>/dashboard/,进入 应用 → 版本,检查 job 版本,选择旧版本并确认回滚。

CLI 操作:

luma history <service>
luma rollback <service>
luma rollback <service> --to-version <N>

luma history 列出 Nomad job 旧版本(GET /v1/job/<id>/versions);luma rollback 通过 POST /v1/job/<id>/revert 回退上一版或 --to-version 指定版本。Jobspec 渲染 update { auto_revert = true },新版本健康检查失败时自动回退到最近健康版本。

这只回滚运行 job,不改写 Git 历史或 Control 保存的清单/YAML,不逆转数据库迁移或恢复卷。Compose 回滚作用于整个 job/stack。生产使用固定标签或 digest;latest 等可变标签可能让旧 job 拉取到新内容。

如需清单与运行 job 保持同步,采用 Git 优先流程:

git revert <deploy-commit>
luma deploy <service>.yaml

重启服务#

无需拉取新镜像或改变存储清单即可重启。重启不仅是进程信号,还会协调交付:等待替换 allocation,刷新 Nomad CNI 主机端口状态,根据记录部署和实际节点重建 HTTP/TCP 路由,同步 DNS,并验证所有公共 HTTP 端点后才返回成功。

luma service restart <stack>
luma service restart <stack> --service <task>
luma service restart <stack> --mode task

两种重启模式:

省略 --mode 时按上述默认值,也可显式覆盖。Compose 的 luma service restart <app> --service <svc> 原地重启一个服务任务,luma service restart <app> 重建全部 allocation。--timeout <seconds> 限制 Control 响应等待,默认 120

控制台 → 应用 → 应用详情 → 服务中,运行服务有 Shell 操作;节点 Shell 位于 基础设施 → 节点。都打开独立终端页,离开页面结束浏览器会话。通过节点 agent 的 docker exec 进入容器,复用节点 Shell 的终端 supervisor。用于实时诊断,不能替代日志或重启。系统 stack 被禁止。节点 agent 需声明 container-terminal,不支持时先更新。

响应包含 replacementAllocations 和结构化 deliveryroutesdnsprobes)。平台管理但无保存记录的部署会报告跳过交付协调;托管公共部署只有公网探测成功才返回 delivery.status=ready。协调后的 HTTP 文件路由使用显式优先级,安全覆盖仍广播不可达私网地址的旧 Nomad-provider 路由。

拒绝重启 traefikegressluma-control 系统 stack;Control 本身就在 luma-control allocation 内,应用管理中循环重启会终止自身。

删除部署#

使用已部署服务或 Compose 应用名:

luma service remove <service>

Control 使用最近成功部署记录的清单,删除 Luma 管理的公共 DNS,注销并清除 Nomad job(DELETE /v1/job/<id>?purge=true),删除 Manager 生成文件。单服务与 Compose 共用命令,客户端没有本地 YAML 也可删除网页创建的部署。tailscale-relay 同时删除 /opt/luma/routes/<service>.yml。cloudflare-tunnel 主机名仍归 Cloudflare Zero Trust 管理,跳过其清理。

默认保留存储。如需删除记录中引用的可移除存储,先预览再执行:

luma service remove <service> --dry-run --delete-storage
luma service remove <service> --delete-storage

单服务会删除 storage.<volume>.path 托管路径和清单中的 Docker 命名卷,跳过 bind mount。Compose 删除 sidecar 引用的托管卷子目录,不删除 class 本身。不能与 --skip-orchestrator 同用。

只预览清理,不修改 Manager:

luma service remove <service> --dry-run

部分清理时可保留 DNS 或运行 job。--skip-orchestrator 不移除 Nomad job:

luma service remove <service> --skip-dns
luma service remove <service> --skip-orchestrator

Control 不可用时,在 Manager 直接删除 Nomad job,再删除生成文件:

nomad job stop -purge <service>
sudo rm -rf /opt/luma/stacks/<region>/<service>
sudo rm -f /opt/luma/routes/<service>.yml

删除节点#

从任意已登录客户端:

luma node remove <node-name>

Manager Control 删除 Luma 注册并排空匹配 client(PUT /v1/node/<id>/drain),死亡 client 随后由 Nomad 自动回收。如果 Nomad 对该 ID 返回 404 或 node not found,Control 会跳过 drain(nomadDrainSkipped: nomad_node_not_found)并继续删除 Luma 注册记录。网络错误、鉴权失败或 Nomad 不可用仍会让删除失败。适用于已本地退出的旧节点、失败加入或退役工作/家庭机器。Manager/Nomad server 受保护,不能用此命令删除。

Nomad 身份是稳定 UUID,同名退出并重新加入的机器保留 meta.luma_node_name,固定服务无需刷新 NodeID。清单保持按 Luma 节点名固定,不要换成 Docker 主机名。

排空节点#

nomad node drain -enable <node-id>

恢复调度:

nomad node drain -disable <node-id>

刷新出网#

export EGRESS_SUBSCRIPTION_URL='...'
luma egress refresh

在目标节点验证镜像拉取:

sudo docker pull hello-world:latest

修复控制面#

luma bootstrap manager --domain luma.example.com
luma doctor

所需网络端口#

Linux 初始化/加入时会配置 UFW,云安全组或 Tailscale ACL 应允许相同访问:

端口 通信方向 用途
80/tcp 公网客户端 → 边缘 Manager HTTP 跳转及 Let's Encrypt 验证。
443/tcp 公网客户端 → 边缘 Manager Control 和公共服务 HTTPS。
tcp-relay 发布端口 公网客户端 → 边缘 Manager 如 MySQL 3306/tcp。Luma 从 Control 状态恢复 Traefik 监听器,云防火墙/安全组须放行同端口。
4646/tcp 客户端/Traefik → Nomad server HTTP API:部署、状态、服务发现。
4647/tcp Nomad client → server RPC。
4648/tcp4648/udp Nomad agent 之间 Serf gossip/server 成员通信。

Nomad agent 绑定 0.0.0.0 并广播 Tailscale 地址。UFW 仅在 tailscale0 放行 4646/4647/4648;公网隔离依赖防火墙,不依赖广播地址。无 UFW 主机应配置等价主机防火墙与云安全组,并验证公网接口无法访问这些端口。

Tailscale 中继#

tailscale-relay 按服务显式选择,适合需要公网域名的家庭工具、预览或低频内部面板。

它不是常规公共流量的默认路径。

安装路径变化后节点 agent 失败#

Nomad 节点可能仍 ready,但 Luma agent 离线。安装缺失 Python 包前,检查服务实际 ExecStart、启动器及其 Python 环境。主机可能同时有正常 /opt/luma-cli 和不完整用户本地安装。

安装程序在发布 shim 或刷新服务前验证目标环境:依赖导入、CLI/agent 命令加载和 pip check 必须通过。包安装失败只有通过这些检查才可使用源码回退。Shim 通过已验证 Python 的 -m luma.cli 启动,不复用 shebang 可能指向其他环境的旧脚本。验证失败非零退出,不显示成功、不替换 shim,也不刷新/重启服务。

该发布门禁不会事务性回滚目标目录内已发生的源码或包变化。受影响主机应先恢复到验证正常的环境,再检查 systemd 重启次数与新鲜 Control 心跳;进程存在不代表已重新连接。