<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Posts on Tsic&#39;s Blog</title>
    <link>https://tsic.top/post/</link>
    <description>Recent content in Posts on Tsic&#39;s Blog</description>
    <generator>Hugo -- 0.154.0</generator>
    <language>zh-CN</language>
    <lastBuildDate>Fri, 15 Mar 2024 17:45:17 +0800</lastBuildDate>
    <atom:link href="https://tsic.top/post/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>linux 下使用wayland合成器将插件分进程</title>
      <link>https://tsic.top/post/ui%E6%8F%92%E4%BB%B6%E5%88%86%E8%BF%9B%E7%A8%8B%E6%96%B9%E6%A1%88/</link>
      <pubDate>Fri, 15 Mar 2024 17:45:17 +0800</pubDate>
      <guid>https://tsic.top/post/ui%E6%8F%92%E4%BB%B6%E5%88%86%E8%BF%9B%E7%A8%8B%E6%96%B9%E6%A1%88/</guid>
      <description>&lt;p&gt;介绍如何使用wayland合成器实现UI插件分进程的实现。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>介绍如何使用wayland合成器实现UI插件分进程的实现。</p>
<h2 id="背景">背景</h2>
<ol>
<li>
<p>为什么要将插件分进程</p>
<p>原有的dde-dock经常因为插件问题导致假死崩溃卡顿等问题，插件与dock在相同进程就避免不了因为插件代码质量等导致的同生共死，所以有将插件独立进程出去将插件的影响范围降低到最小，只影响自己。</p>
</li>
<li>
<p>分进程有什么好处与坏处</p>
<p>分进程后带来的好处可以从以下几个方面体现：</p>
<pre><code> 1. 兼容性：只要确定了插件进程与dock进程通信的方式，可以使用这种通信方式都可以被dock当作插件加载上来。无论widget，qml，qt5/6还是其他语言等。

 2. 流畅性：dock自身更加专注于dock本身的业务逻辑，不需要发生变化时去更新插件的状态，也不会被插件阻塞住。

 3. 稳定性：dock进程只有dock自身，不再受插件的影响。
</code></pre>
<p>缺点方面：</p>
<pre><code> 最主要的一点就是总体的系统资源占用会比之前稍高。
 开发复杂度和维护复杂度都会上升。
</code></pre>
</li>
<li>
<p>怎么去分进程</p>
<p>插件的主要作用：</p>
<pre><code> 1. 用于显示，显示插件的UI部分。
 2. 获取输入，获取用户的鼠标或者键盘输入，并作出对应的响应。
</code></pre>
<p>确定一种通信方式可以让 dock 和插件通信，直接使用 socket 方式不能通信UI相关的信息，共享 buffer 来实现显示 = 换个类似的上层封装，可以接受 UI 相关 &mdash;“显示服务器！”</p>
<p>linux上的显示服务器有xorg，wayland等。采用 wayland 的原因是现代化，方便扩展，并且 Qt 做好了 qt-wayland 的上层封装很方便开发者去开发Wayland相关。</p>
</li>
</ol>
<h2 id="wayland-简单介绍">wayland 简单介绍</h2>
<ol>
<li>
<p>wayland 是什么</p>
<p>wayland 是x11的取代品，wayland是一套应用程序用于获取用户输入和显示的协议。<a href="https://wayland.freedesktop.org/">wayland</a></p>
<p>正好与插件的需求相切合，用于显示和获取输入。</p>
<p>显示和输入的两方面问题</p>
<p>wayland中如何显示？        surface</p>
<p>如何暴露插件属性和插件交互？ shell-surface</p>
</li>
<li>
<p>wayland 有什么好处</p>
<ol>
<li>更现代化的设计</li>
<li>更低的延迟</li>
<li>更好的性能</li>
<li>更好的安全性</li>
<li>更简单的代码库</li>
</ol>
</li>
<li>
<p>shell-surface介绍</p>
<p>显示比较好理解，surface 是wayland中需要渲染的一片区域。</p>
<p>那 shell-surface 是什么呢？</p>
<p>shell-surface 是具有元数据属性的 surface。它可以具有各种属性比如窗管中定义的窗口标题，窗口类型，窗口状态等，还具有布局和排列的能力和交互响应等。</p>
</li>
</ol>
<h2 id="dock-插件接口介绍">dock 插件接口介绍</h2>
<ol>
<li>
<p>dock 提供给插件的接口</p>
<p><a href="https://github.com/linuxdeepin/dde-dock/blob/32bd005492009aaa7e9ea2d59237fa8bf9a1f75c/interfaces/pluginproxyinterface.h">pluginproxyinterface.h</a></p>
</li>
<li>
<p>插件提供给dock的接口</p>
<p><a href="https://github.com/linuxdeepin/dde-dock/blob/32bd005492009aaa7e9ea2d59237fa8bf9a1f75c/interfaces/pluginsiteminterface.h">pluginsiteminterface.h</a></p>
</li>
<li>
<p>之前的工作流程</p>
<p>dock 通过 pluginloader 将插件加载到 pluginmanager，然后对插件进行初始化。</p>
<p>dock 再根据 pluginmanager 加载进来的插件，去加载对应类型区域的部分。</p>
<p>比如：</p>
<ul>
<li>工作区预览（Fixed类型插件） 将显示在 dock 定义的 Fixed 区域</li>
<li>电源按键（system类型插件）显示在 dock 定义的 System 区域</li>
<li>回收站（Tools类型插件）显示在 dock 定义的 Tool 区域</li>
<li>托盘（tray类型）显示在 dock 定义的 Tray 区域</li>
<li>快捷面板将被快捷面板加载，获取到各个插件的快捷面板里面的UI。</li>
</ul>
</li>
<li>
<p>shell-surafce 与 插件的相似之处</p>
<p>插件需要按照一定的顺序显示，shell-surface 可以根据窗口的属性进行布局和排列。</p>
<p>插件需要响应用户的输入，shell-surface 具有交互性和事件处理。</p>
<p>所以接下来需要定一个自定义类型的 shell surface 来实现dock 插件管理的需求。</p>
</li>
</ol>
<h2 id="通过-shell-surface-实现插件加载和通信流程">通过 shell surface 实现插件加载和通信流程</h2>
<ol>
<li>
<p>wayland 协议介绍</p>
<p>wayland 是一套应用程序用于获取用户输入和显示的协议。<a href="https://wayland.freedesktop.org/">wayland</a></p>
<p>现有的wayland显示协议都不满足dock插件管理的要求，所以定义一套dock的插件管理协议，用于dock插件的显示和响应。</p>
</li>
<li>
<p>确定对应的shell-surface和对应的wayland协议</p>
<p>根据上面的内容，输入转换</p>
<pre><code> 插件向dock的接口    -&gt;      wayland request
 dock向插件的接口    -&gt;      wayland event
</code></pre>
<p>得出下面一份简单的 <a href="https://github.com/linuxdeepin/dde-shell/blob/7d3437492afc37c2d5a6bd908fb7a7fce501581f/panels/dock/dockplugin/protocol/dock-plugin-manager-v1.xml">Wayland 协议</a>，仍有需要补充部分</p>
</li>
<li>
<p>制定协议后的工作流程</p>
<ol>
<li>
<p>加载流程</p>
<ol>
<li>
<p>widget 插件由 widget 的loader进行初始化</p>
</li>
<li>
<p>实现一个 widgetplugin 将初始化后的插件和协议的具体实现连接起来。</p>
</li>
<li>
<p>将 每个widget 初始化称独立窗口，使用窗口的显示和隐藏控制 shell-surface 的创建和隐藏达到控制插件的注册后的显示与否。</p>
</li>
</ol>
</li>
<li>
<p>通信流程</p>
<ol>
<li>
<p>插件通过 wayland 的request 向 dock 发送插件提供的接口</p>
</li>
<li>
<p>dock 通过 wayland 的 event 向插件发送 dock 提供的能力</p>
</li>
</ol>
<p>比如点击事件：</p>
<pre><code>  1. 点击 dock 上面的 item， item 通过 wayland 产生一个自定的 event

  2. 该 event 通过 wayland 发送到协议的客户端实现，调用对应的event 处理接口，将事件发送到 widgetplugin实现中。

  3. widgetplugin收到转发后的 点击事件，调用插件对应的点击接口

  4. 插件响应对应的点击行为。
