分类 其他 下的文章

利用VMware OVF文件快速部署CentOS7

当新项目上线和测试时候免不了要创建一堆容器或者虚拟机. 然而创建的虚拟机过程很长步骤需要手动人工介入操作很繁琐. 所以VMware有个基于OVF文件来快速部署的功能. 当创建OVF文件时候可以指定OVF内文件的配置文件以供虚拟机来读取做相应自动配置.

目前我们想创建一个基于CentOS7的OVF快速部署文件:

  1. 已标准方式安装CentOS7并安装好VMTools以及使用yum update更新下系统包以及内核.

  2. 在虚拟机vApp options选项卡中勾选Enable vApp options以供可以自定义配置文件项.

    EA3267EC-D270-4889-B37C-8B3413BF7888.png

    同时勾选OVF settings内的OVF environment transport / VMware Tools

    1962D7DA-D549-4C2C-B19A-E7A9A79AB00E.png

  3. 创建OVF自定义配置文件项:

    2D8039BF-E6BB-4239-8B10-B977F12688F6.png

    此时在虚拟机内已经可以通过vmtoolsd --cmd "info-get guestinfo.ovfenv"来获取配置项的值了

    <?xml version="1.0" encoding="UTF-8"?>
    <Environment
         xmlns="http://schemas.dmtf.org/ovf/environment/1"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:oe="http://schemas.dmtf.org/ovf/environment/1"
         xmlns:ve="http://www.vmware.com/schema/ovfenv"
         oe:id=""
         ve:vCenterId="vm-52">
       <PlatformSection>
          <Kind>VMware ESXi</Kind>
          <Version>6.7.0</Version>
          <Vendor>VMware, Inc.</Vendor>
          <Locale>en</Locale>
       </PlatformSection>
       <PropertySection>
             <Property oe:key="dns1" oe:value=""/>
             <Property oe:key="dns2" oe:value=""/>
             <Property oe:key="gateway" oe:value=""/>
             <Property oe:key="hostname" oe:value=""/>
             <Property oe:key="ip" oe:value=""/>
             <Property oe:key="netmask" oe:value=""/>
       </PropertySection>
       <ve:EthernetAdapterSection>
          <ve:Adapter ve:mac="00:50:56:ab:0d:7e" ve:network="VM Network" ve:unitNumber="7"/>
       </ve:EthernetAdapterSection>
    </Environment>
    
  4. 编写脚本在虚拟机克隆后第一次开机时自动按照给定的配置完成分配IP等操作

  5. 清理环境:

    1. 为了清理环境我们先需要停止日志服务避免操作的时候再次污染环境:

      service auditd stop
      service rsyslog stop
      
    2. 清理yum update留下的老版本内核:

      yum install yum-utils -y
      package-cleanup --oldkernels --count=1
      
    3. 清理yum留下的缓存数据:

      yum clean all && rm -rf /var/cache/yum
      
    4. 删除已经留存的日志:

      /usr/sbin/logrotate -f /etc/logrotate.conf 
      rm -f /var/log/*-???????? /var/log/*.gz 
      rm -f /var/log/dmesg.old 
      rm -rf /var/log/anaconda
      cat /dev/null > /var/log/audit/audit.log 
      cat /dev/null > /var/log/wtmp 
      cat /dev/null > /var/log/lastlog 
      cat /dev/null > /var/log/grubby
      
    5. 删除设备文件:

      rm -f /etc/udev/rules.d/70*
      sed -i '/^(HWADDR|UUID)=/d' /etc/sysconfig/network-scripts/ifcfg-e*
      
    6. 清理/tmp目录

      rm -rf /tmp/* 
      rm -rf /var/tmp/*
      
    7. 清理SSH密钥

      rm -f /etc/ssh/*key*
      rm -rf ~root/.ssh/ 
      rm -f ~root/anaconda-ks.cfg
      
    8. 清理命令历史

      rm -f ~root/.bash_history 
      unset HISTFILE
      history -c
      sys-unconfig
      
    9. 此时系统会自动关闭已经可以将虚拟机转换成模板进行克隆部署或导出为OVF通过OVF来部署.

DP Edit Distance

Edit Distance使用DP解决可以大幅度提高计算性能在对比递归解决情况下.

function editDistance(str1: string, str2: string): number {

    var str1len: number = str1.length;
    var str2len: number = str2.length;

    if (str1len === 0) return str2len;
    if (str2len === 0) return str1len;

    var matrix: Array<Array<number>> = []

    matrix[0] = new Array(str1len + 1);

    for (let i = 0; i <= str1len; i++) {
        matrix[0][i] = i;
    }

    for (let i = 1; i <= str2len; i++) {
        matrix[i] = Array(str1len + 1);
        matrix[i].fill(0);
        matrix[i][0] = i;
    }

    for (let i = 1; i <= str2len; i++) {
        const yChar: string = str2[i - 1];
        for (let j = 1; j <= str1len; j++) {
            const xChar: string = str1[j - 1];
            const a: number = matrix[i - 1][j] + 1;
            const b: number = matrix[i][j - 1] + 1;
            const c: number = matrix[i - 1][j - 1] + (yChar === xChar ? 0 : 1);
            matrix[i][j] = Math.min(a, b, c);
        }
    }

    printMatrix(matrix);

    return matrix[str2len][str1len];
}

function printMatrix(matrix: Array<Array<number>>) {
    for (let i = 0; i < matrix.length; i++) {
        process.stdout.write("[ ");
        for (let j = 0; j < matrix[i].length; j++) {
            process.stdout.write(`${matrix[i][j]} `);
        }
        process.stdout.write("]\n");
    }
}

console.log("edit distance:", editDistance("GCTATAC", "GCGTATGC"));

Edit distance核心在于:

const a: number = matrix[i - 1][j] + 1;
const b: number = matrix[i][j - 1] + 1;
const c: number = matrix[i - 1][j - 1] + (yChar === xChar ? 0 : 1);

6F82A156-5490-4F81-8B3E-E1BFFB0A5B9E.png

参考:
Using dynamic programming for edit distance

Smokeping使用Nginx显示

由于Nginx必须调用第三方FastCGI来处理fcgi程序. 所以在此需要安装spawn-fcgi

spawn-fcgi安装完毕后在/etc/systemd/system/smokeping-fcgi.service创建服务文件

[Unit]
Description=SmokePing FastCGI Service
After=network.target smokeping.service
Wants=smokeping.service

[Service]
StandardOutput=null
StandardError=syslog
ExecStart=/opt/spawn-fcgi/bin/spawn-fcgi -u smokeping -s /var/run/smokeping-fcgi.sock -M 600 -n -U www-data -- /opt/smokeping-www/smokeping.cgi
Restart=always

[Install]
WantedBy=multi-user.target

Nginx调用spawn-fcgi

server {
    listen 10000;

    root /opt/smokeping-www;
    index smokeping.cgi;

    location ~ \.cgi$ {
        include /opt/nginx/conf/fastcgi_params;
        fastcgi_pass unix:/var/run/smokeping-fcgi.sock;
    }
}

ESXi直通NVIDIA GeForce显卡

目前家里的ESXi服务器集成了路由器,写代码,囤东西,下东西,测试之类的作用. 就差个玩游戏就完美了. 所以我就看上了Intel Direct I/O技术. 可以将PCIE上的设备直接映射至虚拟机内从而降低性能的损耗.

不过在ESXi兼容列表内的NVIDIA显卡只有Quadro系列卡. 所以就尝试了在外网寻找如何使用Direct I/O将GeForce系列显卡映射至虚拟机内.

如果在国内搜索相关N卡在ESXi内的相关信息, 只会说明到需要在虚拟机配置文件中添加一行:

hypervisor.cpuid.v0 = FALSE

经过尝试后证实只做这一步是不行的, 在Windows系统能可以看到的确显卡驱动已经正常加载了没有43错误, 但是等一有负载显卡驱动就会立即退出.

由于这个问题我在网上寻找了几天, 最终在一个Reddit一个有关于AMD+NVIDIA平台直通教程内发现了关键的一步:

在ESXi主机/etc/vmware/passthru.map文件内根据PCIE ID添加以下行:

10de 1c02 d3d0 false

其中10de是PCIE设备的供应商ID. 1c02是PCIE设备的设备ID.

当添加完毕之后重启ESXi主机后直通后的显卡就应该可以工作了.

如果重启后任然出现43错误请将ESXi主机彻底关机断电后重试.

已测试平台:
CPU: E3-1230v2
主板: MS-S0121
显卡: GT440 与 GTX1060
驱动版本: 388.71
操作系统: Windows 10
ESXi版本: 6.5.0 Update 1 (Build 7388607)

snapshot.png

参考资料:

Nginx模块开发中使用PCRE正则表达式匹配

Nginx内部对pcre库的常用操作进行了封装. 封装的源码位于nginx/src/core/ngx_regex.c, 同时将pcre内使用的内存池更变为了Nginx的内存池.

  • pcre_compile:

    Nginx封装了pcre_compile方法. 方法名为ngx_regex_compile.

    ngx_regex_compile方法的参数需要传入一个ngx_regex_compile_t来进行编译正则等操作.

    ngx_regex_compile_t结构如下:

    typedef struct {
        ngx_str_t     pattern; // 正则
        ngx_pool_t    *pool;   // 每个request分配的内存池
        ngx_int_t     options; // pcre options
    
        ngx_regex_t   *regex;  // 编译完毕后的pcre实例
        int           captures;
        int           named_captures;
        int           name_size;
        u_char       *names;
        ngx_str_t     err;     // 错误信息
    } ngx_regex_compile_t;`
    

    当编译正则成功时会返回NGX_OK并且会在内部调用pcre_study来进一步提高正则匹配性能. 失败时会返回NGX_ERROR. 同时失败的错误信息会保存在err成员变量中.

  • pcre_exec

    Nginx同样封装了pcre_exec封装后的方法名为:ngx_regex_exec 源码位于nginx/src/core/ngx_regex.h文件中:

    #define ngx_regex_exec(re, s, captures, size)                                \
        pcre_exec(re->code, re->extra, (const char *) (s)->data, (s)->len, 0, 0, \
                  captures, size)
    

    可以看到参数re要求的是ngx_regex_compile_t中的regex成员变量. 而被搜索的字符串被替换成了Nginx内部的字符串类型ngx_str_t. 同时也将Nginx内部不常用的搜索偏移以及选项设置为成0. 如果仍需要使用偏移以及选项的话可以直接使用pcre_exec来跳过Nginx的封装.

Refs: