Skip to main content
把 Lager Box 软件、Docker 容器和配套工具部署到新的或已有的 Box 上。

语法

选项

--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 必须能从远端拉取该提交。较短的十六进制值会被当作分支名。 镜像在使用之前会先被验证:
  1. 运行 lager install 的计算机把标签解析为不可变的镜像摘要。这一步需要 curl 并且能访问 ghcr.io。
  2. Box 按它自己的架构拉取该摘要对应的镜像。
  3. 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 释放它。

会安装哪些内容

主机防火墙不保护已发布的端口。 Docker 把它的转发规则装在主机链之前。因此,无论 ufw status 报告什么,一个已发布的端口都会响应任何能路由到该 Box 的人。请把 Box 放在 VPN 上或隔离的局域网中。请参阅 SECURITY.md 的 Security Model 部分。
防火墙脚本把入站流量的默认策略设为拒绝,并允许来自任意位置的 SSH。它在 lo、docker0、tailscale0(如果 Tailscale 已启动)和 --corporate-vpn 指定的接口上放行 Lager 端口,并在其他所有接口上拒绝它们。只有在设置了 lager box-config network-mode host 的 Box 上(容器不发布端口),这些规则才管辖 Lager 端口。 该脚本每次运行都会先重置 ufw。因此,之后不带 --skip-firewall 的 lager install 会删除您手动添加的防火墙规则。lager update 不运行该脚本。

安装流程

  1. 解析目标 - 根据 --box 名称查出 Box IP,或直接使用 --ip
  2. 验证 SSH - 测试基于密钥的认证,并确定该命令后续使用哪个身份
  3. 显示摘要 - 显示将要安装的内容并请求确认
  4. 部署 - 运行部署脚本。使用预构建镜像时约 2 分钟;在普通 Box 硬件上从零构建大约 14 分钟(见上文)。这一步受 --timeout 限制,默认 30 分钟 —— 在较慢的硬件上请调高它,那里正常的构建也可能合理地超过默认值
  5. 保存版本 - 把部署的版本和 CLI 版本写入 /etc/lager/version,把部署的 ref 和提交写入 /etc/lager/ref。它还会把构建哈希写入 /etc/lager/build-hash,并读回版本文件进行核对。任何一次写入失败时,install 会指出该文件,打印手动修复方法,并以 1 退出。此时部署本身已经完成
  6. 检查免密码 sudo - 确认 lager box-config apply 所需的 sudoers 授权已经就位。通常部署步骤已经写好了它,这一步就不会再要求输入任何内容。如果授权缺失,这一步会写入它,并要求输入 Box 的 sudo 密码。这里失败只是警告,不算安装失败
  7. 添加到配置 - 询问是否把该 Box 添加到 ~/.lager。使用 --yes 时以及使用 --box 时(该 Box 已经保存过)会跳过这一步

示例

免密码 sudo

安装过程会为 Box 的登录用户配置免密码 sudo。CLI 通过非交互式 SSH 驱动 Box,那里的 sudo 没有终端可以用来提示输入。这些授权必须在配置流程运行之前就位。 Lager 在 /etc/sudoers.d/ 下写入以下文件,并且只写这些文件:
Box 的登录用户在设计上等同于 root。 配置 Box 需要 root 权限。部署 udev 规则在构造上就是以 root 运行命令,而 apt-get 会通过它自己的配置以 root 执行任意命令。Lager 把上面的授权写成具体的命令,以缩小影响面并保持文件可读,但它们不是权限边界。任何能以 Box 用户身份登录的人,都可以在该 Box 上取得 root。在决定谁持有它的 SSH 密钥时,请把 Box 登录账户视为等同于 root,并建议在专用计算机上使用专用用户。
这三个文件在 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 会在会话之前停止,并显示这条消息:
install 跳过这次会话时,或者 Box 登录用户拥有免密码的 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 照常可用。 如果两者都无法认证,安装会主动提出为您配置密钥:
接受之后会提示输入一次 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