</code></pre>
</li>
<li>
<p>通过 wayland 后的插件时序图</p>
</li>
</ol>
<p><img alt="时序图" loading="lazy" src="https://s2.loli.net/2024/03/18/bVyNdEwWLQBtZTo.png"></p>
</li>
</ol>
<h2 id="使用qt-wayland-实现协议">使用Qt wayland 实现协议</h2>
<ol start="0">
<li>
<p>工具 qtwayland-scanner 根据协议生成胶水代码</p>
<p>1.1 客户端自动填充好 request 相关接口的调用逻辑，需要实现收到对应 event 后的处理和 request 如何暴露对外的方式。</p>
<p>对于 dock 插件来说， event 一般就是 dock 的状态变更，将其关联到对应的信号处理即可，将协议定义的 request 与旧插件接口相关的调用关联起来即可。</p>
<p>1.2 服务端自动填充好 event 相关接口的调用逻辑，需要实现收到对应的 reqeust 后的处理逻辑和 event 暴露对外的方式。</p>
</li>
<li>
<p>server端（也就是dock本体的合成器）实现</p>
<p>server 是作为一个 QWaylandCompositorExtension 实现，需要将PluginManager暴露到QML中用于注册到 wayland 合成器中作为受支持的协议。并且需要关联 dock 对应的属性到上面，用于发送对应的 dock 状态变化后的事件。</p>
<p>通过 Qt的 QML_ELEMENT 和 Q_COMPOSITOR_DECLARE_QUICK_EXTENSION_CLASS()
宏注册到 QML 中作为QWaylandCompositorExtension</p>
<p>PluginSurface 是由 PluginManager 控制创建，不需要 QML 中创建暴露，但是 PluginSurface 需要响应对应的输入行为，所以一些输入行为接口需要设置成 Q_INVOKABLE 由 QML 直接调用。</p>
<p>细节：</p>
<ol>
<li>
<p>实现 DockPluginManager</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DockPluginManager</span> <span class="o">:</span> <span class="k">public</span> <span class="n">QWaylandCompositorExtensionTemplate</span><span class="o">&lt;</span><span class="n">DockPluginManager</span><span class="o">&gt;</span><span class="p">,</span> <span class="k">public</span> <span class="n">QtWaylandServer</span><span class="o">::</span><span class="n">dock_plugin_manager_v1</span>
</span></span></code></pre></div></li>
<li>
<p>实现胶水代码中的虚函数，暴露属性并关联到 event 上，用于向插件通知 dock 的状态变更。</p>
</li>
<li>
<p>实现 surface 创建流程，根据 QWaylandSurface 和 QWaylandResource 创建 PluginSurface。</p>
</li>
<li>
<p>实现 PluginSurface</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">PluginSurface</span> <span class="o">:</span> <span class="k">public</span> <span class="n">QWaylandShellSurfaceTemplate</span><span class="o">&lt;</span><span class="n">PluginSurface</span><span class="o">&gt;</span><span class="p">,</span> <span class="k">public</span> <span class="n">QtWaylandServer</span><span class="o">::</span><span class="n">dock_plugin_surface</span>
</span></span></code></pre></div></li>
<li>
<p>定义对应的属性和对外暴露，用于接收插件上报的属性。</p>
</li>
<li>
<p>定义对应的信号，用于插件发生对应的 request 后转发给 dock。</p>
</li>
<li>
<p>实现对外的接口，将输入事件转成对应的 event 发送给插件。</p>
</li>
</ol>
</li>
<li>
<p>client端（也就是插件）实现</p>
<p>由于 widget 插件是使用 Qt5 编写，所以注册方式采用 Qt5 的方式。</p>
<p>将 PluginManager 通过 QWaylandShellIntegration 和 QWaylandShellIntegrationPlugin 注册到 wayland 的createSurface上。</p>
<p>当有对应类型的 surface 创建时，便会调用里面的接口。实现 PluginSurface 的创建和 wayland 合成器端的bingding。</p>
<p>widget 插件将通过 客户端封装的接口来调用 实现后的request 和接受对应的 event。</p>
<p>细节：</p>
<ol>
<li>
<p>作为一个 wayland-shell-integration 插件实现</p>
</li>
<li>
<p>实现一个 QWaylandShellIntegrationPlugin 和 QWaylandShellIntegration 将 DockPluginManager 的创建和 PluginSurface 的创建注册到 wayland 中</p>
</li>
<li>
<p>定义 DockPlugin 作为 QWindow 和 shell-surafce 的桥梁。QWindow， DockPlugin 和 DockPluginSurface 一一对应。</p>
</li>
<li>
<p>实现 DockPluginManager</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DockPluginManager</span> <span class="o">:</span> <span class="k">public</span> <span class="n">QObject</span><span class="p">,</span> <span class="k">public</span> <span class="n">QtWayland</span><span class="o">::</span><span class="n">dock_plugin_manager_v1</span>
</span></span></code></pre></div></li>
<li>
<p>将 event 转成对应的信号对外暴露，实现属性关联 request。</p>
</li>
<li>
<p>实现 createPluginSurface 接口，创建DockPluginSurface</p>
</li>
<li>
<p>实现 DockPluginSurface 并根据 DockPlugin 将对应的 QWindow 关连起来。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">DockPluginSurface</span> <span class="o">:</span> <span class="k">public</span> <span class="n">QtWaylandClient</span><span class="o">::</span><span class="n">QWaylandShellSurface</span><span class="p">,</span> <span class="k">public</span> <span class="n">QtWayland</span><span class="o">::</span><span class="n">dock_plugin_surface</span>
</span></span></code></pre></div></li>
<li>
<p>将 event 转成对应的信号暴露给 DockPlugin，并将 DockPlugin 的信号关联到 DockPluginSurface 调用 request 的槽上。</p>
</li>
</ol>
</li>
<li>
<p>widget 插件的接口转到实现的协议上</p>
<p>widget 插件是一个旧接口对接到新协议的中间类。他通过实现 proxy 的接口来让插件认为它就是 dock 本体。又通过和 dock 插件管理协议的关联，将插件的请求通过 wayland 转发给 dock。</p>
<p>在 main 中通过 PluginLoader 将插件进行加载，成功加载后构造对应的widgetplugin 对象， widgetplugin 将旧接口 pluginsiteminterface 和 pluginproxyinterface 通过 DockPlugin 接口类与协议关联起来，实现将对应的 wayland event/request 转成 dock 的接口相关。</p>
</li>
<li>
<p>dock 又是如何&quot;抓取&quot;插件</p>
<p>插件注册到 wayland 合成器后，在dock 的 DockCompositoer 中根据 surface 中定义的 type 属性，将 surface 存入到不同的 Model 中。然后 dock 对应的部分（比如tray部分）将对应的Model（traySurfaceModel）用于 tray 区域的显示，并使用 Qt 提供的 ShellSurfaceItem 将对应的  surface 显示出来。在 dock 上的布局和排列就可以按照 shell-surface 上定义的属性来实现。</p>
<p>但是对于插件的 tooltip 和 popup 处理特殊一下，主要有两种思路：</p>
<ol>
<li>
<p>tooltip 和 popup 按需提供，需要将对应的 hover 事件转到客户端，然后调用插件接口产生 tooltip/popup 的窗口出来，然后将该窗口贴到 tooltip 和 popup 上去。</p>
</li>
<li>
<p>tooltip 和popup 上来就注册到wayland中，dock 按需将对应的 item 贴到 dock 的 tooltip/popup 上去。</p>
</li>
</ol>
<p>目前采用的是第二种方案，但是对于网络插件自身有判断，不能同时产生 tooltip 和 popup，两者只可存在一个，导致目前网络插件没有对应的 tooltip 产生。</p>
</li>
</ol>
<h2 id="实现后的效果">实现后的效果</h2>
<p>dde-shell 中插件与dock分进程，目前托盘插件正常显示和响应对应输入，tooltip和popup正常处理。</p>
<p>所有插件各自独立进程
<img alt="效果图" loading="lazy" src="https://s2.loli.net/2024/03/18/inZueY643Cha1HE.png"></p>
<h2 id="畅想和待做">畅想和待做</h2>
<ol>
<li>
<p>对于有输入插件（比如网络插件，输入情况的支持需要确认，应该是需要添加输入法协议的支持）</p>
</li>
<li>
<p>不同类型的插件需要准备多种loader</p>
</li>
</ol>
<p>待做：</p>
<ol>
<li>实现一个 QML loader 并完善 QML的支持，用于编写 QML 插件。</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Change Scheduler for k3s</title>
      <link>https://tsic.top/post/change-scheduler/</link>
      <pubDate>Sun, 08 Oct 2023 11:12:10 +0800</pubDate>
      <guid>https://tsic.top/post/change-scheduler/</guid>
      <description>&lt;p&gt;本文主要介绍使用load-watcher + scheduler-plugins + descheduler 配合实现k3s根据资源占用平衡调度。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>本文主要介绍使用load-watcher + scheduler-plugins + descheduler 配合实现k3s根据资源占用平衡调度。</p>
<h2 id="k3s-调度问题">k3s 调度问题</h2>
<p>k8s 默认调度器不会更具节点的实际负载进行调度，只会根据request中申请的资源来。所以会导致多数的部署都是往一台比较强劲的节点上，或者新加入的节点不会有任何的pod分配过来。</p>
<h2 id="metrics-server">metrics-server</h2>
<p>使用 k8s 默认的metrics-server 来获取节点资源使用情况</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
</span></span></code></pre></div><h2 id="load-watcher">load-watcher</h2>
<p>为 <a href="https://github.com/kubernetes-sigs/scheduler-plugins/blob/master/kep/61-Trimaran-real-load-aware-scheduling/README.md">trimaran</a> 打分时提供当前node的资源使用情况数据。
上游项目地址: <a href="https://github.com/paypal/load-watcher">https://github.com/paypal/load-watcher</a>
镜像: <a href="https://github.com/tsic404/docker-images/pkgs/container/load-watcher">https://github.com/tsic404/docker-images/pkgs/container/load-watcher</a></p>
<p>为了 load-watcher 方便读取集群各个节点的资源使用信息，将kubeconfig作为configmap传递到容器中，并指定 KUBE_CONFIG 环境变量。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w"> </span><span class="c"># kube-config configmap</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">ConfigMap</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">kube-config</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">load-watcher</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">loadwatcher</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">immutable</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">data</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">kube-config</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">    xxxxx</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">apps/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Deployment</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">load-watcher-deployment</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">loadwatcher</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">load-watcher</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">replicas</span><span class="p">:</span><span class="w"> </span><span class="m">1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">selector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">matchLabels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">load-watcher</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">template</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">load-watcher</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">containers</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">load-watcher</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">ghcr.io/tsic404/load-watcher:latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">env</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">KUBE_CONFIG</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">           </span><span class="nt">value</span><span class="p">:</span><span class="w"> </span><span class="l">/kube-config</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="m">2020</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">volumeMounts</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">kube-config</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l">/kube-config</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">subPath</span><span class="p">:</span><span class="w"> </span><span class="l">kube-config</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">kube-config</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">configMap</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">kube-config</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">items</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span>- <span class="nt">key</span><span class="p">:</span><span class="w"> </span><span class="l">kube-config</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">kube-config</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Service</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">loadwatcher</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">load-watcher</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">load-watcher</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">ClusterIP</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">http</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="m">2020</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">targetPort</span><span class="p">:</span><span class="w"> </span><span class="m">2020</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">protocol</span><span class="p">:</span><span class="w"> </span><span class="l">TCP</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">selector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l">load-watcher</span><span class="w">
</span></span></span></code></pre></div><h2 id="scheduler-plugins">scheduler-plugins</h2>
<p>采用 helm install as a second scheduler
使用 trimaran 插件来根据当前 node 的实际资源占用情况来进行调度。
values.yaml</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">scheduler</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">trimaran</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">registry.k8s.io/scheduler-plugins/kube-scheduler:v0.26.7</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">replicaCount</span><span class="p">:</span><span class="w"> </span><span class="m">1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">leaderElect</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">controller</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">scheduler-plugins-controller</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">registry.k8s.io/scheduler-plugins/controller:v0.26.7</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">replicaCount</span><span class="p">:</span><span class="w"> </span><span class="m">1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">plugins</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">enabled</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;TargetLoadPacking&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">disabled</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;NodeResourcesBalancedAllocation&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;NodeResourcesLeastAllocated&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">pluginConfig</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">TargetLoadPacking</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">args</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">watcherAddress</span><span class="p">:</span><span class="w"> </span><span class="l">http://load-watcher.loadwatcher.svc.cluster.local:2020</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">helm install scheduler-plugins as-a-second-scheduler/ --create-namespace --namespace scheduler-plugins -f values.yaml
</span></span></code></pre></div><h2 id="descheduler">descheduler</h2>
<p>k8s 中pod一旦绑定了节点就不会在进行调度，但是pod运行过程中，pod使用的资源可能会不断变化，这样分配时的平衡就会被打破。所以引入重平衡工具<code>descheduler</code>，让其找到可以可以移除的pod并驱逐他们，重新触发k8s的调度。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">helm install descheduler --namespace kube-system descheduler/descheduler --set <span class="nv">kind</span><span class="o">=</span>Deployment
</span></span></code></pre></div><h2 id="depolyment">depolyment</h2>
<p>由于采用的是将 trimaran 安装成第二调度器，所以需要在 deployment 中显示指明调度器名称</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">apps/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Deployment</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">template</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">schedulerName</span><span class="p">:</span><span class="w"> </span><span class="l">trimaran</span><span class="w">
</span></span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>k3s with multus cni</title>
      <link>https://tsic.top/post/k3s-with-multus-cni/</link>
      <pubDate>Mon, 24 Jul 2023 11:38:08 +0800</pubDate>
      <guid>https://tsic.top/post/k3s-with-multus-cni/</guid>
      <description>&lt;p&gt;介绍一下如何配置k3s的multus cni。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>介绍一下如何配置k3s的multus cni。</p>
<h1 id="k3s-with-multus-cni">k3s with multus cni</h1>
<p>最近在家部署了一个k3s，用于管理一些家用服务比如jellyfin，homeassistant等，在使用homeassistant时，遇到一些网络问题，在了解k8s一点网络架构后，需要在k8s中安装multus cni，为pod创建额外网口来解决我的问题。</p>
<h2 id="一安装multus">一、安装multus</h2>
<p>拉取官方git仓库<code>git clone https://github.com/k8snetworkplumbingwg/multus-cni.git</code></p>
<p>然后打开<code>code multus-cni</code></p>
<p>修改<code>deployments/multus-daemonset.yml</code></p>
<p>需要修改有三处</p>
<ol>
<li>cniVersion</li>
</ol>
<p>k3s 默认采用的 flannel 的 cniVersion 已经升级到 1.0.0 版本，为了 multus 可以正确生成 flannel 相关配置，需要把cniVersion提高到 1.0.0</p>
<ol start="2">
<li>kubeconfig</li>
</ol>
<p>multus 默认读取 kubeconfig 的路径为 <code>/etc/cni/net.d/multus.d/multus.kubeconfig</code>，但是 k3s 将相关配置保存在 <code>/var/lib/rancher/k3s/agent/etc/</code> 中，导致 cni 相关的配置（下面volume）会改动到此，所以需要修改 kubeconfig 路径到 <code>/var/lib/rancher/k3s/agent/etc/cni/net.d/multus.d/multus.kubeconfig</code></p>
<ol start="3">
<li>volume</li>
</ol>
<p>为了配置 k3s 资源的默认保存路径
将 <code>/etc/cni/net.d</code> 修改为 <code>/var/lib/rancher/k3s/agent/etc/cni/net.d</code>
将 <code>/opt/multus/bin</code> 修改为 <code>/var/lib/rancher/k3s/data/current/bin</code></p>
<p>生成的diff文件</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-diff" data-lang="diff"><span class="line"><span class="cl"><span class="gh">diff --git a/deployments/multus-daemonset.yml b/deployments/multus-daemonset.yml
</span></span></span><span class="line"><span class="cl"><span class="gh">index ab626a66..28eb48af 100644
</span></span></span><span class="line"><span class="cl"><span class="gd">--- a/deployments/multus-daemonset.yml
</span></span></span><span class="line"><span class="cl"><span class="gi">+++ b/deployments/multus-daemonset.yml
</span></span></span><span class="line"><span class="cl"><span class="gu">@@ -125,7 +125,7 @@ data:
</span></span></span><span class="line"><span class="cl">       },
</span></span><span class="line"><span class="cl">       &#34;delegates&#34;: [
</span></span><span class="line"><span class="cl">         {
</span></span><span class="line"><span class="cl"><span class="gd">-          &#34;cniVersion&#34;: &#34;0.3.1&#34;,
</span></span></span><span class="line"><span class="cl"><span class="gi">+          &#34;cniVersion&#34;: &#34;1.0.0&#34;,
</span></span></span><span class="line"><span class="cl">           &#34;name&#34;: &#34;default-cni-network&#34;,
</span></span><span class="line"><span class="cl">           &#34;plugins&#34;: [
</span></span><span class="line"><span class="cl">             {
</span></span><span class="line"><span class="cl"><span class="gu">@@ -145,7 +145,7 @@ data:
</span></span></span><span class="line"><span class="cl">           ]
</span></span><span class="line"><span class="cl">         }
</span></span><span class="line"><span class="cl">       ],
</span></span><span class="line"><span class="cl"><span class="gd">-      &#34;kubeconfig&#34;: &#34;/etc/cni/net.d/multus.d/multus.kubeconfig&#34;
</span></span></span><span class="line"><span class="cl"><span class="gi">+      &#34;kubeconfig&#34;: &#34;/var/lib/rancher/k3s/agent/etc/cni/net.d/multus.d/multus.kubeconfig&#34;
</span></span></span><span class="line"><span class="cl">     }
</span></span><span class="line"><span class="cl"> ---
</span></span><span class="line"><span class="cl"> apiVersion: apps/v1
</span></span><span class="line"><span class="cl"><span class="gu">@@ -183,8 +183,8 @@ spec:
</span></span></span><span class="line"><span class="cl">         command: [&#34;/thin_entrypoint&#34;]
</span></span><span class="line"><span class="cl">         args:
</span></span><span class="line"><span class="cl">         - &#34;--multus-conf-file=auto&#34;
</span></span><span class="line"><span class="cl"><span class="gd">-        - &#34;--multus-autoconfig-dir=/host/etc/cni/net.d&#34;
</span></span></span><span class="line"><span class="cl"><span class="gd">-        - &#34;--cni-conf-dir=/host/etc/cni/net.d&#34;
</span></span></span><span class="line"><span class="cl"><span class="gi">+        - &#34;--cni-version=1.0.0&#34;
</span></span></span><span class="line"><span class="cl"><span class="gi">+        - &#34;--multus-kubeconfig-file-host=/var/lib/rancher/k3s/agent/etc/cni/net.d/multus.d/multus.kubeconfig&#34;
</span></span></span><span class="line"><span class="cl">         resources:
</span></span><span class="line"><span class="cl">           requests:
</span></span><span class="line"><span class="cl">             cpu: &#34;100m&#34;
</span></span><span class="line"><span class="cl"><span class="gu">@@ -222,10 +222,10 @@ spec:
</span></span></span><span class="line"><span class="cl">       volumes:
</span></span><span class="line"><span class="cl">         - name: cni
</span></span><span class="line"><span class="cl">           hostPath:
</span></span><span class="line"><span class="cl"><span class="gd">-            path: /etc/cni/net.d
</span></span></span><span class="line"><span class="cl"><span class="gi">+            path: /var/lib/rancher/k3s/agent/etc/cni/net.d
</span></span></span><span class="line"><span class="cl">         - name: cnibin
</span></span><span class="line"><span class="cl">           hostPath:
</span></span><span class="line"><span class="cl"><span class="gd">-            path: /opt/cni/bin
</span></span></span><span class="line"><span class="cl"><span class="gi">+            path: /var/lib/rancher/k3s/data/current/bin
</span></span></span><span class="line"><span class="cl">         - name: multus-cfg
</span></span><span class="line"><span class="cl">           configMap:
</span></span><span class="line"><span class="cl">             name: multus-cni-config
</span></span></code></pre></div><p>修改完后，部署 multus cni 的 daemonset 即可。</p>
<h2 id="二配置-cni-网络">二、配置 cni 网络</h2>
<p>根据我家的网络情况，我需要在homeassistant中访问lan和iot两个网段。所以定义了两个NetworkAttachmentDefinition。
一个 macvlan 对 lan 的访问，一个 vlan 对 iot 的访问。
cni中更多网络介绍 <a href="https://www.cni.dev/plugins/current/main/">https://www.cni.dev/plugins/current/main/</a>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">NetworkAttachmentDefinition</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w">  </span><span class="l">lan</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">homeassistant</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">config</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">    {
</span></span></span><span class="line"><span class="cl"><span class="sd">      &#34;cniVersion&#34;: &#34;0.3.1&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">      &#34;type&#34;: &#34;macvlan&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">      &#34;master&#34;: &#34;eth0&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">      &#34;ipam&#34;: {
</span></span></span><span class="line"><span class="cl"><span class="sd">        &#34;type&#34;: &#34;host-local&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">        &#34;subnet&#34;: &#34;192.168.18.0/24&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">        &#34;rangeStart&#34;: &#34;192.168.18.32&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">        &#34;rangeEnd&#34;: &#34;192.168.18.100&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">        &#34;routes&#34;: [
</span></span></span><span class="line"><span class="cl"><span class="sd">          { &#34;dst&#34;: &#34;192.168.18.0/24&#34; }
</span></span></span><span class="line"><span class="cl"><span class="sd">        ]
</span></span></span><span class="line"><span class="cl"><span class="sd">      }
</span></span></span><span class="line"><span class="cl"><span class="sd">    }</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;k8s.cni.cncf.io/v1&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">NetworkAttachmentDefinition</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w">  </span><span class="l">iot</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">homeassistant</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">config</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">    {
</span></span></span><span class="line"><span class="cl"><span class="sd">      &#34;cniVersion&#34;: &#34;0.3.1&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">      &#34;type&#34;: &#34;vlan&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">      &#34;master&#34;: &#34;eth0&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">      &#34;vlanId&#34;: 2,
</span></span></span><span class="line"><span class="cl"><span class="sd">      &#34;linkInContainer&#34;: false,
</span></span></span><span class="line"><span class="cl"><span class="sd">      &#34;ipam&#34;: {
</span></span></span><span class="line"><span class="cl"><span class="sd">        &#34;type&#34;: &#34;host-local&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">        &#34;subnet&#34;: &#34;192.168.32.0/24&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">        &#34;rangeStart&#34;: &#34;192.168.32.3&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">        &#34;rangeEnd&#34;: &#34;192.168.32.100&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">        &#34;routes&#34;: [
</span></span></span><span class="line"><span class="cl"><span class="sd">          { &#34;dst&#34;: &#34;192.168.32.0/24&#34; }
</span></span></span><span class="line"><span class="cl"><span class="sd">        ]
</span></span></span><span class="line"><span class="cl"><span class="sd">      }
</span></span></span><span class="line"><span class="cl"><span class="sd">    }</span><span class="w">
</span></span></span></code></pre></div><h2 id="三使用-multus">三、使用 multus</h2>
<p>使用前需要注意，k3s 中不包含一些 cni 比如vlan，使用时会报vlan找不到的错误。
此时需要自己拉取 cni plugins 的仓库，编译对应的 cni。
<code>git clone https://github.com/containernetworking/plugins</code>
并将编译好的二进制放到 k3s data 下的 bin 里面。
然后在 pod 中加上下面内容即可。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">annotations</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">k8s.v1.cni.cncf.io/networks</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">        [
</span></span></span><span class="line"><span class="cl"><span class="sd">            {
</span></span></span><span class="line"><span class="cl"><span class="sd">                &#34;name&#34;: &#34;lan&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">                &#34;ips&#34;: [&#34;192.168.18.32/24&#34;],
</span></span></span><span class="line"><span class="cl"><span class="sd">                &#34;namespace&#34;: &#34;homeassistant&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">                &#34;interface&#34;: &#34;net1&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">                &#34;mac&#34;: &#34;32:44:0b:5a:0e:2e&#34;
</span></span></span><span class="line"><span class="cl"><span class="sd">            },
</span></span></span><span class="line"><span class="cl"><span class="sd">            {
</span></span></span><span class="line"><span class="cl"><span class="sd">                &#34;name&#34;: &#34;iot&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">                &#34;ips&#34;: [&#34;192.168.32.3/24&#34;],
</span></span></span><span class="line"><span class="cl"><span class="sd">                &#34;namespace&#34;: &#34;homeassistant&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">                &#34;interface&#34;: &#34;net1.2&#34;,
</span></span></span><span class="line"><span class="cl"><span class="sd">                &#34;mac&#34;: &#34;00:e0:4c:68:02:3d&#34;
</span></span></span><span class="line"><span class="cl"><span class="sd">            }
</span></span></span><span class="line"><span class="cl"><span class="sd">        ]</span><span class="w">
</span></span></span></code></pre></div><p>这样homeassistant 就会有 loopback，eth0，net1，net1.2 四个网口。</p>
<h2 id="四一些问题的处理方式">四、一些问题的处理方式</h2>
<ol>
<li>遇到不断加 ip 到 net1 和 eth0。从 rangeStart 直到 rangeEnd 为止。</li>
</ol>
<p>将 multus daemonset停下，清理各个节点 multus 相关的配置，重新部署 multus。</p>
<ol start="2">
<li>报 loopback 或者 macvlan 等非 链式调用。</li>
</ol>
<p>在对应节点上运行 <code>k3s check-config</code>。查看 <code>cni</code> 相关的(md5sum, link)是否正常。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Rpi4 Diskless</title>
      <link>https://tsic.top/post/rpi4-diskless/</link>
      <pubDate>Mon, 24 Jul 2023 10:52:40 +0800</pubDate>
      <guid>https://tsic.top/post/rpi4-diskless/</guid>
      <description>&lt;p&gt;使用tftp + nfssroot/iscsi 实现树莓派无盘启动。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>使用tftp + nfssroot/iscsi 实现树莓派无盘启动。</p>
