分类目录归档:技术笔记

Linux 下 Shell 命令寻址顺序

起源

当出现 PATH 下有一个与系统命令重名的命令时,先执行哪一个呢?当 PATH 下有多个重名命令,会执行哪一个呢?这就涉及到 SHELL 执行命令的寻找顺序。

默认顺序

shel在执行命令时,并不是直接就在PATH路径中查找,而是按照固定的位置依次寻找命令。

搜索顺序如下,

1、别名,使用 alias 创建的命令。

2、关键字,如if,for。

3、函数

4、内置命令,如cd,pwd等

5、外部命令,在PATH路径中寻找

指定位置

如果我想执行的是我自己的程序cd呢?或者跳过1,2,3直接执行内置命令呢?那么这时候就用到commandbuiltin这两个命令了。

  • command ,执行PATH下的命令。
  • builtin ,执行内置命令。

PATH中的查找顺序

linux执行命令时在 PATH 中的查找顺序是从前往后查找的。

/dir1/dir2 目录下有同一个文件 test ,执行 export PATH=/dir1:/dir2:$PATH 之后,由于 dir1dir2 前面,所以执行 test 时会执行 dir1 中的 test

所以一个比较好的习惯是,导出 PATH 时将新增的路径放在前面如:

export PATH=/xxx:$PATH

参考文献

Linux虚拟化入门(五)KVM 管理命令指南

  • qemu-img是QEMU的磁盘管理工具
格式: qemu-img command [command options]
command:
        check                          对磁盘镜像文件进行一致性检查,查找镜像文件中的错误
        create                         创建一个可以指定格式、大小、名称的镜像文件
        convert                        镜像文件格式转换
        info                           展示镜像文件的信息
  • virsh kvm虚拟机管理工具
