订阅内容

OpenShift 虚拟化为非容器化应用提供了出色的解决方案,但相较于传统虚拟化产品和裸机系统,它确实带来了一些挑战。其中一项挑战涉及与虚拟机(VM)的交互。OpenShift 主要面向容器化应用,这些应用通常不需要传入连接来配置和管理,至少不需要与虚拟机相同类型的连接来进行管理或使用。

本博客讨论了访问在 OpenShift 虚拟化环境中运行的虚拟机的几种方法。以下是这些方法的简要总结。

  • OpenShift 用户界面(UI)

    通过 UI 进行的 VNC 连接允许用户直接访问虚拟机的控制台,这一功能由 OpenShift 虚拟化提供。使用红帽提供的镜像时,通过 UI 进行的串行连接不需要任何配置。这些连接方法对于排查虚拟机的问题非常有用。

  • virtctl 命令

     virtctl 命令使用 websocket 来连接虚拟机。它提供对虚拟机的 VNC 控制台、串行控制台和 SSH 访问。VNC 控制台访问和串行控制台访问由 OpenShift 虚拟化提供,与 UI 中一样。VNC 控制台访问需要在运行 virtctl 命令的客户端上安装 VNC 客户端。串行控制台访问需要与通过 UI 进行的串行控制台访问相同的虚拟机配置。SSH 访问则需要在虚拟机的操作系统中进行配置,以便允许 SSH 访问。有关 SSH 要求,请参见虚拟机镜像的文档。

  • 容器集网络

    使用服务公开端口可将网络连接接入虚拟机。虚拟机上的任何端口都可以通过服务公开。常见的端口有 22(SSH)、5900+(VNC)和 3389(RDP)。这篇博客中介绍了三种不同类型的服务。

    • ClusterIP

      ClusterIP 服务在集群内部公开虚拟机的端口。这可以让虚拟机相互通信,但不允许从集群外部进行连接。

    • NodePort

      NodePort 服务通过集群节点在集群外部公开虚拟机的端口。虚拟机的端口映射到节点上的端口。节点上的端口通常与虚拟机上的端口不同。连接到节点 IP 和相应的端口号即可访问虚拟机。

    • LoadBalancer(LB)

      LB 服务提供一个 IP 地址池供虚拟机使用。此服务类型向集群外部公开虚拟机的端口。使用获取的或指定的 IP 地址池来连接虚拟机。

  • 第 2 层接口

    集群节点上的网络接口可以配置为桥接,以实现与虚拟机的 L2 连接。虚拟机的接口使用 NetworkAttachmentDefinition 连接到桥接。这会绕过集群的网络堆栈,并将虚拟机的接口直接公开到桥接网络。绕过集群的网络堆栈,也就绕过了集群的内置安全防护。虚拟机应该像连接到网络的物理服务器一样受到保护。

集群概述

本博客中使用的集群名为 wd ,位于 example.org 域中。它由三个裸机控制平面节点( wcp-0、wcp-1 和 wcp-2)和三个裸机工作节点( wwk-0、wwk-1 和 wwk-2)组成。这些节点位于集群的主网络 10.19.3.0/24 上。

节点角色IPFQDN
wcp-0控制平面10.19.3.95wcp-0.wd.example.org
wcp-1控制平面10.19.3.94wcp-1.wd.example.org
wcp-2控制平面10.19.3.93wcp-2.wd.example.org
wwk-0工作节点10.19.3.92wwk-0.wd.example.org
55wwk-1工作节点10.19.3.91wwk-1.wd.example.org
wwk-2工作节点10.19.3.90wwk-2.wd.example.org

MetalLB 配置为从该网络向虚拟机提供四个 IP 地址(10.19.3.112-115)。

集群节点在 10.19.136.0/24 网络上有一个辅助网络接口。该辅助网络具有一个提供 IP 地址的 DHCP 服务器。

集群安装了以下 Operator。所有 Operator 均由 Red Hat, Inc. 提供。