<h1 id="树莓派使用网络启动">树莓派使用网络启动</h1>
<p>pi  通过 tftp 和 dhcp 拉取 boot 分区的内容。然后把拉取的 boot 分区中的 initramfs 加载到内存，通过 内核启动参数（nfsroot，iscsi）和iniramfs 完成网络启动过程。</p>
<p>其他比如 rock5b 不支持 tftp, 但是可以用后面 initramfs 和内核参数。所以理论上可以做到本地 sd 卡只存放 boot 分区，然后通过网络启动 rootfs。</p>
<h2 id="一-tftp-hpa">一、 tftp-hpa</h2>
<ol>
<li>安装 tftp-hpa</li>
</ol>
<p><code>sudo apt install tftp-hpa</code></p>
<ol start="2">
<li>修改配置文件</li>
</ol>
<p><code>sudo vim /etc/default/tftpd-hpa</code></p>
<p>修改一下配置</p>
<pre tabindex="0"><code># /etc/default/tftpd-hpa

TFTP_USERNAME=&#34;tftp&#34;
TFTP_DIRECTORY=&#34;/data/pxe/&#34;
TFTP_ADDRESS=&#34;:69&#34;
TFTP_OPTIONS=&#34;--secure&#34;
</code></pre><ol start="3">
<li>重启 tftp-hpa 服务</li>
</ol>
<p><code>sudo systemctl restart tftp-hpa</code></p>
<ol start="4">
<li>在 TFTP_DIRECTORY 放置对应的网络启动文件。</li>
</ol>
<p>将 pi img 中 boot 分区相关的文件放到对应的目录下，下文修改 boot 相关内容时，需要同步 tftp server中。</p>
<pre tabindex="0"><code>root@rock5b:~# ls /data/pxe/
rapi4-1_boot  rapi4-2_boot  rapi4-3_boot rpi4-1-root.img  rpi4-2-root.img  rpi4-3-root.img
</code></pre><h2 id="二-nfsroot">二、 nfsroot</h2>
<p>相关链接： <a href="https://docs.kernel.org/admin-guide/nfs/nfsroot.html">https://docs.kernel.org/admin-guide/nfs/nfsroot.html</a></p>
<ol>
<li>安装nfs服务</li>
</ol>
<p><code>sudo apt install nfs-kernel-server</code></p>
<ol start="2">
<li>生成nfs路径</li>
</ol>
<p><code>mkdir /data/pxe/nfsroot1</code></p>
<p><code>vim /etc/exportfs</code></p>
<p>加入以下内容</p>
<pre tabindex="0"><code># rootfs
/data/pxe/nfsroot1    192.168.28.1/24(rw,no_root_squash,async,insecure)

