[翻译]Nomad运行时驱动接口

URL: https://www.nomadproject.io/docs/internals/plugins/task-drivers.html

创作任务驱动程序插件

在Nomad中编写任务驱动程序(在本文档中简称为驱动程序)包括实现DriverPlugin接口和添加主包以启动插件。驱动程序插件的寿命很长,并且其寿命不受Nomad客户端的约束。这意味着Nomad客户端可以在不重新启动驱动程序的情况下重新启动。 Nomad将确保驱动程序的一个实例正在运行,这意味着如果驱动程序崩溃或终止,Nomad将启动它的另一个实例。

驱动程序应保持尽可能少的状态。任务状态由Nomad客户端在任务创建时存储。这将启用一种模式,其中驱动程序可以维护正在运行的任务的内存状态,并且如有必要,Nomad客户端可以将任务恢复到驱动程序状态。

驱动程序插件骨架项目,可以帮助引导新驱动程序插件的开发。它提供了驱动程序插件所需的大部分样板,以及详细的注释。 我写了另一篇博客解析。

继续阅读[翻译]Nomad运行时驱动接口

[issue翻译]提议:为CNI支持虚拟机监控程序容器运行时

URL: https://github.com/containernetworking/cni/issues/251

feiskyer
Overview
CNI旨在为Linux上的应用程序容器提供基于通用插件的联网解决方案。今天有许多容器运行时实现。为了将容器网络与主机隔离,其中一些基于Linux网络 命名空间(例如docker,没有lkvm的rkt),而其他的则基于管理程序(例如rkt带有lkvmHyperContainer)。 当前的CNI设计已经支持基于网络名称空间的运行时,但不支持虚拟机管理程序。因此,该提案旨在为CNI添加虚拟机监控程序运行时支持。 当前的CNI设计已经支持基于网络命名空间的运行时,但不支持虚拟机管理程序。因此,该提案旨在为CNI添加虚拟机监控程序运行时支持。
Considerations
网络上的hypervisor和linux网络名称空间之间有很多区别:
- 虚拟机监控程序具有自己的网络栈,无需为虚拟机监控程序创建网络名称空间。相反,CNI应该为管理程序创建一个Tap设备。
- 由于网络是在系统管理程序内部配置的,因此CNI网络插件无法直接在外部配置IP地址。相反,CNI应该准备网络设备(例如,创建网桥并连接tap设备),然后将网络信息(包括设备,IP地址,网关,路由等)传递回运行时,并让运行时完成剩余工作配置工作。
Design
- 为了支持基于管理程序的运行时,应在CNI中进行一些更改:
- 让CNI知道运行时类型( hypervisor 或netns) 为基于 hypervisor 的运行时配置tap设备而非veth对
- 将网络信息传递回运行时

1) 知道运行时类型
在RuntimeConf中添加一个新字段UsesTapDevice, 例如:

type RuntimeConf struct {
    // The ID of the container
    ContainerID string
    // If set, a tap device instead of veth pair should be created
    UsesTapDevice bool
    // The network namespace path. 
    // Optional. Only need if IsHypervisor is not set.
    NetNS       string
    // Name of the interface inside the container. 
    IfName      string
    // Extra arguments
    Args        [][2]string
}

2) 配置tap设备,而不是veth对
这将是网络插件的工作。由于没有网络名称空间,因此网络插件应直接在主机上创建Tap设备。现有插件将被重构以创建用于虚拟机管理程序运行时的tap设备。
网络配置和IPAM可以保持不变,因此可以像以前一样分配容器的IP地址。

3) 将网络信息传递回运行时
Dan已经从#145开始了

feiskyer:CNI不在乎虚拟机监控程序的实现细节,它只是知道运行时基于虚拟机监控程序,并且希望使用Tap设备而不是veth对。容器运行时应将此Tap设备连接到虚拟机监控程序。

lukasredynk :我研究了 #145 ,它在接口更改方面显得更改量很大,添加像“ CNI_VIRT”这样的env并返回tap索引还不够吗?

feiskyer :添加环境可能有效,但不是那么明确。当前所有的cni插件都应该是基于netns的,它需要知道运行时明确是虚拟机管理程序。
仅返回tap索引是不够的,因为我们不希望每个插件都直接与hypervisor交互。取而代之的是,cni将创建的tap设备和相关的IP地址/掩码/网关/dns返回到运行时,并让运行时本身将其配置到虚拟机监控程序中。

lukasredynk : 抱歉,我不确切,是的,我同意。
我正在考虑的方案:

  1. Set CNI_VIRT (optional)
  2. Run plugin (from plugins/main)
  3. Plugin checks if CNI_VIRT set
    • CNI_VIRT not set: no changes in flow
    • CNI_VIRT set: creates tap instead of veth
  4. Plugin executes IPAM plugin (and passes CNI_VIRT if set)
    • CNI_VIRT not set: no changes in flow
    • CNI_VIRT set: only reserves IP and returns information about how to configure iface in VM
  5. Top-most plugin returns:
    • CNI_VIRT not set: no changes in flow
    • CNI_VIRT set: to the usual output would be added additional param "Iface *uint" in types.IPConfig

feiskyer: 确实需要一个新的环境变量(例如CNI_VIRT),但是仅此一个环境变量是不够的:
- 许多外部cni插件都在使用libcni,这当然需要知道运行时是否基于管理程序
- invoke.Args和CmdArgs还需要知道运行时是否基于虚拟机管理程序
顺便说一句,我对IsHypervisor bool不满意,您对此有何建议?也许 Virtualized bool?例如

type RuntimeConf struct {
    // If set, the runtime is based on hypervisor
    Virtualized bool
    ....
}

lukasredynk:我已经开始着手研究可以显示的代码,以进一步推动讨论,但是现在,我已经在pkg / skel / skel.go“ CNI_VIRT”中添加了放入CmdArgs的环境变量列表。 首先,我正在考虑提供ptp和bridge插件的基本实现,但我仍在努力,看来netlink库版本应该受到影响,因为所使用的版本不支持创建tun / tap设备。 感谢您指出invoke.Args,我完全错过了它,我本以为在pkg / skel / skel.go中添加文件就足够了。
关于IsHypervisor bool:也许TunTap bool,默认为false?因为可能会出现这种情况,tap优先于veth,而不与虚拟机管理程序字段相关?

jellonek : 要使用tap设备,您不必使用虚拟化,因此应该使用UsesTapDevice 而不是Virtualized 。

feiskyer: 谢谢。已将提案更新为UsesTapDevice而不是IsHypervisor。

lukasredynk:非常早期且非常WIP的分支,它为ptp插件创建和配置Tap设备:https://github.com/lukasredynk/cni/pull/1/files,这里的大部分更改与更新netlink库有关(供应商的版本不能处理 Tap设备 )。

lukasredynk:我已经使用rkt-kvm进行了测试,并且至少在默认受限网络中有效。

lukasredynk: RFC:应该如何命名接口?我认为它应该与“ veth_”不同,不要混用不同的设备类型,也许是“ tap_”,其中“ *”后缀的生成方式与veth_型接口相同。你怎么看待这件事?

lukasredynk:我更新了PR: 将CNI_VIRT更改为CNI_USE_TAP ;向libcni添加了代码路径;重构tap创建。
唯一缺少的是在netlink存储库中合并挂起的PR。

thockin :我不确定,但是对我来说,这似乎是一个错误的转折。并非所有的CNI插件都将使用veth。感觉就像是在获取内部信息并将其放在外部。您现在使每个网络插件负责了解tap设备吗?
为什么不能在CNI插件中完全完成此操作?我们是否需要在CNI API中提供一些能力以为插件提供线索,我也许可以买单。但总的来说,这对我来说很困难。只是感觉不对。