Operator为何安装
Kubernetes NMState Operator用于配置节点上的第二个接口
OpenShift 虚拟化提供运行虚拟机的机制
本地存储使用本地 HDD 时,OpenShift 数据基础 Operator 需要使用
MetalLB Operator提供本博客中使用的 LoadBalancing 服务
OpenShift 数据基础为集群提供存储。该存储是在节点上使用第二个 HDD 创建的

集群上运行着几个虚拟机。虚拟机在 blog 命名空间中运行。

  • fedora - Fedora 38 虚拟机
  • rhel9 - 红帽企业 Linux 9(RHEL9)虚拟机
  • win11 - Windows 11 虚拟机

通过 UI 进行连接

通过 UI 查看虚拟机时会显示各种选项卡。它们都提供了查看或配置与虚拟机相关的各个方面的方法。其中一个特别的选项卡是 控制台 选项卡。该选项卡提供三种连接虚拟机的方法:VNC 控制台、串行控制台或桌面查看器(RDP)。只有运行 Microsoft Windows 的虚拟机才会显示 RDP 方法。

VNC 控制台

VNC 控制台始终可供任何虚拟机使用。VNC 服务由 OpenShift 虚拟化提供,不需要对虚拟机操作系统(OS)进行任何配置,它可以直接工作。

Screenshot of VNC Console Windows 11

串行控制台

串行控制台需要在虚拟机的操作系统内进行配置。如果操作系统未配置为输出到虚拟机的串行端口,则此连接方法不起作用。红帽提供的虚拟机镜像已配置为将启动信息输出到串行端口,并在虚拟机完成启动流程后提供登录提示。 

rhel9-serial-console-web-console-1

桌面查看器

此连接要求在虚拟机上安装并运行远程桌面(RDP)服务。在“控制台”选项卡中选择使用 RDP 进行连接时,系统将指出虚拟机当前没有 RDP 服务,并提供用于创建服务的选项。选择此选项会生成一个弹出窗口,其中包含“公开 RDP 服务”复选框。选中该复选框可为虚拟机创建一个允许 RDP 连接的服务。

ui-rdp-enable-service-rdp1-win-1

创建服务后,“控制台”选项卡会提供 RDP 连接的信息。 

ui-rdp-enable-service-win-1

还会提供“启动远程桌面”按钮。选择此按钮会下载 console.rdp 文件。如果浏览器配置为打开 .rdp 文件,则应该会在 RDP 客户端中打开 console.rdp 文件。

使用 virtctl 命令进行连接

 virtctl 命令使用基于 WebSocket 协议的网络隧道,提供对虚拟机的 VNC、串行控制台和 SSH 访问。

  • 运行 virtctl 命令的用户需要从命令行登录集群。
  • 如果用户与虚拟机不在同一命名空间中,则需要指定 --namespace 选项。

可从集群下载 virtctl 和其他客户端的正确版本,URL 类似于 https://console-openshift-console.apps.CLUSTERNAME.CLUSTERDOMAIN/command-line-tools。也可通过单击 UI 顶部的问号图标并选择 命令行工具进行下载。

VNC 控制台

 virtctl 命令可连接到 OpenShift 虚拟化提供的 VNC 服务器。运行 virtctl 命令的系统需要安装 virtctl 命令和 VNC 客户端。

只需运行 virtctl vnc 命令即可打开 VNC 连接。终端会显示有关连接的信息,并且会开启一个新的 VNC 控制台会话。 

virtctl-vnc-win11-1

串行控制台

若要使用 virtctl 命令连接到串行控制台,可以运行 virtctl console。如果虚拟机配置为输出到其串行端口(如前文所述),则应该会显示启动流程的输出或登录提示。

$ virtctl console rhel9
Successfully connected to rhel9 console. The escape sequence is ^]