[root@node1 ~]# virsh help
command:

 Domain Management (help keyword 'domain'):
    attach-device                  从一个XML文件附加装置
    attach-disk                    附加磁盘设备
    attach-interface               获得网络界面
    autostart                      自动开始一个域
    blkdeviotune                   设定或者查询块设备 I/O 调节参数。
    blkiotune                      获取或者数值 blkio 参数
    blockcommit                    启动块提交操作。
    blockcopy                      启动块复制操作。
    blockjob                       管理活跃块操作
    blockpull                      使用其后端映像填充磁盘。
    blockresize                    创新定义域块设备大小
    change-media                   更改 CD 介质或者软盘驱动器
    console                        连接到客户会话
    cpu-stats                      显示域 cpu 统计数据
    create                         从一个 XML 文件创建一个域
    define                         从一个 XML 文件定义(但不开始)一个域
    desc                           显示或者设定域描述或者标题
    destroy                        销毁(停止)域
    detach-device                  从一个 XML 文件分离设备
    detach-device-alias            detach device from an alias
    detach-disk                    分离磁盘设备
    detach-interface               分离网络界面
    domdisplay                     域显示连接 URI
    domfsfreeze                    Freeze domain's mounted filesystems.
    domfsthaw                      Thaw domain's mounted filesystems.
    domfsinfo                      Get information of domain's mounted filesystems.
    domfstrim                      在域挂载的文件系统中调用 fstrim。
    domhostname                    输出域主机名
    domid                          把一个域名或 UUID 转换为域 id
    domif-setlink                  设定虚拟接口的链接状态
    domiftune                      获取/设定虚拟接口参数
    domjobabort                    忽略活跃域任务
    domjobinfo                     域任务信息
    domname                        将域 id 或 UUID 转换为域名
    domrename                      rename a domain
    dompmsuspend                   使用电源管理功能挂起域
    dompmwakeup                    从 pmsuspended 状态唤醒域
    domuuid                        把一个域名或 id 转换为域 UUID
    domxml-from-native             将原始配置转换为域 XML
    domxml-to-native               将域 XML 转换为原始配置
    dump                           把一个域的内核 dump 到一个文件中以方便分析
    dumpxml                        XML 中的域信息
    edit                           编辑某个域的 XML 配置
    event                          Domain Events
    inject-nmi                     在虚拟机中输入 NMI
    iothreadinfo                   view domain IOThreads
    iothreadpin                    control domain IOThread affinity
    iothreadadd                    add an IOThread to the guest domain
    iothreaddel                    delete an IOThread from the guest domain
    send-key                       向虚拟机发送序列号
    send-process-signal            向进程发送信号
    lxc-enter-namespace            LXC 虚拟机进入名称空间
    managedsave                    管理域状态的保存
    managedsave-remove             删除域的管理保存
    managedsave-edit               edit XML for a domain's managed save state file
    managedsave-dumpxml            Domain information of managed save state file in XML
    managedsave-define             redefine the XML for a domain's managed save state file
    memtune                        获取或者数值内存参数
    perf                           Get or set perf event
    metadata                       show or set domain's custom XML metadata
    migrate                        将域迁移到另一个主机中
    migrate-setmaxdowntime         设定最大可耐受故障时间
    migrate-getmaxdowntime         get maximum tolerable downtime
    migrate-compcache              获取/设定压缩缓存大小
    migrate-setspeed               设定迁移带宽的最大值
    migrate-getspeed               获取最长迁移带宽
    migrate-postcopy               Switch running migration from pre-copy to post-copy
    numatune                       获取或者数值 numa 参数
    qemu-attach                    QEMU 附加
    qemu-monitor-command           QEMU 监控程序命令
    qemu-monitor-event             QEMU Monitor Events
    qemu-agent-command             QEMU 虚拟机代理命令
    reboot                         重新启动一个域
    reset                          重新设定域
    restore                        从一个存在一个文件中的状态恢复一个域
    resume                         重新恢复一个域
    save                           把一个域的状态保存到一个文件
    save-image-define              为域的保存状态文件重新定义 XML
    save-image-dumpxml             在 XML 中保存状态域信息
    save-image-edit                为域保存状态文件编辑 XML
    schedinfo                      显示/设置日程安排变量
    screenshot                     提取当前域控制台快照并保存到文件中
    set-lifecycle-action           change lifecycle actions
    set-user-password              set the user password inside the domain
    setmaxmem                      改变最大内存限制值
    setmem                         改变内存的分配
    setvcpus                       改变虚拟 CPU 的号
    shutdown                       关闭一个域
    start                          开始一个(以前定义的)非活跃的域
    suspend                        挂起一个域
    ttyconsole                     tty 控制台
    undefine                       取消定义一个域
    update-device                  从 XML 文件中关系设备
    vcpucount                      域 vcpu 计数
    vcpuinfo                       详细的域 vcpu 信息
    vcpupin                        控制或者查询域 vcpu 亲和性
    emulatorpin                    控制火车查询域模拟器亲和性
    vncdisplay                     vnc 显示
    guestvcpus                     query or modify state of vcpu in the guest (via agent)
    setvcpu                        attach/detach vcpu or groups of threads
    domblkthreshold                set the threshold for block-threshold event for a given block device or it's backing chain element

 Domain Monitoring (help keyword 'monitor'):
    domblkerror                    在块设备中显示错误
    domblkinfo                     域块设备大小信息
    domblklist                     列出所有域块
    domblkstat                     获得域设备块状态
    domcontrol                     域控制接口状态
    domif-getlink                  获取虚拟接口链接状态
    domifaddr                      Get network interfaces' addresses for a running domain
    domiflist                      列出所有域虚拟接口
    domifstat                      获得域网络接口状态
    dominfo                        域信息
    dommemstat                     获取域的内存统计
    domstate                       域状态
    domstats                       get statistics about one or multiple domains
    domtime                        domain time
    list                           列出域

 Host and Hypervisor (help keyword 'host'):
    allocpages                     Manipulate pages pool size
    capabilities                   性能
    cpu-baseline                   计算基线 CPU
    cpu-compare                    使用 XML 文件中描述的 CPU 与主机 CPU 进行对比
    cpu-models                     CPU models
    domcapabilities                domain capabilities
    freecell                       NUMA可用内存
    freepages                      NUMA free pages
    hostname                       打印管理程序主机名
    hypervisor-cpu-baseline        compute baseline CPU usable by a specific hypervisor
    hypervisor-cpu-compare         compare a CPU with the CPU created by a hypervisor on the host
    maxvcpus                       连接 vcpu 最大值
    node-memory-tune               获取或者设定节点内存参数
    nodecpumap                     节点 cpu 映射
    nodecpustats                   输出节点的 cpu 状统计数据。
    nodeinfo                       节点信息
    nodememstats                   输出节点的内存状统计数据。
    nodesuspend                    在给定时间段挂起主机节点
    sysinfo                        输出 hypervisor sysinfo
    uri                            打印管理程序典型的URI
    version                        显示版本

 Interface (help keyword 'interface'):
    iface-begin                    生成当前接口设置快照,可在今后用于提交 (iface-commit) 或者恢复 (iface-rollback)
    iface-bridge                   生成桥接设备并为其附加一个现有网络设备
    iface-commit                   提交 iface-begin 后的更改并释放恢复点
    iface-define                   define an inactive persistent physical host interface or modify an existing persistent one from an XML file
    iface-destroy                  删除物理主机接口(启用它请执行 "if-down")
    iface-dumpxml                  XML 中的接口信息
    iface-edit                     为物理主机界面编辑 XML 配置
    iface-list                     物理主机接口列表
    iface-mac                      将接口名称转换为接口 MAC 地址
    iface-name                     将接口 MAC 地址转换为接口名称
    iface-rollback                 恢复到之前保存的使用 iface-begin 生成的更改
    iface-start                    启动物理主机接口(启用它请执行 "if-up")
    iface-unbridge                 分离其辅助设备后取消定义桥接设备
    iface-undefine                 取消定义物理主机接口(从配置中删除)

 Network Filter (help keyword 'filter'):
    nwfilter-define                使用 XML 文件定义或者更新网络过滤器
    nwfilter-dumpxml               XML 中的网络过滤器信息
    nwfilter-edit                  为网络过滤器编辑 XML 配置
    nwfilter-list                  列出网络过滤器
    nwfilter-undefine              取消定义网络过滤器
    nwfilter-binding-create        create a network filter binding from an XML file
    nwfilter-binding-delete        delete a network filter binding
    nwfilter-binding-dumpxml       XML 中的网络过滤器信息
    nwfilter-binding-list          list network filter bindings

 Networking (help keyword 'network'):
    net-autostart                  自动开始网络
    net-create                     从一个 XML 文件创建一个网络
    net-define                     define an inactive persistent virtual network or modify an existing persistent one from an XML file
    net-destroy                    销毁(停止)网络
    net-dhcp-leases                print lease info for a given network
    net-dumpxml                    XML 中的网络信息
    net-edit                       为网络编辑 XML 配置
    net-event                      Network Events
    net-info                       网络信息
    net-list                       列出网络
    net-name                       把一个网络UUID 转换为网络名
    net-start                      开始一个(以前定义的)不活跃的网络
    net-undefine                   undefine a persistent network
    net-update                     更新现有网络配置的部分
    net-uuid                       把一个网络名转换为网络UUID

 Node Device (help keyword 'nodedev'):
    nodedev-create                 根据节点中的 XML 文件定义生成设备
    nodedev-destroy                销毁(停止)节点中的设备
    nodedev-detach                 将节点设备与其设备驱动程序分离
    nodedev-dumpxml                XML 中的节点设备详情
    nodedev-list                   这台主机中中的枚举设备
    nodedev-reattach               重新将节点设备附加到他的设备驱动程序中
    nodedev-reset                  重置节点设备
    nodedev-event                  Node Device Events

 Secret (help keyword 'secret'):
    secret-define                  定义或者修改 XML 中的 secret
    secret-dumpxml                 XML 中的 secret 属性
    secret-event                   Secret Events
    secret-get-value               secret 值输出
    secret-list                    列出 secret
    secret-set-value               设定 secret 值
    secret-undefine                取消定义 secret

 Snapshot (help keyword 'snapshot'):
    snapshot-create                使用 XML 生成快照
    snapshot-create-as             使用一组参数生成快照
    snapshot-current               获取或者设定当前快照
    snapshot-delete                删除域快照
    snapshot-dumpxml               为域快照转储 XML
    snapshot-edit                  编辑快照 XML
    snapshot-info                  快照信息
    snapshot-list                  为域列出快照
    snapshot-parent                获取快照的上级快照名称
    snapshot-revert                将域转换为快照

 Storage Pool (help keyword 'pool'):
    find-storage-pool-sources-as   找到潜在存储池源
    find-storage-pool-sources      发现潜在存储池源
    pool-autostart                 自动启动某个池
    pool-build                     建立池
    pool-create-as                 从一组变量中创建一个池
    pool-create                    从一个 XML 文件中创建一个池
    pool-define-as                 在一组变量中定义池
    pool-define                    define an inactive persistent storage pool or modify an existing persistent one from an XML file
    pool-delete                    删除池
    pool-destroy                   销毁(删除)池
    pool-dumpxml                   XML 中的池信息
    pool-edit                      为存储池编辑 XML 配置
    pool-info                      存储池信息
    pool-list                      列出池
    pool-name                      将池 UUID 转换为池名称
    pool-refresh                   刷新池
    pool-start                     启动一个(以前定义的)非活跃的池
    pool-undefine                  取消定义一个不活跃的池
    pool-uuid                      把一个池名称转换为池 UUID
    pool-event                     Storage Pool Events

 Storage Volume (help keyword 'volume'):
    vol-clone                      克隆卷。
    vol-create-as                  从一组变量中创建卷
    vol-create                     从一个 XML 文件创建一个卷
    vol-create-from                生成卷,使用另一个卷作为输入。
    vol-delete                     删除卷
    vol-download                   将卷内容下载到文件中
    vol-dumpxml                    XML 中的卷信息
    vol-info                       存储卷信息
    vol-key                        为给定密钥或者路径返回卷密钥
    vol-list                       列出卷
    vol-name                       为给定密钥或者路径返回卷名
    vol-path                       为给定密钥或者路径返回卷路径
    vol-pool                       为给定密钥或者路径返回存储池
    vol-resize                     创新定义卷大小
    vol-upload                     将文件内容上传到卷中
    vol-wipe                       擦除卷

 Virsh itself (help keyword 'virsh'):
    cd                             更改当前目录
    echo                           echo 参数
    exit                           退出这个非交互式终端
    help                           打印帮助
    pwd                            输出当前目录
    quit                           退出这个非交互式终端
    connect                        连接(重新连接)到 hypervisor

