语法
选项
--box 和 --ip 必须提供其中之一。如果两个都提供,命令会报错退出。
Box 镜像
安装过程中最慢的部分是 Box 的 Docker 镜像。在 Box 上从零构建大约需要 14 分钟。 有预构建镜像可用时,部署会先拉取它,再停止正在运行的容器。下载期间,Box 的服务保持运行。只有在拉取成功之后,旧容器才会停止。随后部署会清理 Docker 构建缓存,因为拉取的镜像不需要构建。 部署在 Box 上构建时,会保留构建缓存。之后在同一台 Box 上的构建会复用没有变化的层。lager uninstall 会清理该缓存。
每个发布标签都会发布一个预构建镜像,lager install 默认使用它:大约 2 分钟,而不是 14 分钟。
这只适用于版本为发布标签的情况。不指定 --version 时,install 部署与 CLI 相匹配的发布标签(例如 lager 0.52.0 对应 v0.52.0),因此默认安装会使用该镜像。--version main
没有已发布的镜像,其他分支也没有,因此它们总是在 Box 上构建。发布标签就是两分钟安装和十四分钟安装之间的区别。
完整的 40 位提交 SHA 同样会在 Box 上构建,并且 Box 必须能从远端拉取该提交。较短的十六进制值会被当作分支名。
镜像在使用之前会先被验证:
- 运行
lager install的计算机把标签解析为不可变的镜像摘要。这一步需要curl并且能访问ghcr.io。 - Box 按它自己的架构拉取该摘要对应的镜像。
- Box 检查镜像的版本标签,该标签必须与您请求的版本完全一致。
curl、注册表不可达,或标签缺失/不一致。能用的慢速安装胜过不能用的快速安装。
拉取之后,/etc/lager/image-source 会记录 ghcr:<digest>。在 Box 上构建则会删除该文件。
镜像把它的许可证声明放在 /usr/share/licenses/lager/ 中。该目录包含 Lager 自身的 LICENSE 和 NOTICE,以及列出镜像中第三方软件的 THIRD_PARTY.md。pip/ 目录保存每个 Python 软件包的声明文件。要列出它们,请在 Box 上运行 docker exec lager ls /usr/share/licenses/lager。
传入 --no-pull 可以跳过预构建镜像,始终进行构建。若要在整个 shell 中关闭安装时的拉取,请把 LAGER_BOX_IMAGE_PULL 设置为 0、false、no 或 off。该变量只有取 1、true 或 yes(不区分大小写)时才打开拉取,其他任何值都会关闭它。--pull 优先于该变量。
lager update 以完全相同的方式解读这些取值,只有默认值不同:install 对发布标签默认使用预构建镜像,而 update 不会。同时传入 --pull 和 --no-pull 属于用法错误。
部署超时
--timeout 限制部署步骤,其中包括容器构建。默认值为 1800 秒。不带该标志时,由 LAGER_INSTALL_TIMEOUT 决定其值。
LAGER_INSTALL_TIMEOUT 无法解析或为负值时,取默认值。
--timeout 0 取消该限制,负的 --timeout 会被拒绝。
预算用尽时,install 会打印 Deployment timed out after ...。它还会说明该构建仍可能是正常的,并打印出把预算加倍的重试命令,然后以 1 退出。重新运行是安全的。
安装锁的有效期取 3600 秒与超时时间两倍之中的较大者。在提供该锁的容器停止期间,锁无法续期。使用 --timeout 0 时,锁不会过期,因为没有任何固定时长能超过一次不限时长的部署。正常结束的安装会释放该锁。如果进程被强制终止(例如断电),锁没有过期时间来清除它,这时用 lager boxes unlock 释放它。
会安装哪些内容
防火墙脚本把入站流量的默认策略设为拒绝,并允许来自任意位置的 SSH。它在
lo、docker0、tailscale0(如果 Tailscale 已启动)和 --corporate-vpn
指定的接口上放行 Lager 端口,并在其他所有接口上拒绝它们。只有在设置了 lager box-config network-mode host 的 Box 上(容器不发布端口),这些规则才管辖 Lager 端口。
该脚本每次运行都会先重置 ufw。因此,之后不带 --skip-firewall 的
lager install 会删除您手动添加的防火墙规则。lager update 不运行该脚本。
安装流程
- 解析目标 - 根据
--box名称查出 Box IP,或直接使用--ip - 验证 SSH - 测试基于密钥的认证,并确定该命令后续使用哪个身份
- 显示摘要 - 显示将要安装的内容并请求确认
- 部署 - 运行部署脚本。使用预构建镜像时约 2 分钟;在普通 Box 硬件上从零构建大约 14 分钟(见上文)。这一步受
--timeout限制,默认 30 分钟 —— 在较慢的硬件上请调高它,那里正常的构建也可能合理地超过默认值 - 保存版本 - 把部署的版本和 CLI 版本写入
/etc/lager/version,把部署的 ref 和提交写入/etc/lager/ref。它还会把构建哈希写入/etc/lager/build-hash,并读回版本文件进行核对。任何一次写入失败时,install 会指出该文件,打印手动修复方法,并以1退出。此时部署本身已经完成 - 检查免密码 sudo - 确认
lager box-config apply所需的 sudoers 授权已经就位。通常部署步骤已经写好了它,这一步就不会再要求输入任何内容。如果授权缺失,这一步会写入它,并要求输入 Box 的 sudo 密码。这里失败只是警告,不算安装失败 - 添加到配置 - 询问是否把该 Box 添加到
~/.lager。使用--yes时以及使用--box时(该 Box 已经保存过)会跳过这一步
示例
免密码 sudo
安装过程会为 Box 的登录用户配置免密码sudo。CLI 通过非交互式 SSH 驱动 Box,那里的 sudo 没有终端可以用来提示输入。这些授权必须在配置流程运行之前就位。
Lager 在 /etc/sudoers.d/ 下写入以下文件,并且只写这些文件:
这三个文件在 Lager 每次写入时都会被完整重新生成 —— 正是这一点让 Box 始终保持当前的授权形态。写在其中内部的额外授权,会在下次写入时丢失,因此每个文件开头都有一段说明这一点的注释。
Lager 从不读取、编辑或删除
/etc/sudoers.d/ 中的任何其他文件。如果您或某个 Box 管理平台需要额外授权,请把它们放在该目录下的单独文件中。例如 /etc/sudoers.d/zz-local 排在 Lager 的文件之后,因此它的规则会生效。
Lager 不会碰那个文件,lager uninstall 期间也不会。
sudo 密码提示
lager install 在部署步骤的早期,用一次 sudo 会话写入它的两个文件。它只在这次会话里要求输入 Box 的 sudo 密码,其他地方都不会:
在这次会话之前,install 会在不分配终端的情况下检查 Box。它把
/etc/lager/.deploy-sudoers-v1 与本次运行将要写入的授权的摘要进行比较,并用 sudo -n 运行一条已授权的命令。两项检查都通过时,install 会跳过这次会话。不同的 --user 或 --corporate-vpn 值会改变授权,更新的 CLI 也可能改变它们。此时 install 会运行一次会话,并要求输入一次密码。
这次会话需要一个终端来要求输入密码。如果 install 在没有终端的情况下运行,而 Box 的 sudo 需要密码,install 会在会话之前停止,并显示这条消息:
sudo 时,不需要终端。
如果想让下一次安装重新写入这些文件,请在 Box 上删除 /etc/lager/.deploy-sudoers-v1。lager update 不使用这个文件,也不要求输入密码。
同一次会话还会安装 /usr/local/lib/lager/etc_lager_perms.sh。这个属主为 root 的脚本会创建 /etc/lager 并设置它的属主。它不会改动 /etc/lager/authorized_keys.d。授权按确切路径指明该脚本,而脚本会拒绝一切参数。Lager 不授权 find 命令,也不授权递归的 chown。
SSH 认证
安装要求使用基于密钥的 SSH 认证。它会显式提供~/.ssh/lager_box ——
即 lager ssh-setup 和 lager install 生成的密钥 —— 因为 ssh 不会自己尝试这个文件名。如果 Box 不接受它,安装会退回到您自己的默认身份,因此用 ssh-copy-id 授权过的 Box 照常可用。
如果两者都无法认证,安装会主动提出为您配置密钥:
--yes 会直接接受而不询问。拒绝则会停止安装,并指引您使用
lager ssh-setup --box <name-or-ip>,它作为单独的一步完成同样的工作。
对于部署本身,安装不提供密码回退。配置了 PasswordAuthentication no 的 Box
永远收不到密码,因此过去那条”密码失败”的提示描述的是根本没有发生过的事。
对于新主机,SSH 主机密钥会被自动接受。如果主机密钥相对上次连接发生了变化,命令会要求您先手动核实这个变化。
安装不会写入 ~/.ssh/config。早期版本会添加一个按 IP 划分、指明密钥的 Host 块。另一个会重新生成该文件的工具删除了那个块,而且那个块还对该 Box 关闭了主机密钥验证。现在改为按命令传入身份。
Box 前面的网关
有些 Box 在 lager 前面有一个网关:它是lagernet Docker 网络上的另一个容器,发布 lager 的主机端口,并把请求转发给 lager 容器。控制平面可以运行这样的网关。
- 当这样的容器已经发布了端口 5000、8080、8765 或 9000 时,lager 容器以
--no-publish模式启动,只能通过网关访问。之后的启动会保持这个模式。 - 在停止任何容器之前,该命令会检查是否有其他容器占用了 lager 要发布的主机端口。如果有,命令会停止并指出该端口和容器,Box 保留当前的 lager 容器。
- 如果
lagernet上仍有容器在运行,但/etc/lager/control_plane.json已不存在,命令会显示警告。在您从控制平面重新关联该 Box 之前,该网关会拒绝所有连接。Lager 无法恢复该文件。
说明
- 逐步操作的指南,请参阅 设置 Lager Box
- 需要本地安装 SSH 客户端工具(
ssh、ssh-keygen) - 部署脚本随
lager-cli包一起分发 - 安装完成后,请用
lager hello --box <name>验证连通性 - 对已安装的 Box 部署代码更新,请使用
lager update - 从 Box 上移除 Lager 软件,请使用
lager uninstall

