LXC 容器中的 SSH 运维技巧

posts/ssh-tips-for-lxc

上一篇 LXC 搭建 K8s 集群计划通 中部署了一组 LXC 容器,后续的容器管理、服务访问和文件操作都大量使用了 SSH。本文整理一些 LXC 场景下常用的 SSH 技巧。

SSH 连接管理

ProxyJump 跳板配置

LXC 容器默认走 lxcbr0 的 NAT 网络,从外部无法直接 SSH 进入。可将宿主机作为跳板机,借助 ProxyJump 一次连通,配置写入 ~/.ssh/config

Host lan.arch-lxc-1
        Hostname <ip>
        User root
        ServerAliveInterval 10
        IdentityFile ~/.ssh/personal/id_ed25519
        IdentitiesOnly yes
        ProxyJump lan.arch

Host lan.arch
        HostName <ip>
        ServerAliveInterval 10
        IdentityFile ~/.ssh/personal/id_ed25519
        IdentitiesOnly yes

执行 ssh lan.arch-lxc-1 时,SSH 会先连接宿主机,再由宿主机跳转至对应容器。容器数量较多时,可按 lan.arch-lxc-N 依次添加配置。

ssh -J 一次性跳板

若不想写入 config,可直接用 -J 在命令行指定跳板机:

ssh -J lan.arch lan.arch-lxc-1

效果等同于 ProxyJump,适合临时性场景。

复用 SSH 连接

在跳板机跳转的场景下,每次执行命令都需要重新进行 SSH 握手,会带来明显的延迟。可以通过 ControlMaster 实现 SSH 连接复用:

mkdir ~/.ssh/sockets/
Host lan.arch lan.arch-lxc-*
        ControlMaster auto
        ControlPath ~/.ssh/sockets/%C
        ControlPersist 10m

%C 是 OpenSSH 根据连接参数计算出的哈希值,可以避免 ControlPath 过长。相比 %r@%h:%p 这类可读形式,使用 %C 更适合作为 Unix socket 路径。

首次执行 ssh lan.arch-lxc-1 建立主连接后,在十分钟内再次连接同一目标时,SSH 会复用已有 socket,从而跳过重复的 SSH 握手过程。

如果跳板机发生重启,已有的 master connection 会因远端连接中断而失效,本地 control socket 可能暂时残留。再次连接时,SSH 会检测到已有 master connection 不可用,并重新建立新的主连接,通常无需手动删除 socket 文件。

如果 control socket 异常残留导致连接失败,可以使用 ssh -O exit 关闭 master connection,或手动删除对应 socket。

身份认证

首次推送公钥

使用密钥认证前,需要先用 ssh-copy-id 把本机公钥推送到跳板机与容器:

ssh-copy-id -i ~/.ssh/personal/id_ed25519.pub [email protected]

后续 SSH 即可全程走密钥认证,免去每次手动输入密码。

转发 SSH Agent

跳板机或容器内需要操作 git 仓库时,可将本机的 ssh-agent 透传过去,避免在每台机器上都部署私钥:

Host lan.arch-lxc-*
        ForwardAgent yes

配置后,远程主机会创建一个 SSH 转发的 Unix socket($SSH_AUTH_SOCK 通常指向 /tmp/ssh-XXX/agent.XXX),签名请求代理回本机 ssh-agent,git push/pull 等操作将走本机鉴权。需要注意的是 ForwardAgent 仅透传 agent 连接,本机 agent 内还需先加载密钥才能生效:

ssh-add ~/.ssh/personal/id_ed25519
ssh-add -l

另外 ForwardAgent 会让目标主机上的特权用户获得本机 agent 中已加载身份的使用权(虽然拿不到私钥本身,但能以这些身份登录其他机器),公网环境慎用。

文件系统访问

guest 挂载 host

容器里挂宿主机的目录:

sshfs lan.arch:/path/on/host /mnt/host

host 挂载 guest

宿主机也可挂载容器内的目录(例如调试容器内某个服务的配置文件):

sshfs lan.arch-lxc-1:/path/in/container /mnt/guest

guest 挂载 guest

一个容器挂另一个容器:

sshfs lan.arch-lxc-2:/path/in/container /mnt/other

上面三条默认以 root 身份执行,非 root 用户挂载需要加 -o allow_other,并确保 fuse 配了 user_allow_other

网络穿透

容器里的服务默认只能从宿主机内部访问。相比 nftables 配 DNAT,用 SSH 端口转发更轻量。

Local Forward

从本地访问容器里的服务(本地浏览器打开容器内起的 dashboard):

ssh -L 8080:127.0.0.1:8080 lan.arch-lxc-1

如果想让 LAN 里其他机器一起访问,把本地地址改成 0.0.0.0

ssh -L 0.0.0.0:8080:127.0.0.1:8080 lan.arch-lxc-1

Remote Forward

反过来,让宿主机或 LAN 里其他机器访问容器内服务(典型场景:在容器里跑 dashboard,希望宿主机 http://lan.arch:8000 能访问到):

ssh -R 0.0.0.0:8000:127.0.0.1:8000 lan.arch

这条命令要在容器内执行。SSH 会在 lan.arch(宿主机)的 8000 端口监听,远端请求沿 SSH 通道回到容器里的 127.0.0.1:8000-R 方向和 -L 相反:客户端起连接,宿主机的端口负责监听。