参考文献

Linux虚拟化入门(四)KVM 创建一个 Centos 实例

前提条件

  • 完整 KVM 环境
  • Centos 镜像

步骤

  • 第一步、创建磁盘
qemu-img create -f qcow2 centos_kvm1.qcow2 16G
  • 第二步、安装虚拟机
virt-install \
--virt-type=kvm \
--name=centos-kvm \
--hvm \
--vcpus=1 \
--memory=1024 \
--cdrom=/srv/kvm/CentOS-7-x86_64-Minimal-1810.iso \
--disk path=/srv/kvm/centos_kvm1.qcow2,size=16,format=qcow2 \
--graphics vnc,password=kvm,listen=::,port=5911 \
--network bridge=virbr0 \
--autostart \
--force

安装成功后使用任意一个可以访问KVM宿主机的带有桌面的设备上的 VNC viewer 进入 YourIp:5911 输入密码 kvm 就可以进入虚拟机,然后继续安装了。

  • 第三步、基础操作
virsh list --all           # 查看所有运行和没有运行的虚拟机
virsh list                 # 查看在运行的虚拟机
virsh dumpxml vm-name      # 查看kvm虚拟机配置文件
virsh start vm-name        # 启动kvm虚拟机
virsh shutdown vm-name     # 正常关机

virsh destroy vm-name      # 非正常关机,强制关闭虚拟机(相当于物理机直接拔掉电源)
virsh undefine vm-name     # 删除vm的配置文件

virsh define file-name.xml # 根据配置文件定义虚拟机
virsh suspend vm-name      # 挂起,终止
virsh resumed vm-name      # 恢复被挂起的虚拟机
virsh autostart vm-name    # 开机自启动vm
virsh console <虚拟机名称>   # 连接虚拟机

install 常用参数说明展开目录

–name指定虚拟机名称
–memory分配内存大小。
–vcpus分配CPU核心数,最大与实体机CPU核心数相同
–disk指定虚拟机镜像,size指定分配大小单位为G。
–network网络类型,此处用的是默认,一般用的应该是bridge桥接。
–accelerate加速
–cdrom指定安装镜像iso
–vnc启用VNC远程管理,一般安装系统都要启用。
–vncport指定VNC监控端口,默认端口为5900,端口不能重复。
–vnclisten指定VNC绑定IP,默认绑定127.0.0.1,这里改为0.0.0.0。
–os-type=linux,windows
–os-variant=rhel6

--name      指定虚拟机名称
--ram       虚拟机内存大小,以 MB 为单位
--vcpus     分配CPU核心数,最大与实体机CPU核心数相同
–-vnc       启用VNC远程管理,一般安装系统都要启用。
–-vncport   指定VNC监控端口,默认端口为5900,端口不能重复。
–-vnclisten  指定VNC绑定IP,默认绑定127.0.0.1,这里改为0.0.0.0。
--network   虚拟机网络配置
  # 其中子选项,bridge=br0 指定桥接网卡的名称。

–os-type=linux,windows
–os-variant=rhel7.2

--disk 指定虚拟机的磁盘存储位置
  # size,初始磁盘大小,以 GB 为单位。

--location 指定安装介质路径,如光盘镜像的文件路径。
--graphics 图形化显示配置
  # 全新安装虚拟机过程中可能会有很多交互操作,比如设置语言,初始化 root 密码等等。
  # graphics 选项的作用就是配置图形化的交互方式,可以使用 vnc(一种远程桌面软件)进行链接。
  # 我们这列使用命令行的方式安装,所以这里要设置为 none,但要通过 --extra-args 选项指定终端信息,
  # 这样才能将安装过程中的交互信息输出到当前控制台。
--extra-args 根据不同的安装方式设置不同的额外选项

参考文献

Linux虚拟化入门(三)Fedora 安装 KVM 管理环境

部署步骤

  • 第一步、检查环境要求

使用如下命令检查您的 CPU 是否支持虚拟化:

$ egrep '^flags.*(vmx|svm)' /proc/cpuinfo

如果没有任何输出,则说明您的系统不支持相关扩展功能。您仍然可以使用 QEMU/KVM ,但是虚拟将只能使用软件虚拟化(想当慢)。

  • 第二步、安装虚拟化软件包

