作者: Sa1ka

  • CentOS 7 与 Windows 10 双系统安装

    因为某项目的需要,我被要求在一个工作站上安装 CentOS 7 和 Windows 10/11 双系统。考虑到自从研究生毕业先是参加工作后是重回学校读博,很久没有搞过太应用的东西了,而且印象中 Linux 和 Windows 10 系统两者安装起来并不是那么的一帆风顺,因此考虑认真看看具体的步骤。经过一下午的尝试和研究,发现整个安装过程中还是收获蛮大的,遂考虑将这一经历整理一下,供后续自己遇到类似问题能更快结果,当然如果能帮助到其他读者那我更是倍感欣慰。

    XFS 并不支持缩小空间!

    首先,在网上找到一个相关的教程非常容易,尤其是这种 Linux 和 Windows双系统混装的场景更是非常常见,我没花多少功夫便找到一个非常详尽的博客:centos7中安装win10搭建双系统

    由于我在开始着手这一工作时还没有拿到最终需要安装的机器,因此我考虑直接在一个 VMware Workstation 的虚拟机中安装测试。首先是比较顺利的下载CentOS 7 安装 ISO,导入到 VMware Workstation 中安装,所有配置均选择默认选项,磁盘分配了 100 GB 。因为我想完整模拟从一个仅安装了 CentOS 7 系统的机器到双系统的过程,所以我在磁盘配置里选择让 CentOS 安装程序自动为我分区。

    按照博客内容,我应该在第二步的时候将 100 GB 的空间缩小,然后把空余的空间分配到 Windows。然而,我在这一步就首先遇到了问题:CentOS 安装程序默认情况下会采用 LVM 的存储管理方法,一共分配了 3 个逻辑卷(Logical Volume),分别是 swap、root和 home,其中 root 和 home 采用 xfs 文件系统。结果当我用 gparted LiveCD 引导 gparted 图形程序打算缩小 LVM 分区时,发现完全无法缩小。使用命令行 lvreduce --resizefs -L -50G centos 命令手动缩放(https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/6/html/logical_volume_manager_administration/lv_reduce#LV_reduce),发现直接报错file system reduce is required and not supported (xfs),即xfs 不能执行 reduce 操作。因为对 xfs 并不是那么了解(经常用 Ubuntu/Debian 这类发行版的更多的和 ext4/3 等文件系统接触更多),我搜索了相关资料(https://unix.stackexchange.com/questions/619099/why-cant-we-reduce-xfs-filesystem),发现结论是

    XFS 并不支持缩小空间!

    之所以没有这样做,是因为基本上没有缩小大型文件系统的需求。存储很便宜,而且在大多数环境中,数据集和容量只会增长。

    大致意思就是说,xfs 的开发人员认为目前而言磁盘空间应该不是太大问题了,所以他们并不是很愿意增加这个功能,虽然按照 StackOverflow 的说法后续的一些 xfsutils 工具提供了体验版的缩小功能,但是我看到这个回复的时间(2021 年)后我决定直接放弃这一想法了,因为我只是做测试环境,环境应当是完全可控的。但是这里就留下来一个未来需要考虑的问题,假如**碰到那种xfs 占据了整个硬盘的系统该如何解决呢?**将所有文件全部备份再安装到一个新系统里固然可行,但是非常繁琐麻烦,如果以后有时间的话可以看看后续的新工具是否有效。

    Resizefs 选项在很多场景下不可用

    我决定绕过 xfs 的这一障碍,因此我开始重新安装了 CentOS 系统,这次我选择先让 CentOS 安装程序默认为我规划一个分区过程,然后我手动删除了 home 逻辑区,用 root 做 Linux 的根目录。安装过程非常顺利,anaconda 提供的安装程序界面也非常简洁美观。安装完毕后我顺利打开了 gparted LiveCD,结果发现 LVM 管理的磁盘分区仍然不支持直接用 gparted 来缩小,所以这次我先运行 lvreduce 命令,结果再一次碰到了问题:

    /usr/libexec/lvresize_fs_helper: execvp failed: No such file or directory
    

    看起来是缺少某个具体做 resize 工作的可执行文件,如果是在联网且系统安装完毕的环境中这个问题应该不大,但是在目前这个 LiveCD 的环境下面对这个问题是有些棘手的。我认为这个问题应当是 lvm 软件包可能缺失了一些非必需文件,讲道理不应当在这种一应俱全的 LiveCD 里出现。直接搜索这一问题有很多解决方案,可见这个问题并不是一个罕见问题,多数需要重新安装包或者做一些 patch 工作等,但是显然这些在 LiveCD 里执行太麻烦了,好在我在某个 maillist 下找到了最快的解决方案(https://bugs-devel.debian.org/cgi-bin/bugreport.cgi?bug=1065606):使用 –fs resize_fsadm 而不是 –resizefs。

    VMware SCSI 控制器大敌

    完成了 CentOS 7 的安装,也为 Windows 系统留足了存储空间,只要完成Windows 安装这一最简单的步骤,是否很快就能开始做引导调整这一核心工作了呢?答案是否定的,因为一直到这里我才了解到一个收获最大的难点。

    按照步骤打开Windows 安装程序,选择刚才分配好的 NTFS 分区安装!界面马上坡上冷水:

    嗯?这什么情况?硬盘没了?我立马重新引导 CentOS,结果一切正常啊,那看来问题应该不在硬盘这里。搜索下 Vmware、Windows、no drive等关键词,一些链接提到 ESXi下安装 Windows 可能出现这一情况,且最终答案是 SCSI 控制器的类型问题(https://answers.microsoft.com/en-us/insider/forum/all/win-10-doesnt-seem-to-install-on-vmware-it-doesnt/d277bcc1-9edf-431d-bb05-dd940ab7dbe3),但是没有找到和 Workstation 有关的。这时候我突然想到,因为我这次使用虚拟机的逻辑和往常有很大不同,一般而言虚拟机在安装后操作系统就已经确定了,一般也没有人会选择在虚拟机里装一个双系统,会不会是因为VMWare 给 CentOS 选择的支持的 SCSI 控制器和 Windows 并不那么无缝兼容(比如需要借助一些驱动程序),因此导致我换成 Windows 安装程序后无法读到原有的磁盘。经过一番查找我终于发现了https://www.nakivo.com/blog/scsi-controller-and-other-vmware-controller-types/这篇帖子,到这里我终于明白了,VMware Workstation 默认给 CentOS 7 准备的 SCSI 控制器是LSI Logic Parallel,但是 Windows 系统在 2008 版本后最佳支持的是LSI Logic SAS,这就是为什么找不到磁盘的原因。由于 ESXI 同样作为 VMware 的虚拟化产品,所以我猜想类似的解决方案应当能直接应用在 Workstation 上。最直接的解决方法当然是用额外的驱动找到原有的 SCSI 控制器(可参考这个帖子https://blog.csdn.net/weixin_42376940/article/details/113322604 ,虽然他是缺少RST 驱动),但是这样做要麻烦很多,由于在测试环境下我采用直接更改 SCSI 控制器类型的方法,由于Workstation 的管理界面并不支持直接指定类型,我直接修改vmx 文件中的scsi0:0.deviceType,根据博客信息:

    • buslogic – BusLogic SCSI
    • lsilogic – LSI Logic SCSI
    • lsisas1068 – LSI Logic SAS
    • pvscsi – VMware Paravirtual SCSI

    所以从 lsilogic 改成 lsisas1068。修改后重新开机,完美!Windows 安装程序已经能够正常运作了,但是这里就会留下另一个隐患:CentOS7 那边是不是就不能正常引导了呢?暂时不考虑这个问题,我们先按部就班把双系统引导工作做了。

    按照双系统安装博客的内容,安装好 Windows 后果然 CentOS 的引导被 Windows 覆盖了,此时系统只能进入 Windows。我重新用 CentOS 7 LiveCD 引导,选择 Troubleshooting — Rescue a CentOS System选项,让 LiveCD 自动找到CentOS 安装位置并挂载到/mnt/sysimage 目录下,然后就是chroot 操作切换到根,执行 grub2-install 和 grub2-mkconfig 操作,将 grub 和 initramdisk 问题解决。操作完成后,此时只看到了 CentOS的两个启动项,Windows 启动项没有出现,这个问题先放一下,我们先进入 CentOS 来看看。

    结果果然没那么简单,点击 CentOS 后系统迟迟没有进入,等待很久后出现了报错:

    dracut-initqueue[1697]: Warning: dracut-initqueue timeout - staring timeout scripts
    dracut-initqueue[1697]: Warning: Could not boot. 
    dracut-initqueue[1697]: Warning: dev/centos/root does not exist 
    dracut-initqueue[1697]: Warning: dev/centos/swap does not exist
    Starting Dracut Emergency Shell...
    

    也就是说,本应存在的两个LVM 分区找不到了。不算太出乎预料,我猜测应当是因为我改了 SCSI 设备的原因,导致 CentOS 已有的驱动并不能识别出来LSI Logic SAS。经过一番搜索,我找到了类似情况https://blog.csdn.net/Micha_Lu/article/details/125063992,但是帖子里对/etc/dracut.conf 文件进行了修改,然而在我的 Dracut 这个紧急情况终端下(我猜测是只有 initramfs ),根本没有/etc/、/boot 这些目录的挂载,甚至也没有大部分终端命令,只能用 journalctl 看看崩溃日志等等。

    因此这里我想到了,如果我进入到刚才用 LiveCD 引导后找到的根目录,chroot 后再执行这些功能应当可行。这样操作后我确实能够直接访问根系统了,但是发现没有/etc/dracut.conf 文件,这个我认为可能是发行版的差异问题。我在https://serverfault.com/questions/296015/change-vmware-scsi-in-redhat 这里终于知道了最终解决方案,帖子里提到 RHEL 7.0(猜想和 CentOS 7 仅仅有商业版和社区版的差别)没法通过 modprobe.conf 来应用驱动,所以应当用dracut -f -v --add-drivers mptsas 命令实现驱动在 initramfs加载,如此操作后问题终于得以解决,重启后 CentOS 7 成功引导。

    最为简单的双系统引导

    结果,我认为可能是最复杂的一个步骤反而没有遇到太大问题。成功进入 CentOS 后确实无论怎么执行 grub-install 和 grub-mkconfig 都没办法自动找到 Windows,因此我根据双系统安装帖子的方法,手动编辑/etc/grub.d/40_custem 文件,根据引导方式(BIOS 还是 UEFI)来决定添加内容。

    UEFI

    menuentry 'Windows 10' { 
      insmod part_gpt 
      insmod ntfs 
      set root='UUID=YOUR_WINDOWS_PARTITION_UUID' 
      chainloader EFI/Microsoft/Boot/bootmgfw.efi
    }
    

    UUID 可以通过 blkid 命令找到指定分区。

    BIOS

    menuentry 'Windows 10' {
      insmod part_msdos
      insmod ntfs
      set root='hd0,msdos3'
      chainloader +1
    }
    

    hd0,msdos3 指/dev/sda3,如果是其他分区则修改数字即可。

    自定义 Windows 位置后执行grub2-mkconfig -o /boot/grub2/grub.cfg 即可。

    结语

    没有想到双系统本身需要做的引导工作并不多,大部分时间竟然花在了测试环境所使用的SCSI 驱动问题上,不过总的来说还是收获不少的😄。

  • Go语言项目的组织方式

    构建方式

    最好保持传统使用make构建,避免新构建工具的构建成本

    Lint

    golangci-lint,并开启所有默认的linter规则

    文档

    doc.go存放该包的一般描述 如果一个文件放不下,那么可以准备一个docs文件夹

    Readme文件

    • 项目目标
    • 快速入门部分:开始处理项目时应该做的事情,任何依赖项,基本示例,描述项目的外部链接

    包组织方式

    最推荐的方法:在不被迫添加新包的前提下,直接将整个代码保存在根目录下,避免循环依赖 创建新包的理由:

    1. 当你有不止一种启动应用程序的方式,例如Web API和CLI共存的时候,创建一个/cmd包并包含cliweb子包,并在运行时指定到文件go run ./cmd/cli
    2. 当你想提取更详细的实现时
    3. 当你开始为密切相关的事物添加公共前缀时
    r := networkReader{}
    //
    r := network.Reader{}
    

    模块化

    两种组织方法

    1. 按种类组织
    .
    |-- handlers
    |   |-- course.go
    |   |-- lecture.go
    |   |-- profile.go
    |   |-- user.go
    |-- main.go
    |-- models
    |   |-- course.go
    |   |-- lecture.go
    |   |-- user.go
    |-- repositories
    |   |-- course.go
    |   |-- lecture.go
    |   |-- user.go
    |-- services
    |   |-- course.go
    |   |-- user.go
    |-- utils
        |-- strings.go
    

    缺点:每个类型、常量或函数都必须是公开的,才能在项目的另一部分访问;在写代码或者debug的时候,经常需要在多个包之间寻找问题。

    1. 按组件组织
    .
    |-- course
    |   |-- httphandler.go
    |   |-- model.go
    |   |-- repository.go
    |   |-- service.go
    |-- main.go
    |-- profile
        |-- httphandler.go
        |-- model.go
        |-- repository.go
        |-- service.go
    

    缺点:容易发生相互依赖的问题 例如,想在用户的个人资料上显示最近的课程,从个人资料的角度上来看,课程是一种外部依赖,解决方法是在profile下创建一个接口。

    type Courses interface {
        MostRecent(ctx context.Context, userID string, max int) ([]course.Model, error)
    }
    

    然后在course包中,公开实现该接口的服务

    type Courses struct {
        // 一些不能导出的变量
    }
    
    func (c Courses) MostRecent(ctx context.Context, userID string, max int) ([]Model, error) {
        // 实现逻辑
    }
    

    最后,在main.go中从course包中创建Courses实例并传递给profile包,便可以在不引发循环依赖的情况下实现该功能。此外,写profile的测试时,可以直接mock创建一个实现,甚至可以在没有course实现包的情况下开发和测试profile的功能。

    简洁架构

    应用程序或模块有4层,分别是Domain、Application、Ports、Adapters。

    • Domain:业务核心,没有外部依赖,不应该知道代码是在哪个上下文执行的
    • Application:应用程序用法的粘合点,所有Domain、Ports、Adapter的逻辑串联位置
    • Ports: 用户输入,获取信息后传入给Application
    • Adapters: 与外部通信,存储和获取数据,对低层细节的抽象。
  • Consul 学习

    consul agent -dev启动一个调试用的Consul agent,该agent运行在Server模式下。使用 <kbd>Ctrl</kbd> + <kbd>C</kbd>

  • 解决Xcode编译时因库文件CPU架构导致无法在 iOS Simulator运行的问题

    最近在编译mlc-llm的iOS客户端时,遇到了一个无法编译通过的问题。具体来说,mlc-llm的iOS客户端在编译时需要多个a库文件,生成过程按照mlc-llm的README介绍(包括在iOS目录下的README)编译生成,库的具体作用在mlc-llm项目中有详细描述,与编译问题无关故这里不再赘述。

    如果直接按照流程编译app在真机(我使用的是iPhone 14 Pro Max)上运行则没有问题,但如果是选择build target为Simulator时就会出现building for iOS Simulator, but linking in object file built for iOS, for architecture arm64的提示。

    一开始的时候我直接在StackOverflow上进行搜索,大部分的答案都指向了这个链接https://stackoverflow.com/questions/63607158/xcode-building-for-ios-simulator-but-linking-in-an-object-file-built-for-ios-f?answertab=modifieddesc#tab-top,其中最完整的解释了这个问题的帖子是https://stackoverflow.com/a/76270278

    简单来说,Xcode编译时iOS和iOS Simulator作为两种不同的build target,iOS Simulator运行时需要a文件同时包括x86_64和arm64两种架构的库函数,而iOS运行时仅需要arm64(因为所有的iOS设备的CPU都是ARM架构的)。从这个链接里可以看出来Xcode这种报错很常见了,大部分人提供的解决方案是:

    1、开启Release编译模式的Build Active Architecture Only

    2、设置EXCLUDED_ARCHS项,或者在Build选项中指定Excluded Architectures,对于DEBUG和RELEASE选项均设置Any iOS Simulator SDK中指定过滤掉arm64

    如果我们在编译这些a文件的时候完全按照mlc-llm的教程,那么可以发现只包含了arm64(可以使用lipo -info来查看a文件信息),所以如果我们不做任何修改的话,那么由于不包含x86_64的,无法通过Xcode的编译。考虑使用上述提到的两种解决方案,编译确实能够通过,但是仍然无法运行。

    这个时候我就想到了,因为我现在使用的是M2的Mac进行的编译,如果exclude掉了arm64,此时运行库里就并没有arm64的库了。遵循这个思路,那么是不是我们把exclude里的arm64换成x86_64就可以了呢?然而答案是否定的,Xcode仍然会提示缺少框架可用的库,并提示说需要联系vendor提供所有架构的函数库。也就是说运行在Apple Silicon上的iOS Simulator一定要保证APP所需的库包含x86_64和ARM64两种。这个地方我仍然有疑问,按道理说我在M2芯片的Mac上的iOS Simulator应该也是ARM64架构的(已经通过活动监视器确认),那么为什么会一定需要intel架构的库呢?

    再次搜索相关的信息,发现有人提到使用Rosetta来运行Xcode可以解决这个问题,我没有去尝试这个方案,一是觉得Rosetta运行的速度会大打折扣,二是觉得我本来就是一个Apple Silicon的机器,为何需需要Rosetta来运行Xcode的x86部分然后再转成一个ARM来运行。更何况,我们编译得到的库本来就缺少x86。

    最终,我决定更换思路,不考虑从Xcode编译这边来解决问题,而是按照提示把a库文件的x86部分补充上。分析mlc-llm的源代码,发现大部分库文件是由C++编写而成,因此只需要替换掉prepare_libs.sh文件中的运行CMake的CMAKE_OSX_ARCHITECTURES选项,由arm64修改为arm64;x86_64即可得到包含两种架构的库文件。

    然而,仅仅修改了这里并不能完全解决问题,虽然我们从Xcode的编译结果来看报错的库减少为只有两个了,但是仍然是有两个库报错,仔细查看CMakeList文件,可以发现这两个库中的libtokenizers_c.a这个文件是单独由rust编译而来,因此需要单独处理,我这边是在编译脚本文件中添加了rustup target add x86_64-apple-ios,然后重新编译后再用lipo -create aarch64-apple-ios/release/libtokenizers_c.a ../../x86_64-apple-ios/release/libtokenizers_c.a -output libtokenizers_c.a将两种架构的库整合为一个。这样操作后解决了问题,APP也成功在iOS Simulator中成功运行。不过,这里又留下了一个疑问,我使用lipo查看libmodel_iphone.a文件时发现这个库文件其实仅仅包含了arm64,但是这一次我没有做任何处理Xcode也没有报错了,合理推测是这个库用到的函数仅仅只被某些特定LLM模型使用,或者是Simulator运行过程中暂时没有用到。

  • 通过WIM的方式控制Windows

    首先需要开启windows中WIM服务,并且授权所有用户都能够进行访问(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system中LocalAccountTokenFilterPolicy设置成1)。

    其次,如果要支持psexec,还需要开启C盘的文件共享

    如果在linux下,使用到的是impacket里的psexec和wimexec工具。(使用时注意windows的防火墙和Windows defender)

    clone下来后在examples里面找到相关工具,不过首先需要先pip install这个包。

    使用方法参考: https://www.freebuf.com/sectool/175208.html https://blog.csdn.net/qq_37077262/article/details/103979530

    此外,可以在windows中直接用wbemtest工具来检查WIM的相关状况。

  • Win10 高版本不支持SNMP的解决方法

    参考:snmp-service-on-windows-10

    Win10 1809版本之后直接去掉了SNMP的支持,改成用自家的CIM模型来配置Windows Remote Management。如果仍然需要SNMP的配置,那么需要使用FoD(features on demand)的方法来安装。

    在管理员权限的powershell里输入

    Add-WindowsCapability -Online -Name "SNMP.Client~~~~0.0.1.0"
    

    或者是DISM的方式

    DISM /online /add-capability /capabilityname:SNMP.Client~~~~0.0.1.0
    

    检查是否安装成功

    Get-WindowsCapability -Online -Name "SNMP*"
    

    卸载方式

    Remove-WindowsCapability -Online -Name "SNMP.Client~~~~0.0.1.0"
    

    为了让SNMP能够访问,还需要进行相关的配置

  • LXD中Windows VM的初始化方法

    基本思路:使用Cloudbase-init,在容器初始化的时候将需要配置的IP地址配置信息填入到LXD容器的config里,借助LXD的配置功能为每一个VM配置一个名字为tzdata的光盘镜像,cloudbase-init在windows vm启动时自动读取镜像,将需要的配置执行。

    华为云对cloudbase-init工具的介绍

    Cloudbase-init基本原理类似于cloud-init,只是由于cloud-init并没有提供对windows的支持才有了cloudbase-init,这个工具可以在虚拟机首次启动时根据某一些信息来初始化VM,使得VM在云基础设施上配置时可以完全自动化。这些信息来源是通过Service来确定的,例如各个云平台的自定义初始化方法(AWS、GCP),或者一些通用的虚拟机话基础设施(OpenStack、MaaS、VMware),具体的Service在文档中有详细描述(https://cloudbase-init.readthedocs.io/en/latest/services.html#nocloud-configuration-drive)。每一个Service又支持多个Plugin来配置不同的设置。

    由于LXD本身对于虚拟机的支持还是experimental,大部分的qemu配置都很难直接应用在LXD config里(有一个raw.qemu但也只是单纯将其参数补充在qemu运行命令之后),对于Windows的支持就更少了。好在LXD支持添加一个名为cloud-init:config的device,结合填入的user.meta-data等等参数即可以自动完成cloud-init初始化光盘的创建和连接。为了让cloud-init初始化光盘的配置能应用在cloudbase-init上,我们需要选择cloudbaseinit.metadata.services.nocloudservice.NoCloudConfigDriveService 这个配置和cloud-init的配置基本上是一致的,但是需要注意的是对于网络配置而言只能选择cloud-init的V1版本,对于V2版本(即官方宣称的network-config配置文件)是不能使用的(非常确定,因为我已经到源码里找了V2实现是空的)。

    V1版本的配置方法也非常讲究,通过分析源码我发现他针对每一个网络端口并不是根据名称来配置的,而是根据MAC地址,因此如果需要修改的名字也只需要在配置项中指定即可。

    network-interfaces:|
      iface Ethernet0 inet static
      address 10.0.0.2
      network 10.0.0.0
      netmask 255.255.255.0
      broadcast 10.0.0.255
      gateway 10.0.0.1
      hwaddress ether 00:11:22:33:44:55
    

    还有需要注意的一点是,如果是使用lxc工具使用edit修改的VM config,那么yaml需要从那一项开始对齐。例如

    Config:
      user.meta-data: |
        network-interfaces: |
          iface Ethernet0 inet static
    .…
    

    如果顶头写的话,那么lxc在解析修改后的yml文件时认为是无效参数直接忽略掉,而且不会有任何报错提示。因此,在修改lxc config后一定要再show一次检查一下是否修改成功。

    完成配置后,可以检查虚拟机里的配置是否正常了,但是这里又出现了一个问题是,cloudbase-init在完成了一次修改后会在注册表里写入一些信息,这样第二次启动的时候就会检查有无相关信息,如果有那么会直接跳过配置项。这种策略在我们调试cloudbase-init配置的时候很麻烦。解决方法是,手动在具有管理员权限的powershell里执行(https://ask.cloudbase.it/question/1334/sethostnameplugin-execution-already-done/)

    Remove-Item -Recurse "HKLM:\\Software\Cloudbase Solutions"
    
  • LXD使用ZFS做存储后端的扩容方法

    以使用lxd init初始化创建的default ZFS存储池为例,如果是apt安装版本则该存储文件在/var/lib/lxd/disks/default.img,以snap方式安装的则在/var/snap/lxd/common/lxd/disks/default.img,对该文件进行扩容处理。

    在操作之前首先保证自己有root权限,安装有zfsutils-linux,并保证所有的LXD容器均处于stop状态

    这里以增加20G容量为例。

    truncate -s +20G /var/lib/lxd/disks/default.img
    zpool set autoexpand=on default
    device=$(zpool status -vg default)
    zpool online -e default $device
    zpool set autoexpand=off default
    service lxd restart
    

    接下来就可以用lxc storage info default命令查看default存储池的扩容情况了。

  • 使用VMware vctl工具创建K8s集群

    vctl是VMware最新开发的一个CLI工具,主要是用来创建满足OCI标准的容器。vctl包含在VMware Workstation Pro 16 和 VMware Fusion 12以上版本中。

    使用vctl

    首先在使用vctl之前,我们首先需要知道,该工具只是一个管理前端,真正的容器操作是由守护进程来实现的。因此在使用该命令之前,我们要首先检查守护进程的状态(默认情况下是关闭的)。vctl的容器运行时包括三个文件:

    • bin/containerd:这个进程就是用来执行容器相关指令的,检查方法是vctl system info,开启方法是vctl system start,结束方法是vctl system stop
    • bin/containerd-shim-crx-v2:看到shim这个词,应该能够从docker联想到是用来作为容器根进程的,工作在CRX VM的容器和containerd进程之间。
    • bin/vctl:这个就是我们上面提到的前端管理工具。

    上面我们提到了CRX VM,这个其实就是VMware专门用来运行容器的轻量级虚拟机,只要有一个容器创建那么就会开启一个CRX VM,同样删掉这个容器这个VM就会停止并删除。容器名和CRX VM的名字是一样的。

    vctl的基本命令和docker完全一致,这也就是说,ps/run/start/stop/rm/rmi/build/create等命令都可以使用相同的方式使用。这里作为示例,给出一个nginx容器的创建过程。

    vctl pull nginx
    vctl run --name=myNginx -t -p 8888:80 -d nginx
    vctl ps -a
    vctl stop nginx
    vctl rm nginx
    vctl rmi nginx
    

    可以从任务管理器上看到相关进程的启动情况。

    进程图

    vctl的详细使用方法可以参考VMware的官方文档

    创建k8s集群

    从上面我们可以看到,vctl提供了类似于docker的容器管理功能,那么现在要创建k8s集群,只需要使用类似kubeadm的工具创建多个容器构成k8s的运行环境即可。这其中,KIND就是一个比较好用的k8s安装工具。从VMware Fusion 12开始,vctl工具提供了KIND的支持。使用方法也非常简单,只需要运行vctl kind即可。这条命令会做四件事情:

    • 在用户目录下创建一个.vctl文件夹

    • 下载kubectlkindcrx.vmdk三个文件,保存在bin目录下

    • 创建一个名为docker的链接文件,指向vctl

    • 创建一个基于vctl的KIND上下文,主要是将~/.vctl/bin文件夹加入到PATH环境变量中

    运行这条命令后,会弹出一个新的终端,这个终端上的kubectl、kind、docker等命令均指向的是刚才安装的KIND上下文环境,而不是原先系统安装的。

    需要注意的是,vctl并不支持kind buildkind export logs命令,且CRX VM的默认配置是2G 2C。

    现在已经有了kind的环境了,剩下的事情就交给kind了。KIND文档

    最简单的命令,kind create cluster

    C:\Program Files (x86)\VMware\VMware Workstation\bin>kind create cluster
    Creating cluster "kind" ...
     • Ensuring node image (kindest/node:v1.18.2) ?  ...
     ✓ Ensuring node image (kindest/node:v1.18.2) ?
     • Preparing nodes ?   ...
     ✓ Preparing nodes ?
     • Writing configuration ?  ...
     ✓ Writing configuration ?
     • Starting control-plane ?️  ...
     ✓ Starting control-plane ?️
     • Installing CNI ?  ...
     ✓ Installing CNI ?
     • Installing StorageClass ?  ...
     ✓ Installing StorageClass ?
    Set kubectl context to "kind-kind"
    You can now use your cluster with:
    
    kubectl cluster-info --context kind-kind
    
    Thanks for using kind! ?
    

    使用kubectl cluster --context kind-kind可以看看刚刚创建的k8s集群状态。

    C:\Program Files (x86)\VMware\VMware Workstation\bin>kubectl cluster-info --context kind-kind
    Kubernetes master is running at https://127.0.0.1:64039
    KubeDNS is running at https://127.0.0.1:64039/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    
    To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
    
    

    此时,kubectl get nodeskubectl get pods等命令已经可以正常使用了,我们已经使用vctl创建了一个单节点的k8s环境。

    看看原理

    安装过程到这里就差不多了,更复杂的k8s集群只需要在kind中传入自定义的配置文件即可。如果这个时候我们使用docker ps命令查看真正用来承载k8s集群的容器,就会发现实际上只有一个容器在运行。

    C:\Program Files (x86)\VMware\VMware Workstation\bin>docker ps -a
    ────                 ─────                                                                                  ───────                   ──                ─────            ──────    ─────────────
    NAME                 IMAGE                                                                                  COMMAND                   IP                PORTS            STATUS    CREATION TIME
    ────                 ─────                                                                                  ───────                   ──                ─────            ──────    ─────────────
    kind-control-plane   kindest/node@sha256:7b27a6d0f2517ff88ba444025beae41491b016bc6af573ba467b70c5e8e0d85f   /usr/local/bin/entry...   192.168.100.132   64039:6443/tcp   running   2020-09-17T16:50:22+08:00
    

    是不是感觉很奇怪,因为如果你尝试过其他的安装方法,应该会有印象,那就是k8s的运行组件相当多,控制节点的apiServerschedulercontroller-manager以及计算节点上kubelet这些在其他安装方法中一般都是由独立的容器来运行的,那么在这里为什么会只有一个呢?

    通过查阅KIND文档可以发现,原来KIND使用node-image来运行这些组件,例如kubeadmkubelet等等,而这些运行依赖和node-image本身则是由base-image来生成的。生成过程我们可以不用关心,现在让我们主要来看看node-image这个镜像生成的单个容器是如何运行所有的k8s组件。

    使用docker exec -it kind-control-plane /bin/bash进入到容器中,首先ps看看运行的进程。

    root@kind-control-plane:/kind# ps ajxf
     PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
        0  6178  6178  6178 pts/3     6913 Ss       0   0:00 /bin/bash
     6178  6913  6913  6178 pts/3     6913 R+       0   0:00  \_ ps ajxf
        0     1     1     1 ?           -1 Ss       0   0:00 /sbin/init
        1   104   104   104 ?           -1 S<s      0   0:00 /lib/systemd/systemd-journald
        1   113   113   113 ?           -1 Ssl      0   0:18 /usr/local/bin/containerd
        1   311   311   113 ?           -1 Sl       0   0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 00d79d58327ca059b96cdd9c651d12853a2e2622e65472230414dc15d65821bd -address /run/containerd/con
      311   405   405   405 ?           -1 Ss       0   0:00  \_ /pause
      311   507   507   507 ?           -1 Ssl      0   0:38  \_ kube-controller-manager --allocate-node-cidrs=true --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf --authorization-kubeconfig=/etc
        1   322   322   113 ?           -1 Sl       0   0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 482207771a3b7eba237dc037dba4f5717e54842f7bf38d367f391030a9091f38 -address /run/containerd/con
      322   401   401   401 ?           -1 Ss       0   0:00  \_ /pause
      322   547   547   547 ?           -1 Ssl      0   1:56  \_ kube-apiserver --advertise-address=192.168.100.132 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/etc/kubernetes/pki/ca.crt
        1   323   323   113 ?           -1 Sl       0   0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 5101a9a24071e5c10d052d01918361dee8a97a2822b4bb82bc772460ce0045a2 -address /run/containerd/con
      323   399   399   399 ?           -1 Ss       0   0:00  \_ /pause
      323   586   586   586 ?           -1 Rsl      0   0:47  \_ etcd --advertise-client-urls=https://192.168.100.132:2379 --cert-file=/etc/kubernetes/pki/etcd/server.crt --client-cert-auth=true --data-dir=/var/lib/
        1   324   324   113 ?           -1 Sl       0   0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id e68a9f43205edd282548f6db0942c0c0b503a66894b8bf5e3d7d1b7e5be8a71d -address /run/containerd/con
      324   404   404   404 ?           -1 Ss       0   0:00  \_ /pause
      324   500   500   500 ?           -1 Ssl      0   0:10  \_ kube-scheduler --authentication-kubeconfig=/etc/kubernetes/scheduler.conf --authorization-kubeconfig=/etc/kubernetes/scheduler.conf --bind-address=127
        1   632   632   632 pts/0      632 Ssl+     0   0:50 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.
        1   810   810   113 ?           -1 Sl       0   0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 6bb16a0dfa1b006c0c241d54f84c8fc17d719ca791f482ede021e0a9ae118eec -address /run/containerd/con
      810   860   860   860 ?           -1 Ss       0   0:00  \_ /pause
      810   928   928   928 ?           -1 Ssl      0   0:01  \_ /usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.conf --hostname-override=kind-control-plane
      928   986   983   928 ?           -1 Z        0   0:01      \_ [iptables-nft-sa] <defunct>
        1   837   837   113 ?           -1 Sl       0   0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id e17005058a2afb322c2c9179d5468b65be0bd8c2a24e3774373988413c93a7ec -address /run/containerd/con
      837   877   877   877 ?           -1 Ss       0   0:00  \_ /pause
      837   935   935   935 ?           -1 Ssl      0   0:00  \_ /bin/kindnetd
      935   994   992   935 ?           -1 Z        0   0:00      \_ [iptables-nft-sa] <defunct>
        1  1108  1108   113 ?           -1 Sl       0   0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 905595d932140fd9406ae9487893d6e6351b15f33ab39528a4da00650df485ec -address /run/containerd/con
     1108  1131  1131  1131 ?           -1 Ss       0   0:00  \_ /pause
     1108  1160  1160  1160 ?           -1 Ssl      0   0:03  \_ local-path-provisioner --debug start --helper-image k8s.gcr.io/debian-base:v2.0.0 --config /etc/config/config.json
        1  1244  1244   113 ?           -1 Sl       0   0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 410e09a86cb001d1b40378e153406d7a1c85c9f04f3e68ded23dc19c1fe50940 -address /run/containerd/con
     1244  1305  1305  1305 ?           -1 Ss       0   0:00  \_ /pause
     1244  1380  1380  1380 ?           -1 Ssl      0   0:08  \_ /coredns -conf /etc/coredns/Corefile
        1  1252  1252   113 ?           -1 Sl       0   0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 0fdc07bfbd62610b783122e3d8dca8f5b1ad2a1aa07f2bb7b1194df280116957 -address /run/containerd/con
     1252  1294  1294  1294 ?           -1 Ss       0   0:00  \_ /pause
     1252  1374  1374  1374 ?           -1 Ssl      0   0:08  \_ /coredns -conf /etc/coredns/Corefile
    

    那么从这里看就可以看出来KIND的构建方法了,在kind-control-plane这个容器中运行由kubelet程序用来支持一个运行节点,控制节点所需要的组件则是由内置的一个containerd来运行的,使用ctr -n k8s.io containers ls命令可以更加直观的看到。

    root@kind-control-plane:/kind# ctr -n k8s.io containers ls
    CONTAINER                                                           IMAGE                                               RUNTIME
    00d79d58327ca059b96cdd9c651d12853a2e2622e65472230414dc15d65821bd    k8s.gcr.io/pause:3.2                                io.containerd.runc.v2
    07dd95f8b88f11974154232d894e1ac9be76dec8c7e88c74a5d7f611d4bf94a0    k8s.gcr.io/kube-controller-manager:v1.18.2          io.containerd.runc.v2
    0fdc07bfbd62610b783122e3d8dca8f5b1ad2a1aa07f2bb7b1194df280116957    k8s.gcr.io/pause:3.2                                io.containerd.runc.v2
    410e09a86cb001d1b40378e153406d7a1c85c9f04f3e68ded23dc19c1fe50940    k8s.gcr.io/pause:3.2                                io.containerd.runc.v2
    470d408aa74f66355ab637295a8e4777ec6775f84aba75a17efa861e5ede6470    k8s.gcr.io/kube-scheduler:v1.18.2                   io.containerd.runc.v2
    482207771a3b7eba237dc037dba4f5717e54842f7bf38d367f391030a9091f38    k8s.gcr.io/pause:3.2                                io.containerd.runc.v2
    5101a9a24071e5c10d052d01918361dee8a97a2822b4bb82bc772460ce0045a2    k8s.gcr.io/pause:3.2                                io.containerd.runc.v2
    652f25e9876c8efaae6b21f7289bfd88372ce9ec4ae6593f9e1c81bb3f513ddd    k8s.gcr.io/etcd:3.4.3-0                             io.containerd.runc.v2
    6bb16a0dfa1b006c0c241d54f84c8fc17d719ca791f482ede021e0a9ae118eec    k8s.gcr.io/pause:3.2                                io.containerd.runc.v2
    7f9f6cd14c83c08f5906a280f7fc5b178e766c0e4bb137a316d35c61f05c5031    k8s.gcr.io/kube-apiserver:v1.18.2                   io.containerd.runc.v2
    905595d932140fd9406ae9487893d6e6351b15f33ab39528a4da00650df485ec    k8s.gcr.io/pause:3.2                                io.containerd.runc.v2
    c90fa3e64763263042ac6f29657e3a76de67a90308b9c7cf3a5cefbeda6788c8    k8s.gcr.io/kube-proxy:v1.18.2                       io.containerd.runc.v2
    d0c86ec34d96251e5bc4992183b21021c803e033463f581de9adf3bdadd4b4c8    k8s.gcr.io/coredns:1.6.7                            io.containerd.runc.v2
    d43682f949020c15ff5a7997bfbd872fd6959949962e57e9ccfaf4633ae77039    k8s.gcr.io/coredns:1.6.7                            io.containerd.runc.v2
    dbabbb66c17ba1317706b3e13a473b7e52653d6097f1fb4e71ca3aca51c17e37    docker.io/rancher/local-path-provisioner:v0.0.12    io.containerd.runc.v2
    e17005058a2afb322c2c9179d5468b65be0bd8c2a24e3774373988413c93a7ec    k8s.gcr.io/pause:3.2                                io.containerd.runc.v2
    e68a9f43205edd282548f6db0942c0c0b503a66894b8bf5e3d7d1b7e5be8a71d    k8s.gcr.io/pause:3.2                                io.containerd.runc.v2
    f49eaf48b0b9ac0ef29d5dc6a8c3b8e26c9dd9a681715e8f431ad6ec4d452dbd    docker.io/kindest/kindnetd:0.5.4                    io.containerd.runc.v2
    

    这里还有一个疑问,大部分容器引擎在Nesting运行的时候是需要做一定设置的,然而在containerd这里我没有看到额外的设置。是containerd原生就支持nesting运行还是说这是因为vctl的特殊运行方式(指一个容器一个VM)就不得而知了,未来有空会看看原理。

  • Suricata学习

    Suricata是一款开源免费的网络威胁检测系统,可以在网络中作为IDS(Intrusion Detection System,入侵检测系统)、IPS(Intrusion Prevention System,入侵防御系统)和NSM(Network Security Monitoring,网络安全监控)使用,同样还可以离线分析pcap文件。Suricata使用专门的语言编写的规则来对网络流量进行分析,还可以利用Lua脚本来更加精确地分析,并以类似YAML或JSON的形式输出,可以方便存储在数据库中。目前Suricata项目属于OISF所有,OISF是一个非营利组织。

    Installation

    Suricata和其他的Linux软件类似,也具有两种安装方法,即直接安装发行版和编译安装。

    PPA安装法

    以下操作均在Ubuntu 16.04中,其他发行版可以查阅官方wiki。

    sudo add-apt-repository ppa:oisf/suricata-stable
    sudo apt-get update 
    sudo apt-get install suricata 
    

    编译安装法

    首先需要安装程序依赖库

    sudo apt-get -y install libpcre3 libpcre3-dbg libpcre3-dev \
    build-essential autoconf automake libtool libpcap-dev libnet1-dev \
    libyaml-0-2 libyaml-dev zlib1g zlib1g-dev libcap-ng-dev libcap-ng0 \
    make libmagic-dev libjansson-dev libjansson4 pkg-config
    

    下载源码

    VER=3.1
    wget "http://www.openinfosecfoundation.org/download/suricata-$VER.tar.gz" 
    tar -xvzf "suricata-$VER.tar.gz" 
    cd "suricata-$VER" 
    

    配置安装

    ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var
    make
    sudo make install
    sudo ldconfig
    

    Suricata还提供了一些自动安装的脚本

    make install-conf 自动创建和安装配置文件
    make install-rules 自动从Emergeing Threats下载最新的规则集
    make install-full 将上面两者都包括
    

    Setup

    接下来我们需要部署Suricata,保证下面的命令均具备管理员权限。

    mkdir /var/log/suricata # 日志信息
    mkdir /etc/suricata # 配置文件
    cp classification.config /etc/suricata
    cp reference.config /etc/suricata
    cp suricata.yaml /etc/suricata
    

    /etc/suricata/suricata.yaml文件中正确配置好变量。HOME_NET设置为本地网络的IP地址,而EXTERNAL_NET建议的设置值是!$HOME_SET,这样所有不是本地IP的流量均被当作外界地址,当然设置成any也是可以的,只是这样的话会产生一些假的警报。下面的一些服务器均会被默认设置为$HOME_NETAIM_SERVERS设置为any

    Run

    Suricata的运行方式比较简单,只需要选择需要监听的网络接口,使用类似于下面的命令即可。

    sudo suricata -c /etc/suricata/suricata.yaml -i wlan0
    

    运行后产生的日志文件在/var/log/suricata目录下,我们可以使用类似于tail -f http.log stats.log的命令来监视程序的执行结果。

    Rules

    Suricata中最重要的就是关于规则的指定,使用特定的规则集就可以对特定的流量进行分析和处理,如果使用了IPS模式那么还可以直接处理报文内容。一般来说,我们会可以从互联网上下载最新的规则集,一般来自于Emerging Threats(Pro)和Sourcefire的VRT。手动管理的方式比较麻烦,我们可以使用到一款工具Oinkmasteroinkmaster可以自动化下载、管理rules。一般来说,规则由三个部分构成:Action、Header和Rule options。 例如下面这条

    alert tcp $EXTERNAL_NET any -> $HOME_NET 8888 (msg: "meow"; content: "meow"; )
    
    • alert表示动作,表示匹配后将发出警报。
    • tcp表示是TCP报文,还可以是ipudpicmp等,还包括一些常见的应用层协议。
    • $EXTERNAL表示使用前面定义的外部地址,可以使用!1.1.1.1![1.1.1.1, 1.1.1.2][10.0.0.0/24, !10.0.0.5]等形式。
    • any表示端口,有[79,80:82,83]这样的形式。
    • ->表示方向,可以是-><>
    • (msg: "meow"; content: "meow"; )表示规则选项,中间使用分号断开,包括meta-information、headers、payloads和flows等选项。具体内容将在后面说明。

    Meta-settings

    Meta-settings不会影响检测过程,只是用来完成记录等附属功能。

    msg: "some description"; 将显示在日志中
    sid: 123; 每条规则的编号
    rev: 123; 规则的版本号
    gid: 1; 组编号
    classtype: trojan-activity; 规则的分类
    reference: bugtraq, 123; http://www.securityfocus.com/bid; 规则的参考位置
    priority:1; 规则优先级
    metadata: ...;
    target: [src_ip|dest_ip];
    

    Header Keywords

    ttl: 10;
    ipopts: lsrr; IP选项
    sameip; 源IP和目的IP相同
    ip_proto: TCP;
    id: 1;
    geoip: src, RU;
    fragbits:[*+!]<[MDR]>;
    fragoffset:[!|<|>]<number>;
    seq:0;
    ack:1;
    window:[!]<number>;
    itype:min<>max;
    itype:[<|>]<number>;
    icode:min<>max;
    icode:[<|>]<number>;
    icmp_id:<number>;
    icmp_seq:<number>;
    

    Payload Keywords

    content:"a|0D|bc";
    content:"|61 0D 62 63|";
    content:"a|0D|b|63|";
    nocase;
    depth:12;
    offset:3;
    

    Flowbits

    通过在Suricata中保存标志位来判断若干个流量的关联性

    flowbits: set, name                设置name指定的条件
    flowbits: isset, name              检查是否有name指定的条件设置
    flowbits: toggle, name             切换name指定的条件设置情况
    flowbits: unset, name              取消设置name指定的条件
    flowbits: isnotset, name           检查是否没有name指定的条件设置
    flowbits: noalert                  不产生alert
    

    Flow

    匹配流的方向,是否建立连接等

    flow:to_client, established
    flow:to_server, established, only_stream
    flow:to_server, not_established, no_frag
    

    原理

    Suricata有几个关键组件构成:线程、线程模块和队列。Suricata以多线程的方式运行,而线程模块即对应其包获取、解码、检测和输出模块。一个包在Suricata会以类似流水线的方式一级一级地传递给下一个线程模块处理,而在这里的“传送带”就是队列。一个线程可以包含多个线程模块,这就是Runmode。 使用suricata --list-runmodes可以看到Suricata目前可以使用的runmodes。

    ------------------------------------- Runmodes ------------------------------------------
    | RunMode Type      | Custom Mode       | Description 
    |----------------------------------------------------------------------------------------
    | PCAP_DEV          | single            | Single threaded pcap live mode 
    |                   ---------------------------------------------------------------------
    |                   | autofp            | Multi threaded pcap live mode.  Packets from each flow are assigned to a single detect thread, unlike "pcap_live_auto" where packe
    ts from the same flow can be processed by any detect thread 
    |                   ---------------------------------------------------------------------
    |                   | workers           | Workers pcap live mode, each thread does all tasks from acquisition to logging 
    |----------------------------------------------------------------------------------------
    | PCAP_FILE         | single            | Single threaded pcap file mode 
    |                   ---------------------------------------------------------------------
    |                   | autofp            | Multi threaded pcap file mode.  Packets from each flow are assigned to a single detect thread, unlike "pcap-file-auto" where packe
    ts from the same flow can be processed by any detect thread 
    |----------------------------------------------------------------------------------------
    | PFRING(DISABLED)  | autofp            | Multi threaded pfring mode.  Packets from each flow are assigned to a single detect thread, unlike "pfring_auto" where packets fro
    m the same flow can be processed by any detect thread 
    |                   ---------------------------------------------------------------------
    |                   | single            | Single threaded pfring mode 
    |                   ---------------------------------------------------------------------
    |                   | workers           | Workers pfring mode, each thread does all tasks from acquisition to logging 
    |----------------------------------------------------------------------------------------
    | NFQ               | autofp            | Multi threaded NFQ IPS mode with respect to flow 
    |                   ---------------------------------------------------------------------
    |                   | workers           | Multi queue NFQ IPS mode with one thread per queue 
    |----------------------------------------------------------------------------------------
    | NFLOG             | autofp            | Multi threaded nflog mode   
    |                   ---------------------------------------------------------------------
    |                   | single            | Single threaded nflog mode  
    |                   ---------------------------------------------------------------------
    |                   | workers           | Workers nflog mode          
    |----------------------------------------------------------------------------------------
    | IPFW              | autofp            | Multi threaded IPFW IPS mode with respect to flow 
    |                   ---------------------------------------------------------------------
    |                   | workers           | Multi queue IPFW IPS mode with one thread per queue 
    |----------------------------------------------------------------------------------------
    | ERF_FILE          | single            | Single threaded ERF file mode 
    |                   ---------------------------------------------------------------------
    |                   | autofp            | Multi threaded ERF file mode.  Packets from each flow are assigned to a single detect thread 
    |----------------------------------------------------------------------------------------
    | ERF_DAG           | autofp            | Multi threaded DAG mode.  Packets from each flow are assigned to a single detect thread, unlike "dag_auto" where packets from the 
    same flow can be processed by any detect thread 
    |                   ---------------------------------------------------------------------
    |                   | single            | Singled threaded DAG mode   
    |                   ---------------------------------------------------------------------
    |                   | workers           | Workers DAG mode, each thread does all  tasks from acquisition to logging 
    |----------------------------------------------------------------------------------------
    | AF_PACKET_DEV     | single            | Single threaded af-packet mode 
    |                   ---------------------------------------------------------------------
    |                   | workers           | Workers af-packet mode, each thread does all tasks from acquisition to logging 
    |                   ---------------------------------------------------------------------
    |                   | autofp            | Multi socket AF_PACKET mode.  Packets from each flow are assigned to a single detect thread. 
    |----------------------------------------------------------------------------------------
    | NETMAP(DISABLED)  | single            | Single threaded netmap mode 
    |                   ---------------------------------------------------------------------
    |                   | workers           | Workers netmap mode, each thread does all tasks from acquisition to logging 
    |                   ---------------------------------------------------------------------
    |                   | autofp            | Multi threaded netmap mode.  Packets from each flow are assigned to a single detect thread. 
    |----------------------------------------------------------------------------------------
    | UNIX_SOCKET       | single            | Unix socket mode            
    |                   ---------------------------------------------------------------------
    |                   | autofp            | Unix socket mode            
    |----------------------------------------------------------------------------------------
    

    可以看到,在Suricata中包含三种Custom Mode,single/workers/autofp,根据右边的介绍我们能够知道当前模式的运行特点。在workers模式下,每一个线程上包含一个完整的包处理模块,也就是说将获取到的报文将分发到包处理线程中,而Suricata将会将属于同一个flow的流量放在一个线程中避免出现问题。

    其他支持软件

    Oinkmaster

    oinkmaster.pl -C /etc/oinkmaster.conf -o /etc/suricata/rules -i
    

    Suricata配置文件suricata.yaml中的outputs2 > unified2-alert可以设定在产生alert时dump出可疑数据包的信息,这个格式的好处是:

    • 方便归档管理
    • 生成速度快。

    Barnyard2

    Barnyard2就是个类似Syslog的东西,从Snort/Suricata处取得unified2格式的输入,产生其他格式的输出,比如给Prelude Hybrid IDS system、Syslog、MySQL。