feiskyer: 是的,该建议将使每个cni插件负责理解tap设备。这是有道理的,因为CNI是所有容器(包括基于管理程序的运行时)的所有容器的通用网络接口。
可以在CNI插件中完全完成此操作 ,但是该插件不再通用。通常,所有内置网络插件(不确定这是否正确,我的意思是这里的插件)应在所有支持CNI的运行时中正常工作。

thockin : 我认为这是一个非常可疑的起点。你不能合理地 希望所有容器供应商都支持这一点。
有人对网络有图表或详尽的解释吗 为虚拟化运行时设置?我想看一个例子 设备链接在一起,以及如何配置IP路由。

lukasredynk : 遵循@jellonek的建议,我已经准备了带有更新的netlink(包括我的更改)的PR(#274),合并之后,我将使用PTP插件对原始PR进行重新设置。

lukasredynk : @thockin CNI插件无法在VM内部设置网络,因为它始终在主机上运行。对于基于systemd-nspawn的容器来说,在主机生成之前先建立网络连接并不是问题,因为主机和容器共享内核空间,但是在VM的情况下,没有直接的方法来创建虚拟接口(它将如何连接到主机上的网络?) ,请通过syscall分配IP地址并设置路由(有效执行CNI的操作),因为在生成VM之前无法执行此操作。系统管理程序也无法将veth设备附加到VM(当前由ptp,bridge和flannel插件创建)。

lukasredynk : 您可以看一下rkt中的网络(在github.com/coreos/rkt/networking:networking.go和kvm.go中):当前实现对nspawn容器使用CNI,对于基于VM的容器,使用自定义路径(使用CNI代码库)设置tap,获取路由,获取IP并将此信息传递回虚拟机监控程序(tap设备名称, 通过cli )。还创建了systemd单元文件,VM的systemd使用该文件来设置所有网络。实际上,所有插件均能通过这种“野路子”支持,但是会a)部分复制了CNI功能 b)使其难以维护。
集装箱供应商对此有何担忧?选择加入创建tap。在将特定的可选标志传递给CNI之前,它们将像以前一样工作。实际上,对于希望通过CNI处理网络配置并且还需要针对特定​​情况需要基于tap的网络的项目而言,这是很大的收获。

jellonek: 老实说-并非所有插件(ipvlan 不支持)。将这些代码从rkt移到cni 仍然可以解决很多问题-首先消除了提到项目上的代码重复,其次-为其他基于VM的运行时(例如HyperKube或vocker)提供了相同的功能。 而且,这还提供了在容器启动之前配置网络,并在结束后在其他网络上重用它的可能性。

thockin:明确地说-我理解为什么这对于超虚拟化运行时更好。我比较关注的是API的丑陋性以及现有驱动程序的想法:应该实现两种模式。只是感觉不对。
如果我有一个可以处理OVS的CNI插件-我可以将Tap设备链接到我的 OVS 设备中吗 ?
我可以在Calico上使用tap设备吗? Weave ? Contiv 呢?
为什么这比一组明确支持"仅tap设备"的新CNI插件更好 ?是“需要开放的FD”问题吗?

feiskyer : @thockin创建水龙头已启用。现有的驱动程序可以像今天一样选择仅支持基于netns的容器。你能解释为什么它很丑吗?
当然可以支持OVS 。只需稍作改动即可:连接到容器时,创建分接设备而不是veth对。
如果Calico / Weave / Contiv添加了对tap设备的支持,则也是如此。

feiskyer:
1) 减少代码重复 :
- 一个二进制和代码库都可以
- 网络插件可以执行许多步骤来设置网络,例如分配IP地址,创建网桥,设置iptables规则,设置隧道,将网桥连接到容器(通过veth对或Tap设备)。只有最后一步是不同的。两者的所有其他步骤完全相同。
2) 扩展CNI的范围,因此它可以支持所有类型的运行时,无论是netns还是hypervisor。 (否则,我们可能需要另一个专用于Tap设备的CNI)
3) 切换运行时时具有一致的用户体验,因此用户无需重写新插件即可与现有网络基础架构集成。