当安装 Fedora 时,可以通过勾选安装基本组中的虚拟化组以安装虚拟化软件包。

在已经完成 Fedora 安装的系统中, QEMU、KVM和其他一些虚拟化工具的安装可以通过运行如下命令安装虚拟化组:

su -c "yum install @virtualization"

该命令将安装 qemu-kvm、 python-virtinst、 qemu、 virt-manager、 virt-viewer 以及所有需要的依赖软件包。

su -c "systemctl start libvirtd"

确认所有 kvm 内核模块已正常加载:

$ lsmod | grep kvm
kvm_amd                55563  0
kvm                   419458  1 kvm_amd

如果该命令没有列出 kvm_intel 或 kvm_amd, 则说明 KVM 没有正常配置。参看 确保系统正常使用 KVM 以获得解决问题的建议。

  • 第三步、使用虚拟机

您可以使用命令行工具 virsh 管理虚拟机。 你可以在命令行下使用 virsh 工具管理guest 。 virsh 工具是基于 libvirt 管理 API 实现的:

  • virsh 有一套稳定的命令,其语法与虚拟化平台无关。
  • virsh 可以作为仅有只读权限的工具使用(如:列出所有主机及其统计信息)。
  • virsh 可以管理 Xen,Qemu/KVM,esx 及其他一些类具有相同贵发后端下的主机。

一个有效地址可以使用 “-c” 参数传递给 virsh 来连接到远程 libvirtd 实例。详情请参看 http://libvirt.org/uri.html

如下命令启动虚拟机:

su -c "virsh create <name of virtual machine>"

要列出当前运行的虚拟机,执行:

su -c "virsh list"

列出所有虚拟机(不管是否运行):

su -c "virsh list --all"

正常关闭 guest :

su -c "virsh shutdown <virtual machine (name | id | uuid)>"

强制关闭 guest :

su -c "virsh destroy <virtual machine (name | id | uuid)>"

保存虚拟机快照到文件:

su -c "virsh save <virtual machine (name | id | uuid)> <filename>"

从快照恢复虚拟机:

su -c "virsh restore 
<filename>"

导出虚拟机配置文件:

su -c "virsh dumpxml <virtual machine (name | id | uuid)"

列出全部 virsh 可用命令:

su -c "virsh help"

也可以查看手册: man 1 virsh

参考文献

Linux虚拟化入门(一)Qemu,KVM,Virsh 概念指南

当你安装了一台Linux,想启动一个KVM虚拟机的时候,你会发现需要安装不同的软件,启动虚拟机的时候,有多种方法:

  • virsh start
  • kvm命令
  • qemu命令
  • qemu-kvm命令
  • qemu-system-x86_64命令

QEMU

首先看qemu,其中关键字emu,全称emulator,模拟器,所以单纯使用qemu是采用的完全虚拟化的模式。

Qemu向Guest OS模拟CPU,也模拟其他的硬件,GuestOS认为自己和硬件直接打交道,其实是同Qemu模拟出来的硬件打交道,Qemu将这些指令转译给真正的硬件。由于所有的指令都要从Qemu里面过一手,因而性能比较差。

完全虚拟化是非常慢的,所以要使用硬件辅助虚拟化技术Intel-VT,AMD-V,所以需要CPU硬件开启这个标志位,一般在BIOS里面设置。查看是否开启

# 对于Intel CPU 可用命令判断
grep "vmx" /proc/cpuinfo 

# 对于AMD CPU 可用命令判断
grep "svm" /proc/cpuinfo 

当确认开始了标志位之后,通过KVM,GuestOS的CPU指令不用经过Qemu转译,直接运行,大大提高了速度。

所以KVM在内核里面需要有一个模块,来设置当前CPU是Guest OS在用,还是Host OS在用。

KVM

基于内核的虚拟机(英语:Kernel-based Virtual Machine,缩写为KVM)是一种用于Linux内核中的虚拟化基础设施,可将Linux内核转化为一个虚拟机监视器。

KVM提供抽象的设备,但不模拟处理器。它开放了/dev/kvm接口,供用户模式的主机使用。

https://imagehost-cdn.frytea.com/images/2021/07/05/2021070511463525bc131220fa136e.png

qemu-kvm

Qemu将KVM整合进来,通过ioctl调用/dev/kvm接口,将有关CPU指令的部分交由内核模块来做,就是qemu-kvm (qemu-system-XXX)

qemu和kvm整合之后,CPU的性能问题解决了,另外Qemu还会模拟其他的硬件,如Network, Disk,同样全虚拟化的方式也会影响这些设备的性能。

于是qemu采取半虚拟化或者类虚拟化的方式,让Guest OS加载特殊的驱动来做这件事情。

例如网络需要加载virtio_net,存储需要加载virtio_blk,Guest需要安装这些半虚拟化驱动,GuestOS知道自己是虚拟机,所以数据直接发送给半虚拟化设备,经过特殊处理,例如排队,缓存,批量处理等性能优化方式,最终发送给真正的硬件,一定程度上提高了性能。

https://imagehost-cdn.frytea.com/images/2021/07/05/202107051150145c91ed5fd0d33987.png

virsh

然而直接用 qemu 或者 qemu-kvm 或者 qemu-system-xxx 的少,大多数还是通过 virsh 启动, virsh 属于 libvirt 工具, libvirt 是目前使用最为广泛的对 KVM 虚拟机进行管理的工具和 API ,可不止管理KVM。

Libvirt 分服务端和客户端, Libvirtd 是一个daemon进程,是服务端,可以被本地的virsh调用,也可以被远程的virsh调用,virsh相当于客户端。

Libvirtd调用 qemu-kvm 操作虚拟机,有关CPU虚拟化的部分,qemu-kvm调用 kvm 的内核模块来实现

https://imagehost-cdn.frytea.com/images/2021/07/05/202107051152022b49de7970473781.png

这下子,整个相互关系才搞清楚了。

参考文献

Linux虚拟化入门(二)Hyper-V 开启 KVM 嵌套虚拟化

日常办公使用 Windows 平台,需要研究 KVM 的使用,此时就需要在 Windows 提供的 Hyper-V 工具运行 Linux 虚拟机来测试 KVM 相关的使用,但是在 Hyper-V 虚拟机中再次运行 KVM 虚拟化属于嵌套虚拟化,需要开启相关功能。

下面给出 Hyper-V 开启嵌套虚拟化的方法,默认您已经创建出一个虚拟机实例,下面的操作在虚拟实例中进行。

  • 查看 Hyper-V 虚拟机是否支持虚拟化
egrep -o 'vmx|svm' /proc/cpuinfo

没有输出说明不支持,下面进行设置,在 Windows 宿主机进行:

  • 查看虚拟机参数

关闭虚拟机,管理员权限打开 Powershell

Get-VM  ##列出虚拟机
Get-VMProcessor -VMName [KVM主机] | fl
#查看虚拟化选项参数

# 示例,ExposeVirtualizationExtensions 为 false 说明不支持虚拟化
PS C:\Users\lenovo> Get-VMProcessor -VMName Fedora-Dev | fl
ResourcePoolName                             : Primordial
Count                                        : 2
CompatibilityForMigrationEnabled             : False
CompatibilityForOlderOperatingSystemsEnabled : False
HwThreadCountPerCore                         : 0
ExposeVirtualizationExtensions               : False
EnablePerfmonPmu                             : False
EnablePerfmonLbr                             : False
EnablePerfmonPebs                            : False
EnablePerfmonIpt                             : False
EnableLegacyApicMode                         : False
AllowACountMCount                            : False
Maximum                                      : 100
Reserve                                      : 0
RelativeWeight                               : 100
MaximumCountPerNumaNode                      : 12
MaximumCountPerNumaSocket                    : 1
EnableHostResourceProtection                 : False
OperationalStatus                            : {Ok, HostResourceProtectionDisabled}
StatusDescription                            : {确定, 主机资源保护已禁用。}
Name                                         : 处理器
Id                                           : Microsoft:369F6873-EDEE-4FCB-B154-E09A3095C743\b637f346-6a0e-4dec-af52-b
                                               d70cb80a21d\0
VMId                                         : 369f6873-edee-4fcb-b154-e09a3095c743
VMName                                       : Fedora-Dev
VMSnapshotId                                 : 00000000-0000-0000-0000-000000000000
VMSnapshotName                               :
CimSession                                   : CimSession: .
ComputerName                                 : MYIEUCD_DP
IsDeleted                                    : False
VMCheckpointId                               : 00000000-0000-0000-0000-000000000000
VMCheckpointName                             :
  • 开启嵌套虚拟化
Set-VMProcessor -ExposeVirtualizationExtensions $true -VMName [KVM主机]
##将其设置为True
# 重启虚拟机,查看已支持虚拟化
# 示例,ExposeVirtualizationExtensions 已经被设置为 true

PS C:\Users\lenovo> Get-VMProcessor -VMName Fedora-Dev | fl

ResourcePoolName                             : Primordial
Count                                        : 2
CompatibilityForMigrationEnabled             : False
CompatibilityForOlderOperatingSystemsEnabled : False
HwThreadCountPerCore                         : 0
ExposeVirtualizationExtensions               : True
EnablePerfmonPmu                             : False
EnablePerfmonLbr                             : False
EnablePerfmonPebs                            : False
EnablePerfmonIpt                             : False
EnableLegacyApicMode                         : False
AllowACountMCount                            : False
Maximum                                      : 100
Reserve                                      : 0
RelativeWeight                               : 100
MaximumCountPerNumaNode                      : 12
MaximumCountPerNumaSocket                    : 1
EnableHostResourceProtection                 : False
OperationalStatus                            : {}
StatusDescription                            : {}
Name                                         : 处理器
Id                                           : Microsoft:369F6873-EDEE-4FCB-B154-E09A3095C743\b637f346-6a0e-4dec-af52-b
                                               d70cb80a21d\0
VMId                                         : 369f6873-edee-4fcb-b154-e09a3095c743
VMName                                       : Fedora-Dev
VMSnapshotId                                 : 00000000-0000-0000-0000-000000000000
VMSnapshotName                               :
CimSession                                   : CimSession: .
ComputerName                                 : MYIEUCD_DP
IsDeleted                                    : False
VMCheckpointId                               : 00000000-0000-0000-0000-000000000000
VMCheckpointName                             :
# 虚拟机上查看,已经有多个VMX,有几个就意味着有几个CPU
$ egrep -o 'vmx|svm' /proc/cpuinfo
vmx
vmx
vmx
vmx

参考文献

C++中冒号(:)和双冒号(::)的用法总结

冒号(:)用法

(1)表示机构内位域的定义(即该变量占几个 bit 空间)

typedef struct _XXX{
unsigned char a:4;
unsigned char c;
} ; XXX

(2)构造函数后面的冒号起分割作用,是类给成员变量赋值的方法,初始化列表,更适用于成员变量的常量 const 型。

// 例1
struct _XXX{
    _XXX() : y(0xc0) {}
};

相当于
struct _XXX{
    _XXX() {
        y = 0xc0;
    }
};

// 例2
class myClass
{
public :
myClass();// 构造函数,无返回类型,可以有参数列表,这里省去
~myClass();// 析构函数
int a;
const int b;
}

myClass::myClass():a(1),b(1)// 初始化列表
{
}
  • 注 1:初始化列表的作用相当于在构造函数内进行相应成员变量的赋值,但两者是有差别的。

在初始化列表中是对变量进行初始化,而在构造函数内是进行赋值操作。两都的差别在对于像 const 类型数据的操作上表现得尤为明显。我们知道,const 类型的变量必须在定义时进行初始化,而不能对 const 型的变量进行赋值,因此 const 类型的成员变量只能(而且必须)在初始化列表中进行初始化,即下面的代码将会出错:

myClass::myClass()
{
a = 1;// 没错,效果相当于在初始化列表中进行初始化
b = 1;// 出错,const变量不能进行赋值操作;
}
  • 注 2:初始化的顺序与成员变量声名的顺序相同。

先看一下下面的程序:

myClass::myClass():b(1),a(b)
{
}

这样的执行结果 a,b 各是多少呢?b=1,a=1?不是,b=1 而 a 是个随机数。这一点是相当重要的哦,一般在初始化列表中进行初始化时,初始化的顺序应与声明的顺序保持一致,防止出现不必要的错误。

  • 注 3:对于继承的类来说,在初始化列表中也可以进行基类的初始化,初始化的顺序是先基类初始化,然后再根据该类自己的变量的声明顺序进行初始化。

