AIGC标识 kubectl 进入 virt-launcher pod 之后如何进入虚拟机内部

结论

kubectl exec 进入 virt-launcher pod ≠ 进入虚拟机内部。 virt-launcher pod 只是承载 QEMU 进程的容器,guest 系统运行在 QEMU 进程内部,既不是容器进程,也不在容器的命名空间里,无法用 nsenter/chroot 进入。

进入虚拟机内部的几种方式:

方式 命令 说明
串行控制台 virtctl console <vm> 文本终端,Linux 排障最常用,官方推荐
SSH virtctl ssh <user>@<vm> 需在创建 VM 时注入 SSH 公钥
图形桌面 virtctl vnc <vm> 需本机装 virt-viewer / VNC 客户端
Pod 内应急 pod 内执行 sock-connector 连接串口 socket 等价于 virtctl console,仅 virtctl 不可用时使用

核心原理:virtctl console 的底层实现,就是 virt-handler 通过 Kubernetes API 在 compute 容器内执行一个名为 sock-connector 的辅助程序,让它连接 QEMU 暴露的串口 unix socket(/var/run/kubevirt-private/<vmi-dir>/virt-serial0)。所以只要在 pod 里找到这个 socket,手动执行同样的连接,就能进入虚拟机内部。

分析版本

  • 软件:KubeVirt(virtctl / virt-api / virt-handler / virt-launcher)
  • 版本:v1.x(以 v1.3+ 及同源的 OpenShift Virtualization 4.x 为准;串口 socket 机制与 sock-connector 自早期版本沿用至今)
  • 关键路径:/var/run/kubevirt-private/<vmi-dir>/virt-serial0(串口)、virt-vnc(图形)、virtqemusock(QMP)
  • 关键二进制:/usr/share/kubevirt/virt-launcher/sock-connector(compute 容器内自带)

详细分析

1. 为什么 kubectl exec 进 pod 不等于进入虚拟机

virt-launcher pod 内通常有多个容器,核心是 compute 容器,里面运行:

  • virt-launcher 进程:管理 libvirtd 和 QEMU 的生命周期,对外提供 gRPC 服务供 virt-handler 调用;
  • libvirtd:根据 VMI 定义生成 domain XML;
  • qemu-system-*:真正的虚拟机进程,guest 操作系统运行在 QEMU 内部。

guest 内的进程对容器来说不可见,guest 的文件系统、内核都不在容器的挂载/进程命名空间中,因此 kubectl exec -it <pod> -c compute -- bash 只能拿到 QEMU 所在容器的 shell,拿不到虚拟机内部。

2. virtctl console 的底层原理(调用链)

virtctl console 表面是一条命令,实际是一条完整链路:

virtctl(客户端)
  → virt-api(控制面,WebSocket 代理)
  → virt-handler(节点 DaemonSet)
  → 经 Kubernetes API exec 进入 virt-launcher pod 的 compute 容器,执行 sock-connector
  → sock-connector 连接 unix socket virt-serial0
  → QEMU 串口 → guest 的 ttyS0

也就是说,virtctl 本身并没有"直连虚拟机"的魔法,它在 pod 里干的事和我们手动做的一模一样:连 pod 内的串口 socket。知道这一点后,在 pod 内手动进入 guest 就顺理成章了。

kubevirt-进入虚拟机内部-调用链

3. 方法一:在 pod 内直连串口 socket(等价 virtctl console)

# 1. 进入 compute 容器(注意指定 -c compute)
kubectl exec -it virt-launcher-<vm>-xxxxx -c compute -- bash