[ 8.463919] cloud-init[1145]: Cloud-init v. 22.1-7.el9_1 running 'modules:config' at Wed, 05 Apr 2023 19:05:38 +0000. Up 8.41 seconds.
[ OK ] Finished Apply the settings specified in cloud-config.
Starting Execute cloud user/final scripts...
[ 8.898813] cloud-init[1228]: Cloud-init v. 22.1-7.el9_1 running 'modules:final' at Wed, 05 Apr 2023 19:05:38 +0000. Up 8.82 seconds.
[ 8.960342] cloud-init[1228]: Cloud-init v. 22.1-7.el9_1 finished at Wed, 05 Apr 2023 19:05:38 +0000. Datasource DataSourceNoCloud [seed=/dev/vdb][dsmode=net]. Up 8.95 seconds
[ OK ] Finished Execute cloud user/final scripts.
[ OK ] Reached target Cloud-init target.
[ OK ] Finished Crash recovery kernel arming.

Red Hat Enterprise Linux 9.1 (Plow)
Kernel 5.14.0-162.18.1.el9_1.x86_64 on an x86_64

Activate the web console with: systemctl enable --now cockpit.socket

rhel9 login: cloud-user
Password:
Last login: Wed Apr 5 15:05:15 on ttyS0
[cloud-user@rhel9 ~]$

 

SSH

使用 virtctl ssh 命令可调用 SSH 客户端。此命令的 -i 选项允许用户指定要使用的私钥。

$ virtctl ssh cloud-user@rhel9-one -i ~/.ssh/id_rsa_cloud-user
Last login: Wed May 3 16:06:41 2023

[cloud-user@rhel9-one ~]$

此外,还有 virtctl scp 命令,可用于将文件传输到虚拟机。提及此命令是因为,它的工作方式与 virtctl ssh 命令类似。

端口转发

 virtctl 命令也可以将流量从用户的本地端口转发到虚拟机上的端口。请参阅 OpenShift 文档 ,了解其工作原理。

其用途之一是将本地 OpenSSH 客户端(更加稳定可靠)转发到虚拟机,而不是使用 virtctl 命令的内置 SSH 客户端。有关如何执行此操作的示例,请参见 Kubevirt 文档 

另一种用途是在您不想创建 OpenShift 服务来公开端口的情况下,连接到虚拟机上的服务。

例如,我有一个名为 fedora-proxy 的虚拟机,其中安装了 NGINX webserver。虚拟机上的自定义脚本会将一些统计信息写入到名为 process-status.out 的文件中。我是唯一对该文件内容感兴趣的人,但我希望能在一天中随时查看该文件。我可以使用 virtctl port-forward 命令,将笔记本电脑或台式机上的本地端口转发到虚拟机的端口 80。我还可以编写一个简短脚本,以便在需要时随时收集数据。

#! /bin/bash

# Create a tunnel
virtctl port-forward vm/fedora-proxy 22080:80 &

# Need to give a little time for the tunnel to come up
sleep 1

# Get the data
curl http://localhost:22080/process-status.out

# Stop the tunnel
pkill -P $$

运行该脚本可获取所需的数据,并在执行后自行清理。

$ gather_stats.sh 
{"component":"","level":"info","msg":"forwarding tcp 127.0.0.1:22080 to 80","pos":"portforwarder.go:23","timestamp":"2023-05-04T14:27:54.670662Z"}
{"component":"","level":"info","msg":"opening new tcp tunnel to 80","pos":"tcp.go:34","timestamp":"2023-05-04T14:27:55.659832Z"}
{"component":"","level":"info","msg":"handling tcp connection for 22080","pos":"tcp.go:47","timestamp":"2023-05-04T14:27:55.689706Z"}

Test Process One Status: Bad
Test Process One Misses: 125

Test Process Two Status: Good
Test Process Two Misses: 23

通过容器集网络上公开的端口进行连接(服务)

服务

OpenShift 中的服务用于公开虚拟机的端口,以接收传入流量。这些传入流量可能来自其他虚拟机和容器集,也可能来自集群外部的来源。