(3) public:private: 后面的冒号,表示后面定义的所有成员都是公有或私有的,直到下一个 public:private: 出现为止。

(4)类名冒号后面的是用来定义类的继承。

class 派生类名 :继承方式 基类名
{
派生类的成员
};

// 继承方式:public、private和protected,默认处理是public。

双冒号(::)用法

(1)表示 域操作符 / 作用域分解运算符

[cpp] view plaincopy
class CA {  
public:  
  int ca_var;  
  int add(int a, int b);  
  int add(int a);  
};   

//那么在实现这个函数时,必须这样书写:  
int CA::add(int a, int b)  
{  
  return a + b;  
}  

//另外,双冒号也常常用于在类变量内部作为当前类实例的元素进行表示,比如:  
int CA::add(int a)  
{  
  return a + ::ca_var;  
}   
//表示当前类实例中的变量ca_var

(2)全局作用域符号:当全局变量在局部函数中与其中某个变量重名,那么就可以用 :: 来区分如

char zhou; //全局变量 
void sleep()
{
    char zhou; //局部变量
    zhou(局部变量) = zhou(局部变量) * zhou(局部变量);
    ::zhou(全局变量) =::zhou(全局变量) *zhou(局部变量);
}

(3)表示引用成员函数及变量,作用域成员运算符

System::Math::Sqrt()
// 相当于
System.Math.Sqrt()

参考文献

Typecho 博客文首自动添加本页链接

自己的博客不觉间已经上线两年多了,随着内容和浏览量的增加,我的博客开始被一些搬运站盯上,常常搜索自己博客内容却在其他人博客里找到完全一样的内容,关键是还不署名!

https://imagehost-cdn.frytea.com/images/2021/06/09/20210609092801367a020d9b6ee926.png

为了防止这种脑残爬虫党,我会在博客文首新增 “本文首发于: “ 字样,后面跟上本页地址链接,这样及时博客被爬虫爬取,也会保留本文原始链接,需要的人可以通过这个链接找到我的源站。但是一篇一篇手动加起来太累了,就想了一种很简单的自动添加的方法。

https://imagehost-cdn.frytea.com/images/2021/06/09/20210609092900ae858a6c62a85958.png

方法介绍