# 2. 查看 VMI 的 socket 目录(目录名可能是 VMI UID 或 namespace-name,以实际为准)
ls -la /var/run/kubevirt-private/*/

# 3. 连接串口 socket,直接进入 guest 控制台
/usr/share/kubevirt/virt-launcher/sock-connector \
  /var/run/kubevirt-private/<vmi-dir>/virt-serial0

连接成功后会直接看到 guest 的 login: 提示,输入账号密码即可进入虚拟机内部。

  • 断开方式:在 guest 里 logout / exit,或另开一个终端杀掉 sock-connector 进程。注意 Ctrl+] 是 virtctl 客户端本地处理的转义键,在 pod 里裸连 socket 时不受支持。
  • 容器里没有 sock-connector 怎么办:可改用 socat(如果容器内有):
    socat - UNIX-CONNECT:/var/run/kubevirt-private/<vmi-dir>/virt-serial0
    
  • 两个工具都没有:可在 pod 外执行同一条转发命令(效果等同免装 virtctl):
    kubectl exec -i <pod> -c compute -- \
      /usr/share/kubevirt/virt-launcher/sock-connector \
      /var/run/kubevirt-private/<vmi-dir>/virt-serial0
    

4. 方法二:virsh + QEMU monitor 控制 guest(排障用)

compute 容器自带 virsh(libvirt 客户端),域名为 default_<vm-name>,可以对 guest 发按键、查状态、看事件,适合排障:

# 确认域名
virsh list

# 模拟按键(如向 guest 发送 Ctrl+Alt+Del)
virsh qemu-monitor-command default_<vm-name> --hmp "sendkey ctrl-alt-del"

# 查询运行状态
virsh qemu-monitor-command default_<vm-name> query-status --pretty

# 持续观察 QEMU 事件(另开终端配合 virtctl pause/unpause 观察)
virsh qemu-monitor-event --pretty --loop

注意:virsh 的 console 命令在 KubeVirt 里通常不可用,因为 KubeVirt 把串口配置成了 unix socket(而非 libvirt 分配的 pty),virsh console 会失败或连错对象;串口请走方法一。

5. 方法三:转发 VNC socket 获取图形界面

pod 内同样暴露了 VNC socket(<vmi-dir>/virt-vnc)。用 socat 把它转发到本机,再用 VNC 客户端连接即可看到图形桌面:

# 在能访问集群的机器上执行,把 pod 内的 VNC socket 转发到本机 5901
kubectl exec -i <pod> -c compute -- \
  socat TCP-LISTEN:5901,reuseaddr,fork \
  UNIX-CONNECT:/var/run/kubevirt-private/<vmi-dir>/virt-vnc

然后本机用 VNC 客户端连接 127.0.0.1:5901(需确保网络可达,或结合端口转发)。

6. 方法四:正规做法——退出 pod 用 virtctl

除非 virtctl 完全不可用(离线、网络隔离、只允许在节点上操作)的极端场景,否则正规做法还是退出 pod,直接用 virtctl:

virtctl console <vm>    # 文本控制台,Ctrl+] 退出
virtctl ssh <user>@<vm> # SSH 登录(需预置公钥)
virtctl vnc <vm>        # 图形桌面(需 virt-viewer)

pod 内连 socket 本质是"曲线救国",只适合应急排障。

7. 常见问题

7.1 virtctl console 是 VNC 登录吗?

不是。两者完全不同:

命令 类型 看到什么 底层通道
virtctl console <vm> 串行控制台 纯文本终端(login: 命令行),无图形界面 pod 内的 virt-serial0 socket
virtctl vnc <vm> 图形控制台 虚拟机桌面(GUI),类似远程桌面 pod 内的 virt-vnc socket
virtctl ssh <vm> SSH 登录 命令行(网络 SSH 协议) 走虚拟机网络

virtctl console 相当于把一根"串口线"接到虚拟机上(ttyS0),Linux 虚拟机排障最常用,Windows 虚拟机基本无法使用(没有串口登录)。virtctl vnc 才相当于"看显示器",是图形界面,Windows/Linux 桌面都能用。

7.2 socket 目录名是 VMI UID 还是 name?

新旧版本有差异:早期版本 /var/run/kubevirt-private/<vmi-UID>/,较新版本可能为 <namespace>-<name> 或 <namespace>/<name>。不要背路径,先 ls /var/run/kubevirt-private/*/ 看实际目录,再找其中的 virt-serial0。

7.3 容器里没有 sock-connector / socat 怎么办?

  • 先确认是否在 compute 容器内(kubectl exec ... -c compute);
  • 用 ls /usr/share/kubevirt/virt-launcher/ 确认 sock-connector 是否存在;
  • 都没有时,可用 kubectl debug 起一个带 socat 的临时容器共享 pod 环境,或在 pod 外经 kubectl exec 转发(见方法一)。

7.4 进入后提示 login 但不知道密码?

KubeVirt 不保存虚拟机内部密码。创建 VM 时需要通过 cloud-init 的 userData 注入账号密码,或通过 accessCredentials(sshPublicKey)注入 SSH 公钥;没有注入过凭据,控制台会停在 login: 让你输入一个不存在的账号。

参考链接

posted on 2026-09-20 08:52  王景迁  阅读(12)  评论(0)    收藏  举报

导航