本博客演示了如何创建三种类型的服务:ClusterIP、NodePort 和 LoadBalancer。ClusterIP 服务类型不允许从外部访问虚拟机。这三种类型的服务都提供虚拟机和容器集之间的内部访问,这是集群内虚拟机相互通信的首选方法。下表列出了三种服务类型及其可访问范围。

类型集群内部 DNS 的内部范围外部范围
ClusterIP<service-name>.<namespace>.svc.cluster.local
NodePort<service-name>.<namespace>.svc.cluster.local集群节点的 IP 地址
LoadBalancer<service-name>.<namespace>.svc.cluster.localLoadBalancers IPAddressPools 的外部 IP 地址

服务可以通过多种方式创建,包括使用 virtctl expose 命令或在 YAML 中进行定义。要使用 YAML 创建服务,可以通过命令行或 UI 来完成。

首先,我们使用 virtctl 命令来定义服务。

使用 virtctl 命令创建服务

使用 virtctl 命令时,用户需要登录集群。如果用户与虚拟机不在同一命名空间中,可以使用 --namespace 选项来指定虚拟机所在的命名空间。

 virtctl expose vm 命令可创建用于公开虚拟机端口的服务。以下是创建服务时与 virtctl expose 命令搭配使用的常见选项。

  
--name要创建的服务的名称。
--type指定要创建的服务类型:ClusterIP、NodePort、LoadBalancer
--port这是服务侦听流量的端口号。
--target-port可选。这是要公开的虚拟机端口。如果未指定,则与 --port 相同
--protocol可选。服务应侦听的协议。默认为 TCP。

以下命令会创建一项服务,用于通过 SSH 访问 RHEL9 虚拟机。

$ virtctl expose vm rhel9 --name rhel9-ssh --type NodePort --port 22

查看服务,以确定用于从集群外部访问虚拟机的端口。

$ oc get service

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
rhel9-ssh NodePort 172.30.244.228 <none> 22:32317/TCP 3s

我们暂时删除端口。

$ oc delete service rhel9-ssh
service "rhel9-ssh" deleted

使用 YAML 创建服务

要使用 YAML 创建服务,可以从命令行使用 oc create -f 命令或使用 UI 中的编辑器来完成。这两种方法都可行,而且各有优势。命令行更容易编写脚本,但 UI 提供对用于定义服务的模式的帮助。

首先,我们来讨论一下 YAML 文件,因为这两种方法的 YAML 文件是一样的。

单个服务定义可以公开一个或多个端口。下面的 YAML 文件是一个示例服务定义,它公开了两个端口,一个用于 SSH 流量,另一个用于 VNC 流量。这些端口以 NodePort 类型公开。关键项的说明列在 YAML 之后。

apiVersion: v1
kind: Service
metadata:
name: rhel-services
namespace: blog
spec:
ports:
- name: ssh
protocol: TCP
nodePort: 31798
port: 22000
targetPort: 22
- name: vnc
protocol: TCP
nodePort: 31799
port: 22900
targetPort: 5900
type: NodePort
selector:
kubevirt.io/domain: rhel9

以下是文件中需要注意的几项设置:

  
metadata.name服务的名称,在其命名空间中是唯一的。
metadata.namespace服务所在的命名空间。
spec.ports.name所定义端口的名称。
spec.ports.protocol网络流量协议,即 TCP 或 UDP。
spec.ports.nodePort集群外部公开的端口。它在集群内是唯一的。
spec.ports.port集群网络内部使用的端口。
spec.ports.targetPort虚拟机公开的端口,多个虚拟机可以公开同一端口。
spec.type这是要创建的服务类型。我们选择使用的是 NodePort
spec.selector用于将服务绑定到虚拟机的选择器。在示例中,绑定到名为 fedora的虚拟机
从命令行创建服务

让我们从命令行使用 YAML 文件来创建这两个服务。要使用的命令是 oc create -f

$ oc create -f service-two.yaml 
service/rhel-services created

$ oc get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
rhel-services NodePort 172.30.11.97 <none> 22000:31798/TCP,22900:31799/TCP 4s