原理大概就是在文章页首部 新增一个 `

Bullet Journal (肆)& 日常管理

不知不觉,Bullet Journal 模版系列文章就要迎来尾声啦。今天带来的是 Bullet Journal 中的核心部分 —— 日常管理。

我认为 Bullet Journal 的核心就在于其每日记录,用最快的方式回顾这一天,顺便为其加入复盘的属性,让每一天发生的特别的、有趣的事情留在你的 Bullet Journal 中。等一个月完毕,或是一年后的某一天翻开某一天的 Bullet Journal ,还能回忆起当时的那种感动。

每日一句(月末回顾)

为了统一管理每日记录的数据条目,在 Notion 首页创建一个 Journal 数据库用于存放每日的 Bullet Journal:

https://imagehost-cdn.frytea.com/images/2021/06/08/2021-06-08-11.40.3245499a34be22aea8.png

在数据库中,可以包括你希望每天记录的各种记录值,习惯养成也可以在这里记录,甚至可以记下每日的早餐、睡眠时长、运动状况等等数据,记录的越丰富,月末复盘时可以回顾更多的内容。

https://imagehost-cdn.frytea.com/images/2021/06/08/2021-06-08-11.41.584b30d8d836dd6ccf.png

之后将该数据库插入每月记录中的 Journal 标题下,用列表视图,Name 字段就作为每日一句话,可以记录今日最让我印象深刻的一件事,这样一个月下来,每天的大致情况就一目了然啦!

https://imagehost-cdn.frytea.com/images/2021/06/08/2021-06-08-11.45.51ad9120f409ecea75.png

这大概就是每日一句的内容啦,记下当天最令我印象深刻的话,就顺便再花五分钟做一个简单的复盘吧!

每日复盘(每日精进)

在每日记录模块,我结合多种日记模版,制作了一个属于自己的模版,既能快速记录当日特别的事情,又能在想记录的时候记录细节。

https://imagehost-cdn.frytea.com/images/2021/06/08/2021-06-08-11.47.543b05d241307d9812.png

主要包括四个部分:

✨ 特别的事:记录几件我认为今天最特别的事;

??‍? 进步的事:记录我认为今天做的比之前要好的事;

?? 成功故事:记录我认为今天做的最成功或是可以更好的事情;

? 特别故事:记录我认为今天有意思的小故事。

这几个部分可以按照自己的喜好分别调整,也无需强求填满,只需按照实际情况及心情、灵感状况,随性填写即可,放得开可能可以记下更多有意思的事情。如果很累,或是没什么特别的事,就简单写几条也可,重点是要每天去记录,每天去精进。 等到月末总结时,翻开每天的复盘日记,就可以一目了然想起当时发生的事情,说不定还可以想起许多有意思的回忆呢,而这一切,只需要每天抽出 5 分钟就可以完成啦!

每日打卡(习惯养成)

出了每日精进,还要记得好习惯的养成哟!在 Journal 数据库中内嵌了几个字段用于习惯养成,还做了公示统计当日的完成程度。等到月末总结时,只需简单 checked 一下,就知道这个月坚持了几天,复盘了几次,直观数据一目了然。

https://imagehost-cdn.frytea.com/images/2021/06/09/2021-06-09-12.01.53f0e2f430dfd87a67.png

好习惯一定要坚持呀!

终极模版(完全体)

至此,我的 Bullet Journal 模版系列文章正式完结!在文章的最后,祭出本人使用了数个月,反复调整后的集大成之 Bullet Journal 模版,免费提供给您克隆使用,如果好用记得评论告诉我!

Bullet Journal 个人管理模版:https://www.notion.so/Bullet-Journal-6367af1cab744eb59c33b7bd857919f3 作者:宋天伦

从 Redis 表项看 SONiC 架构

SONiC 系统的架构由各种模块组成,这些模块通过集中式和可扩展的基础架构相互交互。这个基础设施依赖于使用一个 redis-database 引擎来提供一个独立于语言的接口,一个在所有 SONiC 子系统之间进行数据持久化、复制和多进程通信的方法。

通过依赖 redis 引擎基础设施提供的 发布者/订阅者 消息传递范式,应用程序可以只订阅它们需要的数据视图,并避免与其功能无关的实现细节。

SONiC 将每个模块放置在独立的 docker 容器中。这些组件中的每一个都是完全独立于平台特定细节而编写的,这些细节是与底层抽象交互所必需的。

SONiC 容器架构

截至目前(6 Jun 2019),SONiC 将其主要功能组件分解为以下 docker 容器:

  • Dhcp-relay: 将DHCP请求从没有DHCP服务器的子网中继到其他子网的一个或多个DHCP服务器。
  • Pmon: 负责运行“sensor”,这是一个守护进程,用于定期记录硬件组件的传感器读数,并在警报发出时发出警报。Pmon容器还承载“风扇控制”进程,从相应的平台驱动程序中收集风扇相关的状态。
  • Snmp: 承载Snmp特性。
  • Lldp: 承载Lldp功能。
  • Bgp: 运行支持的路由栈之一: Quagga或FRR。(实际上,这些路由栈可以运行各种其他协议(如ospf、isis、ldp等))
  • Teamd: 在SONiC设备中运行链接聚合功能(LAG)。“teamd”是一个基于linux的LAG协议的开源实现。“团队同步”过程允许“团队”和南向子系统之间的交互。
  • Database: 承载redis-database引擎:
  • Swss: Switch State Service (Swss)容器由一组工具组成,允许所有SONiC模块之间进行有效通信,主要侧重于提供促进所有不同方之间的通信和仲裁的机制。
  • Syncd: 容器的目标是提供一种机制,允许交换机的网络状态与交换机的实际硬件/ASIC同步。这包括初始化、配置和收集交换机的ASIC当前状态。

右图显示了每个docker容器中包含的功能的高级视图,以及这些容器之间如何相互作用。注意,并不是所有的SONiC应用程序都与其他SONiC组件交互,因为其中一些组件从外部实体收集它们的状态。我们使用 蓝色箭头 表示与集中的 redis引擎 的交互,使用 黑色箭头 表示所有其他的( netlink/sys 文件系统等)。

尽管 SONiC 的大部分主要组件都在 docker 容器中,但也有一些关键模块位于 linux 主机系统本身。这就是 SONiC 的配置模块 SONiC -cfggen 和 SONiC 的 CLI

数据库架构

https://imagehost-cdn.frytea.com/images/2021/06/08/202106081716469ccbb04be94fc671.png

以下是redis引擎所承载的主要数据库:

APPL_DB:存储所有应用程序容器生成的状态——路由、下一跳、邻居等。这是所有希望与其他SONiC子系统交互的应用程序的南向入口点。

CONFIG_DB:存储由SONiC应用程序创建的配置状态——端口配置、接口、vlan等。

STATE_DB:为系统中配置的实体存储“key”操作状态。此状态用于解析不同SONiC子系统之间的依赖关系。例如,一个LAG端口通道(由teamteam子模块定义)可以潜在地引用系统中可能存在也可能不存在的物理端口。另一个例子是VLAN的定义(通过vlanmgrd组件),它可能引用系统中未确定是否存在的端口成员。本质上,这个DB存储了解决跨模块依赖关系所必需的所有状态。

ASIC_DB:存储驱动asic配置和操作所需的状态——这里的状态以asic友好的格式保存,以简化syncd(参见后面的详细信息)和asic sdk之间的交互。

COUNTERS_DB:存储与系统中每个端口关联的计数器/统计信息。此状态可用于满足CLI本地请求,或为远程使用提供遥测通道。

SONiC 子系统交互

LLDP 状态交互

下图描述了在 lldp 状态转移期间观察到的一组相互作用。在这个特定的示例中,我们迭代了在携带状态变化的 LLDP 消息到达时发生的一系列步骤。

(1)在 LLDP 容器初始化期间, lldpmgrd 订阅 STATE_DB 以实时获取系统中物理端口的状态—— lldpmgrd 的轮询周期每5秒运行一次。基于这些信息, Lldpd (及其网络对等体)将了解系统端口状态的变化以及影响其运行的任何配置变化。

(2)一个新的 LLDP 报文到达内核空间的 LLDP socket 。内核的网络栈最终将相关的有效负载交付给 lldp 进程。

(3) Lldp 解析并消化这个新状态, lldp_syncd 在执行 lldpctl cli 命令(通常每10秒运行一次)的过程中最终获取这个新状态。

Lldp_syncd 将这个新状态推到 APPL_DB 中,具体地说,推到LLDP_ENTRY_TABLE 表中。

(5)从现在开始,所有订阅这个表的实体都应该收到一个新状态的副本(目前, snmp 是唯一感兴趣的侦听器)。

https://imagehost-cdn.frytea.com/images/2021/06/08/2021060817171113f0b73ae9072558.png


SNMP 状态交互

如前所述, snmp 容器同时承载一个snmp主代理(snmpd)和一个特定于sonic的agentX进程( snmp_subagent )。该子代理与所有redis数据库/表进行交互,这些redis数据库/表提供了可以派生MIB状态的信息。具体来说, snmp-agent 订阅了以下数据库/表:

  • APPL_DB: PORT_TABLE, LAG_TABLE, LAG_MEMBER_TABLE, LLDP_ENTRY_TABLE
  • STATE_DB: *
  • COUNTERS_DB: *
  • ASIC_DB: ASIC_STATE:SAI_OBJECT_TYPE_FDB*

下图描述了系统处理传入 snmp 查询期间各种 SONiC 组件之间的典型交互。

(0)在初始化snmp-subagent进程中支持的不同MIB子组件时,该MIB子组件与上述各个db建立连接。从这一刻起,从所有这些db获得的状态被本地缓存到snmp-subagent中。该信息每隔几秒(< 60)刷新一次,以确保db和snmp-subagent完全同步。

(1)一个snmp查询到达内核空间的snmp的套接字。内核的网络栈将数据包发送给snmpd进程。

(2) snmp消息被解析,一个相关的请求被发送到SONiC的agentX子代理(即sonic_ax_impl)。

(3) Snmp-subagent服务于其本地数据结构中缓存的状态之外的查询,并将信息发送回snmpd进程。

(4) Snmpd最终通过常用的socket接口向发起者发送一个应答。

https://imagehost-cdn.frytea.com/images/2021/06/08/202106081717261c81afc21457834b.png


路由状态交互

在本节中,我们将遍历发生在SONiC中的一系列步骤,以处理从eBGP对等体接收到的新路由。我们假设这个会话已经建立,并且我们正在学习一条新的路由,它使用一个直接连接的对等体作为它的下一跳。

(0)在 BGP 容器初始化过程中, zebra 通过常规TCP套接字连接到 fpmsyncd 。在稳定/非瞬态条件下,存放在 zebralinux 内核、APPL_DBASIC_DB中的路由表应该是完全一致/等效的。

(1)一个新的TCP报文到达内核空间的bgp socket。内核的网络栈最终将相关的有效载荷传递给bgpd进程。

(2) Bgpd解析新报文,处理bgp-update,并通知zebra这个新前缀的存在及其相关的下一跳协议。

(3) zebra通过判断该前缀的可行性/可达性(例如现有的转发nh),生成一个route-netlink消息将这个新的状态注入到kernel中。 Zebra利用FPM接口将这个网络链路路由消息传递给fpmsyncd。

(5) Fpmsyncd处理netlink消息,并将此状态推入 APPL_DB

作为一个APPL_DB订阅者,它将接收先前推送到 APPL_DB 的信息的内容。

(7)处理完接收到的信息后,orchagentd会调用sairedis api将路由信息注入到ASIC_DB 中。同步一个ASIC_DB订阅者时,它将接收由orchagentd生成的新状态。

(9) Syncd将处理该信息,并调用SAI api将该状态注入到相应的asic驱动程序中。

(10)新路由最终推送到硬件。

https://imagehost-cdn.frytea.com/images/2021/06/08/20210608171744539868b84fce9068.png


端口状态交互

本节描述在端口相关信息传输过程中发生的系统交互。考虑到portsyncd扮演的关键角色,以及它在其他SONiC子系统中施加的依赖关系,我们将从介绍它的初始化过程开始本节。

这个练习有两个目的。首先,我们公开了系统中对生成或使用端口相关信息感兴趣的多个组件。其次,我们将通过一个图形示例向读者介绍 STATE_DB 在系统中是如何使用的,以及不同的应用程序如何依赖它的信息进行内部操作。

(0) 在初始化过程中,portsyncd 与redis-engine 中的主要数据库建立通信通道。Portsyncd 声明其意图充当 APPL_DBSTATE_DB 的发布者,以及 CONFIG_DB 的订阅者。同样,portsyncd 也订阅系统的 netlink 通道,负责携带端口/链路状态信息。

(1) Portsyncd 通过解析与系统中使用的硬件配置文件/sku 相关联的端口配置文件 (port_config.ini) 开始(有关更多详细信息,请参阅配置部分)。通道、接口名称、接口别名、速度等与端口相关的信息通过该通道传输到 APPL_DB

(2) Orchagent 会听到所有这些新状态,但会推迟对其采取行动,直到 portsyncd 通知它已完全解析 port_config.ini 信息。一旦发生这种情况,orchagent 将继续在硬件/内核中初始化相应的端口接口。Orchagent 调用 sairedis API 以通过通常的 ASIC_DB 接口将此请求传送到同步。

(3) Syncd 通过 ASIC_DB 接收到这个新请求,并准备调用满足 Orchagent 请求所需的 SAI API。

(4) Syncd 利用 SAI APIs + ASIC SDK 创建与正在初始化的物理端口相关联的内核主机接口。

(5) 上一步将生成一个 netlink 消息,该消息将被 portsyncd 接收。当与先前从 port_config.ini 解析的所有端口相关联的消息到达 portsyncd 时(在步骤 1 中),portsyncd 将继续声明“初始化”过程已完成。

(6) 作为上一步的一部分,portsyncd 将记录条目写入与成功初始化的每个端口对应的 STATE_DB。

(7) 从这一刻起,之前订阅了 STATE_DB 内容的应用程序将收到通知,允许这些应用程序开始使用它们所依赖的端口。换句话说,如果在 STATE_DB 中找不到特定端口的有效条目,则任何应用程序都无法使用它。

https://imagehost-cdn.frytea.com/images/2021/06/08/202106081717566d8d80df28b7b6c0.png

NOTE : As of today, these are the applications actively
listening to the changes in STATE_DB: teamsyncd, intfmgrd, vlanmgrd
and lldpmgr. We will cover all these components in subsequent
sections -- lldpmgr has been already tackled abov

现在,让我们遍历物理端口关闭时发生的一系列步骤:

(0) 正如前面概述部分中提到的,syncd 在 ASIC_DB 的上下文中既作为发布者又作为订阅者执行。“订阅者”模式显然是因为需要 syncd 从北向应用程序接收状态,就像迄今为止看到的所有模块交互的情况一样。需要“发布者”模式以允许 syncd 将硬件产生的事件到达通知更高级别的组件。

(1) 在相应 ASIC 的光模块检测到载波丢失后,将向相关驱动程序发送通知,后者又将此信息传递给 syncd。

(2) Syncd 调用适当的通知处理程序并将端口关闭事件发送到 ASIC_DB

(3) Orchagent 利用其通知线程(专用于此任务)从 ASIC_DB 收集新状态,并执行“port-state-change”处理程序以:

a.  Generate an update to APPL\_DB to alert applications relying on
    this state for their operation (e.g. CLI -- "show interface
    status").

b.  Invoke sairedis APIs to alert syncd of the need to update the
    kernel state associated to the host-interface of the port being
    brought down. Again, orchagent delivers this request to syncd
    through the usual ASIC\_DB interface.

(4) Syncd 通过ASIC_DB 接收到这个新请求,并准备调用满足orchagent 请求所需的SAI API。

(5) Syncd 使用 SAI APIs + ASIC SDK 来更新内核与受影响主机接口的最新操作状态 (DOWN)。

(6) 在 portsyncd 处接收到与上一步相关联的 netlink 消息,由于所有 SONiC 组件现在完全知道端口关闭事件,因此该消息被静默丢弃。

https://imagehost-cdn.frytea.com/images/2021/06/08/20210608171807dc16592980fabb79.png

参考文献