lukasredynk: 并且只有以下插件是受此变更集影响 :

  • ptp
  • bridge
  • macvlan
  • flannel (because internally wraps bridge plugin)

一些来自主要的CNI存储库。如果外部插件希望支持创建tap,则可以,但这不是强制性的。 AFAIK Calico仅使用ipam进行IP管理(单独管理veth),我不确定Weave,但快速浏览他们的文档后,情况似乎是这样。

thockin :您正在详细说明:
网络设备的特定类型并且使其成为API的一部分。一旦支持,就没有根据了 拒绝下一个不同的想法,而您的APi变成 混乱的条件和可选的if字段。有优雅和 简单到不透明。这感觉不是最简单的 可能的解决方案。
我们可以做一些管理程序存在于网络中的事情吗? 主机os)和net插件在所有情况下都是相同的,并委托 虚拟机管理程序的复杂性仅在管理程序中出现?
MacVLAN? IPVLAN?我的意思是您已经强迫用户 考虑他们的插件是否支持特定的操作模式 。 为什么将其作为API的一部分。
我的观点是,tap是一种非常特殊的技术。立刻 更好的东西来了,此API就过时。可能是一样的 说到netns(实际上,libnetwork甚至不公开netns,如果我 回想一下),但那是一个较低的水平,因此对我来说风险较小。
但实际上他们确实有不同的插件。它可能会使用80% 相同的代码,但是其行为和执行方式有所不同,因此它 是不同的。

thockin : 用户也可以针对不同的运行时使用相同的配置。

rosenhouse : 不要堆得太多,但我还会问我们如何计划在CI系统中测试这种虚拟机监控程序支持? Travis允许我们创建netns并在这些netns中执行插件。是否可以使用CI环境来行使管理程序代码路径?

squeed : 与其让“ ADD”命令具有两种相当不同的语义,不如在规范中添加一个附加命令?诸如“ CONFIGURE”之类的东西,它通过一个已经初始化的接口(例如,由管理程序创建tap)来由CNI插件配置?