我们可以看到单个服务中公开了两个端口。现在,我们使用 oc delete service 命令来删除该服务。

$ oc delete service rhel-services
service "rhel-services" deleted
从 UI 创建服务

让我们使用 UI 创建相同的服务。要使用 UI 创建服务,请前往“网络”->“服务”,然后选择“创建服务”。此时将打开一个编辑器,其中包含预填充的服务定义和对模式的引用。将上方的 YAML 粘贴到编辑器中,并选择 创建 以创建服务。

service-ui-two

选择 创建后,将显示服务的详细信息。 

service-rhel-services

附加到虚拟机的服务也可以在“虚拟机详细信息”选项卡中查看,或者像之前一样在命令行中使用 oc get service 命令查看。与之前一样,删除该服务。

$ oc get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
rhel-services NodePort 172.30.11.97 <none> 22000:31798/TCP,22900:31799/TCP 4s

$ oc delete service rhel-services
service "rhel-services" deleted

轻松创建 SSH 和 RDP 服务

UI 提供简单的点击式方法,用于在虚拟机上创建 SSH 和 RDP 服务。

虚拟机的“详细信息”选项卡上有一个 SSH 服务类型 下拉菜单,从中可轻松启用 SSH。该下拉菜单还支持轻松创建 NodePort 或 LoadBalancer 服务。 

ssh-ui-dropdown

选择服务类型后,服务便创建完成。UI 会显示一个命令,可用于连接到该服务及其创建的服务。 

lb-service-enabled-1

可通过虚拟机的“控制台”选项卡启用 RDP。对于基于 Windows 的虚拟机,控制台下拉菜单中会显示 桌面查看器 选项。 

rdp-viewer-dropdown

选择后,将显示 创建 RDP 服务 选项。 

create-rdp-ui-1

选择该选项会弹出 公开 RDP 服务窗口。 

rdp-popup

创建服务后,“控制台”选项卡中会显示连接信息。 

rdp-connection-info

使用 ClusterIP 服务的连接示例

ClusterIP 类型的服务允许虚拟机在集群内部相互连接。如果一个虚拟机需要向其他虚拟机提供服务(如数据库实例),这将非常有用。我们不在虚拟机上配置数据库,而是使用 ClusterIP 在 Fedora 虚拟机上公开 SSH。

让我们创建一个 YAML 文件,用于创建一项服务,以便在集群内部公开 Fedora 虚拟机的 SSH 端口。

apiVersion: v1
kind: Service
metadata:
name: fedora-internal-ssh
namespace: blog
spec:
ports:
- protocol: TCP
port: 22
selector:
kubevirt.io/domain: fedora
type: ClusterIP

我们来应用配置。

$ oc create -f service-fedora-ssh-clusterip.yaml 
service/fedora-internal-ssh created

$ oc get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
fedora-internal-ssh ClusterIP 172.30.202.64 <none> 22/TCP 7s

使用 RHEL9 虚拟机时,我们可以看到可以使用 SSH 连接到 Fedora 虚拟机。

$ virtctl console rhel9
Successfully connected to rhel9 console. The escape sequence is ^]

rhel9 login: cloud-user
Password:
Last login: Wed May 10 10:20:23 on ttyS0

[cloud-user@rhel9 ~]$ ssh fedora@fedora-internal-ssh.blog.svc.cluster.local
The authenticity of host 'fedora-internal-ssh.blog.svc.cluster.local (172.30.202.64)' can't be established.
ED25519 key fingerprint is SHA256:ianF/CVuQ4kxg6kYyS0ITGqGfh6Vik5ikoqhCPrIlqM.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'fedora-internal-ssh.blog.svc.cluster.local' (ED25519) to the list of known hosts.
Last login: Wed May 10 14:25:15 2023
[fedora@fedora ~]$

使用 NodePort 服务的连接示例

在本例中,我们使用 NodePort 从 windows11 虚拟机公开 RDP,这样我们就可以连接到其桌面,从而获得比使用“控制台”选项卡更出色的体验。此连接将供受信任的用户使用,因为他们知道集群节点的 IP。