# boot
/data/pxe/ 192.168.28.1/24(rw,no_root_squash,async,insecure)
</code></pre><p>然后在 pi 上尝试挂载 nfs，并将 rootfs 同步到nfs中。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">mount 192.168.18.14:/data/pxe/nfsroot1 /mnt
</span></span><span class="line"><span class="cl">rsync -avz --exclude /mnt --exclude /sys --exclude /proc --exclude /run --exclude /boot / /mnt
</span></span></code></pre></div><p>修改 nfsroot 中的 fstab(/mnt/etc/fstab)，将一些 tmp 和 log 挂载为 tmpfs 节省网络资源。</p>
<pre tabindex="0"><code>proc            /proc           proc    defaults          0       0
192.168.18.14:/data/pxe/rapi4-1_boot/ /boot nfs defaults,vers=4.1,proto=tcp 0 0
tmpfs   /tmp         tmpfs   rw,nodev,nosuid,size=2G,mode=777          0  0
tmpfs   /var/log         tmpfs   rw,nodev,nosuid,size=2G,mode=777          0  0
tmpfs   /var/tmp         tmpfs   rw,nodev,nosuid,size=2G,mode=777          0  0
</code></pre><ol start="3">
<li>修改pi内核启动参数</li>
</ol>
<p>生成initramfs。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">update-initramfs -u -k <span class="sb">`</span>uname -r<span class="sb">`</span>
</span></span></code></pre></div><p>然后修改boot/config.txt, 加载initramfs。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">vim /boot/config.txt
</span></span></code></pre></div><p>加入以下内容，注意修改成对应的 iniramfs 文件。</p>
<pre tabindex="0"><code>initramfs initrd.img-6.1.21-v8+ followkernel
</code></pre><p>修改内核参数 /boot/cmdline.txt</p>
<pre tabindex="0"><code>console=serial0,115200 console=tty1 ip=192.168.18.15::192.168.18.1:255.255.255.0:rpi4-1:eth0:off root=/dev/nfs nfsroot=192.168.18.14:/data/pxe/nfsroot1,tcp,rw rootfstype=nfs rootwait elevator=deadline cgroup_memory=1 cgroup_enable=memory cgroup_enable=cpuset
</code></pre><p><img loading="lazy" src="https://s2.loli.net/2023/07/24/w3SYbkex57HVoID.png"></p>
<p>注意将修改后的 boot 同步到 tftp server pxe 上。</p>
<h2 id="三-bootcmd">三、 bootcmd</h2>
<ol>
<li>查看当前bootloader配置</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">root@rpi4-1:~# vcgencmd bootloader_config
</span></span><span class="line"><span class="cl"><span class="o">[</span>all<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">BOOT_UART</span><span class="o">=</span><span class="m">0</span>
</span></span></code></pre></div><ol start="2">
<li>提取配置文件</li>
</ol>
<pre tabindex="0"><code>cp /lib/firmware/raspberrypi/bootloader/stable/pieeprom-2023-05-11.bin pieeprom.bin
rpi-eeprom-config pieeprom.bin &gt; bootconf.txt
</code></pre><ol start="3">
<li>设置配置文件</li>
</ol>
<pre tabindex="0"><code># bootconf.txt

[all]
BOOT_UART=0
WAKE_ON_GPIO=1
POWER_OFF_ON_HALT=0
DHCP_TIMEOUT=4000
DHCP_REQ_TIMEOUT=4000
TFTP_FILE_TIMEOUT=30000
TFTP_IP=192.168.18.14
TFTP_PREFIX=1
BOOT_ORDER=0x21
SD_BOOT_MAX_RETRIES=3
NET_BOOT_MAX_RETRIES=5
TFTP_PREFIX_STR=rapi4-1_boot/
</code></pre><ol start="4">
<li>一些配置说明</li>
</ol>
<ul>
<li>
<p>BOOT_UART</p>
<p>设置为1，表示使能GPIO 14和 15的输出，也就是我们可以连接串口打开信息。其串口参数为波特率115200，8位，无奇偶校验位，1位的停止位。</p>
</li>
<li>
<p>TFTP_PREFIX</p>
<p>0 - Use the serial number e.g. &ldquo;9ffefdef/&rdquo;</p>
<p>1 - Use the string specified by TFTP_PREFIX_STR</p>
<p>2 - Use the MAC address e.g. &ldquo;DC-A6-32-01-36-C2/&rdquo;</p>
<p>Default: 0</p>
<p>自己定义TFTP_PREFIX_STR，方便识别 pi，所以设置成 1。</p>
</li>
<li>
<p>TFTP_PREFIX_STR</p>
<p>当TFTP_PREFIX设置为1的时候，可以设置TFTP_PREFIX_STR的路径。这样每个 pi 通过有不同的 TFTP_PREFIX_STR 从而启动不同的 rootfs 中去。</p>
</li>
<li>
<p>TFTP_IP</p>
<p>设置TFTP服务器的IP地址，树莓派的IP地址是通过DHCP自动获取的。</p>
</li>
<li>
<p>BOOT_ORDER</p>
<p>该参数配置了不同的启动模式：</p>
<ul>
<li>0x0 - NONE (stop with error pattern)</li>
<li>0x1 - SD CARD</li>
<li>0x2 - NETWORK</li>
</ul>
</li>
</ul>
<ol start="5">
<li>将配置写回到<code>pieeprom.bin</code></li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">rpi-eeprom-config --out pieeprom-new.bin --config bootconf.txt pieeprom.bin
</span></span></code></pre></div><ol start="6">
<li>更新eeprom</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo rpi-eeprom-update -d -f ./pieeprom-new.bin
</span></span></code></pre></div><h2 id="四-iscsi">四、 iscsi</h2>
<p>nfs方式无法支持docker的overlyfs。</p>
<p>iscsi 搭建
<a href="https://www.cnblogs.com/pipci/p/11617680.html">https://www.cnblogs.com/pipci/p/11617680.html</a></p>
<ol>
<li>
<p>搭建iscsi
安装tgt
<code>sudo apt install -y tgt</code></p>
</li>
<li>
<p>创建 rootfs img 文件</p>
</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">dd <span class="k">if</span><span class="o">=</span>/dev/zero <span class="nv">of</span><span class="o">=</span>/data/pxe/rpi4-1-root.img <span class="nv">bs</span><span class="o">=</span>1G <span class="nv">count</span><span class="o">=</span><span class="m">128</span> <span class="nv">status</span><span class="o">=</span>progress
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">root@rock5b:~# cat /etc/tgt/conf.d/rpi.conf 
</span></span><span class="line"><span class="cl">default-driver iscsi
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">&lt;target iqn.cluster.tsic.top:rpi4.rootfs1&gt;
</span></span><span class="line"><span class="cl">        backing-store /data/pxe/rpi4-1-root.img
</span></span><span class="line"><span class="cl">&lt;/target&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">&lt;target iqn.cluster.tsic.top:rpi4.rootfs2&gt;
</span></span><span class="line"><span class="cl">        backing-store /data/pxe/rpi4-2-root.img
</span></span><span class="line"><span class="cl">&lt;/target&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">&lt;target iqn.cluster.tsic.top:rpi4.rootfs3&gt;
</span></span><span class="line"><span class="cl">        backing-store /data/pxe/rpi4-3-root.img
</span></span><span class="line"><span class="cl">&lt;/target&gt;
</span></span></code></pre></div><p>然后使用 iscsiadm 加载iscsi 磁盘。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">iscsiadm -m discovery -t st -p 192.168.18.14
</span></span><span class="line"><span class="cl">iscsiadm --mode node --targetname <span class="s2">&#34;iqn.cluster.tsic.top:rpi4.rootfs2&#34;</span> --portal 192.168.18.14 --login
</span></span></code></pre></div><p><code>lsblk</code>即可看到一个 <code>sdX</code> 磁盘。然后为该磁盘分区，将 <code>/</code> 内容同步到磁盘中即可。</p>
<ol start="2">
<li>修改pi内核启动参数</li>
</ol>
<p>分区时会有相关输出，或者使用 <code>blkid</code> 查询分区的 UUID。
root=UUID=xxxxxxxxxxxxxxxxxxx</p>
<pre tabindex="0"><code>console=serial0,115200 console=tty1 root=UUID=c48523b6-8262-416c-a5da-9dbe6656ac70 ip=192.168.18.15::192.168.18.1:255.255.255.0:rpi4-1:eth0:off ISCSI_INITIATOR=iqn.2016-04.com.open-iscsi:ca33685ee2a ISCSI_TARGET_NAME=iqn.cluster.tsic.top:rpi4.rootfs1 ISCSI_TARGET_IP=192.168.18.14 ISCSI_TARGET_PORT=3260 rw rootfstype=ext4 fsck.repair=yes rootwait elevator=deadline cgroup_memory=1 cgroup_enable=memory cgroup_enable=cpuset
</code></pre><p>其他一些参数
iscsi 认证相关
ISCSI_USERNAME=
ISCSI_PASSWORD=</p>
]]></content:encoded>
    </item>
    <item>
      <title>Homenas</title>
      <link>https://tsic.top/post/homenas/</link>
      <pubDate>Mon, 05 Jun 2023 10:48:53 +0800</pubDate>
      <guid>https://tsic.top/post/homenas/</guid>
      <description>&lt;p&gt;介绍一下家庭服务器使用的硬件和软件配置情况。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>介绍一下家庭服务器使用的硬件和软件配置情况。</p>
<h2 id="零-前言">零. 前言</h2>
<p>部署home nas已经有段时间了，将之前踩过的的一些坑梳理一下，做下总结。</p>
<h2 id="一-硬件">一. 硬件</h2>
<h3 id="1-x86-硬件">1. x86 硬件</h3>
<ul>
<li>aio</li>
</ul>
<p>cpu: i5-11500t</p>
<p>ram: 32G x 2</p>
<p>nic: x540-T2 x 1(10G x 2),RTL8125 2.5GbE x 1</p>
<p>disk: 2t nvme x 1, 4T HHD x 6</p>
<ul>
<li>Game Station</li>
</ul>
<p>cpu: i5-11500</p>
<p>ram: 16G x 4</p>
<p>nic: RTL8125 2.5GbE x 1, ax210 x 1</p>
<p>disk: 1t nvme x 1, 2T SSD x 2</p>
<p>gpu: RTX 3060 mini</p>
<h3 id="2-arm64-硬件">2. arm64 硬件</h3>
<ul>
<li>
<p>sev:</p>
<p>cpu: rk3588</p>
<p>disk: 1t nvme</p>
<p>ram: 16G</p>
</li>
<li>
<p>rpi4 x 2:</p>
<p>cpu: Broadcom BCM2711, Quad core Cortex-A72 (ARM v8) 64-bit SoC @ 1.8GHz
ram: 4G</p>
</li>
</ul>
<h3 id="3-交换机">3. 交换机</h3>
<p>ikuai 2.5G router 支持 2.5G x 8 和万兆光上行</p>
<h3 id="4-qnap-301w">4. qnap 301w</h3>
<p>满血wifi6, 10G x 2, 1G x 4</p>
<h2 id="二-网络拓扑">二. 网络拓扑</h2>
<p>家用主要将访客，物联网和日常网段划分使用。未对存储和业务划分对应专属网段（没必要？）。</p>
<p>lan:   192.168.18.1/24</p>
<p>Iot:   192.168.32.1/24</p>
<p>Guest: 192.168.100.1/24</p>
<p>其中lan 区域</p>
<ul>
<li>192.168.18.1 主软路由</li>
<li>192.168.18.2 lan AP地址</li>
<li>192.168.18.7 aio pve地址</li>
<li>192.168.18.13 master k8s master地址</li>
<li>192.168.18.14 rock5b k8s rock5b node 地址</li>
<li>192.168.18.15 rpi4-1 k8s rpi4-1 node 地址</li>
<li>192.168.18.16 rpi4-2 k8s rpi4-2 node 地址</li>
<li>192.168.18.25 truenas nas地址</li>
<li>192.168.18.32 homeassistant hass 地址</li>
<li>192.168.18.100-200 lan dhcp 地址</li>
</ul>
<p>IOT 区域</p>
<ul>
<li>192.168.32.2 IOT AP地址</li>
<li>192.168.32.3 hass 地址</li>
<li>192.168.32.100-200 IOT dhcp 地址</li>
</ul>
<p>Guest 区域</p>
<ul>
<li>192.168.100.2 Guest AP地址</li>
<li>192.168.100.100-200 Guest dhcp 地址</li>
</ul>
<p>VPN 区域</p>
<ul>
<li>172.28.0.0/16</li>
</ul>
<p>VPN 路由规则</p>
<ul>
<li>192.168.18.0/24 via 172.28.168.8</li>
</ul>
<p><img alt="网络阔普结构" loading="lazy" src="https://s2.loli.net/2023/07/06/zywaYrNZFBL2GqM.png"></p>
<h2 id="三-底层系统安装">三. 底层系统安装</h2>
<h3 id="1-pve-安装x86">1. pve 安装(x86)</h3>
<ol>
<li>下载ISO</li>
<li>BIOS修改相关设置
<ul>
<li>Secure Boot</li>
<li>SRIOV</li>
<li>FastBoot</li>
</ul>
</li>
<li>刷写ISO到U盘，或者使用ventoy</li>
<li>按正常步骤安装pve</li>
<li>开启iommu
<code>vim /etc/default/grub</code>
在GRUB_CMDLINE_LINUX_DEFAULT中加入下面内容 <code>intel_iommu=on iommu=pt</code></li>
<li>开启sriov</li>
</ol>
<p>检查网卡是否支持sriov</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">lspci -s 02:00.0 -vvv <span class="p">|</span> grep Capabilities 
</span></span><span class="line"><span class="cl">        Capabilities: <span class="o">[</span>40<span class="o">]</span> Power Management version <span class="m">3</span>
</span></span><span class="line"><span class="cl">        Capabilities: <span class="o">[</span>50<span class="o">]</span> MSI: Enable- <span class="nv">Count</span><span class="o">=</span>1/1 Maskable+ 64bit+
</span></span><span class="line"><span class="cl">        Capabilities: <span class="o">[</span>70<span class="o">]</span> MSI-X: Enable+ <span class="nv">Count</span><span class="o">=</span><span class="m">64</span> Masked-
</span></span><span class="line"><span class="cl">        Capabilities: <span class="o">[</span>a0<span class="o">]</span> Express <span class="o">(</span>v2<span class="o">)</span> Endpoint, MSI <span class="m">00</span>
</span></span><span class="line"><span class="cl">        Capabilities: <span class="o">[</span>e0<span class="o">]</span> Vital Product Data
</span></span><span class="line"><span class="cl">        Capabilities: <span class="o">[</span><span class="m">100</span> v2<span class="o">]</span> Advanced Error Reporting
</span></span><span class="line"><span class="cl">        Capabilities: <span class="o">[</span><span class="m">150</span> v1<span class="o">]</span> Alternative Routing-ID Interpretation <span class="o">(</span>ARI<span class="o">)</span>
</span></span><span class="line"><span class="cl">        Capabilities: <span class="o">[</span><span class="m">160</span> v1<span class="o">]</span> Single Root I/O Virtualization <span class="o">(</span>SR-IOV<span class="o">)</span>
</span></span><span class="line"><span class="cl">        Capabilities: <span class="o">[</span>1d0 v1<span class="o">]</span> Access Control Services
</span></span></code></pre></div><p>存在<code>Capabilities: [160 v1] Single Root I/O Virtualization (SR-IOV)</code>即支持sriov。</p>
<p>使用systemd service在开机时启动nic的sriov
<code>vim /etc/systemd/system/sriov.service</code>填入以下内容</p>
<p>注意：</p>
<ol>
<li>enp2s0f0 是我pc的网卡，需要修改成自己pc的对应网卡</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">[</span>Unit<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">Description</span><span class="o">=</span>Script to <span class="nb">enable</span> SR-IOV on boot
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">[</span>Service<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">Type</span><span class="o">=</span>simple
</span></span><span class="line"><span class="cl"><span class="nv">ExecStartPre</span><span class="o">=</span>/usr/bin/bash -c <span class="s1">&#39;/usr/bin/echo 6 &gt; /sys/class/net/enp2s0f0/device/sriov_numvfs&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">ExecStartPre</span><span class="o">=</span>/usr/bin/bash -c <span class="s1">&#39;/usr/bin/ip link set enp2s0f0 up&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">ExecStartPre</span><span class="o">=</span>/usr/bin/bash -c <span class="s1">&#39;/usr/bin/ip link set enp2s0f0 vf 0 mac fe:eb:98:20:68:77&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">ExecStartPre</span><span class="o">=</span>/usr/bin/bash -c <span class="s1">&#39;/usr/bin/ip link set enp2s0f0 vf 1 mac 32:ec:28:b3:f8:36&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">ExecStartPre</span><span class="o">=</span>/usr/bin/bash -c <span class="s1">&#39;/usr/bin/ip link set enp2s0f0 vf 2 mac 1a:2c:d1:69:e4:66&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">ExecStartPre</span><span class="o">=</span>/usr/bin/bash -c <span class="s1">&#39;/usr/bin/ip link set enp2s0f0 vf 3 mac 4e:39:21:92:5f:00&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">ExecStartPre</span><span class="o">=</span>/usr/bin/bash -c <span class="s1">&#39;/usr/bin/ip link set enp2s0f0 vf 4 mac 92:32:89:31:0b:9a&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">ExecStartPre</span><span class="o">=</span>/usr/bin/bash -c <span class="s1">&#39;/usr/bin/ip link set enp2s0f0 vf 5 mac 6a:a0:55:be:ca:11&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">ExecStart</span><span class="o">=</span>/usr/bin/bash -c <span class="s1">&#39;/usr/bin/echo done&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">Restart</span><span class="o">=</span>on-failure
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">[</span>Install<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">WantedBy</span><span class="o">=</span>multi-user.target
</span></span></code></pre></div><h4 id="1-openwrt-虚拟机安装">1. openwrt 虚拟机安装</h4>
<p>pve创建虚拟机，不选择iso media然后使用qm import disk 导入 openwrt 的镜像。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">qm disk import <span class="m">100</span> ./openwrt-xxx-xxx-generic-squashfs-combined-efi.img local-lvm
</span></span></code></pre></div><p>pci 直通一个sriov网卡作为LAN口。</p>
<p>pci 直通RTL8125 2.5G 网口作为WAN口。</p>
<h5 id="op-vlan划分">OP vlan划分</h5>
<p>在OP网桥设置</p>
<p>VLAN 1: 在LAN上未Untag，默认加入到18网段</p>
<p>VLAN 2: 在LAN上打Tag</p>
<p>VLAN 3: 在LAN上打Tag</p>
<p><img alt="op网桥设备" loading="lazy" src="https://s2.loli.net/2023/07/06/NRTY8XDwZWgbxzV.png"></p>
<h4 id="2-truenas-安装">2. truenas 安装</h4>
<p>安装truenas scale，基于debain系统可方便开启<code>Qemu User Agent</code></p>
<p>配置LAN地址<code>192.168.18.25</code></p>
<h4 id="3-k3s-master-in-lxc">3. k3s master in lxc</h4>
<p>首先开启 pve 的转发功能</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sysctl net.ipv4.ip_forward<span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">sysctl net.ipv6.conf.all.forwarding<span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">sed -i <span class="s1">&#39;s/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g&#39;</span> /etc/sysctl.conf
</span></span><span class="line"><span class="cl">sed -i <span class="s1">&#39;s/#net.ipv6.conf.all.forwarding=1/net.ipv6.conf.all.forwarding=1/g&#39;</span> /etc/sysctl.conf
</span></span></code></pre></div><p>创建lxc容器后修改lxc配置</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">cat /etc/pve/lxc/200.conf
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">arch: amd64
</span></span><span class="line"><span class="cl">cores: <span class="m">6</span>
</span></span><span class="line"><span class="cl">features: <span class="nv">fuse</span><span class="o">=</span>1,mknod<span class="o">=</span>1,mount<span class="o">=</span>nfs<span class="p">;</span>cifs,nesting<span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">hostname: master
</span></span><span class="line"><span class="cl">memory: <span class="m">8192</span>
</span></span><span class="line"><span class="cl">ostype: debian
</span></span><span class="line"><span class="cl">rootfs: local-lvm:vm-200-disk-0,size<span class="o">=</span>128G
</span></span><span class="line"><span class="cl">swap: <span class="m">0</span>
</span></span><span class="line"><span class="cl">tty: <span class="m">1</span>
</span></span><span class="line"><span class="cl">lxc.net.0.type: phys
</span></span><span class="line"><span class="cl">lxc.net.0.name: eth0
</span></span><span class="line"><span class="cl">lxc.net.0.link: enp2s0f0v5
</span></span><span class="line"><span class="cl">lxc.apparmor.profile: unconfined
</span></span><span class="line"><span class="cl">lxc.cap.drop: 
</span></span><span class="line"><span class="cl">lxc.mount.auto: <span class="s2">&#34;proc:rw sys:rw&#34;</span>
</span></span><span class="line"><span class="cl">lxc.cgroup2.devices.allow: c 10:200 rwm
</span></span><span class="line"><span class="cl">lxc.cgroup2.devices.allow: c 226:0 rwm
</span></span><span class="line"><span class="cl">lxc.cgroup2.devices.allow: c 226:128 rwm
</span></span><span class="line"><span class="cl">lxc.mount.entry: /dev/dri/card0 dev/dri/card0 none bind,optional,create<span class="o">=</span>file
</span></span><span class="line"><span class="cl">lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create<span class="o">=</span>file
</span></span></code></pre></div><p>k3s 需要一下配置</p>
<pre tabindex="0"><code class="language-config" data-lang="config">lxc.apparmor.profile: unconfined
lxc.cap.drop:
lxc.mount.auto: &#34;proc:rw sys:rw&#34;
lxc.cgroup2.devices.allow: c 10:200 rwm
</code></pre><p>然后在lxc中开启宿主机挂载点共享</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;#!/bin/sh -e
</span></span></span><span class="line"><span class="cl"><span class="s1">ln -s /dev/console /dev/kmsg
</span></span></span><span class="line"><span class="cl"><span class="s1">mount --make-rshared /&#39;</span> &gt; /etc/rc.local
</span></span><span class="line"><span class="cl">chmod +x /etc/rc.local
</span></span><span class="line"><span class="cl">reboot
</span></span></code></pre></div><p>最后开始安装k3s</p>
<h3 id="2-pve-安装arm64暂时未安装arm64-pve">2. pve 安装(arm64)(暂时未安装arm64 pve)</h3>
<p>首先按照rock5b官方指导刷写debian系统到nvme中，刷写spi到sd卡。</p>
<p>然后使用foxi的pve-arm64仓库安装pve-manager</p>
<h4 id="1-arm64-hass-安装">1. arm64 hass 安装</h4>
<p>创建虚拟机不使用iso且不创建默认启动磁盘，arm64虚拟机需要uefi引导，需要efi disk。
然后使用下面命令导入下载的hass镜像</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">qm disk import
</span></span></code></pre></div><p>扩容到16G</p>
<h4 id="2-k3s-in-lxc">2. k3s in lxc</h4>
<p>同x86</p>
<h3 id="3-rpi4-网络启动">3. rpi4 网络启动</h3>
<p>参考 <a href="https://tsic.top/post/rpi4-diskless/">Rpi4 Diskless</a></p>
<h2 id="四-hass-接入与个人-cloud-game">四. hass 接入与个人 cloud game</h2>
<p>hass 俩ip</p>
<p>192.168.32.3  IOT网段链接</p>
<p>192.168.18.32 LAN网段访问</p>
<h3 id="1-windows唤醒与关机">1. windows唤醒与关机</h3>
<p>WOL与RPC shutdown</p>
<p>BIOS 开启 WOL，windows 网卡配置开启WOL与魔术包唤醒</p>
<p>hass 创建一个 <code>package</code></p>
<p>注：
1. 官方 ha 中不包含 <code>samba</code> 相关组件，所以无法调用 <code>net rpc</code> 相关命令</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">windows</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">switch</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">platform</span><span class="p">:</span><span class="w"> </span><span class="l">wake_on_lan</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">windows_game</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">mac</span><span class="p">:</span><span class="w"> </span><span class="l">D8:BB:C1:59:7A:17</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">host</span><span class="p">:</span><span class="w"> </span><span class="m">192.168.18.154</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">turn_off</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">service</span><span class="p">:</span><span class="w"> </span><span class="l">shell_command.windows_shutdown</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">data</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">ip</span><span class="p">:</span><span class="w"> </span><span class="m">192.168.18.154</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">user</span><span class="p">:</span><span class="w"> </span>!<span class="l">secret windows_tsic</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">shell_command</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">windows_shutdown</span><span class="p">:</span><span class="w"> </span><span class="l">net rpc shutdown -I {{ ip }} -U {{ user }} -t 60 -C &#34;Home Assistant is shutting down this PC. This cannot be canceled. Please save your work!&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">homeassistant</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">customize</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">switch.windows_game</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">friendly_name</span><span class="p">:</span><span class="w"> </span><span class="l">Game Station</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">icon</span><span class="p">:</span><span class="w"> </span><span class="l">mdi:microsoft-windows</span><span class="w">
</span></span></span></code></pre></div><h3 id="2-串流方案">2. 串流方案</h3>
<p>sunshine + moonlight</p>
<p>parsec</p>
<h3 id="3-远程桌面">3. 远程桌面</h3>
<p>Microsoft Remote Desktop</p>
<h2 id="五-常用服务部署">五. 常用服务部署</h2>
<h3 id="1-zerotier-vpn使用">1. zerotier VPN使用</h3>
<ol>
<li>注册zerotier</li>
<li>创建一个网络</li>
<li>对应设备安装zerotier，然后加入该网络中</li>
<li>创建路由规则，让访问lan的流量从OP转发。</li>
</ol>
<h3 id="2-jellyfin-搭建">2. jellyfin 搭建</h3>
<ol>
<li>lxc 支持 dri 挂载</li>
<li>编写 k8s 配置</li>
<li>部署 jellyfin</li>
<li>Live TV</li>
</ol>
<p><a href="https://github.com/BurningC4/Chinese-IPTV">LiveTV项目地址</a></p>
<p><a href="https://cdn.jsdelivr.net/gh/BurningC4/Chinese-IPTV@master/guide.xml">EPG格式TV信息</a></p>
<h3 id="3-trilium-note-搭建">3. trilium note 搭建</h3>
]]></content:encoded>
    </item>
    <item>
      <title>OBS使用指南</title>
      <link>https://tsic.top/post/obs-user-manual/</link>
      <pubDate>Wed, 01 Feb 2023 20:25:19 +0800</pubDate>
      <guid>https://tsic.top/post/obs-user-manual/</guid>
      <description>&lt;p&gt;介绍OBS的一些使用指南。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>介绍OBS的一些使用指南。</p>
