跳转至

如何访问vm

如何访问虚拟机

在管理虚拟机时,能够访问虚拟机控制台至关重要。KubeVirt 提供了两种主要方式来访问虚拟机的控制台:串行控制台(Serial Console)和图形化(VNC)。

串行控制台和图形化访问虚拟机

使用串行控制台和图形化访问虚拟时,均需要先安装virtctl命令,从github上 kubevirt 仓库下载对应版本即可。

  • 串行控制台访问虚拟机

    通过串行控制台访问虚拟机非常简单,只需要使用virtctl console命令即可。

    virtctl console cirros-vm01
    

  • 图形化访问虚拟机

    通过图形化窗口访问虚拟机,需要先安装virt-viewer命令。

    virtctl vnc cirros-vm01
    
    注意 在执行上述命令时,需要能打开图形窗口,如果服务器端没有桌面,又或者是用secureCRT等工具远程连接,则还需借助Xmanager工具的Passive,将图形窗口映射到本地电脑上。
    ## 1. 在本地电脑上先打开Xmanager的Passive组件
    
    ## 2. 在secureCRT的服务器终端执行export命令,将DISPLAY变量设置为本地电脑的IP地址
    export DISPLAY=192.168.59.1:0.0
    
    ## 3. 最后执行 virtctl vnc命令
    virtctl vnc cirros-vm01
    
    如果连接失败,可尝试加上 -v参数,打印出详细日志
    virtctl vnc cirros-vm01 -v 4
    

如果仅希望开启VNC代理,然后在本地用VNC客户端访问,则可以使用如下命令

virtctl vnc --proxy-only --address 0.0.0.0 --port 5009 cirros-vm01
这样将仅打印出VNC的端口号5009,我们可以根据这个端口手动使用任何兼容 VNC 的客户端工具连接到虚拟机的图形界面。

SSH访问虚拟机

在管理虚拟机时,将SSH公钥注入到虚拟机是一种常见的操作方式。一旦 SSH 公钥成功注入到虚拟机中,我们就可以使用对应的私钥通过 SSH 协议登录并访问虚拟机进行管理和维护操作。

KubeVirt 提供了两种方式来注入 SSH 公钥:静态公钥注入和动态公钥注入。

  • 静态公钥注入:指的是在虚拟机首次启动时通过cloud-init将公钥写入到虚拟机内部。

    在创建虚拟机时,用户可以使用启动脚本来对虚拟机进行多种定制化操作。将SSH公钥注入到虚拟机的一种方法是通过cloud-init,当然还有其他更安全、灵活的方案。 例如,将SSH公钥放到k8s的Secret对象中,这样可以确保应用程序数据(脚本命令)和用于访问虚拟机的凭据数据(秘钥)相互分离。那是如何做到的呢?

虚拟机的访问凭证API提供了一种机制,在虚拟机初始化阶段是不依赖cloud-init用户数据来预配置SSH公钥。这意味着,即使在没有或者不修改cloud-init用户数据的情况下,也可以向虚拟机中注入SSH公钥。 通过将SSH公钥放入k8s的secret对象,这是一种安全存储敏感信息的方式。k8s 的secret对象就是用来保存诸如密码、token 或者 SSH 公钥等敏感数据的。

简而言之,我们通过创建k8 secret来存储SSH公钥,通过 configDrive|noCloud 机制将元数据注入到虚拟机中,而无需将公钥直接写入cloud-init用户数据。

说明: configDrive 用于向虚拟机或裸金属服务器传递元数据和用户数据。它通常表现为一个物理磁盘设备或 ISO 映像,包含启动时配置虚拟机所需的各种信息,如网络配置、SSH 密钥等。 当使用 KubeVirt 并指定了 ConfigDrivePropagation 方法时,意味着公钥不会直接写入虚拟机的文件系统或其他常规启动脚本中,而是以元数据的形式被放在 configDrive 中。 这样,虚拟机在启动过程中会通过 cloud-init 解析 configDrive 中的元数据,并将 SSH 公钥设置为允许登录系统的有效密钥,从而实现对虚拟机的安全访问。

示例1,cloud-init方式注入公钥

cat << END > image-centos.yaml
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: img-centos7
  namespace: default
spec:
  source:
    http:
      url: http://192.168.59.241:10800/images/CentOS-7-x86_64-GenericCloud.qcow2
  pvc:
    storageClassName: "ceph-hdd-block"
    accessModes:
      - ReadWriteMany
    resources:
      requests:
        storage: 10Gi
    volumeMode: Block
END

cat << END > startup-script
#cloud-config
hostname: vm-centos01
ssh_pwauth: True
disable_root: False
timezone: Asia/Shanghai
password: 123456
chpasswd: {"list":"root:123456",expire: False}
runcmd:
  - setenforce 0
  - sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config
  - sed -i "/PermitRootLogin/s/^.*$/PermitRootLogin yes/g" /etc/ssh/sshd_config
  - systemctl restart sshd.service
  #- echo root:12345678 |chpasswd