关于 OVNKubernetes 的注意事项

最新版本的 OpenShift 安装程序默认使用 OVNKubernetes 网络堆栈。如果集群运行 OVNKubernetes 网络堆栈,并且使用了 NodePort 服务,那么虚拟机的出口流量将无法正常工作,直到启用 routingViaHost 

在使用 NodePort 服务时,对集群进行简单修复即可启用出口流量。

$ oc patch network.operator cluster -p '{"spec": {"defaultNetwork": {"ovnKubernetesConfig": {"gatewayConfig": {"routingViaHost": true}}}}}' --type merge

$ oc get network.operator cluster -o yaml
apiVersion: operator.openshift.io/v1
kind: Network
spec:
defaultNetwork:
ovnKubernetesConfig:
gatewayConfig:
routingViaHost: true
...

如果集群使用 OpenShiftSDN 网络堆栈或使用了 MetalLB 服务,则不需要此补丁。

使用 NodePort 服务的连接示例

我们来创建 NodePort 服务,首先在 YAML 文件中进行定义。

apiVersion: v1
kind: Service
metadata:
name: win11-rdp-np
namespace: blog
spec:
ports:
- name: rdp
protocol: TCP
nodePort: 32389
port: 22389
targetPort: 3389
type: NodePort
selector:
kubevirt.io/domain: windows11

创建服务。

$ oc create -f service-windows11-rdp-nodeport.yaml 
service/win11-rdp-np created

$ oc get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
win11-rdp-np NodePort 172.30.245.211 <none> 22389:32389/TCP 5s

由于这是 NodePort 服务,我们可以使用任何节点的 IP 来连接它。运行 oc get nodes 命令可显示节点的 IP 地址。

$ oc get nodes -o=custom-columns=Name:.metadata.name,IP:status.addresses[0].address
Name IP
wcp-0 10.19.3.95
wcp-1 10.19.3.94
wcp-2 10.19.3.93
wwk-0 10.19.3.92
wwk-1 10.19.3.91
wwk-2 10.19.3.90

 xfreerdp 程序是一个可用于 RDP 连接的客户端程序。我们将指示它使用集群上公开的 RDP 端口连接到 wcp-0 节点。

$ xfreerdp /v:10.19.3.95:32389 /u:cnvuser /p:hiddenpass

[14:32:43:813] [19743:19744] [WARN][com.freerdp.crypto] - Certificate verification failure 'self-signed certificate (18)' at stack position 0
[14:32:43:813] [19743:19744] [WARN][com.freerdp.crypto] - CN = DESKTOP-FCUALC4
[14:32:44:118] [19743:19744] [INFO][com.freerdp.gdi] - Local framebuffer format PIXEL_FORMAT_BGRX32
[14:32:44:118] [19743:19744] [INFO][com.freerdp.gdi] - Remote framebuffer format PIXEL_FORMAT_BGRA32
[14:32:44:130] [19743:19744] [INFO][com.freerdp.channels.rdpsnd.client] - [static] Loaded fake backend for rdpsnd
[14:32:44:130] [19743:19744] [INFO][com.freerdp.channels.drdynvc.client] - Loading Dynamic Virtual Channel rdpgfx
[14:32:45:209] [19743:19744] [WARN][com.freerdp.core.rdp] - pduType PDU_TYPE_DATA not properly parsed, 562 bytes remaining unhandled. Skipping.

我们与虚拟机建立了连接。 

freerdp-nodeport

使用 LoadBalancer 服务的连接示例

我们来创建 LoadBalancer 服务,首先在 YAML 文件中进行定义。我们将使用 Windows 虚拟机并公开 RDP。

apiVersion: v1
kind: Service
metadata:
name: win11-rdp-lb
namespace: blog
spec:
ports:
- name: rdp
protocol: TCP
port: 3389
targetPort: 3389
type: LoadBalancer
selector:
kubevirt.io/domain: windows11