<h2 id="obs-介绍">OBS 介绍</h2>
<p><a href="https://openbuildservice.org/">open build service</a>简称OBS，是<a href="https://github.com/openSUSE/open-build-service">openSUSE主导开发</a>的通用构建系统，用于从源码的自动构建和包分发。</p>
<p>假设读者已经了解debian系打包📦相关。本文中对osc的介绍主要作为OBS的CLI接口，本地构建方面可参考<a href="#osc-%E6%9C%AC%E5%9C%B0%E6%9E%84%E5%BB%BA">osc 本地构建</a>。</p>
<h2 id="obs-打包流程">OBS 打包流程</h2>
<p>本文以deepin(debian系)构建，<a href="build.deepin.com">deepin OBS实例</a>为例</p>
<ol>
<li>
<p>创建Project
每个普通账号只有自己的home project。比如：home:tsic404</p>
<p>也可以可以在Subprojects一栏，创建subproject。比如创建 home:tsic404:ddeOnDebian。
<img loading="lazy" src="https://s2.loli.net/2023/02/06/4mSBpOAgrW2fRaD.jpg">
<img loading="lazy" src="https://s2.loli.net/2023/02/06/ymsQDnxCF34vuAh.jpg">
然后</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">osc co home:tsic404:ddeOnDebian
</span></span></code></pre></div><p><code>home:tsic</code>项目内容不会包含<code>home:tsic:ddeOnDebian</code>,两个是各自 “相对独立” 的project。</p>
</li>
<li>
<p>添加构建仓库
在OBS web界面点击Repository，然后add一个Repository到该Project中。
<img loading="lazy" src="https://s2.loli.net/2023/02/06/VmgQ59vcUJbodGn.jpg">
<img loading="lazy" src="https://s2.loli.net/2023/02/06/gaest56XP3kSnic.jpg">
如上图add debian sid repo。</p>
<p>或者使用<code>osc meta prj</code>修改project使用的仓库。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;project</span> <span class="na">name=</span><span class="s">&#34;home:tsic404:ddeOnDebian&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">   <span class="nt">&lt;title/&gt;</span>
</span></span><span class="line"><span class="cl">   <span class="nt">&lt;description/&gt;</span>
</span></span><span class="line"><span class="cl">   <span class="nt">&lt;person</span> <span class="na">userid=</span><span class="s">&#34;tsic&#34;</span> <span class="na">role=</span><span class="s">&#34;maintainer&#34;</span><span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">   <span class="nt">&lt;repository</span> <span class="na">name=</span><span class="s">&#34;Debian_Sid&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;path</span> <span class="na">project=</span><span class="s">&#34;Debian:Sid&#34;</span> <span class="na">repository=</span><span class="s">&#34;standard&#34;</span><span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;path</span> <span class="na">project=</span><span class="s">&#34;Debian:ddeExtra&#34;</span> <span class="na">repository=</span><span class="s">&#34;Debian_Sid&#34;</span><span class="nt">/&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;arch&gt;</span>x86_64<span class="nt">&lt;/arch&gt;</span>
</span></span><span class="line"><span class="cl">   <span class="nt">&lt;/repository&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/project&gt;</span>
</span></span></code></pre></div></li>
<li>
<p>创建Package
可以在web点击create package或者使用osc</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">cd</span> home:tsic404:ddeOnDebian
</span></span><span class="line"><span class="cl">osc mkpac dtkcore
</span></span></code></pre></div></li>
<li>
<p>上传打包文件
点击dtkcore，然后点击add local file。选择dtkcore相关打包文件。即可上传到OBS的Project中。
或者使用 osc
<img loading="lazy" src="https://s2.loli.net/2023/02/06/zJcxQnu98PdMUpG.jpg"></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">cd</span> dtkcore
</span></span><span class="line"><span class="cl">cp xxxx/dtkcore/* ./
</span></span><span class="line"><span class="cl">osc add *
</span></span><span class="line"><span class="cl">osc ci -m <span class="s2">&#34;init&#34;</span>
</span></span></code></pre></div></li>
<li>
<p>OBS开始构建
在dtkcore右侧即可看到对应的状态
点击对应仓库的架构即可看到构建日志，或者使用osc 也可以查看构建日志。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">osc buildlog Debian_Sid x86_64
</span></span></code></pre></div></li>
</ol>
<p><strong>总结</strong>：</p>
<p>使用OBS进行打包，首先先创建Project，添加构建使用的仓库，然后上传需要打包的package到project中，等待OBS构建完成。Project + 构建仓库决定OBS publish的一个仓库。</p>
<h2 id="obs-打包优化service及scm集成">OBS 打包优化(service)及SCM集成</h2>
<p>传统方式需要用户自己手动上传打包需要的全部文件xxxx.org.tar.gz xxx.debain.tar.gz xxxx.dsc三件套，这个过程比较麻烦。我们可以使用OBS的service来生成这些必要的文件。</p>
<h3 id="obs-service介绍">OBS service介绍</h3>
<p>service 简单来说就是一些辅助型的脚本，来协助生成和修改打包所需要的文件。</p>
<p>比如:</p>
<p>使用obs_gbp为git仓库生成debian构建需要的dsc等。</p>
<p>使用set_version动态修改版本号。</p>
<p>使用download_url从指定的url(比如release)下载压缩包等。</p>
<p>service有自己的mode(运行的时机)
service的runmode有</p>
<table>
  <thead>
      <tr>
          <th>Mode</th>
          <th>是否在OBS server上运行</th>
          <th>本地构建时是否运行</th>
          <th>service新增文件处理方式</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Default</td>
          <td>在commit之后</td>
          <td>本地构建之前</td>
          <td>生成_service:前缀的文件</td>
      </tr>
      <tr>
          <td>trylocal</td>
          <td>Yes</td>
          <td>Yes</td>
          <td>生成文件会直接merge到commit里面</td>
      </tr>
      <tr>
          <td>localonly</td>
          <td>No</td>
          <td>Yes</td>
          <td>生成文件会直接merge到commit里面｜</td>
      </tr>
      <tr>
          <td>serveronly</td>
          <td>Yes</td>
          <td>No</td>
          <td>以_service:前缀开始，但是用户本地不会生成</td>
      </tr>
      <tr>
          <td>buildtime</td>
          <td>构建调用dpkg-buildpackage之类的打包工具之前</td>
          <td>每次构建之前</td>
          <td></td>
      </tr>
      <tr>
          <td>manual</td>
          <td>No</td>
          <td>只有OSC命令调用</td>
          <td></td>
      </tr>
      <tr>
          <td>disabled</td>
          <td>No</td>
          <td>只有OSC命令调用</td>
          <td></td>
      </tr>
  </tbody>
</table>
<p>注：</p>
<ol>
<li>
<p>在对应时间运行service时，需要此时安装该service。比如trylocal需要本机，server需要server安装，buildtime需要worker安装。比如选择buildtime，但是worker没有对应service的依赖时，构建就会处于unresolvable状态。</p>
</li>
<li>
<p>build.deepin.com提供了<a href="https://github.com/openSUSE/obs-service-download_files">download_files</a>,<a href="https://github.com/openSUSE/obs-service-download_url">download_url</a>,<a href="https://github.com/openSUSE/obs-service-tar_scm">obs_gbp</a>，<a href="https://github.com/openSUSE/obs-service-tar_scm">obs_scm</a>，<a href="https://github.com/openSUSE/obs-service-tar_scm">tar_scm</a>，<a href="https://github.com/openSUSE/obs-service-set_version">set_version</a>，<a href="https://github.com/openSUSE/obs-service-tar_scm">tar</a>几种服务。</p>
</li>
</ol>
<h3 id="使用service过程">使用service过程</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">cd</span> home:tsic404:ddeOnDebain
</span></span><span class="line"><span class="cl">vim _service
</span></span></code></pre></div><p>加入以下内容</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;services&gt;</span>
</span></span><span class="line"><span class="cl">   <span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&#34;obs_gbp&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">&#34;url&#34;</span><span class="nt">&gt;</span>https://github.com/linuxdeepin/dtkcore.git<span class="nt">&lt;/param&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">&#34;scm&#34;</span><span class="nt">&gt;</span>git<span class="nt">&lt;/param&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">&#34;exclude&#34;</span><span class="nt">&gt;</span>.git<span class="nt">&lt;/param&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">&#34;exclude&#34;</span><span class="nt">&gt;</span>.github<span class="nt">&lt;/param&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">&#34;versionformat&#34;</span><span class="nt">&gt;</span>@CHANGELOG@@DEEPIN_OFFSET@<span class="nt">&lt;/param&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;param</span> <span class="na">name=</span><span class="s">&#34;gbp-dch-release-update&#34;</span><span class="nt">&gt;</span>enable<span class="nt">&lt;/param&gt;</span>
</span></span><span class="line"><span class="cl">   <span class="nt">&lt;/service&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/services&gt;</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">osc add _service
</span></span><span class="line"><span class="cl">osc commit -m <span class="s2">&#34;init&#34;</span>
</span></span></code></pre></div><p>然后web看到service is running的提示，等待service运行完毕，即可看到对应文件的生成。</p>
<p>使用service可以极大方便使用源代码服务器(git等)的项目打包构建。</p>
<h3 id="workflow介绍">workflow介绍</h3>
<p>注：OBS-api需要在2.11版本之后才有workflow功能</p>
<p>workflow 的步骤有</p>
<ol>
<li>
<p>branch_package</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">test_build</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">branch_package</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="nt">source_project</span><span class="p">:</span><span class="w"> </span><span class="l">deepin:Develop:main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="nt">source_package</span><span class="p">:</span><span class="w"> </span><span class="l">%{SCM_REPOSITORY_NAME} </span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="nt">target_project</span><span class="p">:</span><span class="w"> </span><span class="l">deepin:CI</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="nt">filters</span><span class="p">:</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">event</span><span class="p">:</span><span class="w"> </span><span class="l">pull_request</span><span class="w">
</span></span></span></code></pre></div></li>
<li>
<p>link_package</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">test_build</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">link_package</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="nt">source_project</span><span class="p">:</span><span class="w"> </span><span class="l">deepin:Develop:main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="nt">source_package</span><span class="p">:</span><span class="w"> </span><span class="l">%{SCM_REPOSITORY_NAME} </span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="nt">target_project</span><span class="p">:</span><span class="w"> </span><span class="l">deepin:CI</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">configure_repositories</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="nt">project</span><span class="p">:</span><span class="w"> </span><span class="l">deepin:CI</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="nt">repositories</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">deepin_develop</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">paths</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">               </span>- <span class="nt">target_project</span><span class="p">:</span><span class="w"> </span><span class="l">deepin:CI</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                 </span><span class="nt">target_repository</span><span class="p">:</span><span class="w"> </span><span class="l">deepin_develop</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">architectures</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">               </span>- <span class="l">x86_64</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">               </span>- <span class="l">aarch64</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="nt">filters</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">event</span><span class="p">:</span><span class="w"> </span><span class="l">pull_request</span><span class="w">
</span></span></span></code></pre></div></li>
<li>
<p>configure_repositories</p>
<p>configure_repositories 如上面所示，用于配置link_package后的project构建仓库。</p>
</li>
<li>
<p>set_flag</p>
<p>支持的flag有</p>
<ul>
<li>lock (default status disable)</li>
<li>build (default status enable)</li>
<li>publish (default status enable)</li>
<li>debuginfo (default status disable)</li>
<li>useforbuild (default status enable)</li>
<li>binarydownload (default status enable)</li>
<li>sourceaccess (default status enable)</li>
<li>access (default status enable)</li>
</ul>
</li>
<li>
<p>trigger_service</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">commit_build</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">trigger_services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="nt">project</span><span class="p">:</span><span class="w"> </span><span class="l">deepin:Develop:community</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span><span class="nt">package</span><span class="p">:</span><span class="w"> </span><span class="l">%{SCM_REPOSITORY_NAME}</span><span class="w">
</span></span></span></code></pre></div><p>重新trigger 该package的service，用于更新commit仓库的代码。</p>
</li>
<li>
<p>rebuild_package</p>
<p>触发pacakge的rebuild。</p>
</li>
</ol>
<h3 id="使用service与workflow">使用service与workflow</h3>
<ol>
<li>SCM + service 持续集成
osc token 创建SCM token
github 填写对应的webhook
推送.obs/workflows.yml到仓库中，该文件定义了OBS workflow的步骤。</li>
</ol>
<h2 id="obs-集成姿势">OBS 集成姿势</h2>
<p>在package 左侧点击<code>Submit Package</code>。
然后填写如下内容。
<img loading="lazy" src="https://s2.loli.net/2023/02/08/bu2pqBN9S1ovnJc.png">
submit 提交。将生成一个request，等待管理员审核。</p>
<p>project管理员在<a href="https://build.deepin.com/my/tasks">tasks</a>看到所有的请求</p>
<p>点击对应请求，approve或者reject request。</p>
<p>approve后 package将提交到target project中。</p>
<h2 id="osc-本地构建">osc 本地构建</h2>
<p>deepin 20环境</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo apt install osc obs-build rpm <span class="nv">debugedit</span><span class="o">=</span>4.14.2.1+dfsg1.1-1+dde
</span></span></code></pre></div><p>把obs-build设置免密。</p>
<pre tabindex="0"><code>sudo visudo
</code></pre><p>加入以下内容</p>
<pre tabindex="0"><code>LOGIN    ALL = NOPASSWD: /usr/bin/build
LOGIN    ALL = NOPASSWD: /usr/bin/osc
</code></pre><pre tabindex="0"><code>osc co deepin:Develop:main apt
cd deepin\:Develop\:main/apt
osc build xxxxx.dsc
</code></pre><p>即可使用OBS上的仓库进行构建。</p>
<h3 id="deepin-obs-scm一些常见问题">deepin OBS SCM一些常见问题</h3>
<ol>
<li>
<p>GitHub webhooks未触发</p>
<p>大概率是网络问题导致，需要在 GitHub webhook 配置中<code>redeliver</code>该次失败的请求。</p>
</li>
<li>
<p>GitHub webhooks传递过来但是没有对应仓库和架构的情况返回</p>
<p>需要到OBS看看是不是构建前的准备工作出现问题，比如service失败，依赖处于 unresolvable，broken。只有成功构建的 succeeded 和失败的 failed 才会返回到GitHub。</p>
</li>
</ol>
<h2 id="备注">备注</h2>
<p>参考文档</p>
<ol>
<li>
<p>OBS 用户手册</p>
<ol>
<li><a href="https://openbuildservice.org/help/manuals/obs-user-guide/">https://openbuildservice.org/help/manuals/obs-user-guide/</a></li>
<li><a href="https://openbuildservice.org/files/manuals/obs-user-guide.pdf">https://openbuildservice.org/files/manuals/obs-user-guide.pdf</a></li>
<li><a href="https://openbuildservice.org/files/manuals/obs-user-guide.epub">https://openbuildservice.org/files/manuals/obs-user-guide.epub</a></li>
</ol>
</li>
<li>
<p>OBS 管理员手册</p>
<ol>
<li><a href="https://openbuildservice.org/help/manuals/obs-admin-guide/">https://openbuildservice.org/help/manuals/obs-admin-guide/</a></li>
<li><a href="https://openbuildservice.org/files/manuals/obs-admin-guide.pdf">https://openbuildservice.org/files/manuals/obs-admin-guide.pdf</a></li>
<li><a href="https://openbuildservice.org/files/manuals/obs-admin-guide.epub">https://openbuildservice.org/files/manuals/obs-admin-guide.epub</a></li>
</ol>
</li>
<li>
<p>suse wiki</p>
<ol>
<li><a href="https://zh.opensuse.org/Category">https://zh.opensuse.org/Category</a>:构建服务</li>
<li><a href="https://en.opensuse.org/Category:Build_Service">https://en.opensuse.org/Category:Build_Service</a></li>
</ol>
</li>
<li>
<p>osc <a href="https://en.opensuse.org/openSUSE:Build_Service_Tutorial">https://en.opensuse.org/openSUSE:Build_Service_Tutorial</a></p>
</li>
<li>
<p>OBS 调度 <a href="https://wiki.tizen.org/OBS_scheduler_internals">https://wiki.tizen.org/OBS_scheduler_internals</a></p>
</li>
<li>
<p>OBS 开发 wiki <a href="https://github.com/openSUSE/open-build-service/wiki">https://github.com/openSUSE/open-build-service/wiki</a></p>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>kvm 虚拟机去虚拟化</title>
      <link>https://tsic.top/post/hide-vm-info-from-guest/</link>
      <pubDate>Wed, 01 Feb 2023 18:56:05 +0800</pubDate>
      <guid>https://tsic.top/post/hide-vm-info-from-guest/</guid>
      <description>&lt;p&gt;使用promox ve做aio，启动windows主机当游戏机时，遇到游戏的虚拟机检测。&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>使用promox ve做aio，启动windows主机当游戏机时，遇到游戏的虚拟机检测。</p>
<h2 id="方法">方法</h2>
<p>在<a href="https://forum.proxmox.com/threads/hide-vm-from-guest.34905/">promox ve forum</a>中找到了隐藏虚拟机标识的配置。</p>
<pre tabindex="0"><code>args: -cpu &#39;host,-hypervisor,+kvm_pv_unhalt,+kvm_pv_eoi,hv_spinlocks=0x1fff,hv_vapic,hv_time,hv_reset,hv_vpindex,hv_runtime,hv_relaxed,kvm=off,hv_vendor_id=intel&#39;
</code></pre>]]></content:encoded>
    </item>
  </channel>
</rss>
