<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Phoenix&#39;s island</title>
  
  <subtitle>Sun will shine on the horizon.</subtitle>
  <link href="https://blog.phoenixlzx.com/atom.xml" rel="self"/>
  
  <link href="https://blog.phoenixlzx.com/"/>
  <updated>2024-04-21T05:20:13.574Z</updated>
  <id>https://blog.phoenixlzx.com/</id>
  
  <author>
    <name>Phoenix Nemo</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>通过重写 EEPROM 永久修改 MAC 地址</title>
    <link href="https://blog.phoenixlzx.com/2024/04/21/permanently-change-mac-eeprom/"/>
    <id>https://blog.phoenixlzx.com/2024/04/21/permanently-change-mac-eeprom/</id>
    <published>2024-04-21T04:54:29.000Z</published>
    <updated>2024-04-21T05:20:13.574Z</updated>
    
    <content type="html"><![CDATA[<p>起因是装好一台服务器发现莫名其妙丢包 50%，并且同时另外一台机器也出现了这个问题。仔细观察发现是两台机器的 X520 网卡居然有一样的 MAC 地址…!!!</p><a id="more"></a><p>总之发现了问题就来粗暴地解决一下吧。要修改 MAC 地址有很多方法，但是两块 NIC 出厂时就有一样的 MAC 地址，那还是永久修改比较合适，免得后续出问题。</p><p>首先安装 <code>ethtool</code> 和 <code>pciutils</code>。</p><p>获取设备 ID，在这里也就是 EEPROM 的 magic header。其他厂商可能会有所不同。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">~&gt; lspci -nn</span><br><span class="line">02:00.0<span class="built_in"> Ethernet </span>controller [0200]: Intel Corporation 82599ES 10-Gigabit SFI/SFP+<span class="built_in"> Network Connection </span>[8086:10fb] (rev 01)</span><br><span class="line">02:00.1<span class="built_in"> Ethernet </span>controller [0200]: Intel Corporation 82599ES 10-Gigabit SFI/SFP+<span class="built_in"> Network Connection </span>[8086:10fb] (rev 01)</span><br></pre></td></tr></table></figure><p>Intel 的 Vendor ID 是 <code>8086</code>，Device ID 在这里是 <code>10fb</code>。如果是 BSD 系统，也可以用 <code>pciconf -lv</code> 来读取 <code>chip=</code> 值。总之要用的 magic header 就是 <code>0x10fb8086</code> 啦。</p><p>然后来备份 EEPROM 以免搞砸。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~&gt; ethtool -e ens1f0<span class="built_in"> raw </span>on &gt; eeprom-backup-ens1f0.bin</span><br></pre></td></tr></table></figure><p>定位 MAC 地址</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">~&gt; ethtool -e ens1f0 | grep <span class="string">&#x27;90 e2 xx xx xx&#x27;</span></span><br><span class="line"><span class="number">0x0360</span>:         <span class="number">90</span> e2 xx xx xx xx ...</span><br><span class="line"><span class="number">0x0370</span>:         <span class="number">90</span> e2 xx xx xx xx ...</span><br></pre></td></tr></table></figure><p>完整的 MAC 地址就是</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">~&gt; ethtool -e ens1f0 offset <span class="number">0x0360</span> length <span class="number">6</span></span><br><span class="line">Offset          Values</span><br><span class="line">------          ------</span><br><span class="line"><span class="number">0x0360</span>:         <span class="number">90</span> e2 xx xx xx c0</span><br></pre></td></tr></table></figure><p>于是可以把最后两位修改一下：</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">~&gt; ethtool -E ens1f0 magic <span class="number">0x10fb8086</span> offset <span class="number">0x0365</span> value <span class="number">0xc2</span></span><br><span class="line">~&gt; ethtool -E ens1f0 magic <span class="number">0x10fb8086</span> offset <span class="number">0x0375</span> value <span class="number">0xc3</span></span><br></pre></td></tr></table></figure><p>修改完成后不会立即生效，需要拔插一下 NIC。系统里也可以实现，直接重载一下内核模块：</p><figure class="highlight haml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~&gt; modprobe -r ixgbe</span><br></pre></td></tr></table></figure><p>于是就生效啦：</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">~&gt;<span class="built_in"> ip </span>l</span><br><span class="line">6: ens1f0: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN mode<span class="built_in"> DEFAULT group default </span>qlen 1000</span><br><span class="line">    link/ether 90:e2:xx:xx:xx:c2 brd ff:ff:ff:ff:ff:ff</span><br><span class="line">    altname enp2s0f0</span><br></pre></td></tr></table></figure><p>丢包的问题也就消失了。</p><p>顺便吐槽：这种几率的事情落在我头上是不是可以去买彩票了？¯_(ツ)_/¯</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;起因是装好一台服务器发现莫名其妙丢包 50%，并且同时另外一台机器也出现了这个问题。仔细观察发现是两台机器的 X520 网卡居然有一样的 MAC 地址…!!!&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>AMI 主板 IPMI Bonding with ipmitool</title>
    <link href="https://blog.phoenixlzx.com/2023/10/08/ipmitool-bonding-note/"/>
    <id>https://blog.phoenixlzx.com/2023/10/08/ipmitool-bonding-note/</id>
    <published>2023-10-08T08:00:33.000Z</published>
    <updated>2023-10-08T08:05:40.847Z</updated>
    
    <content type="html"><![CDATA[<p>每日笔记时间。</p><p>这东西甚至没有文档。</p><a id="more"></a><p>于是折腾多了一些奇奇怪怪的 AMI 主板之后发现这货的 IPMI 居然有多个端口而且要 bonding。</p><p>虽然完全不懂他们为何要做这么脑残的设计，总之直接操作 ipmitool 配置的 IP 不生效，只能在访问不到 IPMI GUI 的情况下组 bonding 了。</p><p>启用 bonding</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">~&gt; ipmitool<span class="built_in"> raw </span>0x32 0x71 6 0 3</span><br><span class="line">~&gt; ipmitool<span class="built_in"> raw </span>0x32 0x71 0x1 0x1 0x0 0x1 0x64 0x0 0x3 0x1</span><br></pre></td></tr></table></figure><p>另外：禁用 bonding 是</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~&gt; ipmitool raw <span class="number">0x32</span> <span class="number">0x71</span> <span class="number">0x1</span> <span class="number">0x0</span> <span class="number">0x0</span> <span class="number">0x1</span> <span class="number">0x64</span> <span class="number">0x0</span> <span class="number">0x3</span> <span class="number">0x1</span></span><br></pre></td></tr></table></figure><p>然后检查状态，执行</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~&gt; ipmitool<span class="built_in"> raw </span>0x32 0x72 0x1 0x0 0x0</span><br></pre></td></tr></table></figure><p>如果返回 <code>00 00 01 64 00 03 01</code> 则为禁用，<code>01 00 01 64 00 03 01</code> 则是启用。</p><p>然后正常配置 lan 参数就可以了。</p><p>顺便再臭骂 AMI 不干人事。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;每日笔记时间。&lt;/p&gt;
&lt;p&gt;这东西甚至没有文档。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>远程转换 H330 为 HBA330</title>
    <link href="https://blog.phoenixlzx.com/2023/06/27/remote-flash-h330-to-hba/"/>
    <id>https://blog.phoenixlzx.com/2023/06/27/remote-flash-h330-to-hba/</id>
    <published>2023-06-26T15:51:33.000Z</published>
    <updated>2023-06-26T16:39:46.967Z</updated>
    
    <content type="html"><![CDATA[<p>由于 PERC H330 的 passthrough mode 并不适用于 ZFS 所以只好强刷为 HBA330 啦。</p><a id="more"></a><p><strong>注意！此方法不适用于 H730/H830 系列 RAID 卡，且 H730 卡支持直接转换为 HBA。</strong></p><p><strong>操作前先备份！操作前先备份！操作前先备份！重要的事情说三遍！！！</strong></p><h3 id="准备必要程序和固件"><a href="#准备必要程序和固件" class="headerlink" title="准备必要程序和固件"></a>准备必要程序和固件</h3><ol><li><a href="https://docs.broadcom.com/docs/12351629">DOS 版本 <code>megacli.exe</code></a></li><li><a href="https://www.broadcom.com/support/knowledgebase/1211161499804/lsi-pre-boot-usb-tool-download">DOS 版本 <code>megarec3.exe</code>，<code>sas3flsh.exe</code> 和其他必要文件</a></li><li><a href="https://www.dell.com/support/home/en-us/drivers/driversdetails?driverid=847vg">HBA330 固件</a></li></ol><p>…</p><p>我不装了，<a href="https://drive.google.com/file/d/1HqFMJv8ImB93uFhY3d1t8-fJqJMIQvrD/view?usp=sharing">这里</a>有 Sleyk 大神准备好的文件包。</p><h3 id="准备-FreeDOS-启动镜像"><a href="#准备-FreeDOS-启动镜像" class="headerlink" title="准备 FreeDOS 启动镜像"></a>准备 FreeDOS 启动镜像</h3><p>首先下载 FreeDOS 的 USB Lite 镜像，作为基础系统环境。当前版本 1.3 解压后给出 <code>FD13LITE.img</code> 文件。</p><p>扩容 img 镜像到 128M：</p><figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~&gt; truncate -s <span class="number">96</span>M <span class="module-access"><span class="module"><span class="identifier">FD13LITE</span>.</span></span>img</span><br></pre></td></tr></table></figure><p>扩展镜像的 FAT 分区</p><figure class="highlight excel"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~&gt; fatresize -<span class="built_in">n</span> <span class="number">1</span> -s <span class="built_in">max</span> FD13LITE.img</span><br></pre></td></tr></table></figure><p>挂载 img 镜像</p><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">~&gt; udisksctl loop-setup -f FD13LITE.img</span><br><span class="line">Mapped <span class="keyword">file</span> FD13LITE.img as <span class="regexp">/dev/</span>loop0.</span><br><span class="line">~&gt; udisksctl mount -b <span class="regexp">/dev/</span>loop0p1</span><br><span class="line">Mounted <span class="regexp">/dev/</span>loop0p1 at <span class="regexp">/run/m</span>edia<span class="regexp">/user/</span>FD13-LITE</span><br><span class="line">~&gt; cp <span class="regexp">/path/</span>to<span class="regexp">/flash/</span>files <span class="regexp">/run/m</span>edia<span class="regexp">/user/</span>FD13-LITE/</span><br></pre></td></tr></table></figure><p>注意 DOS 并不能识别部分文件名，如果不修改的话，在 DOS 中会显示成类似 <code>HBA~1</code> 的形式。</p><p>复制好文件后卸载镜像</p><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">~&gt; udisksctl unmount -b <span class="regexp">/dev/</span>loop0p1</span><br><span class="line">Unmounted <span class="regexp">/dev/</span>loop0p1.</span><br><span class="line">~&gt; udisksctl loop-<span class="keyword">delete</span> -b <span class="regexp">/dev/</span>loop0</span><br></pre></td></tr></table></figure><p>完事儿后把修改版 <code>FD13LITE.img</code> 远程挂载到 iDRAC KVM 里，然后重启服务器，从 Virtual Floppy 启动即可。</p><ul><li>注意：如果 <code>Virtual Floppy</code> 选项没有识别为 <code>[Hard Disk] Virtual Floppy</code> 的话则可能需要再次重启，因为镜像没有正确识别，无法进入 FreeDOS。具体原因不明。</li></ul><h3 id="Crossflash"><a href="#Crossflash" class="headerlink" title="Crossflash!"></a>Crossflash!</h3><p>进入 FreeDOS 环境后会提示是否安装，选 No 回到 FreeDOS 就可以执行命令啦。</p><ol><li>刷入 SMC3018 ROM</li></ol><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&gt; <span class="selector-tag">megacli</span> <span class="selector-tag">-adpfwflash</span> <span class="selector-tag">-f</span> <span class="selector-tag">smc3108</span><span class="selector-class">.rom</span> <span class="selector-tag">-noverchk</span> <span class="selector-tag">-a0</span></span><br></pre></td></tr></table></figure><p>然后因为是远程挂载镜像，会报一堆写入错误，需要一直忽略这些错误。一直等待操作完成报告成功。</p><ol start="2"><li><p>重启，然后耐心等待直到出现 <code>Baseport not responding. No adapter available</code> 再进入 FreeDOS 环境。</p></li><li><p>清零 Serial Boot ROM (SBR)</p></li></ol><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&gt; megarec3 -writesbr <span class="number">0</span> sbrempty.bin</span><br></pre></td></tr></table></figure><p>过程中的报错可以忽略，最终报告成功即可。</p><ol start="4"><li>清零 flash</li></ol><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&gt; megarec3 -cleanflash <span class="number">0</span></span><br></pre></td></tr></table></figure><ol start="5"><li><p>重启。</p></li><li><p>再次进入 FreeDOS 环境，刷入 HBA330 固件。</p></li></ol><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&gt; <span class="selector-tag">sas3flsh</span> <span class="selector-tag">-o</span> <span class="selector-tag">-f</span> <span class="selector-tag">hba330</span><span class="selector-class">.fw</span> <span class="selector-tag">-b</span> <span class="selector-tag">mptx64</span><span class="selector-class">.rom</span></span><br></pre></td></tr></table></figure><p>如果是 H330Mini，则需要刷 <code>hba330mini.fw</code>，否则会不识别硬盘。</p><ol start="7"><li>最后一步，重编程 SAS 地址。看起来可以省略，默认是 16 个 0。</li></ol><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&gt; sas3flsh -o -sasadd <span class="number">0000000000000000</span></span><br></pre></td></tr></table></figure><p>只能用数字和字母，必须 16 位。可以自己造也可以用原本的地址（<code>megacli -adpallinfo -a0</code>）。如果自己造的话需要保证不和同系统内的其他卡冲突。</p><h3 id="完成"><a href="#完成" class="headerlink" title="完成"></a>完成</h3><p>好耶！(≧∇≦)/</p><p>参考：</p><ol><li><a href="https://sandelinos.com/nerd-stuff/Creating_customized_FreeDOS_images/">https://sandelinos.com/nerd-stuff/Creating_customized_FreeDOS_images/</a></li><li><a href="https://forums.servethehome.com/index.php?threads/flash-crossflash-dell-h330-raid-card-to-hba330-12gbps-hba-it-firmware.25498/">https://forums.servethehome.com/index.php?threads/flash-crossflash-dell-h330-raid-card-to-hba330-12gbps-hba-it-firmware.25498/</a></li></ol><p>顺便还折腾了一台老 HPE 的 P420i，步骤很简单，只需要官方的 <code>ssacli</code> 即可。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 清空所有逻辑磁盘</span></span><br><span class="line">~&gt; ssacli controller <span class="attribute">slot</span>=0 logicaldrive all delete forced</span><br><span class="line"><span class="comment"># 设置为 HBA Mode</span></span><br><span class="line">~&gt; ssacli controller <span class="attribute">slot</span>=0 modify <span class="attribute">hbamode</span>=on forced</span><br></pre></td></tr></table></figure><p>如果不知道 slot 编号，可以 <code>ssacli ctrl all show</code> 来看。</p><p><strong>但！是！</strong></p><p>虽然改成了 HBA，但你不能从这 HBA 的硬盘启动。</p><p>(╯°□°）╯︵ ┻━┻</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;由于 PERC H330 的 passthrough mode 并不适用于 ZFS 所以只好强刷为 HBA330 啦。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>修复 CentOS &#39;org.freedesktop.login1&#39; timed out</title>
    <link href="https://blog.phoenixlzx.com/2022/06/06/rescue-broken-centos-systemd-timeout/"/>
    <id>https://blog.phoenixlzx.com/2022/06/06/rescue-broken-centos-systemd-timeout/</id>
    <published>2022-06-06T02:32:33.000Z</published>
    <updated>2022-06-06T03:22:08.295Z</updated>
    
    <content type="html"><![CDATA[<p>又到了喜闻乐见帮人修系统的时间。</p><a id="more"></a><p>根据情况描述是 “stuck at ‘Starting switch root’”，初步判定是 initramfs 坏掉了。经过询问果不其然，某个特别爱没事儿就更新的家伙在更新的时候被数据中心的智障远程手按了电源¯(ツ)/¯</p><p>既然启动不能那就进 Rescue 呗。虽然 CentOS 这系统不怎么样，但是至少也算在原版 ISO 就提供了 Rescue 的选项，还能自动寻找根分区挂载。本来以为小事一桩，准备 chroot 的时候突然冒出来一句 “chroot: cannot run command `/bin/sh’: Exec format error” 就瞬间心里一顿$#%#$^$#@#%#</p><p>一般来讲，报错 “Exec format error” 代表二进制格式错误，例如在 32 位系统中执行 64 位二进制文件。但这不可能，首先同样是 x86_64 架构，安装的系统和 ISO 的系统也是同样的版本，磁盘也没有报错，为什么会出现这种问题？</p><p>更新时断电导致文件被写坏的可能性并不是没有，但奇怪的是执行 <code>/bin/bash</code> 也报一样的错误。能坏到这种程度怕不是 glibc 挂了…？但总之第一步是要能先进系统瞧瞧究竟，于是心一横，直接用 Live CD 的 <code>/usr</code> 覆盖磁盘上的对应目录。</p><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~&gt; cp -r <span class="regexp">/usr /m</span>nt<span class="regexp">/sysimage/</span></span><br></pre></td></tr></table></figure><p>然后再 chroot，果然成功进入系统，<code>yum</code> 命令也可以用了。既然是更新过程中断电，那应该先尝试修复未完成的更新。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">~&gt; yum-complete-transaction</span><br><span class="line">Loaded plugins: fastestmirror, langpacks</span><br><span class="line">Loading<span class="built_in"> mirror </span>speeds <span class="keyword">from</span> cached hostfile</span><br><span class="line"><span class="literal">No</span> unfinished transactions left.</span><br></pre></td></tr></table></figure><p>啊咧。</p><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">~&gt; yum update</span><br><span class="line"><span class="comment">--&gt; Finished Dependency Resolution</span></span><br><span class="line">Error:  Multilib <span class="built_in">version</span> problems found. This often means <span class="keyword">that</span> <span class="keyword">the</span> root</span><br><span class="line">       cause <span class="keyword">is</span> something <span class="keyword">else</span> <span class="keyword">and</span> multilib <span class="built_in">version</span> checking <span class="keyword">is</span> just</span><br><span class="line">       pointing out <span class="keyword">that</span> there <span class="keyword">is</span> a problem. Eg.:</span><br><span class="line"></span><br><span class="line">         <span class="number">1.</span> You have an upgrade <span class="keyword">for</span> libselinux which <span class="keyword">is</span> missing <span class="keyword">some</span></span><br><span class="line">            dependency <span class="keyword">that</span> another package requires. Yum <span class="keyword">is</span> trying <span class="keyword">to</span></span><br><span class="line">            solve this <span class="keyword">by</span> installing an older <span class="built_in">version</span> <span class="keyword">of</span> glibc <span class="keyword">of</span> <span class="keyword">the</span></span><br><span class="line">            different architecture. If you exclude <span class="keyword">the</span> bad architecture</span><br><span class="line">            yum will <span class="keyword">tell</span> you what <span class="keyword">the</span> root cause <span class="keyword">is</span> (which package</span><br><span class="line">            requires what). You can <span class="keyword">try</span> redoing <span class="keyword">the</span> upgrade <span class="keyword">with</span></span><br><span class="line">            <span class="comment">--exclude glibc.otherarch ... this should give you an error</span></span><br><span class="line">            message showing <span class="keyword">the</span> root cause <span class="keyword">of</span> <span class="keyword">the</span> problem.</span><br><span class="line"></span><br><span class="line">         <span class="number">2.</span> You have multiple architectures <span class="keyword">of</span> glibc installed, <span class="keyword">but</span></span><br><span class="line">            yum can only see an upgrade <span class="keyword">for</span> one <span class="keyword">of</span> those arcitectures.</span><br><span class="line">            If you don&#x27;t want/need both architectures anymore <span class="keyword">then</span> you</span><br><span class="line">            can remove <span class="keyword">the</span> one <span class="keyword">with</span> <span class="keyword">the</span> missing update <span class="keyword">and</span> everything</span><br><span class="line">            will work.</span><br><span class="line"></span><br><span class="line">         <span class="number">3.</span> You have duplicate versions <span class="keyword">of</span> glibc installed already.</span><br><span class="line">            You can use <span class="string">&quot;yum check&quot;</span> <span class="keyword">to</span> <span class="keyword">get</span> yum show these errors.</span><br><span class="line"></span><br><span class="line">       ...you can also use <span class="comment">--setopt=protected_multilib=false to remove</span></span><br><span class="line">       this checking, however this <span class="keyword">is</span> almost never <span class="keyword">the</span> correct thing <span class="keyword">to</span></span><br><span class="line">       do <span class="keyword">as</span> something <span class="keyword">else</span> <span class="keyword">is</span> very likely <span class="keyword">to</span> go wrong (often causing</span><br><span class="line">       much more problems).</span><br><span class="line"></span><br><span class="line">       Protected multilib versions: glibc..... != glibc.....</span><br><span class="line">       kbd... x86_64 != kbd ... x86_64</span><br></pre></td></tr></table></figure><p>…还真是。</p><p>进一步了解到这个系统并没有安装 32 位包，那么这个 32 位的 glibc 是哪儿来的呢？<code>yum check</code> 无果，更何况还有一个奇怪的 kbd 包甚至跟 32 位毫无关系。看来坏的不轻，但是既然确定系统中没有 32 位包，那么可以继续莽到底了。</p><figure class="highlight livescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 完成所有未更新的包</span></span><br><span class="line"><span class="function">~&gt;</span> yum update --setopt=protected_multilib=<span class="literal">false</span></span><br><span class="line"><span class="comment"># 为重装系统做准备</span></span><br><span class="line"><span class="function">~&gt;</span> mkdir /root/tmp</span><br><span class="line"><span class="function">~&gt;</span> cd /root/tmp</span><br><span class="line"><span class="comment"># 重装所有包</span></span><br><span class="line"><span class="function">~&gt;</span> yum reinstall * --setopt=protected_multilib=<span class="literal">false</span></span><br></pre></td></tr></table></figure><p>一通操作猛如虎，第一次重装所有包时还会报错 ldconfig 一些库是空文件，第二次完整重装就看不到报错了。看来可行，果断重启，一堆 OK 之后看到了 login 提示。</p><figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">localhost <span class="keyword">login</span>: root</span><br><span class="line"></span><br><span class="line"><span class="keyword">Login</span> incorrect</span><br><span class="line"></span><br><span class="line"><span class="keyword">Login</span> incorrect</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">Login</span> incorrect</span><br></pre></td></tr></table></figure><p>嗯嗯嗯？？？我还没输入密码呢？？？</p><p>还没输入密码就报错，至少不是 PAM 的问题。在那之前呢？应该是 systemd-logind 了。幸运的是网络可以正常启动，SSH 能够正常登入系统。如果网络或者 SSH 也不行，那就只好再次进 rescue 了。</p><p>系统里很多本来应该有的底层服务没有启动，例如 systemd-logind。想查看这货的状态，结果报错：</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Failed <span class="keyword">to</span> activate<span class="built_in"> service </span><span class="string">&#x27;org.freedesktop.systemd1&#x27;</span>: timed out</span><br></pre></td></tr></table></figure><p>咦？systemd 自己都没正常启动，看看日志：</p><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line">localhost dbus-daemon[1166]: Encountered <span class="keyword">error</span> &#x27;<span class="keyword">Error</span> <span class="keyword">in</span> <span class="keyword">file</span> /etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.hostname1.<span class="keyword">conf</span>, <span class="keyword">line</span> 1, column 0: <span class="keyword">no</span> element found</span><br><span class="line">                                                  &#x27; <span class="keyword">while</span> parsing &#x27;/etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.hostname1.<span class="keyword">conf</span>&#x27;</span><br><span class="line">localhost dbus-daemon[1166]: Encountered <span class="keyword">error</span> &#x27;<span class="keyword">Error</span> <span class="keyword">in</span> <span class="keyword">file</span> /etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.import1.<span class="keyword">conf</span>, <span class="keyword">line</span> 1, column 0: <span class="keyword">no</span> element found</span><br><span class="line">                                                  &#x27; <span class="keyword">while</span> parsing &#x27;/etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.import1.<span class="keyword">conf</span>&#x27;</span><br><span class="line">localhost dbus-daemon[1166]: Encountered <span class="keyword">error</span> &#x27;<span class="keyword">Error</span> <span class="keyword">in</span> <span class="keyword">file</span> /etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.locale1.<span class="keyword">conf</span>, <span class="keyword">line</span> 1, column 0: <span class="keyword">no</span> element found</span><br><span class="line">                                                  &#x27; <span class="keyword">while</span> parsing &#x27;/etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.locale1.<span class="keyword">conf</span>&#x27;</span><br><span class="line">localhost dbus-daemon[1166]: Encountered <span class="keyword">error</span> &#x27;<span class="keyword">Error</span> <span class="keyword">in</span> <span class="keyword">file</span> /etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.login1.<span class="keyword">conf</span>, <span class="keyword">line</span> 1, column 0: <span class="keyword">no</span> element found</span><br><span class="line">                                                  &#x27; <span class="keyword">while</span> parsing &#x27;/etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.login1.<span class="keyword">conf</span>&#x27;</span><br><span class="line">localhost dbus-daemon[1166]: Encountered <span class="keyword">error</span> &#x27;<span class="keyword">Error</span> <span class="keyword">in</span> <span class="keyword">file</span> /etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.machine1.<span class="keyword">conf</span>, <span class="keyword">line</span> 1, column 0: <span class="keyword">no</span> element found</span><br><span class="line">                                                  &#x27; <span class="keyword">while</span> parsing &#x27;/etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.machine1.<span class="keyword">conf</span>&#x27;</span><br><span class="line">localhost dbus-daemon[1166]: Encountered <span class="keyword">error</span> &#x27;<span class="keyword">Error</span> <span class="keyword">in</span> <span class="keyword">file</span> /etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.systemd1.<span class="keyword">conf</span>, <span class="keyword">line</span> 1, column 0: <span class="keyword">no</span> element found</span><br><span class="line">                                                  &#x27; <span class="keyword">while</span> parsing &#x27;/etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.systemd1.<span class="keyword">conf</span>&#x27;</span><br><span class="line">localhost dbus-daemon[1166]: Encountered <span class="keyword">error</span> &#x27;<span class="keyword">Error</span> <span class="keyword">in</span> <span class="keyword">file</span> /etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.timedate1.<span class="keyword">conf</span>, <span class="keyword">line</span> 1, column 0: <span class="keyword">no</span> element found</span><br><span class="line">                                                  &#x27; <span class="keyword">while</span> parsing &#x27;/etc/dbus-1/system.<span class="keyword">d</span>/org.freedesktop.timedate1.<span class="keyword">conf</span>&#x27;</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>病的不轻。这些文件内容消失了，重装包并不会覆盖它们。只好手动来覆盖了。</p><figure class="highlight livescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装必要工具</span></span><br><span class="line"><span class="function">~&gt;</span> yum install yum-utils rpm2cpio</span><br><span class="line"><span class="comment"># 获取并解包 rpm</span></span><br><span class="line"><span class="function">~&gt;</span> cd /root/tmp</span><br><span class="line"><span class="function">~&gt;</span> yumdownloader dbus systemd</span><br><span class="line"><span class="function">~&gt;</span> rpm2cpio dbus-<span class="number">1.10</span>.<span class="number">24</span>-<span class="number">15.el</span>7.x86_64.rpm | cpio -idmv</span><br><span class="line"><span class="function">~&gt;</span> rpm2cpio systemd-<span class="number">219</span>-<span class="number">78.el</span>7_9.<span class="number">5.x</span>86_64.rpm | cpio -idmv</span><br></pre></td></tr></table></figure><p>于是得到了这些包的内容。手动将 <code>etc/dbus-1</code> 目录下的所有文件覆盖到文件系统，然后执行 <code>kill 1</code></p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">localhost systemd[1]: Received SIGTERM <span class="keyword">from</span> PID 4332 (bash).</span><br><span class="line">localhost systemd[1]: Reexecuting.</span><br><span class="line">localhost systemd[1]: systemd 219 running <span class="keyword">in</span><span class="built_in"> system </span>mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ</span><br><span class="line">localhost systemd[1]: Detected architecture x86-64.</span><br><span class="line">localhost dbus[1166]: [system] Successfully activated<span class="built_in"> service </span><span class="string">&#x27;org.freedesktop.systemd1&#x27;</span></span><br><span class="line">localhost systemd[1]: Started Login Service.</span><br><span class="line">localhost systemd-logind[4723]: New seat seat0.</span><br></pre></td></tr></table></figure><p>仔细检查一遍，各种服务都在正常启动了！</p><p>(๑•̀ㅂ•́)و✧</p><p>后记：别没事儿更新生产用系统。</p><p>后记 2：西方国家的数据中心远程手没有一个靠谱的。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;又到了喜闻乐见帮人修系统的时间。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>配置 Fail2ban 保护 Proxmox VE</title>
    <link href="https://blog.phoenixlzx.com/2021/12/02/protect-proxmox-ve-with-fail2ban/"/>
    <id>https://blog.phoenixlzx.com/2021/12/02/protect-proxmox-ve-with-fail2ban/</id>
    <published>2021-12-02T13:40:32.000Z</published>
    <updated>2023-10-08T10:42:37.107Z</updated>
    
    <content type="html"><![CDATA[<p>各种情况下 Proxmox VE 的登陆界面需要暴露在公网的时候，需要使用 fail2ban 来保护它不被暴力破解。</p><a id="more"></a><h3 id="创建-filter"><a href="#创建-filter" class="headerlink" title="创建 filter"></a>创建 filter</h3><p>文件 <code>/etc/fail2ban/filter.d/proxmox.conf</code></p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[Definition]</span><br><span class="line">failregex = pvedaemon\[.<span class="number">*a</span>uthentication failure; <span class="attribute">rhost</span>=&lt;HOST&gt; <span class="attribute">user</span>=.* <span class="attribute">msg</span>=.*</span><br><span class="line">ignoreregex =</span><br></pre></td></tr></table></figure><h3 id="创建-jail"><a href="#创建-jail" class="headerlink" title="创建 jail"></a>创建 jail</h3><p>文件 <code>/etc/fail2ban/jail.d/proxmox.conf</code></p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[proxmox]</span><br><span class="line">enabled = <span class="literal">true</span></span><br><span class="line">port = https,http,8006</span><br><span class="line">filter = proxmox</span><br><span class="line">logpath = /var/log/daemon.log</span><br><span class="line">maxretry = 3</span><br><span class="line"><span class="comment"># 1 hour</span></span><br><span class="line">bantime = 3600</span><br></pre></td></tr></table></figure><h3 id="重启-fail2ban"><a href="#重启-fail2ban" class="headerlink" title="重启 fail2ban"></a>重启 fail2ban</h3><figure class="highlight haml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~&gt; systemctl restart fail2ban</span><br></pre></td></tr></table></figure><p>然后检查是否配置生效</p><figure class="highlight fortran"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">~&gt; fail2ban-client <span class="keyword">status</span></span><br><span class="line"><span class="keyword">Status</span></span><br><span class="line">|- <span class="keyword">Number</span> of jail:      <span class="number">2</span></span><br><span class="line">`- Jail list:   proxmox, sshd</span><br></pre></td></tr></table></figure><h2 id="更新-PVE-8"><a href="#更新-PVE-8" class="headerlink" title="更新 PVE 8"></a>更新 PVE 8</h2><p>由于 Debian 12 的 SSH 和 pveproxy 都使用 systemd 管理日志，可以直接编辑文件 <code>/etc/fail2ban/jail.d/defaults-debian.conf</code> 在最前面加入</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[DEFAULT]</span></span><br><span class="line"><span class="comment"># Debian 12 has no log files, just journalctl</span></span><br><span class="line"><span class="attr">backend</span> = systemd</span><br><span class="line"></span><br><span class="line"><span class="comment"># &quot;bantime&quot; is the number of seconds that a host is banned.</span></span><br><span class="line"><span class="attr">bantime</span>  = <span class="number">1</span>d</span><br><span class="line"><span class="comment"># &quot;maxretry&quot; is the number of failures before a host get banned.</span></span><br><span class="line"><span class="attr">maxretry</span> = <span class="number">5</span></span><br><span class="line"><span class="comment"># A host is banned if it has generated &quot;maxretry&quot; during the last &quot;findtime&quot;</span></span><br><span class="line"><span class="attr">findtime</span>  = <span class="number">1</span>h</span><br></pre></td></tr></table></figure><p>然后移除 <code>/etc/fail2ban/jail.d/proxmox.conf</code> 中的 <code>logpath</code> 行。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;各种情况下 Proxmox VE 的登陆界面需要暴露在公网的时候，需要使用 fail2ban 来保护它不被暴力破解。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>笔记：Arch Linux iPXE 基本启动脚本</title>
    <link href="https://blog.phoenixlzx.com/2021/11/09/basic-ipxe-boot-archlinux/"/>
    <id>https://blog.phoenixlzx.com/2021/11/09/basic-ipxe-boot-archlinux/</id>
    <published>2021-11-08T18:54:29.000Z</published>
    <updated>2021-11-08T19:16:50.209Z</updated>
    
    <content type="html"><![CDATA[<p>似乎一直没有（公开且版本够新）的 Arch Linux 无人值守安装配置，所以想做一个。</p><p>参考 netboot.xyz 的 iPXE 配置，简单记录一下：</p><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!ipxe</span></span><br><span class="line"></span><br><span class="line">set mirror http:<span class="regexp">//</span>archlinux.mirror<span class="regexp">/archlinux/i</span>so/latest</span><br><span class="line">set script http:<span class="regexp">//u</span>nattended.install.script/script.sh</span><br><span class="line">kernel <span class="variable">$&#123;mirror&#125;</span><span class="regexp">/arch/</span>boot<span class="regexp">/x86_64/</span>vmlinuz-linux archisobasedir=arch archiso_http_srv=<span class="variable">$&#123;mirror&#125;</span>/ ip=::: BOOTIF= net.ifnames=<span class="number">0</span> script=<span class="variable">$&#123;script&#125;</span> mirror=auto</span><br><span class="line">initrd <span class="variable">$&#123;base-url&#125;</span><span class="regexp">/arch/</span>boot<span class="regexp">/x86_64/i</span>nitramfs-linux.img</span><br><span class="line">boot</span><br></pre></td></tr></table></figure><p>参考 SYSLINUX 的 PXELINUX 部分和内核 ipconfig 部分的文档写 <code>ip=</code> 参数的时候一边拿不到 DNS 一边疯狂报过多参数，最后发现是<a href="https://bugs.archlinux.org/task/63174">这个 bug</a> 的锅。<strong>而且它还被 netboot.xyz 在脚本里注释出来了我可能需要去检查一下视力</strong>。</p><p>总之目前暂且只能用 DHCP 来在启动过程正确配置网络，否则无法下载系统镜像。</p><p>截至写这篇的 Arch Linux 的官方说明在<a href="https://gitlab.archlinux.org/mkinitcpio/mkinitcpio-archiso/-/blob/ecf3035f9f924fead48f3bec95ca661e642eb5d1/docs/README.bootparams">这里</a>。</p><p>最后就是自动安装脚本了，这个坑暂且撂在这里，以后有时间了再慢慢填…</p><p><del>咕咕咕</del></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;似乎一直没有（公开且版本够新）的 Arch Linux 无人值守安装配置，所以想做一个。&lt;/p&gt;
&lt;p&gt;参考 netboot.xyz 的 iPXE 配置，简单记录一下：&lt;/p&gt;
&lt;figure class=&quot;highlight awk&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td cla</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>修复 LVM XFS 的 Input/output error</title>
    <link href="https://blog.phoenixlzx.com/2021/07/07/fix-lvm-xfs-input-output-error/"/>
    <id>https://blog.phoenixlzx.com/2021/07/07/fix-lvm-xfs-input-output-error/</id>
    <published>2021-07-07T14:51:19.000Z</published>
    <updated>2021-07-07T15:05:31.610Z</updated>
    
    <content type="html"><![CDATA[<p>某服务挂了。</p><p>设备被强制重启之后发现 LVM 满了，但是文件无法访问，所有文件操作显示 <code>Input/output error</code>。</p><a id="more"></a><p>查看 <code>dmesg</code> 发现大量文件系统错误，应该是磁盘写满后仍有进程不断读写的过程中被强制断电的结果。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">[ 1714.217864] XFS (dm-0):<span class="built_in"> page </span>discard on<span class="built_in"> page </span>00000000161e11d5, inode 0xd861b703d, offset 937984.</span><br><span class="line">[ 1714.219674] XFS (dm-0):<span class="built_in"> page </span>discard on<span class="built_in"> page </span>000000001d433e5e, inode 0xd861b703d, offset 942080.</span><br><span class="line">[ 1714.221132] XFS (dm-0):<span class="built_in"> page </span>discard on<span class="built_in"> page </span>00000000820efe8d, inode 0xd861b703d, offset 946176.</span><br><span class="line">[ 1714.222431] XFS (dm-0):<span class="built_in"> page </span>discard on<span class="built_in"> page </span>00000000518c8216, inode 0xd861b703d, offset 950272.</span><br><span class="line">[ 1714.223744] XFS (dm-0):<span class="built_in"> page </span>discard on<span class="built_in"> page </span>00000000753db760, inode 0xd861b703d, offset 954368.</span><br><span class="line">[ 1714.225041] XFS (dm-0):<span class="built_in"> page </span>discard on<span class="built_in"> page </span>00000000da40787d, inode 0xd861b703d, offset 958464.</span><br><span class="line">[ 1714.226341] XFS (dm-0):<span class="built_in"> page </span>discard on<span class="built_in"> page </span>00000000ba8adb4b, inode 0xd861b703d, offset 962560.</span><br><span class="line">[ 1714.227629] XFS (dm-0):<span class="built_in"> page </span>discard on<span class="built_in"> page </span>00000000784c4724, inode 0xd861b703d, offset 966656.</span><br><span class="line">[ 1714.228923] XFS (dm-0):<span class="built_in"> page </span>discard on<span class="built_in"> page </span>0000000063b2c764, inode 0xd861b703d, offset 970752.</span><br><span class="line">[ 1714.228990] XFS (dm-0):<span class="built_in"> page </span>discard on<span class="built_in"> page </span>0000000046a36fd8, inode 0xd861b703d, offset 974848.</span><br><span class="line">[ 1714.337426] dm-0: writeback <span class="builtin-name">error</span> on inode 58084519997, offset 905216, sector 34365282240</span><br><span class="line">[ 1716.586318] dm-0: writeback <span class="builtin-name">error</span> on inode 58084519997, offset 905216, sector 34365309816</span><br><span class="line">[ 1728.444718] xfs_discard_page: 9674 callbacks suppressed</span><br><span class="line"></span><br><span class="line"><span class="built_in">..</span>.</span><br><span class="line"></span><br><span class="line">[ 1763.990454] XFS (dm-0): xfs_do_force_shutdown(0x8) called <span class="keyword">from</span> line 955 of file fs/xfs/xfs_trans.c. Return<span class="built_in"> address </span>= 00000000ea9478e4</span><br><span class="line">[ 1763.990459] XFS (dm-0): Corruption of in-memory data detected.  Shutting down filesystem</span><br><span class="line">[ 1763.992696] XFS (dm-0): Please unmount the filesystem <span class="keyword">and</span> rectify the problem(s)</span><br></pre></td></tr></table></figure><p>日志写的很清楚了，那就来卸载修复吧</p><figure class="highlight haskell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">~&gt; umount /<span class="class"><span class="keyword">data</span></span></span><br><span class="line">~&gt; xfs_repair /dev/mapper/<span class="class"><span class="keyword">data</span></span></span><br></pre></td></tr></table></figure><p>显示</p><figure class="highlight livecodeserver"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Phase <span class="number">1</span> - find <span class="keyword">and</span> verify superblock...</span><br><span class="line">        - reporting progress <span class="keyword">in</span> intervals <span class="keyword">of</span> <span class="number">15</span> minutes</span><br><span class="line">Phase <span class="number">2</span> - <span class="keyword">using</span> internal <span class="built_in">log</span></span><br><span class="line">        - <span class="literal">zero</span> <span class="built_in">log</span>...</span><br><span class="line">ERROR: The filesystem has valuable metadata changes <span class="keyword">in</span> <span class="keyword">a</span> <span class="built_in">log</span> which needs <span class="built_in">to</span></span><br><span class="line">be replayed.  Mount <span class="keyword">the</span> filesystem <span class="built_in">to</span> replay <span class="keyword">the</span> <span class="built_in">log</span>, <span class="keyword">and</span> unmount <span class="keyword">it</span> <span class="keyword">before</span></span><br><span class="line">re-running xfs_repair.  If you are unable <span class="built_in">to</span> mount <span class="keyword">the</span> filesystem, <span class="keyword">then</span> use</span><br><span class="line"><span class="keyword">the</span> -L option <span class="built_in">to</span> destroy <span class="keyword">the</span> <span class="built_in">log</span> <span class="keyword">and</span> attempt <span class="keyword">a</span> repair.</span><br><span class="line">Note that destroying <span class="keyword">the</span> <span class="built_in">log</span> may cause corruption <span class="comment">-- please attempt a mount</span></span><br><span class="line"><span class="keyword">of</span> <span class="keyword">the</span> filesystem <span class="keyword">before</span> doing this.</span><br></pre></td></tr></table></figure><p>咦，为什么还要我 remount。</p><figure class="highlight haskell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">~&gt; mount -a</span><br><span class="line">~&gt; umount /<span class="class"><span class="keyword">data</span></span></span><br><span class="line">~&gt; xfs_repair /dev/mapper/<span class="class"><span class="keyword">data</span></span></span><br></pre></td></tr></table></figure><p>然后就是漫长的等待…（因为是 HDD）</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">Phase <span class="number">1</span> - find <span class="keyword">and</span> verify superblock...</span><br><span class="line">        - reporting progress <span class="keyword">in</span> <span class="built_in">int</span>ervals of <span class="number">15</span> minutes</span><br><span class="line">Phase <span class="number">2</span> - using <span class="built_in">int</span>ernal log</span><br><span class="line">        - zero log...</span><br><span class="line">        - <span class="number">19</span>:<span class="number">33</span>:<span class="number">58</span>: zeroing log - <span class="number">521728</span> of <span class="number">521728</span> blocks done</span><br><span class="line">        - scan filesystem freespace <span class="keyword">and</span> inode maps...</span><br><span class="line">        - <span class="number">19</span>:<span class="number">34</span>:<span class="number">11</span>: scanning filesystem freespace - <span class="number">33</span> of <span class="number">33</span> allocation groups done</span><br><span class="line">        - found root inode chunk</span><br><span class="line">Phase <span class="number">3</span> - <span class="keyword">for</span> each AG...</span><br><span class="line">        - scan <span class="keyword">and</span> clear agi unlinked lists...</span><br><span class="line">        - <span class="number">19</span>:<span class="number">34</span>:<span class="number">11</span>: scanning agi unlinked lists - <span class="number">33</span> of <span class="number">33</span> allocation groups done</span><br><span class="line">        - process known inodes <span class="keyword">and</span> perform inode discovery...</span><br><span class="line">        - agno = <span class="number">0</span></span><br><span class="line">        - agno = <span class="number">15</span></span><br><span class="line">        - agno = <span class="number">30</span></span><br><span class="line">        ...</span><br><span class="line">        - agno = <span class="number">27</span></span><br><span class="line">        - agno = <span class="number">28</span></span><br><span class="line">        - agno = <span class="number">29</span></span><br><span class="line">        - <span class="number">19</span>:<span class="number">43</span>:<span class="number">14</span>: process known inodes <span class="keyword">and</span> inode discovery - <span class="number">16555072</span> of <span class="number">16555072</span> inodes done</span><br><span class="line">        - process newly discovered inodes...</span><br><span class="line">        - <span class="number">19</span>:<span class="number">43</span>:<span class="number">14</span>: process newly discovered inodes - <span class="number">33</span> of <span class="number">33</span> allocation groups done</span><br><span class="line">Phase <span class="number">4</span> - check <span class="keyword">for</span> duplicate blocks...</span><br><span class="line">        - setting up duplicate extent list...</span><br><span class="line">        - <span class="number">19</span>:<span class="number">43</span>:<span class="number">15</span>: setting up duplicate extent list - <span class="number">33</span> of <span class="number">33</span> allocation groups done</span><br><span class="line">        - check <span class="keyword">for</span> inodes claiming duplicate blocks...</span><br><span class="line">        - agno = <span class="number">7</span></span><br><span class="line">        - agno = <span class="number">3</span></span><br><span class="line">        - agno = <span class="number">8</span></span><br><span class="line">        ...</span><br><span class="line">        - agno = <span class="number">30</span></span><br><span class="line">        - agno = <span class="number">31</span></span><br><span class="line">        - agno = <span class="number">32</span></span><br><span class="line">        - <span class="number">19</span>:<span class="number">43</span>:<span class="number">24</span>: check <span class="keyword">for</span> inodes claiming duplicate blocks - <span class="number">16555072</span> of <span class="number">16555072</span> inodes done</span><br><span class="line">Phase <span class="number">5</span> - rebuild AG headers <span class="keyword">and</span> trees...</span><br><span class="line">        - <span class="number">19</span>:<span class="number">43</span>:<span class="number">27</span>: rebuild AG headers <span class="keyword">and</span> trees - <span class="number">33</span> of <span class="number">33</span> allocation groups done</span><br><span class="line">        - reset superblock...</span><br><span class="line">Phase <span class="number">6</span> - check inode connectivity...</span><br><span class="line">        - resetting contents of realtime bitmap <span class="keyword">and</span> summary inodes</span><br><span class="line">        - traversing filesystem ...</span><br><span class="line">        - <span class="number">19</span>:<span class="number">48</span>:<span class="number">58</span>: rebuild AG headers <span class="keyword">and</span> trees - <span class="number">33</span> of <span class="number">33</span> allocation groups done</span><br><span class="line">        - traversal finished ...</span><br><span class="line">        - moving disconnected inodes to lost+found ...</span><br><span class="line">Phase <span class="number">7</span> - verify <span class="keyword">and</span> correct link counts...</span><br><span class="line">        - <span class="number">19</span>:<span class="number">50</span>:<span class="number">02</span>: verify <span class="keyword">and</span> correct link counts - <span class="number">33</span> of <span class="number">33</span> allocation groups done</span><br><span class="line">done</span><br></pre></td></tr></table></figure><p>完事后重启，就可以重新访问 LVM 里的文件啦。</p><p>后记：</p><p>这次所幸根分区是单独的盘，如果根分区和 LVM 在同一块物理盘上的话，需要重启系统进入救援模式，手动激活 LVM 再执行修复。</p><p>以及 XFS 还是靠谱呀（<del>看向某每天摸鱼看番剧透的 btrfs 开发者</del></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;某服务挂了。&lt;/p&gt;
&lt;p&gt;设备被强制重启之后发现 LVM 满了，但是文件无法访问，所有文件操作显示 &lt;code&gt;Input/output error&lt;/code&gt;。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>FAT32 与 FAT32 的不同</title>
    <link href="https://blog.phoenixlzx.com/2021/04/12/difference-between-fat32/"/>
    <id>https://blog.phoenixlzx.com/2021/04/12/difference-between-fat32/</id>
    <published>2021-04-12T06:45:05.000Z</published>
    <updated>2021-04-12T07:19:25.007Z</updated>
    
    <content type="html"><![CDATA[<p>缘由：游戏用的台式机坏掉了。</p><a id="more"></a><p>去年底配了一台 ITX，GIGABYTE AORUS X570 I PRO WIFI 大概是这个型号的主板，在一次 BIOS 升级之后无法进入 POST，配件 LED 都显示正常，风扇正常。于是按照官方说明，准备重刷 BIOS：</p><ul><li>一张闪存盘格式化为 FAT32</li><li>固件改名为 <code>GIGABYTE.BIN</code> 放在根目录下</li><li>插在 BIOS USB 接口，接通电源但不开机的情况下按 Q Flash Plus 开始刷机</li></ul><p>但是按下之后并没有描述的橙色灯亮，只看到闪存盘的存取 LED 快速闪了几下就没了动静。</p><p>一度以为文件有问题，或者闪存盘有问题，或者格式化有问题。于是拆了一个新的闪迪的闪存盘，重新下载保存固件，依然没有效果。</p><p>对着文档回顾一次操作顺序以免有疏漏，然后发现了蹊跷。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">~&gt; sudo fdisk /dev/sdb</span><br><span class="line">Welcome <span class="keyword">to</span> fdisk (util-linux 2.36.2).</span><br><span class="line">Changes will remain <span class="keyword">in</span> memory only, until you decide <span class="keyword">to</span> write them.</span><br><span class="line">Be careful before using the write command.</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Command (m <span class="keyword">for</span> help): o</span><br><span class="line">Created a new DOS disklabel with disk identifier 0x5f576f17.</span><br><span class="line"></span><br><span class="line">Command (m <span class="keyword">for</span> help): n</span><br><span class="line">Partition type</span><br><span class="line">   p   primary (0 primary, 0 extended, 4 free)</span><br><span class="line">   e   extended (container <span class="keyword">for</span> logical partitions)</span><br><span class="line">Select (default p): p</span><br><span class="line">Partition number (1-4,<span class="built_in"> default </span>1):</span><br><span class="line">First sector (2048-15137279,<span class="built_in"> default </span>2048):</span><br><span class="line">Last sector, +/-sectors <span class="keyword">or</span> +/-size&#123;K,M,G,T,P&#125; (2048-15137279,<span class="built_in"> default </span>15137279):</span><br><span class="line"></span><br><span class="line">Created a new partition 1 of<span class="built_in"> type </span><span class="string">&#x27;Linux&#x27;</span> <span class="keyword">and</span> of size 7.2 GiB.</span><br></pre></td></tr></table></figure><blockquote><p>Created a new partition 1 of type ‘Linux’ and of size 7.2 GiB.</p></blockquote><p>嗯？</p><p>Partition Type 是 <code>Linux</code>。这会是读取失败的原因么？于是列出所有的文件系统</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">Command</span> (m for help): l</span><br><span class="line"></span><br><span class="line"><span class="attribute">00</span> Empty            <span class="number">24</span> NEC DOS          <span class="number">81</span> Minix / old Lin  bf Solaris</span><br><span class="line"><span class="attribute">01</span> FAT<span class="number">12</span>            <span class="number">27</span> Hidden NTFS Win  <span class="number">82</span> Linux swap / So  c<span class="number">1</span> DRDOS/sec (FAT-</span><br><span class="line"><span class="attribute">02</span> XENIX root       <span class="number">39</span> Plan <span class="number">9</span>           <span class="number">83</span> Linux            c<span class="number">4</span> DRDOS/sec (FAT-</span><br><span class="line"><span class="attribute">03</span> XENIX usr        <span class="number">3</span>c PartitionMagic   <span class="number">84</span> OS/<span class="number">2</span> hidden or   c<span class="number">6</span> DRDOS/sec (FAT-</span><br><span class="line"><span class="attribute">04</span> FAT<span class="number">16</span> &lt;<span class="number">32</span>M       <span class="number">40</span> Venix <span class="number">80286</span>      <span class="number">85</span> Linux extended   c<span class="number">7</span> Syrinx</span><br><span class="line"><span class="attribute">05</span> Extended         <span class="number">41</span> PPC PReP Boot    <span class="number">86</span> NTFS volume set  da Non-FS data</span><br><span class="line"><span class="attribute">06</span> FAT<span class="number">16</span>            <span class="number">42</span> SFS              <span class="number">87</span> NTFS volume set  db CP/M / CTOS / .</span><br><span class="line"><span class="attribute">07</span> HPFS/NTFS/exFAT  <span class="number">4</span>d QNX<span class="number">4</span>.x           <span class="number">88</span> Linux plaintext  de Dell Utility</span><br><span class="line"><span class="attribute">08</span> AIX              <span class="number">4</span>e QNX<span class="number">4</span>.x <span class="number">2</span>nd part  <span class="number">8</span>e Linux LVM        df BootIt</span><br><span class="line"><span class="attribute">09</span> AIX bootable     <span class="number">4</span>f QNX<span class="number">4</span>.x <span class="number">3</span>rd part  <span class="number">93</span> Amoeba           e<span class="number">1</span> DOS access</span><br><span class="line"><span class="attribute">0a</span> OS/<span class="number">2</span> Boot Manag  <span class="number">50</span> OnTrack DM       <span class="number">94</span> Amoeba BBT       e<span class="number">3</span> DOS R/O</span><br><span class="line"><span class="attribute">0b</span> W<span class="number">95</span> FAT<span class="number">32</span>        <span class="number">51</span> OnTrack DM<span class="number">6</span> Aux  <span class="number">9</span>f BSD/OS           e<span class="number">4</span> SpeedStor</span><br><span class="line"><span class="attribute">0c</span> W<span class="number">95</span> FAT<span class="number">32</span> (LBA)  <span class="number">52</span> CP/M             a<span class="number">0</span> IBM Thinkpad hi  ea Linux extended</span><br><span class="line"><span class="attribute">0e</span> W<span class="number">95</span> FAT<span class="number">16</span> (LBA)  <span class="number">53</span> OnTrack DM<span class="number">6</span> Aux  a<span class="number">5</span> FreeBSD          eb BeOS fs</span><br><span class="line"><span class="attribute">0f</span> W<span class="number">95</span> Ext&#x27;d (LBA)  <span class="number">54</span> OnTrackDM<span class="number">6</span>       a<span class="number">6</span> OpenBSD          ee GPT</span><br><span class="line"><span class="attribute">10</span> OPUS             <span class="number">55</span> EZ-Drive         a<span class="number">7</span> NeXTSTEP         ef EFI (FAT-<span class="number">12</span>/<span class="number">16</span>/</span><br><span class="line"><span class="attribute">11</span> Hidden FAT<span class="number">12</span>     <span class="number">56</span> Golden Bow       a<span class="number">8</span> Darwin UFS       f<span class="number">0</span> Linux/PA-RISC b</span><br><span class="line"><span class="attribute">12</span> Compaq diagnost  <span class="number">5</span>c Priam Edisk      a<span class="number">9</span> NetBSD           f<span class="number">1</span> SpeedStor</span><br><span class="line"><span class="attribute">14</span> Hidden FAT<span class="number">16</span> &lt;<span class="number">3</span>  <span class="number">61</span> SpeedStor        ab Darwin boot      f<span class="number">4</span> SpeedStor</span><br><span class="line"><span class="attribute">16</span> Hidden FAT<span class="number">16</span>     <span class="number">63</span> GNU HURD or Sys  af HFS / HFS+       f<span class="number">2</span> DOS secondary</span><br><span class="line"><span class="attribute">17</span> Hidden HPFS/NTF  <span class="number">64</span> Novell Netware   b<span class="number">7</span> BSDI fs          fb VMware VMFS</span><br><span class="line"><span class="attribute">18</span> AST SmartSleep   <span class="number">65</span> Novell Netware   b<span class="number">8</span> BSDI swap        fc VMware VMKCORE</span><br><span class="line"><span class="attribute">1b</span> Hidden W<span class="number">95</span> FAT<span class="number">3</span>  <span class="number">70</span> DiskSecure Mult  bb Boot Wizard hid  fd Linux raid auto</span><br><span class="line"><span class="attribute">1c</span> Hidden W<span class="number">95</span> FAT<span class="number">3</span>  <span class="number">75</span> PC/IX            bc Acronis FAT<span class="number">32</span> L  fe LANstep</span><br><span class="line"><span class="attribute">1e</span> Hidden W<span class="number">95</span> FAT<span class="number">1</span>  <span class="number">80</span> Old Minix        be Solaris boot     ff BBT</span><br><span class="line"></span><br><span class="line"><span class="attribute">Aliases</span>:</span><br><span class="line">   <span class="attribute">linux</span>          - <span class="number">83</span></span><br><span class="line">   <span class="attribute">swap</span>           - <span class="number">82</span></span><br><span class="line">   <span class="attribute">extended</span>       - <span class="number">05</span></span><br><span class="line">   <span class="attribute">uefi</span>           - EF</span><br><span class="line">   <span class="attribute">raid</span>           - FD</span><br><span class="line">   <span class="attribute">lvm</span>            - <span class="number">8</span>E</span><br><span class="line">   <span class="attribute">linuxex</span>        - <span class="number">85</span></span><br></pre></td></tr></table></figure><p>好家伙，看到一个 <code>0b W95 FAT32</code>。直接把分区类型改为 <code>0b</code> 再重新格式化，放入文件，插回 BIOS USB 接口，按下 Q Flash Plus，瞬间电源启动，橙色 LED 开始闪烁，说明已经开始刷写。</p><p>查了 <a href="https://en.wikipedia.org/wiki/Partition_type">Wikipedia</a>，看到这么一段话：</p><blockquote><p>Lists of assigned partition types to be used in the partition table in the MBR were originally maintained by IBM and Microsoft internally. When the market of PC operating systems and disk tools grew and liberated, other vendors had a need to assign special partition types to their products as well. As Microsoft neither documented all partition types already assigned by them nor wanted to maintain foreign assignments, third parties started to simply assign partition types on their own behalf in a mostly uncoordinated trial-and-error manner. This led to various conflictive double-assignments sometimes causing severe compatibility problems between certain products.([1])[<a href="http://msdn.microsoft.com/en-us/windows/hardware/gg463525.aspx]">http://msdn.microsoft.com/en-us/windows/hardware/gg463525.aspx]</a></p></blockquote><p>所以也就有了 Partition Type 这样一个细节导致刷写任务失败，原因是 GIGABYTE 在开发 Q Flash Plus 的时候没有考虑过不同厂家、设备、操作系统所建立的 FAT32 分区类型的不同，文档中也没有提及这个问题。顺带又看到了同样有很多 GIGABYTE 主板的用户在网络上表示他们没有办法通过这种方式刷写 BIOS，也难怪会让人困惑了。</p><p>再顺便，使用闪迪出厂自带的 FAT32 文件系统无法正常被 Q Flash Plus 识别，是不是也说明了闪迪的闪存盘在出厂时建立的文件系统类型并不是 <code>0b W95 FAT32</code>？</p><p>总之：</p><ol><li>我的主板终于修好了。</li><li>开发任何功能时要考虑好对不同硬件、系统、环境的兼容性。</li><li>下次买主板，还是乖乖选败家之眼 ASUS ROG 吧（笑</li></ol>]]></content>
    
    
    <summary type="html">&lt;p&gt;缘由：游戏用的台式机坏掉了。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>在 Linux 系统中升级超微 BIOS 固件</title>
    <link href="https://blog.phoenixlzx.com/2021/02/03/update-supermicro-bios-to-avoid-2021-issue-in-linux/"/>
    <id>https://blog.phoenixlzx.com/2021/02/03/update-supermicro-bios-to-avoid-2021-issue-in-linux/</id>
    <published>2021-02-03T01:33:17.000Z</published>
    <updated>2021-02-03T03:05:26.937Z</updated>
    
    <content type="html"><![CDATA[<p>最近突然有客户找来说 BIOS 进不去了呀…看截图 stuck 在 POST Code AB 大概就知道什么情况了。</p><p>这不就是经典的 y2k bug 再现嘛…</p><a id="more"></a><p>一般情况下，升级超微 BIOS 固件的推荐方式是制作 DOS 启动盘引导系统升级，不过现在 BIOS 进不去也没有物理 access 就只好在 Linux 里操作啦。</p><h3 id="获取设备信息"><a href="#获取设备信息" class="headerlink" title="获取设备信息"></a>获取设备信息</h3><p>简单命令 <code>lshw</code></p><figure class="highlight smali"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">~&gt; lshw | head -n 25</span><br><span class="line">localhost                  </span><br><span class="line">    description: System</span><br><span class="line">    product: X9SCL/X9SCM (To be<span class="built_in"> filled </span>by O.E.M.)</span><br><span class="line">    vendor: Supermicro</span><br><span class="line">    version: 0123456789</span><br><span class="line">    serial: 0123456789</span><br><span class="line">    width: 64 bits</span><br><span class="line">    capabilities: smbios-2.7 dmi-2.7 smp vsyscall32</span><br><span class="line">    configuration: boot=normal chassis=desktop family=To be<span class="built_in"> filled </span>by O.E.M. sku=To be<span class="built_in"> filled </span>by O.E.M. uuid=[redacted]</span><br><span class="line">  *-core</span><br><span class="line">       description: Motherboard</span><br><span class="line">       product: X9SCL/X9SCM</span><br><span class="line">       vendor: Supermicro</span><br><span class="line">       physical id: 0</span><br><span class="line">       version: 1.11A</span><br><span class="line">       serial: [redacted]</span><br><span class="line">       slot: To be<span class="built_in"> filled </span>by O.E.M.</span><br><span class="line">     *-firmware</span><br><span class="line">          description: BIOS</span><br><span class="line">          vendor: American Megatrends Inc.</span><br><span class="line">          physical id: 0</span><br><span class="line">          version: 1.1a</span><br><span class="line">          date: 09/28/2011</span><br><span class="line">          size: 64KiB</span><br><span class="line">          capacity: 8128KiB</span><br></pre></td></tr></table></figure><p><del>X9 主板不是 2015 年就 EOL 了吗这可真是够老了…</del></p><p>总之主板型号是 <code>X9SCM</code> 于是在超微找到了<a href="https://www.supermicro.com/about/policies/disclaimer.cfm?SoftwareItemID=12747">新版的 BIOS 固件</a>。下载到系统中解压得到一堆文件，其中 <code>X9SCM1.106</code> 这个文件就是需要的 BIOS 固件本体。</p><h3 id="编译-SUM-内核模块"><a href="#编译-SUM-内核模块" class="headerlink" title="编译 SUM 内核模块"></a>编译 SUM 内核模块</h3><p><a href="https://www.supermicro.com/en/solutions/management-software/supermicro-update-manager">Supermicro Update Manager (SUM)</a> 是用于在系统中控制 BIOS/BMC 的程序。首先<a href="https://www.supermicro.com/SwDownload/SwSelect_Free.aspx?cat=SUM">下载</a>并解压，得到 <code>sum</code> 二进制文件和一堆其他东西。在 <code>driver</code> 目录中发现了对应发行版预编译的内核模块，但是直接 <code>insmod sum_bios.ko</code> 出错，好在它也提供了源码，那么就直接编译吧。</p><p>首先安装对应内核的 Linux 头文件，搜索 <code>linux-headers</code> 一般都可以找到。</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">~&gt; uname -a</span><br><span class="line">Linux localhost <span class="number">4.19</span><span class="number">.0</span><span class="number">-13</span>-amd64 #<span class="number">1</span> SMP Debian <span class="number">4.19</span><span class="number">.160</span><span class="number">-2</span> (<span class="number">2020</span><span class="number">-11</span><span class="number">-28</span>) x86_64 GNU/Linux</span><br></pre></td></tr></table></figure><p>然后</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~&gt; apt install linux-headers<span class="number">-4.19</span><span class="number">.0</span><span class="number">-13</span>-amd64 build-essential # 还需要 make 和 gcc</span><br></pre></td></tr></table></figure><p>进入 <code>driver/Source/Linux</code> 执行 <code>make</code>，如果成功编译，则 <code>insmod ./sum_bios.ko</code>。</p><p>嗯，这次没有报错了。</p><h3 id="升级-BIOS"><a href="#升级-BIOS" class="headerlink" title="升级 BIOS"></a>升级 BIOS</h3><p>升级命令和其他主板商以及 RH 系的包命名风格一样喜欢大小写混合 = =…</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">~&gt; ./sum -c UpdateBios --file <span class="built_in">..</span>/X9SCM1.106/X9SCM1.106</span><br><span class="line">Supermicro Update Manager (<span class="keyword">for</span> UEFI BIOS) 2.5.1 (2020/11/12) (x86_64)</span><br><span class="line">Copyright(C) 2013-2020 Super Micro Computer, Inc. All rights reserved.</span><br><span class="line"></span><br><span class="line">WARNING: BIOS setting will be reset without option --preserve_setting</span><br><span class="line">Reading BIOS flash <span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span>. (100%)</span><br><span class="line">Writing BIOS flash <span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span>. (100%)</span><br><span class="line">Verifying BIOS flash <span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span>. (100%)</span><br><span class="line">Checking ME<span class="built_in"> Firmware </span><span class="built_in">..</span>.</span><br><span class="line">Putting ME data <span class="keyword">to</span> BIOS <span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span><span class="built_in">..</span> (100%)</span><br><span class="line">Writing ME region <span class="keyword">in</span> BIOS flash <span class="built_in">..</span>.</span><br><span class="line"> - Update success <span class="keyword">for</span> /FDT!!</span><br><span class="line"> - Updated Recovery Loader <span class="keyword">to</span> OPRx</span><br><span class="line"> - Updated FPT, MFSB, FTPR <span class="keyword">and</span> MFS</span><br><span class="line"> - ME Entire Image done</span><br><span class="line">WARNING:Must power cycle <span class="keyword">or</span> restart the<span class="built_in"> system </span><span class="keyword">for</span> the changes <span class="keyword">to</span> take effect!</span><br></pre></td></tr></table></figure><p>至此就基本完成啦。然后直接重启即可生效。</p><p>不过还是需要注意一下，升级固件都是有变砖风险的，某些情况下需要先联系硬件厂商支持确定升级路线。</p><p>以及新版 X10 开始升级 BIOS 需要激活 license 了… 嘛。<del>听说超微的密钥早就被提取出来写了算号器了（什</del></p><p>最后的最后，提醒各位到 2038 年只有 17 年了哦（笑</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;最近突然有客户找来说 BIOS 进不去了呀…看截图 stuck 在 POST Code AB 大概就知道什么情况了。&lt;/p&gt;
&lt;p&gt;这不就是经典的 y2k bug 再现嘛…&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>软件工程实践上的一点思考</title>
    <link href="https://blog.phoenixlzx.com/2019/06/01/thoughts-on-software-engineering/"/>
    <id>https://blog.phoenixlzx.com/2019/06/01/thoughts-on-software-engineering/</id>
    <published>2019-06-01T02:42:50.000Z</published>
    <updated>2020-09-14T04:20:19.886Z</updated>
    
    <content type="html"><![CDATA[<p>曾经大学时对于软件工程这类理论课不屑一顾，认为这些课本都是只在大学里讲学而并不实际参与工程的教授写的东西。但是经过这些年从自己开发程序编写代码，到与公司团队同学、兴趣圈的朋友一起开发项目，也积累、总结了一些经验和教训。正巧昨晚在游戏建设里参与了这类讨论，于是记下一些思考免得忘记。</p><a id="more"></a><h4 id="案例-1"><a href="#案例-1" class="headerlink" title="案例 1"></a>案例 1</h4><p>命令方块是 Minecraft 里用于执行游戏命令、实现各种触发性或持续性功能的方块。在游戏地图中需要展示一些浮空的名称标签，便是用命令方块生成隐形盔甲架实现的。这些盔甲架参数复杂且需要在地图里很多特定位置生成，负责的同学便在每个生成的位置下面放了重新生成的命令方块，生成的坐标是相对坐标，因此写好标签的命令方块便可被无限复用。</p><p>由于盔甲架属于实体，而实体在 Minecraft 中被认为是不可靠的：有无数种可能这实体会被移动或被清除。<br>因此我的建议是：将这些命令方块全部放到控制室，坐标写成绝对坐标并加上统一标签，便可做到一键生成全部、一键清除全部。</p><p>该同学表示：不想写绝对坐标，因为很麻烦。</p><h4 id="案例-2"><a href="#案例-2" class="headerlink" title="案例 2"></a>案例 2</h4><p>由于游戏玩法的需要，编写了新的插件。几天后按照原计划应当可以准备第一次基本功能测试时，负责开发的同学表示只写了大约 1/4 的功能。进度很慢的原因是 Minecraft 的实现过于糟糕，而 Spigot 和 Paper 等修改版也没有很好封装 API 导致几乎所有的事件都需要手动处理。</p><p>接下来的协同开发中该同学又在反复尝试对配置文件中属性类似的部分使用同一个序列化/反序列化方法处理、对不同配置文件中的不同物品记录项也加上了一层包装来使得其能够被一个序列化/反序列化方法处理、在其他一些程序逻辑上也在尝试复用代码减少冗余度。</p><p>我说，你先专心把功能快速叠出来，然后再去想优化的事情。<br>这位同学表示不能接受，他认为代码应该从编写时就是整洁的。</p><h4 id="论点：矫枉过正的代码复用"><a href="#论点：矫枉过正的代码复用" class="headerlink" title="论点：矫枉过正的代码复用"></a>论点：矫枉过正的代码复用</h4><p>代码复用是很常见的代码结构优化方式。更少的代码冗余可以减少维护的复杂度，也降低出错的可能。</p><p>但是在案例 1 中，如此复用代码（放置同样的命令方块）却实际上造成了更多的冗余：如果要修改一个属性，就需要记录整个世界里每一个命令方块的位置，然后一个个去修改它。相反，由于游戏世界地图里的建筑几乎不可能变化（虽然现实需求很少会有这种条件），统一放在控制室、hard code<br>所有的坐标作为一个大方法调用，却是在这需求前提下的更好的实现方式。如果需要修改属性，可以只在一个地方修改所有的命令方块。</p><p>或者说，重复放置命令方块的过程，就是 copy’n’paste 冗余代码的过程。</p><p>而案例 2 则更具有代表性。在项目初期，是否应当关注代码质量？<br>我认为是应当关注的，但是这基于开发者的工程实践经验。优秀的、熟练的开发者应当在代码编写时就能灵活使用各种简单的优化手段减少初期的代码冗余，但是对于在校大学生没有足够的项目经验时，面对紧凑的项目时间安排应当集中更多精力实现功能。此时过分关注代码优化会被分心导致各种问题——例如这位同学编写的代码基本没有能够一次通过所有测试的情况，而且绝大多数的错误都看起来只是粗心，并不是不理解、写不出的问题。</p><h4 id="论点：实现，调整，优化"><a href="#论点：实现，调整，优化" class="headerlink" title="论点：实现，调整，优化"></a>论点：实现，调整，优化</h4><blockquote><p>“Make it work, make it right, make it fast.” – Kent Beck</p></blockquote><p>这是很多软件工程推崇的敏捷开发指导方向。在案例 1 中，该同学只做了第一步——复用同样的、带有相对坐标的命令方块（方法）快速实现了所有的功能。但是从后续维护的角度来讲，这样的实现没有 make it right，更不用提 fast。</p><p>而在案例 2 中，这位同学将三个阶段在初期就全部揉进去，但是由于工程经验不足，在思考优化方案时花费了过多的精力，也导致了代码精度不够，反复修改也无法顺利通过测试。</p><p>从个人经验来看，前期的代码编写应注重功能实现，并在编码能力基础上直接编写清晰的代码结构。功能实现后，再根据需求和测试中的问题「重构」打磨细节、尝试更好的实现方式。这个过程不仅在完善整个程序，对自己的系统架构把握和设计经验也有很大的提升。最后一个阶段，则是针对性的优化少量代码使整个系统更加稳定、高效。</p><h4 id="论点：架构的改动"><a href="#论点：架构的改动" class="headerlink" title="论点：架构的改动"></a>论点：架构的改动</h4><p>这是一个比较小型的项目。需求和基本功能架构从一开始便已经讨论清楚。后续的调整不大，但是每当有少量的需求修改或架构微调，都导致了很大的代码变动。而按照这位同学的思路，每次改动都要重新思考代码结构，这浪费很多的时间。</p><p>从实际工程角度，需求变化并带来架构的微调甚至大改动都可以说是很常见的事情。在前期编码实现阶段如果揉入过多对于代码结构的过多考量，每次改动都可能会使这些思考的时间被浪费。因此，在前期编码时不应为架构考虑消耗过多的时间，而在重构过程中，由于已经完成基本的功能实现，且对已有代码还处在熟悉的热度，可以快速适配需要修改、调整的架构，并基于前期编码时的各种尝试和实验的结论选择最佳的实现方式。</p><p>以上是基于近期项目中的讨论，在软件工程层面上的思考。如有缺漏不当之处，欢迎指正。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;曾经大学时对于软件工程这类理论课不屑一顾，认为这些课本都是只在大学里讲学而并不实际参与工程的教授写的东西。但是经过这些年从自己开发程序编写代码，到与公司团队同学、兴趣圈的朋友一起开发项目，也积累、总结了一些经验和教训。正巧昨晚在游戏建设里参与了这类讨论，于是记下一些思考免得忘记。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>WireGuard 真香</title>
    <link href="https://blog.phoenixlzx.com/2019/05/07/get-started-with-wireguard/"/>
    <id>https://blog.phoenixlzx.com/2019/05/07/get-started-with-wireguard/</id>
    <published>2019-05-06T17:13:49.000Z</published>
    <updated>2020-09-14T04:20:19.882Z</updated>
    
    <content type="html"><![CDATA[<p><del>真是老了跟不上时代了，这么好的东西为什么我现在才开始用？？</del></p><a id="more"></a><p>其实这东西刚出来就在关注了不过确实前段时间才有机会尝试折腾一下。优点很多，也有无数人写过文章介绍，所以就不再多废话。主要看中它的 PtP 特性（服务器之间）和支持漫游（服务器-客户端）。当然目前在梯子方面的表现，即便是优秀的隧道方案，但由于折腾的人多了，面对万里城墙，这谁顶得住哇。</p><p>所以本文只讨论 WireGuard 作为访问企业网的隧道方案，算是初步折腾的笔记。</p><h4 id="服务器配置"><a href="#服务器配置" class="headerlink" title="服务器配置"></a>服务器配置</h4><p>一个基本的 PtP 配置结构 <code>/etc/wireguard/wg0.conf</code></p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">[Interface]</span><br><span class="line">Address = <span class="number">10.0</span><span class="number">.0</span><span class="number">.1</span>/<span class="number">32</span></span><br><span class="line">PrivateKey = [CLIENT PRIVATE KEY]</span><br><span class="line"></span><br><span class="line">[Peer]</span><br><span class="line">PublicKey = [SERVER PUBLICKEY]</span><br><span class="line">AllowedIPs = <span class="number">10.0</span><span class="number">.0</span><span class="number">.0</span>/<span class="number">24</span>, <span class="number">10.123</span><span class="number">.45</span><span class="number">.0</span>/<span class="number">24</span>, <span class="number">1234</span>:<span class="number">4567</span>:<span class="number">89</span>ab::/<span class="number">48</span></span><br><span class="line">Endpoint = [SERVER ENDPOINT]:<span class="number">48574</span></span><br><span class="line">PersistentKeepalive = <span class="number">25</span></span><br></pre></td></tr></table></figure><p>生成私钥</p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">wg</span> <span class="string">genkey &gt; privatekey</span></span><br><span class="line"><span class="attr">chmod</span> <span class="string">600 privatekey</span></span><br></pre></td></tr></table></figure><p>基于私钥生成本机的公钥</p><figure class="highlight smali"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wg pubkey &lt;<span class="keyword"> private</span>key &gt;<span class="keyword"> public</span>key</span><br></pre></td></tr></table></figure><p>或者一步完成的操作</p><figure class="highlight coq"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wg genkey | <span class="type">tee</span> privatekey | <span class="type">wg</span> pubkey &gt; publickey</span><br></pre></td></tr></table></figure><p>额外生成预共享密钥来进一步增强安全性</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">wg</span> genpsk &gt; preshared</span><br></pre></td></tr></table></figure><p>这样服务器之间的互联配置就基本完成了。使用 <code>wg-quick up &lt;config&gt;</code> 来快速启动 WireGuard。</p><p>如果要配合客户端使用，则需要配置 NAT。顺便如果客户端没有 IPv6，也可以通过此法来给客户端提供 IPv6 Enablement。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">[Interface]</span><br><span class="line">Address = 10.200.200.1/24</span><br><span class="line">Address = fd42:42:42::1/64</span><br><span class="line">SaveConfig = <span class="literal">true</span></span><br><span class="line">ListenPort = 51820</span><br><span class="line">PrivateKey = [SERVER PRIVATE KEY]</span><br><span class="line"></span><br><span class="line"><span class="comment"># note - substitute eth0 in the following lines to match the Internet-facing interface</span></span><br><span class="line">PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t<span class="built_in"> nat </span>-A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -t<span class="built_in"> nat </span>-A POSTROUTING -o eth0 -j MASQUERADE</span><br><span class="line">PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t<span class="built_in"> nat </span>-D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -t<span class="built_in"> nat </span>-A POSTROUTING -o eth0 -j MASQUERADE</span><br><span class="line"></span><br><span class="line">[Peer]</span><br><span class="line"><span class="comment"># client foo</span></span><br><span class="line">PublicKey = [FOO<span class="string">&#x27;s PUBLIC KEY]</span></span><br><span class="line"><span class="string">PresharedKey = [PRE-SHARED KEY]</span></span><br><span class="line"><span class="string">AllowedIPs = 10.200.200.2/32, fd42:42:42::2/128</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">[Peer]</span></span><br><span class="line"><span class="string"># client bar</span></span><br><span class="line"><span class="string">PublicKey = [BAR&#x27;</span>s PUBLIC KEY]</span><br><span class="line">AllowedIPs = 10.200.200.3/32, fd42:42:42::3/128</span><br></pre></td></tr></table></figure><p>在此例中需注意 <code>Allowed IPs</code> 不可 overlap 否则会造成包转发错误。</p><h4 id="客户端"><a href="#客户端" class="headerlink" title="客户端"></a>客户端</h4><p>与上文中服务器配置相照应的客户端配置示例如下：</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">[Interface]</span><br><span class="line">Address = 10.200.200.2/24</span><br><span class="line">Address = fd42:42:42::2/64</span><br><span class="line">PrivateKey = [FOO<span class="string">&#x27;s PRIVATE KEY]</span></span><br><span class="line"><span class="string">DNS = 1.1.1.1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">[Peer]</span></span><br><span class="line"><span class="string">PublicKey = [SERVER PUBLICKEY]</span></span><br><span class="line"><span class="string">PresharedKey = [PRE-SHARED KEY]</span></span><br><span class="line"><span class="string">AllowedIPs = 0.0.0.0/0, ::/0</span></span><br><span class="line"><span class="string">Endpoint = [SERVER PUBLIC IP ADDRESS]:51820</span></span><br></pre></td></tr></table></figure><p>客户端的 <code>AllowedIPs</code> 如果使用 catch-all <code>0.0.0.0/0, ::/0</code> 也就会默认转发所有的流量到服务器。该选项实际作用是路由表，控制哪些流量需要经由服务器转发。</p><p>配置完毕即可使用 <code>wg-quick up &lt;config&gt;</code> 启动 WireGuard。如果一切顺利，通过路由追踪应该可以看到流量已经交由服务器转发。</p><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>由于工作需要，经常合上笔记本动身前往其他地方。在接入传统企业网例如 L2TP/IPSec 甚至 AnyConnect 都无法保证设备下次进入工作状态时可以立即恢复连接。而 WireGuard 在不同网络、不同地域、不同网络中断时间等各种情况下均可在下次进入网络覆盖时立即恢复连接，再也不必担心网络中断恢复时手忙脚乱配置隧道或者不小心泄密啦。</p><p>目前唯一的不足，大概就是还没有 Windows 客户端，没有办法推广到非技术部门（虽然影响不到我…</p><p>总之，真香.jpg</p><p>Reference:</p><p>[1] <a href="https://wiki.archlinux.org/index.php/WireGuard">https://wiki.archlinux.org/index.php/WireGuard</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;del&gt;真是老了跟不上时代了，这么好的东西为什么我现在才开始用？？&lt;/del&gt;&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>制作 Arch Linux 内存系统启动盘</title>
    <link href="https://blog.phoenixlzx.com/2018/12/14/bootable-archlinux-in-memory-rescue-system/"/>
    <id>https://blog.phoenixlzx.com/2018/12/14/bootable-archlinux-in-memory-rescue-system/</id>
    <published>2018-12-14T03:58:39.000Z</published>
    <updated>2020-09-14T04:20:19.882Z</updated>
    
    <content type="html"><![CDATA[<p>之前尝试过 <a href="/2018/08/04/archlinux-ramroot-office-service-router/">Arch Linux in RAM</a> 完全运行在内存中的轻量业务系统，最近在维护一些物理服务器看到没有安装系统的服务器不断重启，想到了可以制作类似的内存系统启动盘，以高效完成系统测试、安装、远程维护等任务。</p><a id="more"></a><p>这时候就要祭出 <a href="https://wiki.archlinux.org/index.php/Archiso">mkarchiso</a> 大法了。这是自动化制作最新版 Arch Live 镜像的工具集，当然也可用于制作定制化的 Arch 镜像。</p><h3 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h3><p>首先安装 <code>archiso</code> 包</p><figure class="highlight haml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~&gt; sudo pacman -Syy archiso</span><br></pre></td></tr></table></figure><p>它提供了两种配置方案，一种是只包含基本系统的 <code>baseline</code>，一种是可以制作定制 ISO 的 <code>releng</code>。要制作维护用 ISO，当然是复制 <code>releng</code> 配置啦。</p><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">~&gt; cp -r <span class="regexp">/usr/</span>share<span class="regexp">/archiso/</span>configs<span class="regexp">/releng/</span> archlive</span><br><span class="line">~&gt; cd archlive</span><br></pre></td></tr></table></figure><h3 id="定制"><a href="#定制" class="headerlink" title="定制"></a>定制</h3><p>整个过程不要太简单。先来了解下各个文件的用途：</p><ul><li><code>build.sh</code> - 用于制作镜像的自动化脚本，可以在这里修改一些名称变量或制作过程的逻辑。</li><li><code>packages.x86_64</code> - 一份要安装的包列表，一行一个。</li><li><code>pacman.conf</code> - pacman 的配置文件，不用多说了吧。</li><li><code>airootfs</code> - Live 系统的 rootfs，除了安装的包之外，其他的定制（以及启动执行脚本等）都在这里。遵循 rootfs 的目录规则。</li><li><code>efiboot</code> / <code>syslinux</code> / <code>isolinux</code> 用于设置 BIOS / EFI 启动的配置。</li></ul><p>将 <code>[archlinuxcn]</code> 仓库加入 <code>pacman.conf</code>：</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[archlinuxcn]</span></span><br><span class="line"><span class="attr">Server</span> = https://cdn.repo.archlinuxcn.org/<span class="variable">$arch</span></span><br></pre></td></tr></table></figure><p>然后修改 <code>packages.x86_64</code>，加入 <code>archlinuxcn-keyring</code> 和其他需要预安装的包：</p><figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">archlinuxcn-keyring</span></span><br><span class="line"><span class="attribute">htop</span></span><br><span class="line"><span class="attribute">iftop</span></span><br><span class="line"><span class="attribute">iotop</span></span><br><span class="line"><span class="attribute">ipmitool</span></span><br></pre></td></tr></table></figure><p>按需修改即可啦。</p><p>要启动为内存系统，需要加启动参数 <code>copytoram</code>。</p><p>修改文件 <code>syslinux/archiso_pxe.cfg</code> 和 <code>syslinux/archiso_sys.cfg</code> 文件，在启动参数后加 <code>copytoram</code>，像这样：</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">INCLUDE boot/syslinux/archiso_head.cfg</span><br><span class="line"></span><br><span class="line">LABEL arch64</span><br><span class="line">TEXT HELP</span><br><span class="line">Boot the Arch Linux (x86_64) live medium.</span><br><span class="line">It allows you <span class="keyword">to</span> install Arch Linux <span class="keyword">or</span> perform<span class="built_in"> system </span>maintenance.</span><br><span class="line">ENDTEXT</span><br><span class="line">MENU LABEL Boot Arch Linux (x86_64)</span><br><span class="line">LINUX boot/x86_64/vmlinuz</span><br><span class="line">INITRD boot/intel_ucode.img,boot/amd_ucode.img,boot/x86_64/archiso.img</span><br><span class="line">APPEND <span class="attribute">archisobasedir</span>=%INSTALL_DIR% <span class="attribute">archisolabel</span>=%ARCHISO_LABEL% copytoram</span><br></pre></td></tr></table></figure><p>启动时即可将整个 SquashFS 文件复制到内存。如果内存比较小，也可以指定 <a href="https://git.archlinux.org/archiso.git/tree/docs/README.bootparams#n53"><code>copytoram_size</code></a> 来限制 tmpfs 占用内存的最大数量。</p><p>同样，也需要修改 <code>efiboot/loader/entries/archiso-x86_64-usb.conf</code> 的启动参数。在 <code>options</code> 行添加</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">options <span class="attribute">archisobasedir</span>=%INSTALL_DIR% <span class="attribute">archisolabel</span>=%ARCHISO_LABEL% copytoram</span><br></pre></td></tr></table></figure><h3 id="制作"><a href="#制作" class="headerlink" title="制作"></a>制作</h3><p>创建工作目录和输出目录</p><figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mkdir -p <span class="keyword">work</span> <span class="keyword">out</span></span><br></pre></td></tr></table></figure><p>最后一步，只需要以 root 权限执行 <code>./build.sh</code> 就可以啦。</p><p>要看具体执行过程的话，加 <code>-v</code>。<code>-h</code> 看所有参数。</p><p>完成后，即可在 <code>out</code> 目录得到准备好的 ISO 文件。将其 <code>dd</code> 到 USB 闪存盘，大功告成(‘・ω・’)</p><p>Ref:</p><ol><li><a href="https://wiki.archlinux.org/index.php/Archiso">https://wiki.archlinux.org/index.php/Archiso</a></li><li><a href="https://git.archlinux.org/archiso.git/tree/docs/README.bootparams#n53">https://git.archlinux.org/archiso.git/tree/docs/README.bootparams#n53</a></li></ol>]]></content>
    
    
    <summary type="html">&lt;p&gt;之前尝试过 &lt;a href=&quot;/2018/08/04/archlinux-ramroot-office-service-router/&quot;&gt;Arch Linux in RAM&lt;/a&gt; 完全运行在内存中的轻量业务系统，最近在维护一些物理服务器看到没有安装系统的服务器不断重启，想到了可以制作类似的内存系统启动盘，以高效完成系统测试、安装、远程维护等任务。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>使用 fs.WriteStream 编写超简单的日志流</title>
    <link href="https://blog.phoenixlzx.com/2018/11/18/super-easy-logger-with-writestream/"/>
    <id>https://blog.phoenixlzx.com/2018/11/18/super-easy-logger-with-writestream/</id>
    <published>2018-11-18T10:08:44.000Z</published>
    <updated>2020-09-14T04:20:19.882Z</updated>
    
    <content type="html"><![CDATA[<p>虽然 <code>console.log</code> 很好用，但是生产环境需要保存日志的时候就比较蛋疼。暴力 <code>fs.appendFile</code> 会消耗大量的 file handler，因此用 writable stream 来复用 file handler 是更好的选择。</p><a id="more"></a><p>大概是个不能再简单的思路了。先创建一个写入流</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> logStream = fs.createWriteStream(<span class="string">&#x27;./test.log&#x27;</span>);</span><br></pre></td></tr></table></figure><p>这样便创建了一个文件写入口，需要时直接调用 <code>logStream.write</code> 即可写入数据。<br>接下来编写一个用于记录日志的函数替代 <code>console.log</code></p><figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">logger</span> <span class="params">(message)</span></span> &#123;</span><br><span class="line">    logStream.<span class="built_in">write</span>(message);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>至此基本功能就写完啦。但是太简陋了对不对，还是要再加点装饰。</p><p>重写 <code>logger</code> 函数，区分 <code>stdout</code> 和 <code>stderr</code></p><figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> logInfo = fs.create<span class="constructor">WriteStream(&#x27;.<span class="operator">/</span><span class="params">stdout</span>.<span class="params">log</span>&#x27;)</span>;</span><br><span class="line"><span class="keyword">let</span> logError = fs.create<span class="constructor">WriteStream(&#x27;.<span class="operator">/</span><span class="params">stderr</span>.<span class="params">log</span>&#x27;)</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> Logger = &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="module-access"><span class="module"><span class="identifier">Logger</span>.</span></span>info =<span class="function"> (<span class="params">message</span>) =&gt;</span> &#123;</span><br><span class="line">    logInfo.write(&#x27;<span class="literal">[INFO]</span> &#x27; + message);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="module-access"><span class="module"><span class="identifier">Logger</span>.</span></span>error =<span class="function"> (<span class="params">message</span>) =&gt;</span> &#123;</span><br><span class="line">    logError.write(&#x27;<span class="literal">[ERROR]</span> &#x27; + message);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>感觉还是少了点什么…日期？</p><figure class="highlight coffeescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Logger.info = <span class="function"><span class="params">(message)</span> =&gt;</span> &#123;</span><br><span class="line">    logInfo.write(<span class="keyword">new</span> <span class="built_in">Date</span>().toISOString() + <span class="string">&#x27; [INFO] &#x27;</span> + message + <span class="string">&#x27;\n&#x27;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>嗯嗯。这就像样了。把代码整合起来</p><figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">const fs = require(&#x27;fs&#x27;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> logInfo = fs.create<span class="constructor">WriteStream(&#x27;.<span class="operator">/</span><span class="params">stdout</span>.<span class="params">log</span>&#x27;)</span>;</span><br><span class="line"><span class="keyword">let</span> logError = fs.create<span class="constructor">WriteStream(&#x27;.<span class="operator">/</span><span class="params">stderr</span>.<span class="params">log</span>&#x27;)</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> Logger = &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="module-access"><span class="module"><span class="identifier">Logger</span>.</span></span>info =<span class="function"> (<span class="params">message</span>) =&gt;</span> &#123;</span><br><span class="line">    logInfo.write(<span class="keyword">new</span> <span class="constructor">Date()</span>.<span class="keyword">to</span><span class="constructor">ISOString()</span> + &#x27; <span class="literal">[INFO]</span> &#x27; + message + <span class="character">&#x27;\n&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="module-access"><span class="module"><span class="identifier">Logger</span>.</span></span>error =<span class="function"> (<span class="params">message</span>) =&gt;</span> &#123;</span><br><span class="line">    logError.write(<span class="keyword">new</span> <span class="constructor">Date()</span>.<span class="keyword">to</span><span class="constructor">ISOString()</span> + &#x27; <span class="literal">[ERROR]</span> &#x27; + message + <span class="character">&#x27;\n&#x27;</span>);    </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">module</span>.exports = Logger;</span><br></pre></td></tr></table></figure><p>需要用时</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Logger.<span class="builtin-name">info</span>(<span class="string">&#x27;This is an information.&#x27;</span>);</span><br></pre></td></tr></table></figure><p>现在看对应的 <code>stdout.log</code> 文件就有相应内容啦。</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">~&gt; tail -f stdout.log</span><br><span class="line"><span class="number">2018</span><span class="number">-11</span><span class="number">-18</span>T10:<span class="number">52</span>:<span class="number">57.333</span>Z [INFO] This <span class="keyword">is</span> an information.</span><br></pre></td></tr></table></figure><p>不够刺激？</p><figure class="highlight coffeescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[...<span class="built_in">Array</span>(<span class="number">10000</span>)].forEach(<span class="function"><span class="params">(item, index)</span> =&gt;</span> &#123;</span><br><span class="line">    Logger.info(<span class="string">&#x27;Hello! &#x27;</span> + index);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">~&gt; tail -f stdout.log</span><br><span class="line">...</span><br><span class="line"><span class="number">2018</span><span class="number">-11</span><span class="number">-18</span>T10:<span class="number">58</span>:<span class="number">30.661</span>Z [INFO] Hello! <span class="number">9990</span></span><br><span class="line"><span class="number">2018</span><span class="number">-11</span><span class="number">-18</span>T10:<span class="number">58</span>:<span class="number">30.661</span>Z [INFO] Hello! <span class="number">9991</span></span><br><span class="line"><span class="number">2018</span><span class="number">-11</span><span class="number">-18</span>T10:<span class="number">58</span>:<span class="number">30.661</span>Z [INFO] Hello! <span class="number">9992</span></span><br><span class="line"><span class="number">2018</span><span class="number">-11</span><span class="number">-18</span>T10:<span class="number">58</span>:<span class="number">30.661</span>Z [INFO] Hello! <span class="number">9993</span></span><br><span class="line"><span class="number">2018</span><span class="number">-11</span><span class="number">-18</span>T10:<span class="number">58</span>:<span class="number">30.661</span>Z [INFO] Hello! <span class="number">9994</span></span><br><span class="line"><span class="number">2018</span><span class="number">-11</span><span class="number">-18</span>T10:<span class="number">58</span>:<span class="number">30.661</span>Z [INFO] Hello! <span class="number">9995</span></span><br><span class="line"><span class="number">2018</span><span class="number">-11</span><span class="number">-18</span>T10:<span class="number">58</span>:<span class="number">30.661</span>Z [INFO] Hello! <span class="number">9996</span></span><br><span class="line"><span class="number">2018</span><span class="number">-11</span><span class="number">-18</span>T10:<span class="number">58</span>:<span class="number">30.661</span>Z [INFO] Hello! <span class="number">9997</span></span><br><span class="line"><span class="number">2018</span><span class="number">-11</span><span class="number">-18</span>T10:<span class="number">58</span>:<span class="number">30.661</span>Z [INFO] Hello! <span class="number">9998</span></span><br><span class="line"><span class="number">2018</span><span class="number">-11</span><span class="number">-18</span>T10:<span class="number">58</span>:<span class="number">30.661</span>Z [INFO] Hello! <span class="number">9999</span></span><br></pre></td></tr></table></figure><p>搞定(┌・ω・)┌超简单的吧。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;虽然 &lt;code&gt;console.log&lt;/code&gt; 很好用，但是生产环境需要保存日志的时候就比较蛋疼。暴力 &lt;code&gt;fs.appendFile&lt;/code&gt; 会消耗大量的 file handler，因此用 writable stream 来复用 file handler 是更好的选择。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>重构 StickerSetBot</title>
    <link href="https://blog.phoenixlzx.com/2018/09/28/stickerset2packbot-refactory-with-telegraf/"/>
    <id>https://blog.phoenixlzx.com/2018/09/28/stickerset2packbot-refactory-with-telegraf/</id>
    <published>2018-09-28T02:51:03.000Z</published>
    <updated>2020-09-14T04:20:19.886Z</updated>
    
    <content type="html"><![CDATA[<p>关注 <a href="https://telegraf.js.org/">Telegraf</a> 有一段时间了。特别是最近 Telegram 上 spammer 猖獗导致 Telegram 对于用户行为限制越来越严格，由此想过写一个简单的 bot 来处理加群请求之类的。</p><p>总之原因都是没时间。终于搞定一些事情之后发现之前瞎写的 <a href="https://blog.phoenixlzx.com/2016/08/23/my-first-yet-useless-telegram-bot/">Telegram 导出贴图 bot</a> 居然备受欢迎…正好 Telegram Bot API 也更新了，来重构吧！</p><a id="more"></a><h2 id="拆分逻辑代码"><a href="#拆分逻辑代码" class="headerlink" title="拆分逻辑代码"></a>拆分逻辑代码</h2><p>最头疼的事情首先是当时写这 bot 的时候只顾着考虑各种情况，逻辑像流水一样全部写成一坨。虽然实际不复杂吧但这不是 best practice。于是把每个功能单独拆出来先。</p><p><code>on(&#39;command&#39;)</code> 的逻辑代码整块移出来作为 handler，然后能够原子化的功能再单独拆分成函数调用。目前的效果虽然还是有不少逻辑层在 handler 里，但是基本达到了比较方便维护的目的。</p><p><del>handler 本来就是拿来写逻辑的啊摔</del></p><p>接下来再清理冗余代码和各种 hard code，加了两个方法让代码看起来更整洁一些。于是就先这样。</p><h2 id="迁移框架"><a href="#迁移框架" class="headerlink" title="迁移框架"></a>迁移框架</h2><p>好在 Telegraf 和之前用的框架在参数上很多兼容，所以这没有花太多时间。顺便尝试采用了一部分 ES6 的风格，嘛…果然不喜欢。</p><p>所以就不要吐槽为什么 ES5 和 ES6 的风格混写了。</p><p>之前要一大长串的传参现在只要一个 <code>context</code> 了好方便啊。中间件也好方便啊~</p><p>以上。</p><h2 id="调试：无尽的-bugfix"><a href="#调试：无尽的-bugfix" class="headerlink" title="调试：无尽的 bugfix"></a>调试：无尽的 bugfix</h2><p>并不指望一通大换血之后的代码能一次跑起来…但是没跑起来的原因是我传错了中间件值这不能忍！！为什么一会儿传的是函数本体一会儿传的是函数调用啊摔！！</p><p>而且这问题还让我调了两个小时！！！</p><p><del>调通了之后就很舒服了</del></p><p>遇到的坑还有 <code>context</code> 本身不能当 session 用，然而不想再引入 session 中间件于是自己写了个超简陋的内存 session。就是为了多语言支持。因为一觉醒来发现这 bot 语言莫名其妙变中文了（<code>messages</code> 成了全局变量 = =</p><p>当然还有 Telegram 自己的坑，比如什么贴纸就是死下载不能然后整个程序就 hang 着了。</p><h2 id="一键导出贴纸包"><a href="#一键导出贴纸包" class="headerlink" title="一键导出贴纸包"></a>一键导出贴纸包</h2><p>终于！Telegram bot API 添加了 <code>StickerSet</code> 类型。只要有贴纸包名称，就可以获取整个贴纸包的信息。考虑不改变用户习惯的情况下（<del>你哪有什么用户啊可恶</del>）对本身处理贴纸和其他消息的函数做了修改，顺便又拆了俩函数出来（怎么代码越来越多了啊喂！</p><p>最后结果就是没有一屏看不到头的函数啦~（你快够</p><p>以及加入了用贴纸包链接导出一整组贴纸的功能，算是真正意义上的 StickerSetBot 了。</p><p><del>然后贴纸过多卡死了 Telegram 的 ratelimiting</del></p><h2 id="直接导出单张贴纸"><a href="#直接导出单张贴纸" class="headerlink" title="直接导出单张贴纸"></a>直接导出单张贴纸</h2><p>既然功能拆分了那也就方便加更多别的功能啦。比如不新建任务，直接甩过去一张贴纸来获得 PNG 文件~</p><p>这只 bot 在<a href="https://t.me/stickerset2packbot">这里</a>，源码在<a href="https://github.com/phoenixlzx/telegram-stickerimage-bot">这里</a>。欢迎各种玩坏~（记得去发 issue</p><p>就酱(,,•﹏•,,)</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;关注 &lt;a href=&quot;https://telegraf.js.org/&quot;&gt;Telegraf&lt;/a&gt; 有一段时间了。特别是最近 Telegram 上 spammer 猖獗导致 Telegram 对于用户行为限制越来越严格，由此想过写一个简单的 bot 来处理加群请求之类的。&lt;/p&gt;
&lt;p&gt;总之原因都是没时间。终于搞定一些事情之后发现之前瞎写的 &lt;a href=&quot;https://blog.phoenixlzx.com/2016/08/23/my-first-yet-useless-telegram-bot/&quot;&gt;Telegram 导出贴图 bot&lt;/a&gt; 居然备受欢迎…正好 Telegram Bot API 也更新了，来重构吧！&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Office Service Router 解决方案：Arch Linux in RAM</title>
    <link href="https://blog.phoenixlzx.com/2018/08/04/archlinux-ramroot-office-service-router/"/>
    <id>https://blog.phoenixlzx.com/2018/08/04/archlinux-ramroot-office-service-router/</id>
    <published>2018-08-04T08:03:11.000Z</published>
    <updated>2020-09-14T04:20:19.886Z</updated>
    
    <content type="html"><![CDATA[<p>一直把自己在办公室的 PC 保持开机用于连回办公区、存取数据工作需求。由于最近办公室所在的写字楼要全馆断电检点，所以诞生了构建一个 Service Router 的想法。</p><a id="more"></a><h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>运行在内存里对于 Linux 系统来说是完全可能（而且简单）的事情。</p><p>最直接的想法就是使用内核 hook 在启动时复制根分区到内存盘然后挂载内存里的数据作为根分区即可。</p><p>设备的话，设置 Power on AC 即可通电自启动。</p><h3 id="ramroot"><a href="#ramroot" class="headerlink" title="ramroot"></a>ramroot</h3><p>作为一只懒卷，这种简单的事情当然先顺手搜索下啦。然后就发现了几乎完美的解决方案——<a href="https://github.com/arcmags/ramroot">ramroot</a></p><p>ramroot 通过加入内核 hook 然后自动在内存建立 zram 分区，同步根分区数据再启动。还可以在启动时选择是否启动进内存，正好解决了所有的需求。</p><h3 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h3><p>硬件选择是一台便宜的 <a href="https://ark.intel.com/products/95062/Intel-NUC-Kit-NUC6CAYH">Intel NUC</a>，安装两根 4GB LPDDR3 低压内存和一块 120G 2.5 SSD。虽然说起来其实并不需要 SSD（因为数据全部都在内存里，速度比 SSD 更快）但是毕竟日本多震，还是为数据安全着想。毕竟硬盘坏了的话内存系统也无法启动了。</p><p><em>当然如果有集成 32GB eMMC 的小型 PC 的话也是好的选择。</em></p><p>正常安装完 Arch Linux 系统，安装 <code>openssh</code> 和各种必要的服务程序，修改配置文件，然后安装 ramroot 并执行</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> ramroot <span class="built_in">enable</span></span></span><br></pre></td></tr></table></figure><p>此时先别急着重启，先把不需要的包、缓存等文件（<code>/var/cache</code>）删除，保持最小化的根分区。然后再重启。便可看到加载内核 hook 时的提示是否进入内存系统，默认超时后就会自动复制根分区到内存啦。</p><p>由于整个系统是运行在内存中的，所以完全没有等待读盘的时间。整个系统的响应速度非常快。限制是内存不够大的话运行一些业务会比较捉襟见肘，而且这样低功耗、低发热的 SoC 处理性能也只能运行一些轻型任务。</p><p>下面是一些 IO 性能测试</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"># ioping -s <span class="number">1</span>G /</span><br><span class="line"><span class="number">1</span> GiB &lt;&lt;&lt; . (ext4 /dev/zram0): request=<span class="number">1</span> time=<span class="number">1.04</span> s (warmup)</span><br><span class="line"><span class="number">1</span> GiB &lt;&lt;&lt; . (ext4 /dev/zram0): request=<span class="number">2</span> time=<span class="number">1.04</span> s</span><br><span class="line"><span class="number">1</span> GiB &lt;&lt;&lt; . (ext4 /dev/zram0): request=<span class="number">3</span> time=<span class="number">1.04</span> s</span><br><span class="line"><span class="number">1</span> GiB &lt;&lt;&lt; . (ext4 /dev/zram0): request=<span class="number">4</span> time=<span class="number">1.04</span> s</span><br><span class="line"><span class="number">1</span> GiB &lt;&lt;&lt; . (ext4 /dev/zram0): request=<span class="number">5</span> time=<span class="number">1.04</span> s</span><br><span class="line"><span class="number">1</span> GiB &lt;&lt;&lt; . (ext4 /dev/zram0): request=<span class="number">6</span> time=<span class="number">1.04</span> s ^C</span><br><span class="line"></span><br><span class="line">--- / (ext4 /dev/zram0) ioping statistics ---</span><br><span class="line"><span class="number">5</span> requests completed <span class="keyword">in</span> <span class="number">5.18</span> s, <span class="number">5</span> GiB read, <span class="number">0</span> iops, <span class="number">988.4</span> MiB/s</span><br><span class="line">generated <span class="number">6</span> requests <span class="keyword">in</span> <span class="number">7.20</span> s, <span class="number">6</span> GiB, <span class="number">0</span> iops, <span class="number">853.8</span> MiB/s</span><br><span class="line">min/avg/max/mdev = <span class="number">1.04</span> s / <span class="number">1.04</span> s / <span class="number">1.04</span> s / <span class="number">550.7</span> us</span><br></pre></td></tr></table></figure><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># ioping -RD /</span></span><br><span class="line"></span><br><span class="line"><span class="string">---</span> <span class="string">/</span> <span class="string">(ext4</span> <span class="string">/dev/zram0)</span> <span class="string">ioping</span> <span class="string">statistics</span> <span class="string">---</span></span><br><span class="line"><span class="number">530.0</span> <span class="string">k</span> <span class="string">requests</span> <span class="string">completed</span> <span class="string">in</span> <span class="number">2.49</span> <span class="string">s,</span> <span class="number">2.02</span> <span class="string">GiB</span> <span class="string">read,</span> <span class="number">212.9</span> <span class="string">k</span> <span class="string">iops,</span> <span class="number">831.7</span> <span class="string">MiB/s</span></span><br><span class="line"><span class="string">generated</span> <span class="number">530.0</span> <span class="string">k</span> <span class="string">requests</span> <span class="string">in</span> <span class="number">3.00</span> <span class="string">s,</span> <span class="number">2.02</span> <span class="string">GiB,</span> <span class="number">176.7</span> <span class="string">k</span> <span class="string">iops,</span> <span class="number">690.1</span> <span class="string">MiB/s</span></span><br><span class="line"><span class="string">min/avg/max/mdev</span> <span class="string">=</span> <span class="number">3.44</span> <span class="string">us</span> <span class="string">/</span> <span class="number">4.70</span> <span class="string">us</span> <span class="string">/</span> <span class="number">69.0</span> <span class="string">us</span> <span class="string">/</span> <span class="number">1.39</span> <span class="string">us</span></span><br></pre></td></tr></table></figure><p>可以看到系统根分区在 zram 里，经过压缩因此 IO 带宽受到了 CPU 处理性能的限制。但是 IOPS 依然高得爆表，对比一下 Intel Optane 900P 的 IOPS 性能：</p><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># ioping -RD /</span></span><br><span class="line">--- <span class="regexp">/ (ext4 /</span>dev/nvme0n1p1) ioping statistics ---</span><br><span class="line"><span class="number">163.1</span> k requests completed <span class="keyword">in</span> <span class="number">3.00</span> s, <span class="number">56.5</span> k iops, <span class="number">220.8</span> MiB/s</span><br><span class="line">min<span class="regexp">/avg/m</span>ax<span class="regexp">/mdev = 11 us /</span> <span class="number">17</span> us <span class="regexp">/ 114 us /</span> <span class="number">4</span> us</span><br></pre></td></tr></table></figure><p>炒鸡厉害对不对！</p><p>不过需要做永久性修改的话还是要下面的方法之一</p><ul><li>重新挂载磁盘（虽然并不麻烦）然后手动修改配置文件</li><li>重新挂载磁盘然后 rsync zram 到磁盘（方便但是可能会多一些不必要的东西）</li><li>重启进入磁盘系统然后运行修改（需要物理接触）</li></ul><h3 id="硬件设置"><a href="#硬件设置" class="headerlink" title="硬件设置"></a>硬件设置</h3><p>进入系统 BIOS 设置，开启 Power on AC 或设置 Power Failure 后的操作，选择为 Power On （默认一般是 Last State）。</p><p>关闭系统、拔出电源，或意外断电后，再接入电源即可自动开机引导系统。因为数据本身就只在内存中，除了运行中的临时更改会丢失，系统和硬盘本体都是安然无恙的。</p><p>再也不担心办公室断电检查啦。</p><p>大概就是这样。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;一直把自己在办公室的 PC 保持开机用于连回办公区、存取数据工作需求。由于最近办公室所在的写字楼要全馆断电检点，所以诞生了构建一个 Service Router 的想法。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>通过 SSH 修正安装有 GPU 的 HPE Proliant 服务器</title>
    <link href="https://blog.phoenixlzx.com/2018/08/04/fix-hpe-proliant-ilo4-display-with-gpu-installed-using-ssh/"/>
    <id>https://blog.phoenixlzx.com/2018/08/04/fix-hpe-proliant-ilo4-display-with-gpu-installed-using-ssh/</id>
    <published>2018-08-03T17:45:00.000Z</published>
    <updated>2020-09-14T04:20:19.886Z</updated>
    
    <content type="html"><![CDATA[<p>由于越来越多的渲染、压制等需求，托供货商的关系搞来一台带有独立显卡的 HPE 服务器。经过几番折腾（包括特别奇怪的 LS26-C14 电源线）麻烦了帮忙托管的数据中心的大兄弟好几回，终于算是上架可以开机了。</p><p>登入 iLO，安装许可证，启动 iLO Remote Console，打开电源，一切都很顺利。但是 Console 里显示 Early Initialization… 完成后，突然画面一黑，完全没了动静。</p><a id="more"></a><p>以为 iLO 出了 bug，冷重启好几次都是一样的结果。百思不得其解。</p><p>再重启一次。仔细观察了一番发现虽然没了画面，但是 POST Code 还是不断变化的，而且 Virtual Media 指示灯不断在闪烁，说明系统仍在正常运行，只是没有视频输出而已。</p><p>因此问题定位在视频输出而非系统硬件。既然这台服务器装了显卡，那么很可能是 PCI-e 初始化后视频输出全部交给显卡处理了。搜索了一下 HPE Community，确实有这样的情况存在。解决方案是通过 BIOS 修改显卡设置为默认集成显卡、备选独立显卡。</p><p>尝试在设备初始化阶段进入 BIOS，失败。</p><p>联系数据中心远程操作的话，可能要等一段时间。</p><p>纠结时随便点开 iLO 的管理页面，突然发现了华点：这货居然支持 SSH。</p><p>对啦，HPE 的底层系统几乎都是魔改版 Linux，连他们的 SmartArray 都是 Linux 启动一个 Firefox 浏览器来操作的（X</p><p>于是正好在网上搜到一篇<a href="https://lukas.dzunko.sk/index.php/Hardware:_HP_Microserver_-_How_to_fix_ILO4_after_adding_second_graphics_card">通过 SSH 修改 BIOS 视频设置</a>的方法。记录如下。</p><h3 id="SSH-进入-iLO"><a href="#SSH-进入-iLO" class="headerlink" title="SSH 进入 iLO"></a>SSH 进入 iLO</h3><p>确保 SSH 在 iLO 管理页面中已开启，然后使用 SSH 客户端正常连接：</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh <span class="symbol">Administrator@</span><span class="number">10.6</span><span class="number">.254</span><span class="number">.121</span></span><br></pre></td></tr></table></figure><p>（ssh 用户名是 Administrator 感觉各种违和）</p><h3 id="连接到-Virtual-Serial-Port"><a href="#连接到-Virtual-Serial-Port" class="headerlink" title="连接到 Virtual Serial Port"></a>连接到 Virtual Serial Port</h3><p>命令很简单：<code>vsp</code></p><p>在 iLO 管理页面重启系统，然后等待初始化完成。如果看到按下 <code>F9</code> 进入 BIOS 设置的提示，<strong>不要按下它</strong>否则会进入 GUI 模式（于是又去独立显卡了就。</p><p>看到 <code>ESC</code> + <code>9</code> 进入 BIOS Setup Utility 时按下键组合，稍等一会儿应该就可以看到提示符 <code>rbsu&gt;</code>。</p><h3 id="修改视频设置"><a href="#修改视频设置" class="headerlink" title="修改视频设置"></a>修改视频设置</h3><p>命令 <code>SHOW CONFIG VIDEO OPTIONS</code></p><p>显示如下</p><figure class="highlight 1c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span><span class="string">|Optional Video Primary, Embedded Video Disabled &lt;=</span></span><br><span class="line"><span class="number">2</span><span class="string">|Optional Video Primary, Embedded Video Secondary</span></span><br><span class="line"><span class="number">3</span><span class="string">|Embedded Video Primary, Optional Video Secondary</span></span><br></pre></td></tr></table></figure><p>即默认关闭了集成显卡，只用独立显卡（不觉得很蠢吗！</p><p>于是修改为第三项，默认使用集成显卡，独立显卡作为备用。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="builtin-name">SET</span><span class="built_in"> CONFIG </span>VIDEO OPTIONS 3</span><br></pre></td></tr></table></figure><figure class="highlight 1c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span><span class="string">|Optional Video Primary, Embedded Video Disabled</span></span><br><span class="line"><span class="number">2</span><span class="string">|Optional Video Primary, Embedded Video Secondary</span></span><br><span class="line"><span class="number">3</span><span class="string">|Embedded Video Primary, Optional Video Secondary &lt;=</span></span><br></pre></td></tr></table></figure><p>然后敲 <code>EXIT</code> 退出并重启系统。</p><h3 id="安装系统和驱动"><a href="#安装系统和驱动" class="headerlink" title="安装系统和驱动"></a>安装系统和驱动</h3><p>至此即可通过 iLO Advanced Console 正常安装操作系统。不过需要注意的是进入操作系统后即便安装了对应的显卡驱动，依然默认使用的是集成显卡。以及 RDP 只能使用软解，无法使用独立显卡加速视频输出。这不影响 Blender 或者 Cinema 4D 等直接操作显卡进行计算的程序，但是会影响直接输出视频到桌面的程序。通过 Teamviewer 则可以强制桌面运行在独立显卡上。</p><p>顺便吐槽：Blender 把我的工程材质弄丢了…</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;由于越来越多的渲染、压制等需求，托供货商的关系搞来一台带有独立显卡的 HPE 服务器。经过几番折腾（包括特别奇怪的 LS26-C14 电源线）麻烦了帮忙托管的数据中心的大兄弟好几回，终于算是上架可以开机了。&lt;/p&gt;
&lt;p&gt;登入 iLO，安装许可证，启动 iLO Remote Console，打开电源，一切都很顺利。但是 Console 里显示 Early Initialization… 完成后，突然画面一黑，完全没了动静。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>在线扩展 LVM root 分区</title>
    <link href="https://blog.phoenixlzx.com/2018/06/06/resize-lvm-rootfs-online/"/>
    <id>https://blog.phoenixlzx.com/2018/06/06/resize-lvm-rootfs-online/</id>
    <published>2018-06-06T14:31:03.000Z</published>
    <updated>2020-09-14T04:20:19.882Z</updated>
    
    <content type="html"><![CDATA[<p><del><em>才不是没东西写了呢</em></del></p><p>遇到一个奇葩的原因导致 root 分区被占满的。而且还是奇葩的 CentOS，root 分区是 LVM，Hypervisor 里扩展磁盘后无法直接用 resize2fs。</p><a id="more"></a><p>既然如此就只能暴力重建分区咯。</p><h4 id="重建分区"><a href="#重建分区" class="headerlink" title="重建分区"></a>重建分区</h4><p>操作前确保操作的分区和之后新建时 Start 保持一致，修改分区表后不至于分区崩坏。</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line">~&gt; fidks /dev/sda</span><br><span class="line">Welcome <span class="keyword">to</span> fdisk (util-linux 2.23.2).</span><br><span class="line"></span><br><span class="line">Changes will remain <span class="keyword">in</span> memory only, until you decide <span class="keyword">to</span> write them.</span><br><span class="line">Be careful before using the write command.</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Command (m <span class="keyword">for</span> help): p</span><br><span class="line"></span><br><span class="line">Disk /dev/sda: 103.1 GB, 103079215104 bytes, 201326592 sectors</span><br><span class="line">Units = sectors of 1 * 512 = 512 bytes</span><br><span class="line">Sector size (logical/physical): 512 bytes / 512 bytes</span><br><span class="line">I/O size (minimum/optimal): 512 bytes / 512 bytes</span><br><span class="line">Disk label type: dos</span><br><span class="line">Disk identifier: 0x000a8e23</span><br><span class="line"></span><br><span class="line">   Device Boot      Start         End      Blocks   Id  System</span><br><span class="line">/dev/sda1   *        2048     2099199     1048576   83  Linux</span><br><span class="line">/dev/sda2         2099200    50331647    24116224   8e  Linux LVM</span><br><span class="line"></span><br><span class="line">Command (m <span class="keyword">for</span> help): d</span><br><span class="line">Partition number (1,2,<span class="built_in"> default </span>2): 2</span><br><span class="line">Partition 2 is deleted</span><br><span class="line"></span><br><span class="line">Command (m <span class="keyword">for</span> help): n</span><br><span class="line">Partition type:</span><br><span class="line">   p   primary (1 primary, 0 extended, 3 free)</span><br><span class="line">   e   extended</span><br><span class="line">Select (default p):</span><br><span class="line">Using<span class="built_in"> default </span>response p</span><br><span class="line">Partition number (2-4,<span class="built_in"> default </span>2):</span><br><span class="line">First sector (2099200-201326591,<span class="built_in"> default </span>2099200):</span><br><span class="line">Using<span class="built_in"> default </span>value 2099200</span><br><span class="line">Last sector, +sectors <span class="keyword">or</span> +size&#123;K,M,G&#125; (2099200-201326591,<span class="built_in"> default </span>201326591):</span><br><span class="line">Using<span class="built_in"> default </span>value 201326591</span><br><span class="line">Partition 2 of<span class="built_in"> type </span>Linux <span class="keyword">and</span> of size 95 GiB is set</span><br><span class="line"></span><br><span class="line">Command (m <span class="keyword">for</span> help): w</span><br><span class="line">The partition table has been altered!</span><br><span class="line"></span><br><span class="line">Calling ioctl() <span class="keyword">to</span> re-read partition table.</span><br><span class="line"></span><br><span class="line">WARNING: Re-reading the partition table failed with <span class="builtin-name">error</span> 16: Device <span class="keyword">or</span><span class="built_in"> resource </span>busy.</span><br><span class="line">The kernel still uses the old table. The new table will be used at</span><br><span class="line">the next reboot <span class="keyword">or</span> after you <span class="builtin-name">run</span> partprobe(8) <span class="keyword">or</span> kpartx(8)</span><br><span class="line">Syncing disks.</span><br><span class="line"></span><br><span class="line">~&gt; partprobe</span><br></pre></td></tr></table></figure><p>现在就可以看到 <code>/dev/sda2</code> 的大小已经变化了：</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">~&gt; lsblk</span><br><span class="line">NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT</span><br><span class="line">sda               <span class="number">8</span>:<span class="number">0</span>    <span class="number">0</span>   <span class="number">96</span>G  <span class="number">0</span> disk</span><br><span class="line">├─sda1            <span class="number">8</span>:<span class="number">1</span>    <span class="number">0</span>    <span class="number">1</span>G  <span class="number">0</span> part /boot</span><br><span class="line">└─sda2            <span class="number">8</span>:<span class="number">2</span>    <span class="number">0</span>   <span class="number">95</span>G  <span class="number">0</span> part</span><br><span class="line">  ├─centos-root <span class="number">253</span>:<span class="number">0</span>    <span class="number">0</span> <span class="number">20.6</span>G  <span class="number">0</span> lvm  /</span><br><span class="line">  └─centos-swap <span class="number">253</span>:<span class="number">1</span>    <span class="number">0</span>  <span class="number">2.4</span>G  <span class="number">0</span> lvm  [SWAP]</span><br><span class="line">sr0              <span class="number">11</span>:<span class="number">0</span>    <span class="number">1</span>  <span class="number">906</span>M  <span class="number">0</span> rom</span><br></pre></td></tr></table></figure><h4 id="扩展-Volume-Group"><a href="#扩展-Volume-Group" class="headerlink" title="扩展 Volume Group"></a>扩展 Volume Group</h4><p>VG 的好处也就是能够灵活扩展分区大小…</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">~&gt; pvresize /dev/sda2</span><br><span class="line">  Physical <span class="keyword">volume</span><span class="bash"> <span class="string">&quot;/dev/sda2&quot;</span> changed</span></span><br><span class="line">  <span class="number">1</span> physical <span class="keyword">volume</span><span class="bash">(s) resized / 0 physical volume(s) not resized</span></span><br></pre></td></tr></table></figure><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">~&gt; vgdisplay</span><br><span class="line">  --- Volume<span class="built_in"> group </span>---</span><br><span class="line">  VG Name               centos</span><br><span class="line"> <span class="built_in"> System </span>ID</span><br><span class="line">  Format                lvm2</span><br><span class="line">  Metadata Areas        1</span><br><span class="line">  Metadata Sequence <span class="literal">No</span>  4</span><br><span class="line">  VG Access             read/write</span><br><span class="line">  VG Status             resizable</span><br><span class="line">  MAX LV                0</span><br><span class="line">  Cur LV                2</span><br><span class="line">  Open LV               2</span><br><span class="line">  Max PV                0</span><br><span class="line">  Cur PV                1</span><br><span class="line">  Act PV                1</span><br><span class="line">  VG Size               &lt;95.00 GiB</span><br><span class="line">  PE Size               4.00 MiB</span><br><span class="line">  Total PE              24319</span><br><span class="line">  Alloc PE / Size       5887 / &lt;23.00 GiB</span><br><span class="line">  Free  PE / Size       18432 / 72.00 GiB</span><br><span class="line">  VG UUID               TpbtuH-AjTZ-PU3v-UN31-FvfX-kSLv-xLiJG7</span><br></pre></td></tr></table></figure><p>至此已经可以看到 <code>Free PE</code> 的部分有多出的 72GB 空间。</p><h4 id="扩展-Logic-Volume"><a href="#扩展-Logic-Volume" class="headerlink" title="扩展 Logic Volume"></a>扩展 Logic Volume</h4><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">~&gt; lvextend -r -l +100%FREE /dev/centos/root</span><br><span class="line">  Size of logical volume centos/root changed <span class="keyword">from</span> 20.59 GiB (5272 extents) <span class="keyword">to</span> 92.59 GiB (23704 extents).</span><br><span class="line">  Logical volume centos/root successfully resized.</span><br><span class="line"><span class="attribute">meta-data</span>=/dev/mapper/centos-root <span class="attribute">isize</span>=512    <span class="attribute">agcount</span>=4, <span class="attribute">agsize</span>=1349632 blks</span><br><span class="line">         =                       <span class="attribute">sectsz</span>=512   <span class="attribute">attr</span>=2, <span class="attribute">projid32bit</span>=1</span><br><span class="line">         =                       <span class="attribute">crc</span>=1        <span class="attribute">finobt</span>=0 <span class="attribute">spinodes</span>=0</span><br><span class="line">data     =                       <span class="attribute">bsize</span>=4096   <span class="attribute">blocks</span>=5398528, <span class="attribute">imaxpct</span>=25</span><br><span class="line">         =                       <span class="attribute">sunit</span>=0      <span class="attribute">swidth</span>=0 blks</span><br><span class="line">naming   =version 2              <span class="attribute">bsize</span>=4096   <span class="attribute">ascii-ci</span>=0 <span class="attribute">ftype</span>=1</span><br><span class="line">log      =internal               <span class="attribute">bsize</span>=4096   <span class="attribute">blocks</span>=2636, <span class="attribute">version</span>=2</span><br><span class="line">         =                       <span class="attribute">sectsz</span>=512   <span class="attribute">sunit</span>=0 blks, <span class="attribute">lazy-count</span>=1</span><br><span class="line">realtime =none                   <span class="attribute">extsz</span>=4096   <span class="attribute">blocks</span>=0, <span class="attribute">rtextents</span>=0</span><br><span class="line">data blocks changed <span class="keyword">from</span> 5398528 <span class="keyword">to</span> 24272896</span><br></pre></td></tr></table></figure><p>确认效果：</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">~&gt; lsblk</span><br><span class="line">NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT</span><br><span class="line">sda               <span class="number">8</span>:<span class="number">0</span>    <span class="number">0</span>   <span class="number">96</span>G  <span class="number">0</span> disk </span><br><span class="line">├─sda1            <span class="number">8</span>:<span class="number">1</span>    <span class="number">0</span>    <span class="number">1</span>G  <span class="number">0</span> part /boot</span><br><span class="line">└─sda2            <span class="number">8</span>:<span class="number">2</span>    <span class="number">0</span>   <span class="number">95</span>G  <span class="number">0</span> part </span><br><span class="line">  ├─centos-root <span class="number">253</span>:<span class="number">0</span>    <span class="number">0</span> <span class="number">92.6</span>G  <span class="number">0</span> lvm  /</span><br><span class="line">  └─centos-swap <span class="number">253</span>:<span class="number">1</span>    <span class="number">0</span>  <span class="number">2.4</span>G  <span class="number">0</span> lvm  [SWAP]</span><br><span class="line">sr0              <span class="number">11</span>:<span class="number">0</span>    <span class="number">1</span>  <span class="number">906</span>M  <span class="number">0</span> rom</span><br><span class="line"></span><br><span class="line">~&gt; df -h</span><br><span class="line">Filesystem               Size  Used Avail Use% Mounted on</span><br><span class="line">/dev/mapper/centos-root   <span class="number">93</span>G   <span class="number">21</span>G   <span class="number">73</span>G  <span class="number">23</span>% /</span><br><span class="line">devtmpfs                 <span class="number">3.9</span>G     <span class="number">0</span>  <span class="number">3.9</span>G   <span class="number">0</span>% /dev</span><br><span class="line">tmpfs                    <span class="number">3.9</span>G  <span class="number">8.0</span>K  <span class="number">3.9</span>G   <span class="number">1</span>% /dev/shm</span><br><span class="line">tmpfs                    <span class="number">3.9</span>G  <span class="number">8.6</span>M  <span class="number">3.9</span>G   <span class="number">1</span>% /run</span><br><span class="line">tmpfs                    <span class="number">3.9</span>G     <span class="number">0</span>  <span class="number">3.9</span>G   <span class="number">0</span>% /sys/fs/cgroup</span><br><span class="line">/dev/sda1               <span class="number">1014</span>M  <span class="number">185</span>M  <span class="number">830</span>M  <span class="number">19</span>% /boot</span><br><span class="line">tmpfs                    <span class="number">783</span>M     <span class="number">0</span>  <span class="number">783</span>M   <span class="number">0</span>% /run/user/<span class="number">0</span></span><br></pre></td></tr></table></figure><p>搞定收工(‘・ω・’)</p><h4 id="后话"><a href="#后话" class="headerlink" title="后话"></a>后话</h4><p>其实虚拟机还用 LVM 的话，直接新增一块虚拟硬盘是最方便的方案。直接 <code>vgextend</code> 一路搞定…</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;del&gt;&lt;em&gt;才不是没东西写了呢&lt;/em&gt;&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;遇到一个奇葩的原因导致 root 分区被占满的。而且还是奇葩的 CentOS，root 分区是 LVM，Hypervisor 里扩展磁盘后无法直接用 resize2fs。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>在 Linux 服务器配置 LACP 与 VLAN</title>
    <link href="https://blog.phoenixlzx.com/2018/04/18/play-with-linux-lacp-bonding-on-vlan/"/>
    <id>https://blog.phoenixlzx.com/2018/04/18/play-with-linux-lacp-bonding-on-vlan/</id>
    <published>2018-04-18T05:59:11.000Z</published>
    <updated>2020-09-14T04:20:19.879Z</updated>
    
    <content type="html"><![CDATA[<p>存储服务器不想放在 OVH 了。所以自己来托管一台机器，顺便折腾下 2x1Gbps 组 LACP Bonding。</p><a id="more"></a><p>前提：服务器需要至少 2 个千兆物理网卡，上联交换机支持 802.3ad。</p><h3 id="配置交换机"><a href="#配置交换机" class="headerlink" title="配置交换机"></a>配置交换机</h3><p>这里使用的是 Cisco Nexus 3064PQ-10GE 交换机，我们的接口在 <code>Eth1/21-22</code>，port-channel 的配置如下：</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># show interface trunk</span></span><br><span class="line"></span><br><span class="line">--------------------------------------------------------------------------------</span><br><span class="line">Port          Native  Status        Port</span><br><span class="line">             <span class="built_in"> Vlan </span>                 Channel</span><br><span class="line">--------------------------------------------------------------------------------</span><br><span class="line">Eth1/21       1       trnk-bndl     Po100</span><br><span class="line">Eth1/22       1       trnk-bndl     Po100</span><br><span class="line">Po100         1       trunking      --</span><br></pre></td></tr></table></figure><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">show port-channel database</span><br><span class="line">port-channel100</span><br><span class="line">    Last membership update <span class="keyword">is</span> successful</span><br><span class="line">    <span class="number">2</span> ports <span class="keyword">in</span> total, <span class="number">2</span> ports up</span><br><span class="line">    First operational port <span class="keyword">is</span> Ethernet1/<span class="number">21</span></span><br><span class="line">    Age of the port-channel <span class="keyword">is</span> <span class="number">0</span>d:<span class="number">00</span>h:<span class="number">02</span>m:<span class="number">16</span>s</span><br><span class="line">    Time since last bundle <span class="keyword">is</span> <span class="number">0</span>d:<span class="number">00</span>h:<span class="number">02</span>m:<span class="number">04</span>s</span><br><span class="line">    Last bundled member <span class="keyword">is</span> Ethernet1/<span class="number">22</span></span><br><span class="line">    Ports:   Ethernet1/<span class="number">21</span>    [active ] [up] *</span><br><span class="line">             Ethernet1/<span class="number">22</span>    [active ] [up]</span><br></pre></td></tr></table></figure><h3 id="配置服务器"><a href="#配置服务器" class="headerlink" title="配置服务器"></a>配置服务器</h3><p>服务器操作系统是 Arch Linux，由于蜜汁问题 netctl 无法启动网卡，就只好用 systemd-networkd 啦。</p><p>麻烦一些，但是也还算顺利。与往常一样，折腾服务器网络的时候需要备着 IPMI 以防 connection lost。</p><h5 id="内核模块"><a href="#内核模块" class="headerlink" title="内核模块"></a>内核模块</h5><p>需要加载 <code>bonding</code> 模块。将模块名写入列表，文件 <code>/etc/modules-load.d/bonding.conf</code>，内容只需要一行：</p><figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">bonding</span></span><br></pre></td></tr></table></figure><p>先别急着加载模块，为了防止模块自动建立一个默认网卡影响后续配置，以及设置 LACP Mode=4 … 等等，先加入一行参数。文件 <code>/etc/modprobe.d/bonding.conf</code></p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">options bonding <span class="attribute">mode</span>=4 <span class="attribute">miimon</span>=100 <span class="attribute">max_bonds</span>=0</span><br></pre></td></tr></table></figure><p>然后安装 <code>ifenslave</code> 包，再 <code>modprobe bonding</code> 即可。</p><h5 id="bonding-虚拟网卡"><a href="#bonding-虚拟网卡" class="headerlink" title="bonding 虚拟网卡"></a>bonding 虚拟网卡</h5><p>首先创建一个虚拟网卡的设备。文件 <code>/etc/systemd/network/bond0.netdev</code> 内容为</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[NetDev]</span></span><br><span class="line"><span class="attr">Name</span>=bond0</span><br><span class="line"><span class="attr">Kind</span>=bond</span><br><span class="line"></span><br><span class="line"><span class="section">[Bond]</span></span><br><span class="line"><span class="attr">Mode</span>=<span class="number">802.3</span>ad</span><br><span class="line"><span class="attr">TransmitHashPolicy</span>=layer2+<span class="number">3</span></span><br><span class="line"><span class="attr">LACPTransmitRate</span>=fast</span><br><span class="line"><span class="attr">AdSelect</span>=bandwidth</span><br></pre></td></tr></table></figure><p>然后在此虚拟网卡上创建网络。这里使用两个物理网卡 <code>eth0</code> 和 <code>eth1</code> 作为 bundle，交换机上的 VLAN id 是 <code>113</code>。文件 <code>/etc/systemd/network/bond0.network</code> 内容为</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[Match]</span></span><br><span class="line"><span class="attr">Name</span>=bond0</span><br><span class="line"></span><br><span class="line"><span class="section">[Network]</span></span><br><span class="line"><span class="attr">VLAN</span>=vlan113</span><br><span class="line"><span class="attr">BindCarrier</span>=eth0 eth1</span><br></pre></td></tr></table></figure><p>接下来分别为 <code>eth0</code> 和 <code>eth1</code> 建立网络设置。</p><ul><li><code>/etc/systemd/network/eth0.network</code></li></ul><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[Match]</span></span><br><span class="line"><span class="attr">Name</span>=eth0</span><br><span class="line"></span><br><span class="line"><span class="section">[Network]</span></span><br><span class="line"><span class="attr">Bond</span>=bond0</span><br></pre></td></tr></table></figure><ul><li><code>/etc/systemd/network/eth1.network</code></li></ul><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[Match]</span></span><br><span class="line"><span class="attr">Name</span>=eth1</span><br><span class="line"></span><br><span class="line"><span class="section">[Network]</span></span><br><span class="line"><span class="attr">Bond</span>=bond0</span><br></pre></td></tr></table></figure><p>最后是 VLAN 的设置。前面设置了上联 VLAN id 是 113，这里分别建立 VLAN 的虚拟网卡(based on bond0) 并设置网络(IP, etc)。</p><ul><li><code>/etc/systemd/network/vlan113.netdev</code></li></ul><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[NetDev]</span></span><br><span class="line"><span class="attr">Name</span>=vlan113</span><br><span class="line"><span class="attr">Kind</span>=vlan</span><br><span class="line"></span><br><span class="line"><span class="section">[VLAN]</span></span><br><span class="line"><span class="attr">Id</span>=<span class="number">113</span></span><br></pre></td></tr></table></figure><ul><li><code>/etc/systemd/network/vlan113.network</code></li></ul><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[Match]</span></span><br><span class="line"><span class="attr">Name</span>=vlan113</span><br><span class="line"></span><br><span class="line"><span class="section">[Network]</span></span><br><span class="line"><span class="attr">VLAN</span>=vlan113</span><br><span class="line"></span><br><span class="line"><span class="section">[Address]</span></span><br><span class="line"><span class="attr">Address</span>=<span class="number">10.1</span>.<span class="number">0.100</span>/<span class="number">24</span></span><br><span class="line"></span><br><span class="line"><span class="section">[Route]</span></span><br><span class="line"><span class="attr">Destination</span>=<span class="number">0.0</span>.<span class="number">0.0</span>/<span class="number">0</span></span><br><span class="line"><span class="attr">Gateway</span>=<span class="number">10.1</span>.<span class="number">0.1</span></span><br><span class="line"><span class="attr">DNS</span>=<span class="number">1.1</span>.<span class="number">1.1</span></span><br><span class="line"></span><br><span class="line"><span class="section">[Address]</span></span><br><span class="line"><span class="attr">Address</span>=<span class="number">2600</span>:x:x:x::<span class="number">2</span>/<span class="number">64</span></span><br><span class="line"></span><br><span class="line"><span class="section">[Route]</span></span><br><span class="line"><span class="attr">Gateway</span>=<span class="number">2600</span>:x:x:x::<span class="number">1</span></span><br></pre></td></tr></table></figure><p>多个地址、IPv6 等可以写多个 <code>[Address]</code> 和 <code>[Route]</code>。</p><p>至此就完成啦。开启 systemd-networkd 的自启动：</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl <span class="builtin-name">enable</span> systemd-networkd.service</span><br></pre></td></tr></table></figure><p>然后重启网络：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">systemctl</span> <span class="selector-tag">restart</span> <span class="selector-tag">systemd-networkd</span><span class="selector-class">.service</span></span><br></pre></td></tr></table></figure><p>如果配置都没有问题，网络会中断十几秒然后恢复。现在查看网卡列表已经可以看到组合的网卡了：</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># ip l</span></span><br><span class="line">1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN mode<span class="built_in"> DEFAULT group default </span>qlen 1000</span><br><span class="line">    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00</span><br><span class="line">2: eth0: &lt;BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP&gt; mtu 1500 qdisc mq master bond0 state UP mode<span class="built_in"> DEFAULT group default </span>qlen 1000</span><br><span class="line">    link/ether &lt;REDACTED&gt; brd ff:ff:ff:ff:ff:ff</span><br><span class="line">3: eth1: &lt;BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP&gt; mtu 1500 qdisc mq master bond0 state UP mode<span class="built_in"> DEFAULT group default </span>qlen 1000</span><br><span class="line">    link/ether &lt;REDACTED&gt; brd ff:ff:ff:ff:ff:ff</span><br><span class="line">4: eth2: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN mode<span class="built_in"> DEFAULT group default </span>qlen 1000</span><br><span class="line">    link/ether &lt;REDACTED&gt; brd ff:ff:ff:ff:ff:ff</span><br><span class="line">5: eno1: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN mode<span class="built_in"> DEFAULT group default </span>qlen 1000</span><br><span class="line">    link/ether &lt;REDACTED&gt; brd ff:ff:ff:ff:ff:ff</span><br><span class="line">6: bond0: &lt;BROADCAST,MULTICAST,MASTER,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP mode<span class="built_in"> DEFAULT group default </span>qlen 1000</span><br><span class="line">    link/ether &lt;REDACTED&gt; brd ff:ff:ff:ff:ff:ff</span><br><span class="line">7: vlan113@bond0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP mode<span class="built_in"> DEFAULT group default </span>qlen 1000</span><br><span class="line">    link/ether &lt;REDACTED&gt; brd ff:ff:ff:ff:ff:ff</span><br></pre></td></tr></table></figure><p><code>ethtool</code> 查看 <code>bond0</code> 的速率显示 <code>2000Mb/s</code>：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># ethtool bond0</span></span><br><span class="line"><span class="attr">Settings for bond0:</span></span><br><span class="line">        <span class="attr">Supported ports:</span> [ ]</span><br><span class="line">        <span class="attr">Supported link modes:</span>   <span class="string">Not</span> <span class="string">reported</span></span><br><span class="line">        <span class="attr">Supported pause frame use:</span> <span class="literal">No</span></span><br><span class="line">        <span class="attr">Supports auto-negotiation:</span> <span class="literal">No</span></span><br><span class="line">        <span class="attr">Supported FEC modes:</span> <span class="string">Not</span> <span class="string">reported</span></span><br><span class="line">        <span class="attr">Advertised link modes:</span>  <span class="string">Not</span> <span class="string">reported</span></span><br><span class="line">        <span class="attr">Advertised pause frame use:</span> <span class="literal">No</span></span><br><span class="line">        <span class="attr">Advertised auto-negotiation:</span> <span class="literal">No</span></span><br><span class="line">        <span class="attr">Advertised FEC modes:</span> <span class="string">Not</span> <span class="string">reported</span></span><br><span class="line">        <span class="attr">Speed:</span> <span class="string">2000Mb/s</span></span><br><span class="line">        <span class="attr">Duplex:</span> <span class="string">Full</span></span><br><span class="line">        <span class="attr">Port:</span> <span class="string">Other</span></span><br><span class="line">        <span class="attr">PHYAD:</span> <span class="number">0</span></span><br><span class="line">        <span class="attr">Transceiver:</span> <span class="string">internal</span></span><br><span class="line">        <span class="attr">Auto-negotiation:</span> <span class="string">off</span></span><br><span class="line">        <span class="attr">Link detected:</span> <span class="literal">yes</span></span><br></pre></td></tr></table></figure><p>搞定收工(‘・ω・’)</p><p>Reference:</p><ul><li><a href="https://wiki.archlinux.org/index.php/Netctl#Bonding">Arch Linux Wiki: Netctl#Bonding</a></li><li><a href="https://wiki.archlinux.org/index.php/VLAN#systemd-networkd_bonded_interface">Arch Linux Wiki: VLAN#systemd-networkd-bonded-interface</a></li><li><a href="https://wiki.archlinux.org/index.php/systemd-networkd">Arch Linux Wiki: Systemd-networkd</a></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;存储服务器不想放在 OVH 了。所以自己来托管一台机器，顺便折腾下 2x1Gbps 组 LACP Bonding。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>迁移 DokuWiki 到 BookStackApp</title>
    <link href="https://blog.phoenixlzx.com/2018/03/23/migrate-dokuwiki-to-bookstack/"/>
    <id>https://blog.phoenixlzx.com/2018/03/23/migrate-dokuwiki-to-bookstack/</id>
    <published>2018-03-22T15:12:08.000Z</published>
    <updated>2020-09-14T04:20:19.876Z</updated>
    
    <content type="html"><![CDATA[<p>Wiki 这么反人类的语法是怎么存在这么久的？？？？？？？</p><a id="more"></a><p>总之受不了 Wiki 语法的可维护性了。什么？这玩意儿有维护性？？？</p><p>以及万年不更新的各种插件。系统升级后 PHP 7 不兼容，一看还是 swiftmail 的问题。生气。</p><p>正好有需求要整合一套知识库平台，搜索了一下 Confluence 的 alternative，发现了 <a href="https://www.bookstackapp.com/">BookStackApp</a> 和 <a href="https://www.phacility.com/">Phabricator</a>。</p><p>前者适合个人或开源社区使用，后者则是一整套企业协作解决方案。对于我的需求来讲，BookStackApp 就足够啦。</p><h3 id="页面数据"><a href="#页面数据" class="headerlink" title="页面数据"></a>页面数据</h3><p>DokuWiki 并不使用数据库，因此没有一个通用的中间件来实现数据格式转换。而 DokuWiki 的语法非常奇葩——比如，它的一级标题是 <code>====== 这样 ======</code>，六级标题才是 <code>= 这样 =</code>，正好和一般的 Wikitext 倒置。图片、内链等的表达方式也相当愚蠢，这些问题使我在思考迁移方案的第一个小时内就放弃了直接从源码转移的途径。</p><p>顺便，还有另外一个问题——本来为了使 Wiki 易于编写，这 DokuWiki 还安装了 Markdown 插件。因此部分页面中混杂着 Markdown 语法，更增加了源码处理的复杂度。</p><p>综合来看，最通用的数据格式，就是最终渲染出来的 XHTML 了。</p><h3 id="图片"><a href="#图片" class="headerlink" title="图片"></a>图片</h3><p>DokuWiki 的图片存储策略也是非常的奇特。由于它没有数据库，因此为了保持图片与页面的对应，它将图片存储在每个页面同样的路径下，并通过执行 PHP 的方式获取（扶额。</p><p>更甚者！！！</p><p>外链的图片，也是通过 <code>/lib/exe/fetch.php</code> 带参数来获取！！</p><p>我  的  天  哪。</p><p>因此既然在页面数据的考量中决定了使用最终渲染输出的 XHTML 来处理数据格式，图片也需要特殊的下载和归档技巧。这将需要使用 <code>sanitize-html</code> 提供的 <code>transformer</code> 方法来实现。</p><h3 id="逻辑实现"><a href="#逻辑实现" class="headerlink" title="逻辑实现"></a>逻辑实现</h3><p>一开始尝试了一些 Site Exporter 插件，但遗憾的是并没有什么真正能派上用场。甚至一些暴力递归下载所有页面和资源的脚本的表现也非常糟糕。</p><p>但是根据 DokuWiki 的官方 Tips，它可以将文章内容单纯导出 XHTML，只需要加上 <code>?do=export_xhtmlbody</code> 参数即可。这就方便了，因为这样只需要一个完整的页面列表就可以了。随便找一个可以输出子命名空间的插件，新建一个页面用于从根命名空间展开就 OK 啦。</p><p>请求这个列表页面的 XHTML body 输出，使用 <code>cheerio</code> 遍历所有的 <code>a</code> 标签，就获得了所有要导出的页面地址。分别再去请求这些页面的 XHTML body 输出，做如下处理：</p><ol><li>跟踪所有的 <code>img</code> 标签，下载图片文件并按预定义的路径规则和文件名归档。</li><li><code>sanitize-html</code> 清除所有不必要的标签、样式、id 和 class。</li><li><code>sanitize-html</code> 按预定义的路径规则更新所有 <code>a</code> 和 <code>img</code> 标签属性。</li></ol><p><a href="https://github.com/phoenixlzx/dokuwiki-exporter/blob/master/exporter.js">看代码</a></p><p>后来发现 DokuWiki 的性能不足以支撑异步请求的速度，额外加上了 <code>sleep</code> 模块来控制请求频率（扶额。</p><p>脚本执行完后，将图片目录移动到 BookStackApp 的对应位置，便可以直接读取所有的 HTML 文件来导入数据啦。</p><p>用了这么久，才发现原来还有比 raw HTML 更难以维护的数据格式啊…（望天。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;Wiki 这么反人类的语法是怎么存在这么久的？？？？？？？&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>制作 Arch Linux 系统模板镜像</title>
    <link href="https://blog.phoenixlzx.com/2018/02/01/build-archlinux-image-template-for-aliyun/"/>
    <id>https://blog.phoenixlzx.com/2018/02/01/build-archlinux-image-template-for-aliyun/</id>
    <published>2018-02-01T05:09:02.000Z</published>
    <updated>2020-09-14T04:20:19.882Z</updated>
    
    <content type="html"><![CDATA[<p>阿里云镜像制作踩坑记。</p><p>此文章主要记录按照<a href="https://www.alibabacloud.com/help/zh/faq-detail/51138.htm">阿里云 Customized Linux</a> 制作 VPC 镜像的过程。一些部分也可用作制作其他平台镜像的参考。                       </p><p>当然记录的原因主要是 Arch 上的 cloud-init 打死无法在阿里云上修改 root 密码，就很气。</p><a id="more"></a><h3 id="建立虚拟机"><a href="#建立虚拟机" class="headerlink" title="建立虚拟机"></a>建立虚拟机</h3><p>因为要制作 Customized Linux，所以第一步无法在阿里云平台上使用公共镜像制作。本机启动一个 Virtual Box，新建虚拟机，虚拟磁盘选择 RAW/IMG 格式即可。</p><p>按照一般步骤安装 Arch Linux，需要整个磁盘仅有一个分区。虽然很多平台支持多分区的镜像文件，但是莫名在这里踩了坑所以。</p><p>（另外吐槽：vps2arch 居然不帮我把 <code>base-devel</code> 装全了？！）</p><h3 id="系统配置"><a href="#系统配置" class="headerlink" title="系统配置"></a>系统配置</h3><p>安装一些必需的包。</p><figure class="highlight vala"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"># pacman -S qemu-guest-ga openssh</span></span><br></pre></td></tr></table></figure><p>启用服务。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> systemctl <span class="built_in">enable</span> qemu-ga</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> systemctl <span class="built_in">enable</span> sshd</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> systemctl <span class="built_in">enable</span> systemd-networkd</span></span><br></pre></td></tr></table></figure><h4 id="网络配置"><a href="#网络配置" class="headerlink" title="网络配置"></a>网络配置</h4><p>哪个魂淡跟我讲 VPC 是 DHCP？装着 cloud-init 的 Arch 就可以自动设置内网 IP，这个没装的就 GG。</p><p>修改文件 <code>/etc/systemd/network/default.network</code></p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[Match]</span></span><br><span class="line"><span class="attr">Name</span>=en*</span><br><span class="line"></span><br><span class="line"><span class="section">[Network]</span></span><br><span class="line"><span class="attr">DHCP</span>=ipv4</span><br></pre></td></tr></table></figure><p>总之先这样放着。</p><h4 id="定制脚本"><a href="#定制脚本" class="headerlink" title="定制脚本"></a>定制脚本</h4><p>根据阿里云的文档，cloud init 不生效的时候需要用约定好的配置文件和脚本完成各种兼容动作。</p><p>新建目录 <code>/aliyun_custom_image</code></p><p>新建文件 <code>/usr/bin/aliyun-custom-os</code>，写入内容</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line">os_conf_dir=/aliyun_custom_image</span><br><span class="line">os_conf_file=<span class="variable">$&#123;os_conf_dir&#125;</span>/os.conf</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">load_os_conf</span></span>() &#123;</span><br><span class="line">    <span class="keyword">if</span> [[ -f <span class="variable">$os_conf_file</span> ]]; <span class="keyword">then</span></span><br><span class="line">        . <span class="variable">$os_conf_file</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="variable">$password</span></span><br><span class="line">        <span class="built_in">return</span> 0</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        <span class="built_in">return</span> 1</span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">cleanup</span></span>() &#123;</span><br><span class="line">    <span class="comment"># ensure $os_conf_file is deleted, to avoid repeating config system</span></span><br><span class="line">    rm <span class="variable">$os_conf_file</span> &gt;&amp; /dev/null</span><br><span class="line">    <span class="comment"># ensure $os_conf_dir is exitst</span></span><br><span class="line">    mkdir -p <span class="variable">$os_conf_dir</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">config_password</span></span>() &#123;</span><br><span class="line">    <span class="keyword">if</span> [[ -n <span class="variable">$password</span> ]]; <span class="keyword">then</span></span><br><span class="line">        password=$(<span class="built_in">echo</span> <span class="variable">$password</span> | base64 -d)</span><br><span class="line">        <span class="keyword">if</span> [[ $? == 0 &amp;&amp; -n <span class="variable">$password</span> ]]; <span class="keyword">then</span></span><br><span class="line">            <span class="built_in">echo</span> <span class="string">&quot;root:<span class="variable">$password</span>&quot;</span></span><br><span class="line">            <span class="built_in">echo</span> <span class="string">&quot;root:<span class="variable">$password</span>&quot;</span> | chpasswd</span><br><span class="line">        <span class="keyword">fi</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="title">config_hostname</span></span>() &#123;</span><br><span class="line">    <span class="keyword">if</span> [[ -n <span class="variable">$hostname</span> ]]; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&quot;<span class="variable">$hostname</span>&quot;</span> &gt; /etc/hostname</span><br><span class="line">        hostnamectl set-hostname <span class="variable">$hostname</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="title">config_network</span></span>() &#123;</span><br><span class="line">    <span class="keyword">if</span> [[ -n <span class="variable">$eth0_ip_addr</span> ]]; <span class="keyword">then</span></span><br><span class="line">        config_interface</span><br><span class="line">        systemctl restart systemd-networkd</span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="title">config_interface</span></span>() &#123;</span><br><span class="line">    mask2cdr <span class="variable">$eth0_netmask</span></span><br><span class="line">    cat &lt;&lt; EOF &gt; /etc/systemd/network/default.network</span><br><span class="line"><span class="comment"># Generated by Aliyun Custom OS helper</span></span><br><span class="line"><span class="comment"># DO NOT EDIT THIS FILE! IT WILL BE OVERWRITTEN</span></span><br><span class="line"></span><br><span class="line">[Match]</span><br><span class="line">Name=$(ip link | awk -F: <span class="string">&#x27;$0 !~ &quot;lo|vir|wl|^[^0-9]&quot;&#123;print $2a;getline&#125;&#x27;</span> | sed -e <span class="string">&#x27;s/^[[:space:]]*//&#x27;</span>)</span><br><span class="line"></span><br><span class="line">[Network]</span><br><span class="line">Address=<span class="variable">$eth0_ip_addr</span>/<span class="variable">$netmask</span></span><br><span class="line">Gateway=<span class="variable">$eth0_gateway</span></span><br><span class="line"></span><br><span class="line">[Link]</span><br><span class="line">MACAddress=<span class="variable">$eth0_mac_address</span></span><br><span class="line"></span><br><span class="line">[Address]</span><br><span class="line">Address=<span class="variable">$eth0_ip_addr</span>/<span class="variable">$netmask</span></span><br><span class="line">EOF</span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;nameserver 1.1.1.1&quot;</span> &gt; /etc/resolv.conf</span><br><span class="line">    <span class="keyword">for</span> ns <span class="keyword">in</span> <span class="variable">$dns_nameserver</span></span><br><span class="line">    <span class="keyword">do</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&quot;nameserver <span class="variable">$ns</span>&quot;</span> &gt;&gt; /etc/resolv.conf</span><br><span class="line">    <span class="keyword">done</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">mask2cdr</span></span>() &#123;</span><br><span class="line">    <span class="comment"># Assumes there&#x27;s no &quot;255.&quot; after a non-255 byte in the mask</span></span><br><span class="line">    <span class="built_in">local</span> x=<span class="variable">$&#123;1##*255.&#125;</span></span><br><span class="line">    <span class="built_in">set</span> -- 0^^^128^192^224^240^248^252^254^ $(( (<span class="variable">$&#123;#1&#125;</span> - <span class="variable">$&#123;#x&#125;</span>)*<span class="number">2</span> )) <span class="variable">$&#123;x%%.*&#125;</span></span><br><span class="line">    x=<span class="variable">$&#123;1%%$3*&#125;</span></span><br><span class="line">    netmask=$(( <span class="variable">$2</span> + (<span class="variable">$&#123;#x&#125;</span>/<span class="number">4</span>) ))</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> load_os_conf ; <span class="keyword">then</span></span><br><span class="line">    config_password</span><br><span class="line">    config_hostname</span><br><span class="line">    config_network</span><br><span class="line">    cleanup</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;not load <span class="variable">$os_conf_file</span>&quot;</span></span><br><span class="line"><span class="keyword">fi</span></span><br></pre></td></tr></table></figure><p>赋予执行权限</p><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"># chmod +x <span class="regexp">/usr/</span>bin/aliyun-custom-os</span><br></pre></td></tr></table></figure><p>新建 systemd unit 文件 <code>/usr/lib/systemd/system/aliyun-custom-os.service</code> 写入内容</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line"><span class="attribute">Description</span>=Aliyun Custom OS Helper Script</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line"><span class="attribute">Type</span>=oneshot</span><br><span class="line"><span class="attribute">ExecStart</span>=/usr/bin/aliyun-custom-os</span><br><span class="line"><span class="attribute">TimeoutSec</span>=30</span><br><span class="line"><span class="attribute">StandardInput</span>=tty</span><br><span class="line"><span class="attribute">RemainAfterExit</span>=<span class="literal">yes</span></span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line"><span class="attribute">WantedBy</span>=multi-user.target</span><br></pre></td></tr></table></figure><p>然后启用这个服务</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl <span class="builtin-name">enable</span> aliyun-custom-os</span><br></pre></td></tr></table></figure><h4 id="挂载镜像"><a href="#挂载镜像" class="headerlink" title="挂载镜像"></a>挂载镜像</h4><p>正常 shutdown 虚拟机，然后拿到镜像文件的路径。例如 <code>~/vm/archlinux.img</code>。</p><p>接下来需要将此镜像挂载到宿主机系统中修改、清理文件。首先确定镜像文件中的分区位置：</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ file ~/vm/archlinux.img</span><br><span class="line">archlinux.img: x86 boot sector; partition <span class="number">1</span>: ID=<span class="number">0x83</span>, active, starthead <span class="number">32</span>, startsector <span class="number">2048</span>, <span class="number">41938944</span> sectors, code offset <span class="number">0x63</span></span><br></pre></td></tr></table></figure><p>得知 <code>startsector</code> 为 <code>2048</code></p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">$</span> <span class="string">fdisk</span> <span class="string">-l</span> <span class="string">~/vm/archlinux.img</span></span><br><span class="line"><span class="string">You</span> <span class="string">must</span> <span class="string">set</span> <span class="string">cylinders.</span></span><br><span class="line"><span class="string">You</span> <span class="string">can</span> <span class="string">do</span> <span class="string">this</span> <span class="string">from</span> <span class="string">the</span> <span class="string">extra</span> <span class="string">functions</span> <span class="string">menu.</span></span><br><span class="line"></span><br><span class="line"><span class="attr">Disk archlinux.img:</span> <span class="number">0</span> <span class="string">MB,</span> <span class="number">0</span> <span class="string">bytes</span></span><br><span class="line"><span class="number">255</span> <span class="string">heads,</span> <span class="number">63</span> <span class="string">sectors/track,</span> <span class="number">0</span> <span class="string">cylinders</span></span><br><span class="line"><span class="string">Units</span> <span class="string">=</span> <span class="string">cylinders</span> <span class="string">of</span> <span class="number">16065</span> <span class="string">*</span> <span class="number">512</span> <span class="string">=</span> <span class="number">8225280</span> <span class="string">bytes</span></span><br><span class="line"><span class="string">Sector</span> <span class="string">size</span> <span class="string">(logical/physical):</span> <span class="number">512</span> <span class="string">bytes</span> <span class="string">/</span> <span class="number">512</span> <span class="string">bytes</span></span><br><span class="line"><span class="string">I/O</span> <span class="string">size</span> <span class="string">(minimum/optimal):</span> <span class="number">512</span> <span class="string">bytes</span> <span class="string">/</span> <span class="number">512</span> <span class="string">bytes</span></span><br><span class="line"><span class="attr">Disk identifier:</span> <span class="number">0x91d8e293</span></span><br><span class="line"></span><br><span class="line">        <span class="string">Device</span> <span class="string">Boot</span>      <span class="string">Start</span>         <span class="string">End</span>      <span class="string">Blocks</span>   <span class="string">Id</span>  <span class="string">System</span></span><br><span class="line"><span class="string">archlinux.img1</span>   <span class="string">*</span>           <span class="number">1</span>        <span class="number">2611    </span><span class="number">20969472</span>   <span class="number">83</span>  <span class="string">Linux</span></span><br><span class="line"><span class="attr">Partition 1 has different physical/logical endings:</span></span><br><span class="line">     <span class="string">phys=(1023,</span> <span class="number">254</span><span class="string">,</span> <span class="number">63</span><span class="string">)</span> <span class="string">logical=(2610,</span> <span class="number">180</span><span class="string">,</span> <span class="number">2</span><span class="string">)</span></span><br></pre></td></tr></table></figure><p>得知 <code>sectorsize</code> 为 <code>512</code>。</p><p>使用 <code>mount</code> 命令带 offset 参数挂载镜像中的分区：</p><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ sudo mkdir -p <span class="regexp">/mnt/img</span></span><br><span class="line">$ sudo mount -t ext4 -o loop,offset=$((<span class="number">2048</span>*<span class="number">512</span>)) <span class="regexp">/path/</span>to<span class="regexp">/archlinux.img /m</span>nt<span class="regexp">/img/</span> <span class="comment"># 更改 -t auto 或者其他此分区使用的文件系统格式</span></span><br></pre></td></tr></table></figure><p>就可以 <code>cd /mnt/img</code> 看到镜像里的 rootfs 啦。</p><h4 id="清理-检查文件"><a href="#清理-检查文件" class="headerlink" title="清理/检查文件"></a>清理/检查文件</h4><p>要删除的：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> rm /root/.bash_history <span class="comment"># _(:з」∠)_</span></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> rm /etc/ssh/ssh_host_* <span class="comment"># 强制每次部署的时候重新生成密钥对</span></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> rm -r /var/<span class="built_in">log</span>/* <span class="comment"># 清理不需要的日志</span></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> rm -r /var/cache/* <span class="comment"># 清理缓存</span></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> rm /etc/resolv.conf.bak <span class="comment"># 避免恢复成制作时的 DNS</span></span></span><br></pre></td></tr></table></figure><p>要检查的：</p><p><code>/etc/hosts</code> - 我不知道为什么，第一次的时候把这个文件留空了<em>(:з」∠)</em></p><p><code>/etc/resolv.conf</code> - 鉴于总是有人喜欢手动修改这个文件，所以直接把它写成静态文件好了。内容例如</p><figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">nameserver <span class="number">8.8</span><span class="number">.8</span><span class="number">.8</span></span><br><span class="line">nameserver <span class="number">8.8</span><span class="number">.4</span><span class="number">.4</span></span><br></pre></td></tr></table></figure><p><code>/etc/ssh/sshd_config</code> 中是否允许 root 密码登陆。</p><h3 id="准备镜像"><a href="#准备镜像" class="headerlink" title="准备镜像"></a>准备镜像</h3><p>退出 <code>/mnt/img</code> 目录，然后卸载镜像</p><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"># umount <span class="regexp">/mnt/img</span></span><br></pre></td></tr></table></figure><p>（可选）使用 <code>qemu-img</code> 转换镜像格式到 VHD，减少镜像文件大小。特别是对国内的小水管上传（心疼</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ qemu-img convert -f<span class="built_in"> raw </span>-O vpc archlinux.img archlinux.vhd</span><br></pre></td></tr></table></figure><h3 id="上传镜像"><a href="#上传镜像" class="headerlink" title="上传镜像"></a>上传镜像</h3><p>在相同的 region 创建一个 OSS bucket，然后创建一个 RAM 子用户赋予 OSS 写权限并创建 Access Key，使用 <a href="https://github.com/aliyun/oss-browser">OSSBrowser</a> 上传准备好的 VHD 文件。</p><p>上传完毕后，在 ECS 标签下的镜像标签即可导入镜像。如果是第一次操作，需要给 ECS 授权访问 OSS。在导入的页面提示中提供了授权的链接。镜像内容配置如下：</p><ul><li>OSS Object 地址：镜像文件在 OSS 中的 URL</li><li>Image 名称：<code>archlinux-2018.1-x86_64</code> … 等符合要求即可</li><li>操作系统：Linux</li><li>系统盘大小：40GB</li><li>系统架构：x86_64</li><li>系统平台：Customized Linux</li><li>镜像格式：VHD（如果是 img 就选 RAW）</li><li>镜像描述：随便写啦。</li></ul><p>确定后应该就会开始制作镜像了。</p><h3 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h3><p>因为没有做经典实例的兼容，这个镜像只能用于 VPC 的实例。总体而言，cloud-init 本来兼容的 Arch 却无法更改 root 密码（其他的倒是没问题），所以才选择了用一个 dirty 的方案来实现。</p><p>不知道应该说阿里云的工程师对自定义镜像的考虑周到还是对不同发行版的考虑欠妥…？</p><p>最后庆幸倒腾来去上传了好多遍 20G 的文件，日本运营商家宽带宽对等真的是帮了大忙，不然一个镜像制作不知道要到什么时候 &gt; &gt; （斜眼看国内三大运营商</p><p>参考：</p><ul><li><a href="https://www.alibabacloud.com/help/zh/faq-detail/51138.htm">https://www.alibabacloud.com/help/zh/faq-detail/51138.htm</a></li><li><a href="https://serverfault.com/questions/842964/bash-script-to-retrieve-name-of-ethernet-network-interface">https://serverfault.com/questions/842964/bash-script-to-retrieve-name-of-ethernet-network-interface</a></li><li><a href="https://wiki.archlinux.org/index.php/systemd-networkd">https://wiki.archlinux.org/index.php/systemd-networkd</a></li><li><a href="https://stackoverflow.com/questions/20762575/explanation-of-convertor-of-cidr-to-netmask-in-linux-shell-netmask2cdir-and-cdir">https://stackoverflow.com/questions/20762575/explanation-of-convertor-of-cidr-to-netmask-in-linux-shell-netmask2cdir-and-cdir</a></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;阿里云镜像制作踩坑记。&lt;/p&gt;
&lt;p&gt;此文章主要记录按照&lt;a href=&quot;https://www.alibabacloud.com/help/zh/faq-detail/51138.htm&quot;&gt;阿里云 Customized Linux&lt;/a&gt; 制作 VPC 镜像的过程。一些部分也可用作制作其他平台镜像的参考。                       &lt;/p&gt;
&lt;p&gt;当然记录的原因主要是 Arch 上的 cloud-init 打死无法在阿里云上修改 root 密码，就很气。&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
</feed>