创建服务。我们可以看到,它自动获得了一个 IP。

$ oc create -f service-windows11-rdp-loadbalancer.yaml 
service/win11-rdp-lb created

$ oc get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
win11-rdp-lb LoadBalancer 172.30.125.205 10.19.3.112 3389:31258/TCP 3s

可以看到,我们从该服务连接到 EXTERNAL-IP ,以及使用服务公开的标准 RDP 端口 3389。 xfreerdp 命令的输出显示连接成功。

$ xfreerdp /v:10.19.3.112 /u:cnvuser /p:changeme
[15:51:21:333] [25201:25202] [WARN][com.freerdp.crypto] - Certificate verification failure 'self-signed certificate (18)' at stack position 0
[15:51:21:333] [25201:25202] [WARN][com.freerdp.crypto] - CN = DESKTOP-FCUALC4
[15:51:23:739] [25201:25202] [INFO][com.freerdp.gdi] - Local framebuffer format PIXEL_FORMAT_BGRX32
[15:51:23:739] [25201:25202] [INFO][com.freerdp.gdi] - Remote framebuffer format PIXEL_FORMAT_BGRA32
[15:51:23:752] [25201:25202] [INFO][com.freerdp.channels.rdpsnd.client] - [static] Loaded fake backend for rdpsnd
[15:51:23:752] [25201:25202] [INFO][com.freerdp.channels.drdynvc.client] - Loading Dynamic Virtual Channel rdpgfx
[15:51:24:922] [25201:25202] [WARN][com.freerdp.core.rdp] - pduType PDU_TYPE_DATA not properly parsed, 562 bytes remaining unhandled. Skipping.

没有附上屏幕截图,因为它与上面的屏幕截图相同。

使用第 2 层接口进行连接

如果虚拟机的接口将在内部使用,并且不需要公开,则使用 NetworkAttachmentDefinition 和节点上的桥接接口进行连接是一个不错的选择。此方法绕过集群网络堆栈,这意味着集群网络堆栈不需要处理每个数据包,这可以提高网络流量的性能。

这种方法确实有一些缺点,即虚拟机直接公开到网络,不受任何集群安全防护的保护。如果虚拟机受到攻击,则入侵者可以访问该虚拟机所连接的网络。使用此方法时,应注意在虚拟机的操作系统内提供适当的安全防护。

NMState

部署集群后,可以使用红帽提供的 NMState operator 在节点上配置物理接口。还可以应用各种配置,包括桥接、VLAN 和绑定等。我们将使用它在集群中每个节点的未使用接口上配置桥接。有关使用 NMState Operator 的更多信息,请参阅 OpenShift 文档 

让我们在节点的未使用接口上配置一个简单的桥接。接口连接到提供 DHCP 的网络,并在 10.19.142.0 网络上分发地址。以下 YAML 会在 ens5f1 网络接口上创建一个名为 brint 的桥接。

---
apiVersion: nmstate.io/v1
kind: NodeNetworkConfigurationPolicy
metadata:
name: brint-ens5f1
spec:
nodeSelector:
node-role.kubernetes.io/worker: ""
desiredState:
interfaces:
- name: brint
description: Internal Network Bridge
type: linux-bridge
state: up
ipv4:
enabled: false
bridge:
options:
stp:
enabled: false
port:
- name: ens5f1

应用 YAML 文件,以在工作节点上创建桥接。

$ oc create -f brint.yaml 
nodenetworkconfigurationpolicy.nmstate.io/brint-ens5f1 created

使用 oc get nncp 命令可查看 NodeNetworkConfigurationPolicy 的状态。使用 oc get nnce 命令可查看各个节点配置的状态。应用配置后,两个命令的 STATUS 都会显示 Available ,并且 REASON 显示 SuccessfullyConfigured

$ oc get nncp
NAME STATUS REASON
brint-ens5f1 Progressing ConfigurationProgressing