jellonek:这将要求管理程序在调用CNI插件之前运行(这与kvm风格的rkt的当前实现的方式非常相似)。 使用当前的建议(以及  #271 中的初始实现),您可以从kubernetes网络准备过程中运行,然后将结果传递给任何基于虚拟机监控程序的运行时(这可能是kvm风格的rkt,hyperd或其他我现在正在工作的东西; ))。
仍然有可能通过网络设备(可以准备veth / tap / macv(lan | tap))作为附加的CNI“主”插件似乎很容易实现。现有的插件也可以重用它,就像它们已经在调用IPAM插件一样。
这样,我们将拥有像这样的链:
- 准备接口(可以通过插件或外部事物完成),该接口调用:
- 在调用特定设备的设备上分配ipv4 / ipv6所需的配置(地址/路由/ iptables) ,该接口调用:
- IPAM
实际上,前两个步骤在主要插件中组合在一起。 如果有人对此感兴趣-我们可以讨论这个问题,但是我看来在另外一个问题上。

翻译声明:并不保证翻译的质量,只是看都看了,顺便把零散的片段整理起来,也能够帮助同样需要的人罢了。

使用云镜像在KVM上创建一个Linux实验环境

参考自: http://giovannitorres.me/create-a-linux-lab-on-kvm-using-cloud-images.html 真可惜,发现是基于CentOS,可我的开发换是Ubuntu。其中的cloud-localds 命令找不到。

发现一个找命令的工具网站 https://command-not-found.com/cloud-localds ,安装 cloud-image-utils。

找到一个cloud-init,这应该是配套云镜像使用:

Ubuntu找到几个有意思的包:有图形化管理qemu的和使用云镜像的,有空试玩

uvtool/xenial,xenial 0~bzr99-0ubuntu1 all
  Library and tools for using Ubuntu Cloud images

uvtool-libvirt/xenial,xenial 0~bzr99-0ubuntu1 all
  Library and tools for using Ubuntu Cloud Images with libvirt

qtemu/xenial 2.0~alpha1-1ubuntu6 amd64
  graphical user interface for QEMU

ubuntu-virt-mgmt/xenial,xenial 1.4 all
  Common packages useful for managing virtual machines graphically

之前参考的文章,脚本更新了,在 https://github.com/giovtorres/kvm-install-vm。Bash包装了virt-install,仅在 Fedora 最新版上测试过。使用的 ssh-authorized-keys 登陆。这是方式一。


好了,正式开始。有一简短的教程可以参考,使用的指定password登陆。这是方式二,可能更方便些。就从这个入手了。

# Ubuntu 16.04
sudo apt install libvirt-dev libvirt0 libvirt-bin virt-top virt-manager virt-what virt-goodies genisoimage cloud-init cloud-image-utils libguestfs-tools qemu qemu-kvm
# reboot

cat > cloud-config <<EOF
#cloud-config
preserve_hostname: False
hostname: centos
fqdn: centos.example.local
password: 123456
chpasswd: { expire: False }
ssh_pwauth: True
runcmd:
  - [ yum, -y, remove, cloud-init ]
EOF

cloud-localds cloud-config.img cloud-config
mv cloud-config.img /var/lib/libvirt/images

# get the qcow2 images
wget http://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2.xz #下载 img 文件
xz -d CentOS-7-x86_64-GenericCloud.qcow2.xz
cp CentOS-7-x86_64-GenericCloud.qcow2 centos.qcow2 #复制一份
# qemu-img resize centos.qcow2 +10G #增加磁盘大小
mv centos.qcow2 /var/lib/libvirt/images

#导入
virt-install --connect=qemu:///system \
 --name centos \
 --ram 2048 \
 --vcpus=2 \
 --os-type=linux \
 --os-variant=centos7.0 \
 --disk /var/lib/libvirt/images/centos.qcow2,device=disk,bus=virtio \
 --disk /var/lib/libvirt/images/cloud-config.img,device=cdrom \
 --graphics none \
 --import

导入后可使用用户名 centos 密码 123456 登陆

virt-install第一次安装时,硬件地址,获取IP是没有问题的。之后通过Libvirt启动该磁盘镜像时,会遇到dhclient没有运行,获取不到IPv4地址的问题,需要修改镜像中网卡的IP地址,使之与Libvirt分配的硬件地址匹配。

# 手动获取IP
/sbin/dhclient -1 -q -lf /var/lib/dhclient/dhclient--eth0.lease -pf /var/run/dhclient-eth0.pid -H centos eth0

(可选)在虚拟机中安装,之后开发要用,通过该软件来获取宿主机的IP。

sudo yum install qemu-guest-agent

qemu-guest-agent是一个助手守护进程,它安装在guest中。它用于在主机和客户端之间交换信息,并在客户端执行命令。 具体特性

基于QMP实现对qemu虚拟机进行交互,qemu命令参数支持2种方法配置qmp,即-qmp和-mon。Libvirt使用的-mon。

$ virsh qemu-monitor-command centos7.0 --pretty '{ "execute": "query-block" }'
{
    "return": [
        {
            "io-status": "ok",
            "device": "drive-virtio-disk0",
            "locked": false,
            "removable": false,
            "inserted": {
                "iops_rd": 0,
                "detect_zeroes": "off",
                "image": {
                    "virtual-size": 8589934592,
                    "filename": "/var/lib/libvirt/images/centos.qcow2",
                    "cluster-size": 65536,
                    "format": "qcow2",
                    "actual-size": 2079526912,
                    "format-specific": {
                        "type": "qcow2",
                        "data": {
                            "compat": "0.10",
                            "refcount-bits": 16
                        }
                    },
                    "dirty-flag": false
                },
                "iops_wr": 0,
                "ro": false,
                "node-name": "#block155",
                "backing_file_depth": 0,
                "drv": "qcow2",
                "iops": 0,
                "bps_wr": 0,
                "write_threshold": 0,
                "encrypted": false,
                "bps": 0,
                "bps_rd": 0,
                "cache": {
                    "no-flush": false,
                    "direct": false,
                    "writeback": true
                },
                "file": "/var/lib/libvirt/images/centos.qcow2",
                "encryption_key_missing": false
            },
            "type": "unknown"
        }
    ],
    "id": "libvirt-6114"
}

$ virsh qemu-monitor-command centos7.0 --hmp 'info block'
drive-virtio-disk0 (#block155): /var/lib/libvirt/images/centos.qcow2 (qcow2)
    Cache mode:       writeback

学习qmp的简单使用

以及, 使用QEMU客户代理查找客户IP地址

# 查看支持的操作
$ virsh qemu-agent-command centos7.0 --pretty '{ "execute": "guest-info" }'
{
    "return": {
        "version": "2.12.0",
        "supported_commands": [
            {
                "enabled": true,
                "name": "guest-get-osinfo",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-get-timezone",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-get-users",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-get-host-name",
                "success-response": true
            },
            {
                "enabled": false,
                "name": "guest-exec",
                "success-response": true
            },
            {
                "enabled": false,
                "name": "guest-exec-status",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-get-memory-block-info",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-set-memory-blocks",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-get-memory-blocks",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-set-user-password",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-get-fsinfo",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-set-vcpus",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-get-vcpus",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-network-get-interfaces",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-suspend-hybrid",
                "success-response": false
            },
            {
                "enabled": true,
                "name": "guest-suspend-ram",
                "success-response": false
            },
            {
                "enabled": true,
                "name": "guest-suspend-disk",
                "success-response": false
            },
            {
                "enabled": true,
                "name": "guest-fstrim",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-fsfreeze-thaw",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-fsfreeze-freeze-list",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-fsfreeze-freeze",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-fsfreeze-status",
                "success-response": true
            },
            {
                "enabled": false,
                "name": "guest-file-flush",
                "success-response": true
            },
            {
                "enabled": false,
                "name": "guest-file-seek",
                "success-response": true
            },
            {
                "enabled": false,
                "name": "guest-file-write",
                "success-response": true
            },
            {
                "enabled": false,
                "name": "guest-file-read",
                "success-response": true
            },
            {
                "enabled": false,
                "name": "guest-file-close",
                "success-response": true
            },
            {
                "enabled": false,
                "name": "guest-file-open",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-shutdown",
                "success-response": false
            },
            {
                "enabled": true,
                "name": "guest-info",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-set-time",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-get-time",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-ping",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-sync",
                "success-response": true
            },
            {
                "enabled": true,
                "name": "guest-sync-delimited",
                "success-response": true
            }
        ]
    }
}

$ virsh qemu-agent-command centos7.0 --pretty '{ "execute": "guest-network-get-interfaces" }'
{
    "return": [
        {
            "name": "lo",
            "ip-addresses": [
                {
                    "ip-address-type": "ipv4",
                    "ip-address": "127.0.0.1",
                    "prefix": 8
                },
                {
                    "ip-address-type": "ipv6",
                    "ip-address": "::1",
                    "prefix": 128
                }
            ],
            "statistics": {
                "tx-packets": 6,
                "tx-errs": 0,
                "rx-bytes": 416,
                "rx-dropped": 0,
                "rx-packets": 6,
                "rx-errs": 0,
                "tx-bytes": 416,
                "tx-dropped": 0
            },
            "hardware-address": "00:00:00:00:00:00"
        },
        {
            "name": "eth0",
            "ip-addresses": [
                {
                    "ip-address-type": "ipv4",
                    "ip-address": "192.168.122.58",
                    "prefix": 24
                },
                {
                    "ip-address-type": "ipv6",
                    "ip-address": "fe80::5054:ff:fe28:c078",
                    "prefix": 64
                }
            ],
            "statistics": {
                "tx-packets": 247,
                "tx-errs": 0,
                "rx-bytes": 100007,
                "rx-dropped": 12,
                "rx-packets": 1531,
                "rx-errs": 0,
                "tx-bytes": 19704,
                "tx-dropped": 0
            },
            "hardware-address": "52:54:00:28:c0:78"
        }
    ]
}

新建一个会话,弹出 cloud init 初始化镜像

$ virsh list
 Id    Name                           State
----------------------------------------------------
 4     centos                         running

$ virsh change-media centos hda --eject --config
Successfully ejected media.

退出时使用 Ctrl 键+ ] (左方括号)键退出

再次命令行界面登陆 virsh console

virsh start centos
virsh list #确保running
virsh console centos

关闭virsh shutdown

$ virsh list --all
 Id    Name                           State
----------------------------------------------------
 -     centos                         shut off

之后立即禁止开机启动cloud-init,或者卸载。导致虚拟机开机启动贼慢。

$ ls /lib/systemd/system/cloud-*.service
/lib/systemd/system/cloud-config.service  /lib/systemd/system/cloud-init-local.service
/lib/systemd/system/cloud-final.service   /lib/systemd/system/cloud-init.service

$ systemctl disable cloud-config cloud-init-local cloud-final cloud-init
Removed symlink /etc/systemd/system/cloud-init.target.wants/cloud-config.service.
Removed symlink /etc/systemd/system/cloud-init.target.wants/cloud-init.service.
Removed symlink /etc/systemd/system/cloud-init.target.wants/cloud-init-local.service.
Removed symlink /etc/systemd/system/cloud-init.target.wants/cloud-final.service.

提供上述制作的镜像centos7.qcow2下载。

链接:https://pan.baidu.com/s/16PT60usy_HhxmtXD-FO-3A 
提取码:j8v1 
复制这段内容后打开百度网盘手机App,操作更方便哦

用virt-manager来启动,手动qemu启动,可能启动之后就找不到了

qemu-system-x86_64 -hda /var/lib/libvirt/images/centos7.qcow2 -enable-kvm  -vnc 0.0.0.0:0

推荐一本KVM入门书:《KVM Virtualization Cookbook》,网上有电子版


那如何在Windows上Libvirt呢? https://libvirt.org/windows.html

https://blog.csdn.net/weiyuanke/article/details/8020657


如何在Windows上使用qemu启动qcow2系统镜像?

https://www.xiexianbin.cn/windows/2017-02-16-use-qemu-start-qcow2-image-in-window/index.html

qemu-system-x86_64 -m 1024 -smp 1 -drive file="G:\VM\qemu\centos7.qcow2" -boot c -net nic -net tap,ifname=my-tap
Windows下启动的qemu虚拟机

一次永久解决cmd窗口汉字显示乱码:

  1. win+R 输入regedit 进入注册表
  2. 找到 HKEY_CURRENT_USER\Console\%SystemRoot%_system32_cmd.exe 如果 该项下已存在CodePage项,则把值改为十进制”65001”;如果不存在,在该项下新建一个 DWORD(32位值),命名为“CodePage”,值设为“65001”
  3. 重启cmd后生效
  4. 对于Power shell修改同样,只需在第2步修改
    %SystemRoot%_system32_WindowsPowerShell_v1.0_powershell.exe 下的项。

生命中一点一滴的温暖

村上春树说:你要记得那些大雨中为你撑伞的人,帮你挡住外来之物的人, 黑暗中默默抱紧你的人,逗你笑的人,陪你彻夜聊天的人,坐车来看望你的人,陪你哭过的人 在医院陪你的人,总是以你为重的人,带着你四处游荡的人,说想念你的人。是这些人组成你生命中一点一滴的温暖 是这些温暖使你远离阴霾。