ssh_authorized_keys:
    - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCz4gfQJ0xW235NjltRUFFFw6AtE5ZDVT7EuEJX7sc/QCICTWdYd+5MG9cDr3hzzi0OS9eiVVNB7JGa57kb/Um1KZCFy/DmNHJXE9TAhTZUf8kgzVr/tHGXrm845adu6Guij1QludChqx0iBAB+X9M3Oh0AD854Mwigi5dxV7uNb8/YWTE8eXOkcV4c7RJsFq2N/ValbtzXMUcgr1ySHmb9ZBncJWK56kZ4OkmoiKrmnJsWHs7Nte/ooBXXfRiLcik7S2G/tgJLL34DGLMedBZ7wzX5tXiYoTcCSpXmGmFAFxoaCwtl3sptdO9tmIZ0f2jtTTYeZ/QEvUiUCw9riCljvIygBht4d9EfFwEhr4pDxs0Rr7Pcq2jBXocqg3ue8AUCySvxNW5WqkAPxKi1sZNrGivadwARxhJ5jkqX91hfcuIFzE3nOrryfrXZ5XEvJZrk7y3a6S+Eo0OfI/Iz1RgPBQr0/iggZlvXgteyjzggviF4g+bmVmi7kGMXZRPiH/8= root@k8s01
END

# Create the VM spec
cat << END > vm-centos01.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-centos01-bootdisk
  namespace: default
spec:
  storageClassName: "ceph-hdd-block"
  volumeMode: Block
  accessModes:
    - ReadWriteMany
  dataSource:
    kind: PersistentVolumeClaim
    name: img-centos7
  resources:
    requests:
      storage: 10Gi
---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: vm-centos01
  namespace: default
spec:
  running: true
  template:
    metadata:
      labels:
        kubevirt.io/size: small
        kubevirt.io/domain: vm-centos01
      #annotations:
      #  ovn.kubernetes.io/ip_address: 12.244.10.203
    spec:
      domain:
        cpu:
          cores: 1
          model: host-passthrough
        memory:
          guest: 2Gi
        devices:
          disks:
            - name: root-disk
              disk:
                bus: virtio
            - name: cloudinitdisk
              disk:
                bus: virtio
          interfaces:
            - name: default
              masquerade: {}
        resources:
          requests:
            memory: 2048M
      networks:
        - name: default
          pod: {}
      volumes:
        - name: root-disk
          persistentVolumeClaim:
            claimName: pvc-centos01-bootdisk
        - name: cloudinitdisk
          cloudInitNoCloud:
            userDataBase64: $(cat startup-script | base64 -w0)
END

## 注意每次修改 startup-script 要 重新生成 vm-centos01.yaml文件,否则 userDataBase64 不会更新

# kubectl apply -f vm-centos01.yaml
# kubectl get vmi
NAME          AGE     PHASE     IP            NODENAME   READY
vm-centos01   107s    Running   12.244.0.42   k8s03      True

## 通过私钥访问虚拟机,注意用的是与公钥对应的私钥
ssh -i /root/.ssh/id_rsa centos@12.244.0.42

示例2,使用k8s的secret来存放SSH公钥,并将公钥与虚拟机关联起来

kubectl create secret generic my-pub-key --from-file=key1=/root/.ssh/id_rsa.pub

cat << END > vm-centos02.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-centos02-bootdisk
  namespace: default
spec:
  storageClassName: "ceph-hdd-block"
  volumeMode: Block
  accessModes:
    - ReadWriteMany
  dataSource:
    kind: PersistentVolumeClaim
    name: img-centos7
  resources:
    requests:
      storage: 10Gi
---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: vm-centos02
spec:
  running: true
  template:
    spec:
      domain:
        cpu:
          cores: 1
          model: host-passthrough
        memory:
          guest: 2Gi
        devices:
          disks:
          - disk:
              bus: virtio
            name: root-disk
          - disk:
              bus: virtio
            name: cloudinitdisk
          rng: {}
          interfaces:
            - name: default
              masquerade: {}
        resources:
          requests:
            memory: 2048M
      networks:
        - name: default
          pod: {}
      terminationGracePeriodSeconds: 0
      accessCredentials:
      - sshPublicKey:
          source:
            secret:
              secretName: my-pub-key
          propagationMethod:
            configDrive: {}
      volumes:
      - name: root-disk
        persistentVolumeClaim:
          claimName: pvc-centos02-bootdisk
      - name: cloudinitdisk
        cloudInitConfigDrive:
          userData: |-
            #cloud-config
            hostname: vm-centos02
            ssh_pwauth: True
            disable_root: False
            timezone: Asia/Shanghai
            password: 123456
            chpasswd: {"list":"root:12345678",expire: False}
            runcmd:
              - setenforce 0
              - sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config
              - sed -i "/PermitRootLogin/s/^.*$/PermitRootLogin yes/g" /etc/ssh/sshd_config
              - systemctl restart sshd.service
              #- echo root:12345678 |chpasswd
END

  • 动态公钥注入:指的是在虚拟机启动时或者在虚拟机运行时(通过qemu-guest-agent)注入公钥。

