详解 Docker 启动 Windows 容器第二篇:技术原理与未来发展方向

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 所遇问题
    • [问题 1:Docker 容器启动的 Windows 实例调用了 KVM 驱动,但为什么用 `virsh list` 命令查不到虚拟机?这意味着它不是一个完整的虚拟机吗?](#问题 1:Docker 容器启动的 Windows 实例调用了 KVM 驱动,但为什么用 virsh list 命令查不到虚拟机?这意味着它不是一个完整的虚拟机吗?)
    • [问题 2:为什么通过 docker stats 查看时显示的是容器占用内存,而不是虚拟机的内存占用?](#问题 2:为什么通过 docker stats 查看时显示的是容器占用内存,而不是虚拟机的内存占用?)
    • [问题 3:Linux 上使用 KVM 启动一个 Windows 虚拟机和通过容器启动一个虚拟机的区别(调用 KVM 驱动)](#问题 3:Linux 上使用 KVM 启动一个 Windows 虚拟机和通过容器启动一个虚拟机的区别(调用 KVM 驱动))
    • [问题 4:为什么在Linux上通过容器启动Windows(KVM)和Linux后,容器内部的网络表现不同?](#问题 4:为什么在Linux上通过容器启动Windows(KVM)和Linux后,容器内部的网络表现不同?)
  • 未来方向探讨
    • [1. 简化虚拟化管理:砍掉OpenStack和VMware](#1. 简化虚拟化管理:砍掉OpenStack和VMware)
    • [2. Windows服务容器化部署](#2. Windows服务容器化部署)
    • [3. Windows 容器结合 AD 实现私有云弹性使用](#3. Windows 容器结合 AD 实现私有云弹性使用)
    • [4. 优化审计工具成本](#4. 优化审计工具成本)
    • [5. 网络管控统一化](#5. 网络管控统一化)
    • [6. 简化高可用架构](#6. 简化高可用架构)
  • 总结

前言

在通过 Docker 启动 Windows 容器的过程中,我对其调用 KVM 驱动的工作原理还不够了解。尤其是与传统虚拟化技术(如 libvirt)相比,这种方法的特殊性让我产生了许多疑问。在查阅了大量资料后,我整理出了一些问题及其解答,希望能帮助对这个话题感兴趣的朋友更好地理解 Docker 容器与虚拟化技术结合的独特之处。

所遇问题

问题 1:Docker 容器启动的 Windows 实例调用了 KVM 驱动,但为什么用 virsh list 命令查不到虚拟机?这意味着它不是一个完整的虚拟机吗?

解答:

  1. 为什么 virsh list 查不到虚拟机?
  • virsh list 的工作机制:
    virsh list 是用来管理和查看由 libvirt 管理的虚拟机的工具。如果虚拟机不是通过 libvirt 创建和管理的,virsh 是无法检测到它的。

  - 

在 Docker 容器中启动 Windows 实例时,通过挂载 /dev/kvm 与宿主机的 KVM 模块直接交互。这个过程绕过了 libvirt,而是可能通过 QEMU + KVM 的方式直接实现硬件虚拟化支持。

因此,virsh 无法列出这些由 Docker 启动的虚拟机实例,因为它们并未被 libvirt 管理。

  1. 这是不是一个完整的虚拟机?
    从严格意义上来说,它并不是传统的「完整虚拟机」,而是介于虚拟机和容器之间的一种轻量化虚拟化实现。
  • 容器化特性:

    • 使用 Docker 技术进行管理,具备容器的轻量化特性。
    • 配置文件中使用了 Docker 的 portscap_add 等功能,属于典型的容器管理方式。
  • 虚拟化特性:

    • 通过 /dev/kvm 使用硬件虚拟化技术,运行了一个独立的 Windows 操作系统实例。
    • 使用了 KVM 提供的虚拟化支持,底层依赖 QEMU 等虚拟化工具。
  • 综合判断:

    • 这类 Windows 容器可以视为一个「通过容器运行的轻量化虚拟机」,但它并没有完整的虚拟机管理功能(如快照、热迁移等)。
  1. 这种实现的工作原理是什么?

    QEMU + KVM 支持:

    • 容器内部可能使用了 QEMU,KVM 提供了硬件虚拟化的加速支持。QEMU 作为用户态应用,借助 /dev/kvm 完成高效的虚拟机运行。

    Docker 容器管理:

    • Docker 负责通过容器技术挂载宿主机的 /dev/kvm,使容器能够访问硬件虚拟化能力。
    • 容器的网络、端口映射、设备挂载等由 Docker 提供支持。
  2. 这种方式的优缺点是什么?

  • 优点:

    • 部署简单: 利用 Docker,能够快速启动和管理虚拟化实例。
    • 轻量化: 不需要额外安装 libvirt 或其他传统虚拟化管理工具。
    • 灵活性高: 可以结合 Docker 的生态系统,如镜像管理、自动化部署等功能。
  • 缺点:

    • 管理不便: 传统虚拟机管理工具(如 virsh 或 vSphere)无法直接管理这些实例。
    • 功能限制: 无法支持复杂的虚拟化场景,例如快照、热迁移等功能。
    • 性能可能受限: 与直接使用 KVM 或 libvirt 的传统虚拟机相比,可能会有一些性能开销。

Docker 容器中运行的 Windows 实例并非传统意义上的虚拟机,而是通过容器技术实现的轻量化虚拟化。它通过 KVM 提供硬件支持,同时利用 Docker 的容器生态完成管理和部署。
这种方式适用于轻量级需求,例如快速启动虚拟化实例或实验环境。但如果需要更强大的功能(如快照、热迁移或集中管理),建议使用 libvirt、vSphere 或 OpenStack 等专业虚拟化平台。
对于开发者来说,理解这种轻量化虚拟化技术的工作原理,可以更好地权衡性能与功能需求,在适合的场景中高效利用 Docker 与虚拟化技术结合的优势。

问题 2:为什么通过 docker stats 查看时显示的是容器占用内存,而不是虚拟机的内存占用?

docker stats 报告的是容器的内存占用,而非虚拟机(通过 KVM 驱动运行的 Windows 系统)的内存。这其中的关键就在于 Docker 的资源管理方式和虚拟化的底层原理。

  1. 为什么 docker stats 显示的是容器占用内存?
    Docker 通过 CGroup(控制组) 对容器的资源进行限制和统计管理。无论容器内部运行的是普通进程,还是像虚拟机这样的特殊应用,其资源消耗都会被归类到该容器中。更具体地说:
  • 容器中的 QEMU 进程: 用于运行虚拟机的 QEMU 本质上是一个普通的用户态进程,运行在 Docker 容器中。

  • 容器进程封装性: Docker 容器将 QEMU 等进程打包运行,而 docker stats 监控的正是这些容器中进程的资源消耗。

  • Docker 的监控逻辑: 容器并不知道它运行的是虚拟机,因此 docker stats 中显示的内存占用,实际上是:

    QEMU 分配的内存 + 容器内其他进程占用的内存

  1. 为什么虚拟机的内存消耗归类到容器中?
    虚拟机的运行依赖于 QEMU + KVM。其中:
  • KVM 的角色:

    • KVM 是一个 Linux 内核模块,用于提供硬件虚拟化支持。它本身不会主动分配内存,而是通过宿主机硬件支持 QEMU 来完成虚拟化任务。
    • 因此,KVM 的工作更多是"桥梁",并不直接产生显性内存开销。
  • QEMU 的角色:

    • QEMU 是虚拟机运行的核心进程,负责实际分配内存和处理虚拟化指令。
    • QEMU 的内存分配会被 CGroup 统计为容器资源开销的一部分,所以我们在 docker stats 中看到的是容器的总内存占用。
  1. 内存占用的分配和流向

假设你为虚拟机分配了 2GB 内存,并通过 Docker 启动:

  • 容器进程的内存分配:

    • QEMU 进程分配了虚拟机的 2GB 内存;
    • 其他容器中运行的进程(如网络工具)也会消耗部分内存。
  • docker stats 的内存显示:

    • 显示的是容器中所有进程的内存消耗总和(包括 QEMU 和其他进程)。
  1. 如何验证虚拟机的实际内存占用?

如果你想具体查看虚拟机的内存使用情况,可以尝试以下方法:
方法 1:宿主机查看容器内进程的内存

在宿主机上,找到容器中的 QEMU 进程,并检查其内存消耗:

bash 复制代码
ps aux | grep qemu

然后使用 tophtop 工具,观察 QEMU 进程的实际内存占用。

方法 2:容器内部查看 QEMU 的内存

进入容器内部,使用类似 tophtop 的工具查看 QEMU 占用的内存:

bash 复制代码
docker exec -it <容器ID> bash
top

方法 3:虚拟机内部查看

登录虚拟机(例如通过 RDP),在虚拟机内查看内存使用情况:

  • Windows 虚拟机: 通过任务管理器查看分配的物理内存。
  • Linux 虚拟机: 使用 free -mtop 等工具查看内存分配。
  1. 优缺点分析
优点 缺点
部署简单:通过 Docker 管理虚拟机,快速启动和停止 管理复杂:虚拟机内存统计需要跨层查看
资源整合:使用 Docker 的 CGroup 统一统计资源 难以实现传统虚拟机功能(如快照、热迁移等)
部署简单:通过 Docker 管理虚拟机,快速启动和停止 管理复杂:虚拟机内存统计需要跨层查看

总的来说:

  • docker stats 显示的内存占用,是 容器内所有进程的总和,包括 QEMU 等虚拟机相关进程的资源消耗。
  • KVM 本身不会直接占用内存,它只是虚拟机运行的硬件支持模块。
  • 如果需要精确统计虚拟机内存,可以通过容器或虚拟机内的工具进行具体分析。
    这种 Docker 和虚拟化结合的方式,虽然不是传统意义上的完整虚拟机,但它在轻量化部署和资源管理上提供了很高的灵活性,非常适合场景化需求。

问题 3:Linux 上使用 KVM 启动一个 Windows 虚拟机和通过容器启动一个虚拟机的区别(调用 KVM 驱动)

它涉及两种不同虚拟化方式的架构、功能、性能和使用场景上的区别。以下从多个角度对比两种方式:直接使用 KVM 启动虚拟机通过容器启动虚拟机

  1. 架构区别
    直接使用 KVM 启动虚拟机
  • 架构

    • 利用 Linux 内核中的 KVM 模块和用户态的 QEMU 模拟器,在宿主机上直接运行虚拟机。
    • KVM 提供硬件加速,QEMU 负责虚拟机管理和硬件模拟。
  • 管理工具

    • 常用 virsh、virt-manager 等工具管理虚拟机,依赖 libvirt 提供标准化 API,支持快照、热迁移等高级功能。
  • 资源隔离

    • 资源由 KVM 和 QEMU 完全管理,宿主机的 CGroup 通常不直接作用于虚拟机。

通过容器启动虚拟机

  • 架构

    • 使用 Docker 容器运行虚拟化环境,容器内部运行 QEMU,利用 KVM 驱动启动虚拟机。
    • 容器本身提供资源隔离和运行环境封装,虚拟机运行在容器之内。
  • 管理工具

    • 使用 Docker 命令(如 docker-compose 或 docker run)管理虚拟机的生命周期,轻量级且无需 libvirt。
  • 资源隔离

    • 容器利用 CGroup 实现资源限制(如内存、CPU 等),虚拟机的资源分配受到容器的约束。
  1. 功能和性能对比
    功能对比
功能 直接使用 KVM 启动虚拟机 容器启动虚拟机
管理方式 通过 virshvirt-manager 提供完整虚拟化功能(如快照、热迁移等)。 使用 Docker 命令,管理简单但功能有限。
隔离性 虚拟机拥有完整的硬件资源隔离,隔离性强。 容器和虚拟机共享部分资源,隔离性稍弱。
扩展性 可扩展性强,可与 OpenStack 等云平台集成。 适合轻量级部署,扩展性依赖 Docker。
便捷性 部署复杂,需要配置 libvirt 和 KVM 依赖。 部署简单,快速与容器化应用整合。
网络配置 支持复杂的网络配置(如多网卡、VLAN 隔离)。 受限于 Docker 网络模式,网络功能稍弱。

性能对比

性能指标 直接使用 KVM 启动虚拟机 容器启动虚拟机
CPU 性能 依赖 KVM 和 QEMU,性能接近裸机。 性能相当,容器增加的开销很小。
内存管理 内存直接由 KVM 和 QEMU 管理,效率更高。 内存由容器分配,增加了一层抽象,但影响微小。
I/O 性能 I/O 性能接近裸机,硬件直通能力强。 略有性能损耗,受限于容器文件系统(如 overlayfs)。
启动速度 启动稍慢,需要加载完整虚拟机环境。 启动更快,受益于 Docker 的轻量化特性。
  1. 使用场景对比
    直接使用 KVM 启动虚拟机的适用场景
  • 传统虚拟化需求
    • 云平台(如 OpenStack)、生产环境中的高性能虚拟化部署。
    • 需要支持快照、热迁移、硬件直通等功能。
  • 性能优先场景
    • I/O 密集型任务(如数据库、大数据分析)需要接近裸机性能。
  • 复杂网络需求
    • 支持自定义网络配置(如多网卡、VLAN、桥接网络)。

容器启动虚拟机的适用场景

  • 轻量化需求
    • 运行特定版本的 Windows 系统以完成简单测试任务。
    • 快速部署和销毁虚拟机实例。
  • 容器化生态
    • 集成到现有容器化应用中,享受容器生态的便利性(如镜像管理、快速部署)。
  • 开发与测试环境
    • 通过 Docker Compose 等工具快速管理虚拟机的生命周期。
  1. 优缺点总结
优缺点 直接使用 KVM 启动虚拟机 容器启动虚拟机
优点 高性能,功能全面,支持复杂场景。 部署轻量、管理简单,符合容器生态。
缺点 部署复杂,依赖更多工具(如 libvirt)。 功能有限,不适合复杂需求场景。

总的来说:

  • 直接使用 KVM 启动虚拟机: 适合需要完整虚拟化功能、高性能和复杂场景的应用,如企业级云平台部署、I/O 密集型任务和复杂网络配置。
  • 容器启动虚拟机: 适合轻量化需求、快速部署和测试环境,尤其是在容器生态中集成虚拟机的场景。
    选择的关键在于场景需求。如果需要快速实验或轻量管理,容器启动虚拟机更方便;而对于复杂功能和高性能要求,直接使用 KVM 是更优选择。

问题 4:为什么在Linux上通过容器启动Windows(KVM)和Linux后,容器内部的网络表现不同?

在容器中启动 Windows ,使用 docker inspect 命令显示 Windows 容器获取的 IP 地址是127.19.0.2,Web 或 远程方式访问 Windows 容器显示 IP 地址却是 20.20.20.21,网关是20.20.20.1

用同样的方式容器中启动 Linux ,使用 docker inspect 命令显示 IP 地址是127.19.0.3,进入 Linux 容器显示的 IP 地址也是 127.19.0.3
两容器内部均能 ping 通宿主机 IP,但是宿主机不能 ping 通 20.20.20.21 和 20.20.20.1 ,可以ping通 127.19.0.3(Linux) 和 127.19.0.2(Windows)

  1. 网络结构差异
  • Linux 容器: 使用的是 Docker 的网络模式(例如 bridge 模式),容器的虚拟网络接口直接桥接到 Docker 的虚拟网桥(docker0)上,默认情况下与宿主机连通。
  • Windows 容器(虚拟机): 由 KVM 使用 QEMU 创建虚拟机,虚拟机内部的网卡由 QEMU 模拟,虚拟机网络默认是隔离的,宿主机与虚拟机之间需要额外配置转发或桥接才能通信。
  1. 容器和宿主机的通信情况
行为 Windows 容器 Linux 容器
宿主机能否 ping 通容器 否(需要手动配置桥接或 NAT) 是(默认连通)
容器能否 ping 通宿主机 是(QEMU 提供 NAT 转发) 是(默认连通)
  • 宿主机无法 ping 通虚拟机(Windows 容器):

    • 原因在于虚拟机使用的是独立的虚拟网络(QEMU 提供),默认没有配置从宿主机到虚拟机的流量转发。
    • 而 Linux 容器的网络则直接使用 Docker 分配的网络,因此宿主机可以直接与容器通信。
  • 容器都能 ping 通宿主机:

    • Windows 容器 通过 QEMU 的 NAT 转发机制,将虚拟机内流量映射到宿主机网络上。
    • Linux 容器 通过 Docker 网桥直接与宿主机网络相连,因此可以通信。
  1. 为什么进入 Windows 容器看到的 IP 是不同的?
  • Windows 容器(虚拟机)由 QEMU 创建的独立虚拟网络提供 IP 地址(例如 20.20.20.21),与 Docker 的网络配置无关。
  • 而 Linux 容器使用 Docker 管理网络,因此看到的 IP 地址与 Docker 分配的地址一致。
  1. 让宿主机可以 ping 通 Windows 容器

以下是几种可行的调整方式:
方案 1:配置桥接模式

将虚拟机的网络直接桥接到宿主机的物理网卡,使虚拟机与宿主机使用相同的物理网络。

示例命令(调整为你的网络环境):

bash 复制代码
qemu-system-x86_64 \
    -net nic \
    -net bridge,br=br0 \
    ...

注意:需要确保宿主机上已创建桥接接口(例如 br0),并正确配置物理网卡桥接到该接口。

方案 2:配置 NAT 转发规则

使用 iptables 将宿主机流量转发到虚拟机的 IP 地址:

bash 复制代码
# 假设 tap 设备为 tap0,虚拟机 IP 为 20.20.20.21
iptables -t nat -A PREROUTING -d 20.20.20.21 -j DNAT --to-destination tap0

注意:需要确认虚拟机的网络接口(tap 设备)名称。

方案 3:使用 QEMU 用户网络

启用 QEMU 提供的 -net user 模式,QEMU 会自动配置 NAT,使宿主机可以访问虚拟机。 示例命令:

bash 复制代码
qemu-system-x86_64 \
    -net nic \
    -net user,hostfwd=tcp::2222-:22 \
    ...

解释:hostfwd=tcp::2222-:22 将宿主机 2222 端口的 SSH 流量转发到虚拟机的 22 端口。

  1. 补充说明
  • 为什么设计成这样?

    • 虚拟机 的网络隔离性更强,适合需要独立网络环境的场景,例如模拟独立主机环境或隔离安全风险。
    • 容器 的网络更贴近宿主机,便于轻量化通信和快速部署。
  • 如何选择配置方案?

    • 如果需要让宿主机与虚拟机频繁通信,推荐使用 桥接模式。
    • 如果仅需要简单访问,可以使用 NAT 转发 或 用户网络模式。
  • 性能与安全性权衡

    • 桥接模式 性能较高,但需要确保宿主机网络配置安全。
    • NAT 模式 或 用户网络模式 更安全,但可能会有一定的性能损耗。

未来方向探讨

1. 简化虚拟化管理:砍掉OpenStack和VMware

除非有快照等特殊需求必须要使用到虚拟机,否则可以直接采用 Ceph + Kubernetes + Windows容器 的组合方案。Windows容器中的数据可以通过持久化存储(Ceph)来管理,减少对复杂虚拟化平台的依赖。

2. Windows服务容器化部署

对于必须部署在 Windows 上的服务(如 SQL Server、IIS 等),可以通过 Windows 容器进行部署。这样只需维护 Windows 容器的持久化数据即可,服务可以实现一键式部署和启动,降低运维复杂度。

3. Windows 容器结合 AD 实现私有云弹性使用

  • Windows 容器接入 Windows AD 后,可以将容器直接分配给用户使用,实现私有云办公环境。
  • 在需要时,通过启动新的 Windows 容器为用户分配资源,支持弹性升级配置,用户数据通过持久化存储保证安全可靠。
  • 不需要时,可以关闭容器以减少资源消耗,提高系统效率。

4. 优化审计工具成本

如果公司引入了审计工具(如 IPG),该方案可以在一定程度上减少 IPG License 的数量需求。原因是部分用户处于等待状态时无需立即分配 Windows 容器,只需在使用时动态启动。

5. 网络管控统一化

通过 Kubernetes 接管 Windows 容器的网络管理,消除 VLAN 的概念,网络管理更加高效和简洁。

6. 简化高可用架构

最终的高可用架构只需重点管理 Ceph 和 Kubernetes 两个核心系统即可,极大地减少了管理的复杂度和运维工作量。

目前尚未进行实际环境搭建测试,但根据上述方案,构建一套全新的 HCI 高可用架构,在网络、性能和稳定性方面应该是可行的。

总结

这篇博文我们讨论了如何通过 Ceph + Kubernetes + Windows 容器 来优化现有的虚拟化和容器化架构。相比传统的 OpenStack 和 VMware,使用 Kubernetes 管理 Windows 容器不仅能减少不必要的资源浪费,还能简化整个系统的运维。

通过这种方式,我们可以轻松地将 SQL Server、IIS 等 Windows 服务容器化,并实现一键式部署和启动,确保数据持久化。对于需要接入 Windows AD 的企业环境,还能方便地进行用户管理,并按需启动、关闭容器,节省资源。

此外,使用 Kubernetes 来管理容器网络,也不再需要复杂的 VLAN 配置,让网络管理更加简单高效。而且,随着 Ceph 和 Kubernetes 提供的高可用解决方案,未来我们只需要管理这两个系统,就能实现更高的可靠性和扩展性。

总体来说,这个方案不仅提高了效率,还能有效降低企业的运维成本,是未来 IT 基础设施发展的一个不错方向。

相关推荐
惟长堤一痕1 小时前
黑马linux入门笔记(01)初始Linux Linux基础命令 用户和权限 实用操作
linux·运维·笔记
码农君莫笑1 小时前
PowerBuilder中调用Excel OLE对象的方法
windows·excel·powerbuilder
ihengshuai2 小时前
Gitlab Runner安装与配置
前端·docker·云原生·gitlab·devops
罗汉松(山水白河)2 小时前
解除WPS登录限制
windows·经验分享·笔记·学习·wps
lida20032 小时前
Open FPV VTX开源之默认MAVLink设置
linux·ardupilot·openipc·diy drone
Nobita Chen2 小时前
Python实现windows自动关机
开发语言·windows·python
CAD芯智库3 小时前
国产信创3D- 中望3D Linux 2025发布,助力企业高效转型国产三维CAD
linux·运维·3d
李一帆'4 小时前
Windows安装Docker Desktop
windows·docker·容器
petunsecn4 小时前
Docker compose 使用 --force-recreate --no-recreate 控制重启容器时的行为
运维·docker·容器
2401_871213304 小时前
dockerfile
docker