$ oc get nnce
NAME STATUS REASON
wwk-0.brint-ens5f1 Pending MaxUnavailableLimitReached
wwk-1.brint-ens5f1 Available SuccessfullyConfigured
wwk-2.brint-ens5f1 Progressing ConfigurationProgressing

NetworkAttachmentDefinition

虚拟机无法直接附加到我们创建的桥接,但可以附加到 NetworkAttachmentDefinition(NAD)。以下命令会创建一个名为 nad-brint 的 NAD,它将附加到在节点上创建的 brint 桥接。有关如何创建 NAD 的说明,请参阅 OpenShift 文档 

apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
name: nad-brint
annotations:
k8s.v1.cni.cncf.io/resourceName: bridge.network.kubevirt.io/brint
spec:
config: '{
"cniVersion": "0.3.1",
"name": "nad-brint",
"type": "cnv-bridge",
"bridge": "brint",
"macspoofchk": true
}'

应用 YAML 后,可以使用 oc get network-attachment-definition 命令查看 NAD。

$ oc create -f brint-nad.yaml 
networkattachmentdefinition.k8s.cni.cncf.io/nad-brint created

$ oc get network-attachment-definition
NAME AGE
nad-brint 19s

也可以从 UI 创建 NAD,方法是导航到“网络”->“NetworkAttachmentDefinitions”。

使用第 2 层接口的连接示例

创建 NAD 后,可以将网络接口添加到虚拟机,或者修改现有接口以使用它。让我们通过导航到虚拟机的详细信息并选择“网络接口”选项卡来添加一个新的网络接口。有一个 添加网络接口选项,请选择此项。对于现有接口,可以通过选择旁边的 kebab 菜单进行修改。 

ui-attach-nad-1

重新启动虚拟机后,虚拟机详细信息的“概述”选项卡中会显示从 DHCP 收到的 IP 地址。 

ui-rhel9-ip

现在,我们可以使用从桥接接口上的 DHCP 服务器获取的 IP 地址来连接虚拟机。

$ ssh cloud-user@10.19.142.213 -i ~/.ssh/id_rsa_cloud-user

The authenticity of host '10.19.142.213 (10.19.142.213)' can't be established.
ECDSA key fingerprint is SHA256:0YNVhGjHmqOTL02mURjleMtk9lW5cfviJ3ubTc5j0Dg.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.19.142.213' (ECDSA) to the list of known hosts.

Last login: Wed May 17 11:12:37 2023
[cloud-user@rhel9 ~]$

SSH 流量从虚拟机通过桥接进行传输,并从物理网络接口传出。流量绕过容器集网络,并且似乎位于桥接接口所在的网络上。以这种方式连接时,虚拟机不受任何防火墙保护,虚拟机的所有端口都可以访问,包括用于 SSH 和 VNC 的端口。

结语

我们已经了解了连接 OpenShift 虚拟化中运行的虚拟机的各种方法。这些方法提供了对无法正常工作的虚拟机进行故障排除的方法,以及连接到虚拟机以进行日常使用的方法。虚拟机可以在集群内本地交互,集群外部的系统可以直接访问它们,也可以使用集群容器集网络来访问。这有助于将物理系统和其他平台上的虚拟机迁移到 OpenShift 虚拟化,并顺利完成过渡。


关于作者

UI_Icon-Red_Hat-Close-A-Black-RGB

按频道浏览

automation icon

自动化

有关技术、团队和环境 IT 自动化的最新信息

AI icon

人工智能

平台更新使客户可以在任何地方运行人工智能工作负载

open hybrid cloud icon

开放混合云

了解我们如何利用混合云构建更灵活的未来

security icon

安全防护

有关我们如何跨环境和技术减少风险的最新信息

edge icon

边缘计算

简化边缘运维的平台更新

Infrastructure icon

基础架构

全球领先企业 Linux 平台的最新动态

application development icon

应用领域

我们针对最严峻的应用挑战的解决方案

Original series icon

原创节目

关于企业技术领域的创客和领导者们有趣的故事