注意,动态公钥注入的前置条件是镜像中已经安装好了合适版本的Qemu-guest-agent、并且关闭了Selinux,否则会出现注入不成功的情况,比如用centos7的镜像就不行,qemu-guest-agent版本太低。

## 此处使用fedora镜像验证,因为centos7镜像中Qemu-guest-agent版本太低,运行时会报"The command guest-ssh-add-authorized-keys has not been found')"  
kubectl create secret generic my-pub-key2 --from-file=key1=/root/.ssh/id_rsa.pub
cat << END > vm-fedora01.yaml
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: vm-fedora01
spec:
  running: true
  template:
    spec:
      domain:
        cpu:
          cores: 1
          model: host-passthrough
        memory:
          guest: 2Gi
        devices:
          disks:
          - disk:
              bus: virtio
            name: root-disk
          - disk:
              bus: virtio
            name: cloudinitdisk
          rng: {}
          interfaces:
            - name: default
              masquerade: {}
        resources:
          requests:
            memory: 2048M
      networks:
        - name: default
          pod: {}
      terminationGracePeriodSeconds: 0
      accessCredentials:
      - sshPublicKey:
          source:
            secret:
              secretName: my-pub-key2
          propagationMethod:
            qemuGuestAgent:
              users:
              - fedora
      volumes:
      - name: root-disk
        containerDisk:
          image: registry.demo.com/containerdisks/fedora:latest
      - name: cloudinitdisk
        cloudInitConfigDrive:
          userData: |-
            #cloud-config
            hostname: vm-fedora01
            ssh_pwauth: True
            disable_root: False
            timezone: Asia/Shanghai
            password: 123456
            chpasswd: {"list":"root:12345678",expire: False}
            bootcmd:
              - setenforce 0
              - sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config
            runcmd:
              - sed -i "/PermitRootLogin/s/^.*$/PermitRootLogin yes/g" /etc/ssh/sshd_config
              - systemctl restart sshd.service
              #- echo root:12345678 |chpasswd
END

centos7 (使用镜像:CentOS-7-x86_64-GenericCloud.qcow2,qemu-guest-agent版本是2.12)公钥注入不成功,可能会遇到如下错误,原因是qemu-guest-agent版本太低,无法识别guest-ssh-add-authorized-keys命令。

{"component":"virt-launcher","kind":"","level":"error","msg":"Error encountered writing access credentials using guest agent","name":"vm-centos03","namespace":"default","pos":"access_credentials.go:491","reason":"virError(Code=1, Domain=10, Message='internal error: unable to execute QEMU agent command 'guest-ssh-add-authorized-keys': The command guest-ssh-add-authorized-keys has not been found')","timestamp":"2024-02-12T08:16:28.739875Z","uid":"223a2a48-411e-407d-a204-dccab7b49241"}

## 基于ubuntu重新掉作镜像,size不要设置太大,安装好qemu-guest-agent,关闭前需要删除 /var/lib/cloud/instance/boot-finished
cat << END > image-ubuntu2204.yaml
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
  name: img-ubuntu2204
  namespace: default
spec:
  source:
    http:
      url: http://192.168.59.241:10800/images/ubuntu-22.04-server-cloudimg-amd64.img
  pvc:
    storageClassName: "ceph-hdd-block"
    accessModes:
      - ReadWriteMany
    resources:
      requests:
        storage: 5Gi
    volumeMode: Block
END

cat << END > vm-ubuntu.yaml
---
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: vm-ubuntu
spec:
  running: true
  template:
    spec:
      domain:
        cpu:
          cores: 1
          model: host-passthrough
        memory:
          guest: 2Gi
        devices:
          disks:
          - disk:
              bus: virtio
            name: root-disk
          - disk:
              bus: virtio
            name: cloudinitdisk
          rng: {}
          interfaces:
            - name: default
              masquerade: {}
        resources:
          requests:
            memory: 2048M
      networks:
        - name: default
          pod: {}
      terminationGracePeriodSeconds: 0
      volumes:
      - name: root-disk
        persistentVolumeClaim:
          claimName: img-ubuntu2204
      - name: cloudinitdisk
        cloudInitConfigDrive:
          userData: |-
            #cloud-config
            hostname: vm-ubuntu
            ssh_pwauth: True
            disable_root: False
            timezone: Asia/Shanghai
            password: 123456
            chpasswd: {"list":"root:12345678",expire: False}
            bootcmd:
              - setenforce 0
              - sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config
            runcmd:
              - sed -i "/PermitRootLogin/s/^.*$/PermitRootLogin yes/g" /etc/ssh/sshd_config
              - systemctl restart sshd.service
              #- echo root:12345678 |chpasswd
END

## 进入vm-ubuntu虚拟机中,执行如下命令
apt-get update
apt-get install qemu-guest-agent -y 

## 删除 cloud-init 执行完成的标记文件
rm -rf /var/lib/cloud/instance/boot-finished
接下来,用上面的img-ubuntu2204镜像就可以使用ssh秘钥登录了