<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>张小凯的博客</title>
  <icon>https://www.gravatar.com/avatar/0a440a9619579f1429aa17ed946ce69c</icon>
  
  <link href="https://jasonkayzk.github.io/cn/atom.xml" rel="self"/>
  
  <link href="https://jasonkayzk.github.io/cn/"/>
  <updated>2026-10-25T04:05:16.294Z</updated>
  <id>https://jasonkayzk.github.io/cn/</id>
  
  <author>
    <name>Jasonkay</name>
    <email>jasonkayzk@gmail.com</email>
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>罗永浩15堂演讲私教课总结</title>
    <link href="https://jasonkayzk.github.io/cn/2026/02/13/%E7%BD%97%E6%B0%B8%E6%B5%A915%E5%A0%82%E6%BC%94%E8%AE%B2%E7%A7%81%E6%95%99%E8%AF%BE%E6%80%BB%E7%BB%93/"/>
    <id>https://jasonkayzk.github.io/cn/2026/02/13/%E7%BD%97%E6%B0%B8%E6%B5%A915%E5%A0%82%E6%BC%94%E8%AE%B2%E7%A7%81%E6%95%99%E8%AF%BE%E6%80%BB%E7%BB%93/</id>
    <published>2026-02-13T06:56:51.000Z</published>
    <updated>2026-10-25T04:05:16.294Z</updated>
    
    <content type="html"><![CDATA[<p>最近看了很多关于老罗的发布会、演讲（相声），以及一些来自“老罗的十字路口”的采访，觉得老罗的口才挺好的；</p><p>正巧看到了有他的私教课，所以记录一下笔记！</p><p>视频地址：</p><ul><li><a href="https://www.bilibili.com/video/BV1PP411T7fv">https://www.bilibili.com/video/BV1PP411T7fv</a></li></ul><br/><span id="more"></span><h1 id="罗永浩15堂演讲私教课总结"><a href="#罗永浩15堂演讲私教课总结" class="headerlink" title="罗永浩15堂演讲私教课总结"></a><strong>罗永浩15堂演讲私教课总结</strong></h1><h2 id="01如何克服“演讲恐惧症”？"><a href="#01如何克服“演讲恐惧症”？" class="headerlink" title="01如何克服“演讲恐惧症”？"></a>01如何克服“演讲恐惧症”？</h2><p>关于演讲恐惧症：</p><ul><li><strong>所有人都害怕当众演讲，只是程度不同而已，不要觉得自己是没用的！</strong></li></ul><br/><p>Jerry Seinfeld 说过：</p><ul><li><strong>人们最害怕的事儿就是当众讲话，第二害怕的才是死亡；因此，参加葬礼的时候，躺在棺材里要比站在那里致悼词说服的多。</strong></li></ul><br/><p>练成能力很有必要：</p><ul><li>员工讲话</li><li>汇报工作</li></ul><p>消除演讲恐惧症的唯一方式就是：<strong>多讲！</strong></p><br/><h2 id="02构成一场优秀演讲的13个要素"><a href="#02构成一场优秀演讲的13个要素" class="headerlink" title="02构成一场优秀演讲的13个要素"></a>02构成一场优秀演讲的13个要素</h2><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>视频地址：</p><ul><li><a href="https://www.bilibili.com/video/BV1PP411T7fv">https://www.bilibili.com/video/BV1PP411T7fv</a></li></ul><br/>]]></content>
    
    
    <summary type="html">最近看了很多关于老罗的发布会、演讲（相声），以及一些来自“老罗的十字路口”的采访，觉得老罗的口才挺好的，正巧看到了有他的私教课，所以记录一下笔记！</summary>
    
    
    
    <category term="课程" scheme="https://jasonkayzk.github.io/cn/categories/%E8%AF%BE%E7%A8%8B/"/>
    
    
    <category term="课程" scheme="https://jasonkayzk.github.io/cn/tags/%E8%AF%BE%E7%A8%8B/"/>
    
    <category term="口才" scheme="https://jasonkayzk.github.io/cn/tags/%E5%8F%A3%E6%89%8D/"/>
    
  </entry>
  
  <entry>
    <title>再见2025，你好2026！</title>
    <link href="https://jasonkayzk.github.io/cn/2026/02/10/%E5%86%8D%E8%A7%812025%EF%BC%8C%E4%BD%A0%E5%A5%BD2026%EF%BC%81/"/>
    <id>https://jasonkayzk.github.io/cn/2026/02/10/%E5%86%8D%E8%A7%812025%EF%BC%8C%E4%BD%A0%E5%A5%BD2026%EF%BC%81/</id>
    <published>2026-02-10T11:30:22.000Z</published>
    <updated>2026-10-25T04:05:16.283Z</updated>
    
    <content type="html"><![CDATA[<p>再有十天就要过年了，这两天刚刚放寒假。</p><p>继续抽出时间来总结一下过去的2025年、再展望一下2026年！</p><p>相关文章：</p><ul><li><a href="/cn/2025/01/17/さよなら２０２４、こんにちは２０２５！/">《さよなら２０２４、こんにちは２０２５！》</a></li></ul><br/><span id="more"></span><h1 id="再见2025，你好2026！"><a href="#再见2025，你好2026！" class="headerlink" title="再见2025，你好2026！"></a><strong>再见2025，你好2026！</strong></h1><h2 id="一、过去的2025"><a href="#一、过去的2025" class="headerlink" title="一、过去的2025"></a>一、过去的2025</h2><p>刚刚过去的2025年可以说是比较忙碌的一年（虽然每年都这么说）。</p><p>回顾过去的一年，大概做了这么几个事情：</p><ul><li>带了新的25级学生；</li><li>参加了教师技能大赛；</li><li>带学生参加了学生技能大赛；</li><li>上了几门新课。</li><li>……</li></ul><p>下面简单聊聊吧。</p><br/><h3 id="1）新学生"><a href="#1）新学生" class="headerlink" title="1）新学生"></a><strong>1）新学生</strong></h3><p>25年除了带 24级的学生之外，又新加入了 25级的学生。</p><p>因为不是第一个班，所以实际上有一种很奇怪的感觉。</p><blockquote><p>  <strong>虽然这个比喻不太恰当，但是：</strong></p><p>  <strong>这个感觉有点类似于，生了一个孩子之后，又有了二胎和三胎……</strong></p></blockquote><p>不过随着国内环境的越来越卷，招收的学生的质量也是在不断提高的；</p><p>有不少同学还是非常愿意学习的，这是一个好事！</p><br/><h3 id="2）教师技能大赛"><a href="#2）教师技能大赛" class="headerlink" title="2）教师技能大赛"></a><strong>2）教师技能大赛</strong></h3><p>除了日常的教学工作，辅导学生竞赛之外，在 2025 年同样也参加了教师技能大赛；</p><p>说实话，这个比赛有点类似于表演的性质，基本上都是提前准备好材料、稿子和PPT。</p><p>但是从比赛当中，确实从几位老教师身上学到了一些讲课的方式方法，包括：</p><ul><li>一个好的 PPT 如何制作、切换</li><li>如何把握好上课的语速、节奏</li><li>如何设计整个课程</li><li>一些教学上的名词，比如：学情分析、教学设计、教学环节、教学过程、教学方法、教学手段、教学模式、教学评价等等</li><li>……</li></ul><p>总的来说，收获还是挺多的，尤其是在上课节奏、内容的把握上！</p><br/><h3 id="3）学生技能大赛"><a href="#3）学生技能大赛" class="headerlink" title="3）学生技能大赛"></a><strong>3）学生技能大赛</strong></h3><p>除了教师的技能大赛之外，每年必不可少的项目就是带学生比赛；</p><p>今年由于赛制改革，把云计算的比赛给砍掉了，所以比赛不是很多，这也给了我不少的时间去构思，如何才能做一个亮眼、有创意的项目。</p><p>当然，虽然说是“学生技能大赛”，但是实际上基本上所有的项目部分都是老师来完成的！</p><p>学生主要还是：熟悉项目功能、完成系统的部署和使用，同时能够做好汇报工作即可！</p><p>虽然今年的比赛拿到了省金奖，但是实际上整个项目还是有非常大的提升空间的！</p><blockquote><p>  <strong>目前新的思路有了，但是还不方便在这里透露，后续可以再额外开一个部分来分享！</strong></p></blockquote><br/><h3 id="4）几门新的课程"><a href="#4）几门新的课程" class="headerlink" title="4）几门新的课程"></a><strong>4）几门新的课程</strong></h3><p>随着 AI 的发展，实际上高校的课程也是在不断的变化和改革的！</p><p>今年就接了一门新的课程：《人工智能导论》</p><p>由于之前做过一些比较有趣的项目，所以这个课程在设计的时候，就融入了一些比较有趣的内容；</p><p>整体的课程上下来，我个人觉得效果是比较好的！</p><p>这个课主要带着学生们做：</p><ul><li>Python 基础；</li><li>图像识别：标注、训练集制作、模型的训练、图像预测等等；</li><li>自然语言：数据的爬取、数据的处理与分析、数据可视化、大模型基本原理、编写简单豆包；</li><li>智能语音：目前这学期没有给大一的学生开，主要是给大二的学生开；</li></ul><p>通过这门课程，实际上大部分学会的学生都能够：</p><ul><li>做自己想要识别的图像识别模型！</li><li>做一个自己的豆包，同时编写简单的 function calling 工具！</li></ul><p>我个人觉得这个课程还是比较有意思的！</p><blockquote><p>  同时为了让学生都能完成作业，我还专门录了B站的视频：</p><ul><li><a href="https://www.bilibili.com/video/BV1GbqzB4E2h/">https://www.bilibili.com/video/BV1GbqzB4E2h/</a></li></ul></blockquote><br/><h3 id="5）关于车"><a href="#5）关于车" class="headerlink" title="5）关于车"></a><strong>5）关于车</strong></h3><p>2025 年年底，终于买了人生的第一辆车！</p><p>有了车之后，可行动的范围也大大扩大，也跑了几次高速，感觉方便了很多！</p><p>目前还在熟练中，后续会做一些旅行、拍照吧！</p><br/><h3 id="6）关于AI"><a href="#6）关于AI" class="headerlink" title="6）关于AI"></a><strong>6）关于AI</strong></h3><p>最后一个部分，想要聊一聊 AI；</p><p>大家也都能感受到，目前 AI 对各行各业都有着不小的冲击！</p><p>实际上教育行业也是一样的：</p><p>学校讲授的大量知识实际上 AI 已经完全可以做的很好了，甚至留的作业 AI 都能完美的完成。</p><p>这就导致，课程的内容在设计后：<strong>实际上即使学生不上这门课、甚至完全不懂这门课的内容，依然可以借助 AI 解决遇到的问题！</strong></p><p>所以，<font color="#f00"><strong>是否还有必要像传统模式一样去授课目前是存在疑问的！</strong></font></p><blockquote><p>  <strong>说实话，就我个人的学习和提升而言，有时候也会迷茫，目前学的东西还是否有用？</strong></p><p>  关于 AI 的讨论，可以看 yihong 大佬的这个讨论：</p><ul><li><a href="https://github.com/yihong0618/gitblog/issues/336">https://github.com/yihong0618/gitblog/issues/336</a></li></ul><p>  <strong>简而言之，我觉得未来在教育形式上，一定会有大的变革！</strong></p></blockquote><p>在期末考试的时候，我甚至设计的是开卷考试：</p><p>提供项目的需求书，让学生们借助大模型去完成项目需求说明中的功能，并测试！</p><p>我觉得这样的考核可能更符合当下企业的需求吧！</p><p><strong>更多的改革，目前我也在思考和探索中！</strong></p><br/><h2 id="二、你好2026"><a href="#二、你好2026" class="headerlink" title="二、你好2026"></a>二、你好2026</h2><p>说完了过去的 2025，现在来展望一下 2026 吧……</p><blockquote><p>  虽然每年列出的计划，到最后大部分都没完成；</p><p>  <strong>但是还是那句话：“梦想还是要有的，万一实现了呢？”</strong></p></blockquote><ul><li>证书：<ul><li><input disabled="" type="checkbox"> 通过软考中级（软件设计师）</li><li><input disabled="" type="checkbox"> 日语N2证书</li><li><input disabled="" type="checkbox"> 雅思证书</li></ul></li><li>跑步：<ul><li><input disabled="" type="checkbox"> 年跑量 1200km</li><li><input disabled="" type="checkbox"> 参加一次半马</li></ul></li><li>旅游：<ul><li><input disabled="" type="checkbox"> 去一次日本旅游</li></ul></li></ul><p>如果后面有新加入的内容，也会再加进来！</p><p>最后，祝愿各位在新的一年都能顺顺利利，无限进步！</p><p><strong>今年も、よろしくお願いします！</strong></p><br/>]]></content>
    
    
    <summary type="html">再有十天就要过年了，这两天刚刚放寒假，继续抽出时间来总结一下过去的2025年、再展望一下2026年！</summary>
    
    
    
    <category term="人生日记" scheme="https://jasonkayzk.github.io/cn/categories/%E4%BA%BA%E7%94%9F%E6%97%A5%E8%AE%B0/"/>
    
    
    <category term="人生日记" scheme="https://jasonkayzk.github.io/cn/tags/%E4%BA%BA%E7%94%9F%E6%97%A5%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>下一代提示词工程语言POML简明教程</title>
    <link href="https://jasonkayzk.github.io/cn/2025/08/20/%E4%B8%8B%E4%B8%80%E4%BB%A3%E6%8F%90%E7%A4%BA%E8%AF%8D%E5%B7%A5%E7%A8%8B%E8%AF%AD%E8%A8%80POML%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B/"/>
    <id>https://jasonkayzk.github.io/cn/2025/08/20/%E4%B8%8B%E4%B8%80%E4%BB%A3%E6%8F%90%E7%A4%BA%E8%AF%8D%E5%B7%A5%E7%A8%8B%E8%AF%AD%E8%A8%80POML%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B/</id>
    <published>2025-08-20T12:39:59.000Z</published>
    <updated>2026-10-25T04:05:16.277Z</updated>
    
    <content type="html"><![CDATA[<p>传统的提示词工程通常涉及编写自由文本，随着应用的发展，提示词文本会变得越来越复杂。</p><p>从而引出：提示词难以维护、难以进行版本控制、在不同场景下难以重用，几乎不可能进行系统化测试等一系列问题。</p><p>如何解决这些问题呢？</p><p>Microsoft给出了一个工程化的答案：POML！</p><p>文章和 Colab 配合，学习效果更佳：</p><ul><li><a href="https://colab.research.google.com/drive/1RrZyqB16XMvsFBjir90m-NCXE35kWFdy?usp=sharing">https://colab.research.google.com/drive/1RrZyqB16XMvsFBjir90m-NCXE35kWFdy?usp=sharing</a></li></ul><br/><span id="more"></span><h1 id="下一代提示词工程语言POML简明教程"><a href="#下一代提示词工程语言POML简明教程" class="headerlink" title="下一代提示词工程语言POML简明教程"></a><strong>下一代提示词工程语言POML简明教程</strong></h1><h2 id="一、简介"><a href="#一、简介" class="headerlink" title="一、简介"></a><strong>一、简介</strong></h2><p><strong>POML通过引入一种结构化方法，使用类似于 HTML 的格式编写提示词内容；</strong></p><p><strong>用户无需编写纯文本提示词，而是可以使用 <code>&lt;role&gt;</code>、<code>&lt;task&gt;</code> 和 <code>&lt;example&gt;</code> 等语义组件来组织提示词意图，从而带来更好的 LLM 性能和更便捷的提示词维护。</strong></p><p><strong>同时，POML具有类似CSS的样式系统，将内容与定义表示分离；</strong></p><h3 id="（一）核心架构"><a href="#（一）核心架构" class="headerlink" title="（一）核心架构"></a><strong>（一）核心架构</strong></h3><p>POML采用三层架构运行，分离关注点并支持灵活的提示词开发：</p><p><img src="https://hub.gitmirror.com/raw.githubusercontent.com/JasonkayZK/blog_static/master/images/poml-structure.png" alt="poml-structure"></p><p>该架构通过几个阶段处理POML文件：</p><ol><li><strong>解析</strong>：将类似XML的语法转换为结构化的中间表示；</li><li><strong>处理</strong>：应用样式表、解析模板并集成外部数据；</li><li><strong>生成</strong>：以各种格式生成最终的优化提示词；</li></ol><p>这种分离使开发者能够在不改变核心逻辑的情况下修改表示样式，无缝集成外部数据源，并在项目中保持一致的提示词结构。</p><br/><h3 id="（二）主要特性"><a href="#（二）主要特性" class="headerlink" title="（二）主要特性"></a><strong>（二）主要特性</strong></h3><h4 id="1、结构化标记系统"><a href="#1、结构化标记系统" class="headerlink" title="1、结构化标记系统"></a><strong>1、结构化标记系统</strong></h4><p>POML使用类似HTML的语法和语义组件，使提示词更具可读性和可维护性。</p><p>主要组件包括：</p><ul><li><code>&lt;role&gt;</code>：定义LLM应采用的角色或身份；</li><li><code>&lt;task&gt;</code>：指定LLM需要完成的任务；</li><li><code>&lt;example&gt;</code>：提供少样本学习示例；</li><li><code>&lt;output-format&gt;</code>：控制预期的响应格式；</li><li><code>&lt;hint&gt;</code>：提供额外的上下文或约束；</li></ul><p>例如：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">poml</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">role</span>&gt;</span>You are a patient teacher explaining concepts to a 10-year-old.<span class="tag">&lt;/<span class="name">role</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">task</span>&gt;</span>Explain the concept of photosynthesis using the provided image as a reference.<span class="tag">&lt;/<span class="name">task</span>&gt;</span></span><br><span class="line"> </span><br><span class="line">  <span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;photosynthesis.png&quot;</span> <span class="attr">alt</span>=<span class="string">&quot;Diagram of photosynthesis&quot;</span> /&gt;</span></span><br><span class="line">  </span><br><span class="line">  <span class="tag">&lt;<span class="name">output-format</span>&gt;</span></span><br><span class="line">    Keep the explanation simple, engaging, and under 100 words.</span><br><span class="line">    Start with &quot;Hey there, future scientist!&quot;.</span><br><span class="line">  <span class="tag">&lt;/<span class="name">output-format</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">poml</span>&gt;</span></span><br></pre></td></tr></table></figure><br/><h4 id="2、外部数据集成"><a href="#2、外部数据集成" class="headerlink" title="2、外部数据集成"></a><strong>2、外部数据集成</strong></h4><p>POML通过专用组件来集成外部数据：</p><ul><li><code>&lt;document&gt;</code>：嵌入文本文件、PDF或Word文档；</li><li><code>&lt;table&gt;</code>：集成电子表格或CSV文件中的结构化数据</li><li><code>&lt;img&gt;</code>：包含带有替代文本的图像，用于支持视觉的模型</li><li><code>&lt;audio&gt;</code>：处理多模态应用的音频文件；</li></ul><p>例如：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">hint</span> <span class="attr">captionStyle</span>=<span class="string">&quot;header&quot;</span> <span class="attr">caption</span>=<span class="string">&quot;Background Knowledge&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">Document</span> <span class="attr">src</span>=<span class="string">&quot;assets/tom_and_jerry.docx&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">hint</span>&gt;</span></span><br><span class="line"> </span><br><span class="line"><span class="tag">&lt;<span class="name">example</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;assets/tom_cat.jpg&quot;</span> <span class="attr">alt</span>=<span class="string">&quot;The image contains the Tom cat character.&quot;</span> <span class="attr">syntax</span>=<span class="string">&quot;multimedia&quot;</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">input</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">output</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">Document</span> <span class="attr">src</span>=<span class="string">&quot;assets/tom_introduction.txt&quot;</span>/&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">output</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">example</span>&gt;</span></span><br></pre></td></tr></table></figure><br/><h4 id="3、解耦的表示样式"><a href="#3、解耦的表示样式" class="headerlink" title="3、解耦的表示样式"></a><strong>3、解耦的表示样式</strong></h4><p>POML具有类似CSS的样式系统，将内容与表示分离。</p><p>例如：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;stylesheet&gt;</span><br><span class="line">  role &#123;</span><br><span class="line">    verbosity: concise;</span><br><span class="line">    format: markdown;</span><br><span class="line">  &#125;</span><br><span class="line">  task &#123;</span><br><span class="line">    emphasis: strong;</span><br><span class="line">  &#125;</span><br><span class="line">&lt;/stylesheet&gt;</span><br></pre></td></tr></table></figure><p>这允许开发者修改详细程度、输出格式和强调等样式方面，而无需改变核心提示词逻辑，显著降低调整提示词时格式漂移的风险。</p><br/><h4 id="4、模板引擎"><a href="#4、模板引擎" class="headerlink" title="4、模板引擎"></a><strong>4、模板引擎</strong></h4><p>POML包含强大的模板引擎，用于动态提示词生成：</p><ul><li>变量：<code>{ { variable_name } }</code></li><li>循环：<code>&lt;for each=&quot;item in items&quot;&gt;...&lt;/for&gt;</code></li><li>条件：<code>&lt;if condition=&quot;variable &gt; 0&quot;&gt;...&lt;/if&gt;</code></li><li>定义：<code>&lt;let name=&quot;variable&quot; value=&quot;expression&quot; /&gt;</code></li></ul><p>这支持创建数据驱动的提示词，能够适应不同的上下文和输入。</p><br/><h3 id="（三）开发生态"><a href="#（三）开发生态" class="headerlink" title="（三）开发生态"></a>（三）开发生态</h3><p>POML提供全面的开发工具包，提高生产力：</p><h4 id="1、VSCode扩展"><a href="#1、VSCode扩展" class="headerlink" title="1、VSCode扩展"></a><strong>1、VSCode扩展</strong></h4><p>Visual Studio Code扩展提供：</p><ul><li>语法高亮和语言支持</li><li>上下文感知的自动补全</li><li>实时预览功能</li><li>与LLM提供商的集成测试</li><li>错误诊断和验证</li><li>可重用组件的提示词库</li></ul><br/><h4 id="2、多语言SDK"><a href="#2、多语言SDK" class="headerlink" title="2、多语言SDK"></a><strong>2、多语言SDK</strong></h4><p>POML为Python和TypeScript/JavaScript提供SDK：</p><p><strong>Python SDK:</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> poml <span class="keyword">import</span> load, render</span><br><span class="line"> </span><br><span class="line"><span class="comment"># Load and render a POML file</span></span><br><span class="line">prompt = load(<span class="string">&quot;example.poml&quot;</span>)</span><br><span class="line">result = render(prompt, variables=&#123;<span class="string">&quot;topic&quot;</span>: <span class="string">&quot;photosynthesis&quot;</span>&#125;)</span><br></pre></td></tr></table></figure><p><strong>TypeScript SDK:</strong></p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; loadPoml, renderPoml &#125; <span class="keyword">from</span> <span class="string">&#x27;pomljs&#x27;</span>;</span><br><span class="line"> </span><br><span class="line"><span class="comment">// Load and render a POML file</span></span><br><span class="line"><span class="keyword">const</span> prompt = <span class="keyword">await</span> <span class="title function_">loadPoml</span>(<span class="string">&#x27;example.poml&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> result = <span class="keyword">await</span> <span class="title function_">renderPoml</span>(prompt, &#123; <span class="attr">topic</span>: <span class="string">&#x27;photosynthesis&#x27;</span> &#125;);</span><br></pre></td></tr></table></figure><br/><h2 id="二、基本使用"><a href="#二、基本使用" class="headerlink" title="二、基本使用"></a>二、基本使用</h2><h3 id="（一）安装"><a href="#（一）安装" class="headerlink" title="（一）安装"></a><strong>（一）安装</strong></h3><p>Node.js (via npm)：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install pomljs</span><br></pre></td></tr></table></figure><p>Python (via pip)：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install poml</span><br></pre></td></tr></table></figure><br/><h3 id="（二）第一个案例"><a href="#（二）第一个案例" class="headerlink" title="（二）第一个案例"></a><strong>（二）第一个案例</strong></h3><h4 id="1、编写POML文件"><a href="#1、编写POML文件" class="headerlink" title="1、编写POML文件"></a><strong>1、编写POML文件</strong></h4><p>编写一个名为 <code>example.poml</code> 的文件，内容如下：</p><p>example.poml</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">poml</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">role</span>&gt;</span>You are a patient teacher(named &#123;&#123;teacher_name&#125;&#125;) explaining concepts to a 10-year-old.<span class="tag">&lt;/<span class="name">role</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">task</span>&gt;</span>Explain the concept of photosynthesis using the provided image as a reference.<span class="tag">&lt;/<span class="name">task</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;photosynthesis.jpg&quot;</span> <span class="attr">alt</span>=<span class="string">&quot;Diagram of photosynthesis&quot;</span> <span class="attr">syntax</span>=<span class="string">&quot;multimedia&quot;</span>/&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">input</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">output-format</span>&gt;</span></span><br><span class="line">    Keep the explanation simple, engaging, and under 100 words.</span><br><span class="line">    Start with &quot;Hey there, future scientist!&quot;.</span><br><span class="line">  <span class="tag">&lt;/<span class="name">output-format</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">poml</span>&gt;</span></span><br></pre></td></tr></table></figure><p>示例定义了：</p><ul><li>LLM 的角色和任务，包含一张图片作为上下文，并指定了所需的输出格式。</li><li>同时，包含了一个变量 <code>teacher_name</code>；</li></ul><p>编写完成后，如果你安装了 <a href="https://marketplace.visualstudio.com/items?itemName=poml-team.poml">Visual Studio Code poml</a>  插件，则可以进行预览：</p><img src="https://hub.gitmirror.com/raw.githubusercontent.com/JasonkayZK/blog_static/master/images/poml-preview.jpg" width="50%" height="50%" /><br/><h4 id="2、解析并渲染POML"><a href="#2、解析并渲染POML" class="headerlink" title="2、解析并渲染POML"></a><strong>2、解析并渲染POML</strong></h4><p>借助 POML 工具包，此提示词可以轻松渲染为灵活的格式，并可通过 LLM 进行测试。</p><p>例如在 Python 中：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> poml <span class="keyword">import</span> poml</span><br><span class="line"> </span><br><span class="line"><span class="comment"># Process a POML file</span></span><br><span class="line"><span class="comment"># result = poml(&quot;example.poml&quot;)</span></span><br><span class="line"> </span><br><span class="line"><span class="comment"># Process with context variables</span></span><br><span class="line">result = poml(<span class="string">&quot;example.poml&quot;</span>, context=&#123;<span class="string">&quot;teacher_name&quot;</span>: <span class="string">&quot;Jasonkay&quot;</span>&#125;)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;Process with context variables: <span class="subst">&#123;result&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Get OpenAI chat format(Within the higher version)</span></span><br><span class="line"><span class="comment"># messages = poml(&quot;example.poml&quot;, format=&quot;openai_chat&quot;)</span></span><br><span class="line"><span class="comment"># print(f&quot;Get OpenAI chat format: &#123;messages&#125;&quot;)</span></span><br></pre></td></tr></table></figure><p><code>poml</code> 函数接受以下参数：</p><ul><li><code>markup</code>：POML 内容（字符串或文件路径）</li><li><code>context</code>：可选的模板注入数据</li><li><code>stylesheet</code>：可选的样式自定义</li><li><code>format</code>：输出格式（”dict”、”openai_chat”、”langchain”、”pydantic” 或 “raw”）</li></ul><p>执行代码后，输出结果为：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Process with context variables: [&#123;<span class="string">&#x27;speaker&#x27;</span>: <span class="string">&#x27;system&#x27;</span>, <span class="string">&#x27;content&#x27;</span>: <span class="string">&#x27;# Role\n\nYou are a patient teacher(named Jasonkay) explaining concepts to a 10-year-old.\n\n# Task\n\nExplain the concept of photosynthesis using the provided image as a reference.&#x27;</span>&#125;, &#123;<span class="string">&#x27;speaker&#x27;</span>: <span class="string">&#x27;human&#x27;</span>, <span class="string">&#x27;content&#x27;</span>: [&#123;<span class="string">&#x27;type&#x27;</span>: <span class="string">&#x27;image/webp&#x27;</span>, <span class="string">&#x27;base64&#x27;</span>: <span class="string">&#x27;UklGRg......&#x27;</span>, <span class="string">&#x27;alt&#x27;</span>: <span class="string">&#x27;Diagram of photosynthesis&#x27;</span>&#125;, <span class="string">&#x27;# Output Format\n\nKeep the explanation simple, engaging, and under 100 words. Start with &quot;Hey there, future scientist!&quot;.&#x27;</span>]&#125;]</span><br></pre></td></tr></table></figure><p>可以看到，输出的内容将内容进行了渲染！</p><br/><h4 id="3、与LLM系统集成-Gemini"><a href="#3、与LLM系统集成-Gemini" class="headerlink" title="3、与LLM系统集成(Gemini)"></a><strong>3、与LLM系统集成(Gemini)</strong></h4><p>最后，将我们的提示词和外部 LLM 系统相结合！</p><blockquote><p>  由于目前最新的 POML SDK 还不支持使用 <code>format</code> 参数来渲染 <code>openai_chat</code> 类型的 Prompt；</p><p>  因此，这里使用 Gemini API 来发送图片！</p></blockquote><p>使用下面的 poml 文件来渲染：</p><p>example.poml</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">poml</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">role</span>&gt;</span>You are a patient teacher(named &#123;&#123;teacher_name&#125;&#125;) explaining concepts to a 10-year-old.<span class="tag">&lt;/<span class="name">role</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">task</span>&gt;</span>Explain the concept of photosynthesis using the provided image as a reference.<span class="tag">&lt;/<span class="name">task</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">output-format</span>&gt;</span></span><br><span class="line">    Keep the explanation simple, engaging, and under 100 words.</span><br><span class="line">    Start with &quot;Hey there, future scientist!&quot;.</span><br><span class="line">  <span class="tag">&lt;/<span class="name">output-format</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">poml</span>&gt;</span></span><br></pre></td></tr></table></figure><br/><p>首先安装 Gemini SDK：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install -U google-genai</span><br></pre></td></tr></table></figure><blockquote><p>  <strong>要运行下面的代码，你需要创建一个 Gemini 的 API Key：</strong></p><ul><li><a href="https://aistudio.google.com/app/apikey">https://aistudio.google.com/app/apikey</a></li></ul><p>  <strong>随后，将下面的 <code>YOUR_API_KEY</code> 替换为你生成的 Key！</strong></p></blockquote><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> google <span class="keyword">import</span> genai</span><br><span class="line"><span class="keyword">from</span> poml <span class="keyword">import</span> poml</span><br><span class="line"><span class="keyword">from</span> google.genai <span class="keyword">import</span> types</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line">GEMINI_API_KEY=<span class="string">&quot;YOUR_API_KEY&quot;</span></span><br><span class="line"></span><br><span class="line">client = genai.Client(api_key=GEMINI_API_KEY)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Read the picture</span></span><br><span class="line"><span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&#x27;photosynthesis.jpg&#x27;</span>, <span class="string">&#x27;rb&#x27;</span>) <span class="keyword">as</span> f:</span><br><span class="line">    image_bytes = f.read()</span><br><span class="line"></span><br><span class="line"><span class="comment"># Render the POML file</span></span><br><span class="line">result = poml(<span class="string">&quot;example.poml&quot;</span>, context=&#123;<span class="string">&quot;teacher_name&quot;</span>: <span class="string">&quot;Jasonkay&quot;</span>&#125;, chat=<span class="literal">False</span>)</span><br><span class="line"><span class="comment"># print(f&quot;Process with context variables: &#123;result&#125;&quot;)</span></span><br><span class="line"></span><br><span class="line">response = client.models.generate_content(</span><br><span class="line">    model=<span class="string">&quot;gemini-2.5-flash&quot;</span>, </span><br><span class="line">    contents=[</span><br><span class="line">        result,</span><br><span class="line">        types.Part.from_bytes(</span><br><span class="line">          data=image_bytes,</span><br><span class="line">          mime_type=<span class="string">&#x27;image/jpeg&#x27;</span>,</span><br><span class="line">      ),</span><br><span class="line">    ]</span><br><span class="line">)</span><br><span class="line"><span class="built_in">print</span>(response.text)</span><br></pre></td></tr></table></figure><p>最后，执行即可输出内容：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Look at our amazing plant friend! Just like you need food, plants need to eat too! This image shows how they do it, a process called **photosynthesis**. Plants use sunlight from the sun, and &quot;drink&quot; water through their roots. They also breathe in a gas called CO2 (carbon dioxide) from the air, shown by the blue arrow going in. Using these, they make their own sugary food to grow! As a super cool bonus, they release O2 (oxygen) for us to breathe, shown by the blue arrow going out. Amazing, right?</span><br></pre></td></tr></table></figure><br/><h3 id="（三）使用样式"><a href="#（三）使用样式" class="headerlink" title="（三）使用样式"></a><strong>（三）使用样式</strong></h3><p>现在，让我们为上面的例子增加相关的样式，来优化的 Prompt 配置！</p><p>example-2.poml</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">poml</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">role</span>&gt;</span>You are a patient teacher(named &#123;&#123;teacher_name&#125;&#125;) explaining concepts to a 10-year-old.<span class="tag">&lt;/<span class="name">role</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">task</span>&gt;</span>Explain the concept of photosynthesis using the provided image as a reference.<span class="tag">&lt;/<span class="name">task</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">output-format</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">list</span> <span class="attr">listStyle</span>=<span class="string">&quot;dash&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">className</span>=<span class="string">&quot;explanation&quot;</span>&gt;</span>Keep the explanation simple, engaging, and under 100 words.<span class="tag">&lt;/<span class="name">item</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">item</span> <span class="attr">className</span>=<span class="string">&quot;greeting&quot;</span>&gt;</span>    Start with &quot;Hey there, future scientist!&quot;.     <span class="tag">&lt;/<span class="name">item</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">list</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">output-format</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">poml</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">stylesheet</span>&gt;</span></span><br><span class="line">  &#123;</span><br><span class="line">    &quot;.explanation&quot;: &#123;</span><br><span class="line">      &quot;syntax&quot;: &quot;json&quot;</span><br><span class="line">    &#125;,</span><br><span class="line">    &quot;list&quot; : &#123;</span><br><span class="line">      &quot;whiteSpace&quot;: &quot;trim&quot;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">stylesheet</span>&gt;</span></span><br></pre></td></tr></table></figure><p>渲染结果如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Role</span></span><br><span class="line"></span><br><span class="line">You are a patient teacher(named ) explaining concepts to a 10-year-old.</span><br><span class="line"></span><br><span class="line"><span class="comment"># Task</span></span><br><span class="line"></span><br><span class="line">Explain the concept of photosynthesis using the provided image as a reference.</span><br><span class="line"></span><br><span class="line"><span class="comment"># Output Format</span></span><br><span class="line"></span><br><span class="line">```json</span><br><span class="line"><span class="string">&quot;Keep the explanation simple, engaging, and under 100 words.&quot;</span></span><br><span class="line">```</span><br><span class="line"></span><br><span class="line">- Start with <span class="string">&quot;Hey there, future scientist!&quot;</span>.     </span><br></pre></td></tr></table></figure><blockquote><p>  更多内容可以参考官方文档：</p><ul><li><a href="https://microsoft.github.io/poml/latest/language/standalone/#stylesheet">https://microsoft.github.io/poml/latest/language/standalone/#stylesheet</a></li></ul></blockquote><br/><h2 id="三、深入学习"><a href="#三、深入学习" class="headerlink" title="三、深入学习"></a><strong>三、深入学习</strong></h2><p>在完成了基础学习之后，可以继续阅读下面的内容：</p><ul><li><a href="https://github.com/microsoft/poml/tree/main/examples">更多官方的案例</a></li><li><a href="https://microsoft.github.io/poml/latest/">官方文档</a></li><li><a href="https://zread.ai/microsoft/poml/6-poml-syntax-and-structure">POML语法结构</a></li><li><a href="https://zread.ai/microsoft/poml/8-intermediate-representation">POML中间表示</a></li><li><a href="https://zread.ai/microsoft/poml/11-api-reference">API参考</a></li><li><a href="https://zread.ai/microsoft/poml/13-integration-with-external-systems">外部系统集成</a></li><li><a href="https://zread.ai/microsoft/poml/14-custom-component-development">自定义组件</a></li></ul><p>进行更加深度的学习！</p><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>文章和 Colab 配合，学习效果更佳：</p><ul><li><a href="https://colab.research.google.com/drive/1RrZyqB16XMvsFBjir90m-NCXE35kWFdy?usp=sharing">https://colab.research.google.com/drive/1RrZyqB16XMvsFBjir90m-NCXE35kWFdy?usp=sharing</a></li></ul><p>参考文章：</p><ul><li><a href="https://github.com/microsoft/poml">https://github.com/microsoft/poml</a></li><li><a href="https://zread.ai/microsoft/poml">https://zread.ai/microsoft/poml</a></li><li><a href="https://microsoft.github.io/poml/latest/">https://microsoft.github.io/poml/latest/</a></li><li><a href="https://ai.google.dev/gemini-api/docs/image-understanding">https://ai.google.dev/gemini-api/docs/image-understanding</a></li></ul><br/>]]></content>
    
    
    <summary type="html">传统的提示词工程通常涉及编写自由文本，随着应用的发展，提示词文本会变得越来越复杂。从而引出：提示词难以维护、难以进行版本控制、在不同场景下难以重用，几乎不可能进行系统化测试等一系列问题。如何解决这些问题呢？Microsoft给出了一个工程化的答案：POML！</summary>
    
    
    
    <category term="人工智能" scheme="https://jasonkayzk.github.io/cn/categories/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/"/>
    
    
    <category term="Python" scheme="https://jasonkayzk.github.io/cn/tags/Python/"/>
    
    <category term="人工智能" scheme="https://jasonkayzk.github.io/cn/tags/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/"/>
    
    <category term="POML" scheme="https://jasonkayzk.github.io/cn/tags/POML/"/>
    
  </entry>
  
  <entry>
    <title>开了一个新的专门学习日语的博客</title>
    <link href="https://jasonkayzk.github.io/cn/2025/07/30/%E5%BC%80%E4%BA%86%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E4%B8%93%E9%97%A8%E5%AD%A6%E4%B9%A0%E6%97%A5%E8%AF%AD%E7%9A%84%E5%8D%9A%E5%AE%A2/"/>
    <id>https://jasonkayzk.github.io/cn/2025/07/30/%E5%BC%80%E4%BA%86%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E4%B8%93%E9%97%A8%E5%AD%A6%E4%B9%A0%E6%97%A5%E8%AF%AD%E7%9A%84%E5%8D%9A%E5%AE%A2/</id>
    <published>2025-07-30T05:22:44.000Z</published>
    <updated>2026-10-25T04:05:16.288Z</updated>
    
    <content type="html"><![CDATA[<p>之前一直都在这里发一些学习日语相关的内容。但是感觉这些可以单独开一个新的网站来总结；</p><p>最近比较有时间，就开了一个新的坑；</p><p>博客主题用的是：<a href="https://github.com/anzhiyu-c/hexo-theme-anzhiyu">hexo-theme-anzhiyu</a>，真的很酷！</p><p>也是花了半个小时，使用hexo，从零搭建了一个博客；</p><p>之前没有好好总结，这里就又简单记录了一下搭建的过程，如果你还没有博客，可以跟着我一步一步来搭建一个GithubPages博客！</p><p>新博客地址：</p><ul><li><a href="https://jasonkayzk.github.io/jp/">https://jasonkayzk.github.io/jp/</a></li></ul><p>源代码：</p><ul><li><a href="https://github.com/JasonkayZK/jp">https://github.com/JasonkayZK/jp</a></li><li><a href="https://github.com/anzhiyu-c/hexo-theme-anzhiyu">https://github.com/anzhiyu-c/hexo-theme-anzhiyu</a></li></ul><br/><span id="more"></span><h1 id="开了一个新的专门学习日语的博客"><a href="#开了一个新的专门学习日语的博客" class="headerlink" title="开了一个新的专门学习日语的博客"></a><strong>开了一个新的专门学习日语的博客</strong></h1><h2 id="一、安装Node-js-amp-Hexo"><a href="#一、安装Node-js-amp-Hexo" class="headerlink" title="一、安装Node.js&amp;Hexo"></a><strong>一、安装Node.js&amp;Hexo</strong></h2><p>可以在官网下载Node：</p><ul><li><a href="https://nodejs.org/zh-cn/download">https://nodejs.org/zh-cn/download</a></li></ul><blockquote><p>  <strong>我这里使用的是 fnm 作为版本管理工具；</strong></p><p>  <strong>配置国内源：</strong></p>  <figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 国内 淘宝 镜像源</span></span><br><span class="line">npm config <span class="built_in">set</span> registry https://registry.npmmirror.com/</span><br></pre></td></tr></table></figure><p>  <strong>参考：</strong></p><ul><li><a href="https://ksh7.com/posts/npm-registry/index.html">npm、yarn、pnpm 设置最新国内镜像源（附官方镜像源和最新阿里源），以及 nrm 的使用教程【2025】</a></li></ul></blockquote><p>也可以把 yarn 安装了：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">npm install -g yarn</span><br><span class="line"></span><br><span class="line"><span class="comment"># 国内 淘宝 镜像源</span></span><br><span class="line">yarn config <span class="built_in">set</span> registry https://registry.npmmirror.com/</span><br></pre></td></tr></table></figure><br/><p>随后下载 Hexo-cli 命令行工具：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-cli -g</span><br></pre></td></tr></table></figure><blockquote><p>  参考：</p><ul><li><a href="https://hexo.io/zh-cn/">https://hexo.io/zh-cn/</a></li></ul></blockquote><br/><h2 id="二、初始化Hexo项目"><a href="#二、初始化Hexo项目" class="headerlink" title="二、初始化Hexo项目"></a><strong>二、初始化Hexo项目</strong></h2><p>直接通过命令行初始化项目 jp：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># hexo init jp</span></span><br><span class="line"></span><br><span class="line">INFO  Cloning hexo-starter https://github.com/hexojs/hexo-starter.git</span><br><span class="line">INFO  Install dependencies</span><br><span class="line">......</span><br><span class="line">INFO  Start blogging with Hexo!</span><br></pre></td></tr></table></figure><p>安装依赖并测试：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> jp</span><br><span class="line">npm i</span><br><span class="line">hexo s <span class="comment"># 本地调试</span></span><br></pre></td></tr></table></figure><p>此时访问：</p><ul><li><a href="http://localhost:4000/">http://localhost:4000/</a></li></ul><p>你就能看到你的博客了！</p><blockquote><p>  <strong>参考文档：</strong></p><ul><li><a href="https://hexo.io/zh-cn/">https://hexo.io/zh-cn/</a></li></ul></blockquote><br/><h2 id="三、更换主题"><a href="#三、更换主题" class="headerlink" title="三、更换主题"></a><strong>三、更换主题</strong></h2><p>默认的主题不太好看，可以在 github 上搜索 hexo 的相关主题（一般为 <code>hexo-</code> 开头）；</p><p>以 <a href="https://github.com/anzhiyu-c/hexo-theme-anzhiyu">hexo-theme-anzhiyu</a> 为例，文档：</p><ul><li><a href="https://docs.anheyu.com/">https://docs.anheyu.com/</a></li></ul><p>首先在你项目的根目录将主题 clone 下来：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> -b main https://github.com/anzhiyu-c/hexo-theme-anzhiyu.git themes/anzhiyu</span><br></pre></td></tr></table></figure><p>随后打开 <strong>Hexo</strong> 根目录下的 <code>config.yml</code>, 找到以下配置项，把主题改为<code>anzhiyu</code></p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Extensions</span></span><br><span class="line"><span class="comment">## Plugins: https://hexo.io/plugins/</span></span><br><span class="line"><span class="comment">## Themes: https://hexo.io/themes/</span></span><br><span class="line"><span class="attr">theme:</span> <span class="string">anzhiyu</span></span><br></pre></td></tr></table></figure><p>然后安装 pug 和 stylus 渲染插件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-renderer-pug hexo-renderer-stylus --save</span><br></pre></td></tr></table></figure><p>再次执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo s</span><br></pre></td></tr></table></figure><p>此时再次访问：</p><ul><li><a href="http://localhost:4000/">http://localhost:4000/</a></li></ul><p>你就能看到你新的主题的博客了！</p><br/><h2 id="四、自定义配置"><a href="#四、自定义配置" class="headerlink" title="四、自定义配置"></a><strong>四、自定义配置</strong></h2><p>拉下来的新的主题，很多内容大概率都不符合你的预期（比如：title、分类等等）；</p><p>此时你可以参考文档进行个性化的配置：</p><ul><li><a href="https://docs.anheyu.com/page/front-matter.html">https://docs.anheyu.com/page/front-matter.html</a></li></ul><p>需要注意的是：</p><p><font color="#f00"><strong>在根目录下存在 <code>_config.yml</code>、各自主题下也有这个文件，优先级为：根目录 &gt; 各自主题配置！</strong></font></p><br/><h2 id="五、撰写新的文章"><a href="#五、撰写新的文章" class="headerlink" title="五、撰写新的文章"></a><strong>五、撰写新的文章</strong></h2><p>通过：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo new xxx</span><br></pre></td></tr></table></figure><p>即可创建一篇新的博文！</p><blockquote><p>  <font color="#f00"><strong>实际上就是在 <code>source/_posts/</code> 目录下创建了一个新的<code>*.md</code>文件而已！</strong></font></p></blockquote><p>可以增加 <code>Post Front-matter</code> 来对文章进行配置！</p><p>文章内容就按照 markdown 的格式去写就可以了！</p><br/><h2 id="六、发布到Github"><a href="#六、发布到Github" class="headerlink" title="六、发布到Github"></a><strong>六、发布到Github</strong></h2><p>本地调试无误后，修改根目录下的 <code>_config.yml</code>：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Deployment</span></span><br><span class="line"><span class="comment">## Docs: https://hexo.io/docs/one-command-deployment</span></span><br><span class="line"><span class="attr">deploy:</span></span><br><span class="line">  <span class="attr">type:</span> <span class="string">&#x27;git&#x27;</span></span><br><span class="line">  <span class="attr">repo:</span> <span class="string">git@github.com:jasonkayzk/jp.git</span>  <span class="comment"># 替换为你的仓库地址</span></span><br><span class="line">  <span class="attr">branch:</span> <span class="string">main</span>  <span class="comment"># 部署分支  </span></span><br></pre></td></tr></table></figure><p>安装插件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-deployer-git --save</span><br></pre></td></tr></table></figure><p>随后，在发布时，通常情况下：</p><ul><li>首先，通过 <code>hexo g</code> 生成静态资源；</li><li>然后使用 <code>hexo d</code> 即可部署！</li></ul><blockquote><p>  <strong>参考：</strong></p><ul><li><a href="https://hexo.io/docs/one-command-deployment">https://hexo.io/docs/one-command-deployment</a></li></ul></blockquote><p><strong>但是这种方式每次都要在本地生成静态资源，效率太低！</strong></p><br/><h3 id="1、使用GitHub-Actions自动部署"><a href="#1、使用GitHub-Actions自动部署" class="headerlink" title="1、使用GitHub Actions自动部署"></a><strong>1、使用GitHub Actions自动部署</strong></h3><p><font color="#f00"><strong>可以通过 Github Actions，每次 push 代码之后自动提交！</strong></font></p><p>在 <code>.github/workflows/</code> 目录下创建：</p><p>deploy.yml</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">name:</span> <span class="string">Build</span> <span class="string">&amp;</span> <span class="string">Deploy</span> <span class="string">Blog</span></span><br><span class="line"></span><br><span class="line"><span class="attr">on:</span></span><br><span class="line">  <span class="attr">workflow_dispatch:</span></span><br><span class="line">  <span class="attr">push:</span></span><br><span class="line">    <span class="attr">branches:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">dev</span></span><br><span class="line"></span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line">  <span class="attr">build:</span></span><br><span class="line">    <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line">    <span class="attr">strategy:</span></span><br><span class="line">      <span class="attr">matrix:</span></span><br><span class="line">        <span class="attr">node_version:</span> [<span class="number">18</span>]</span><br><span class="line">    <span class="attr">steps:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Checkout</span> <span class="string">source</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">actions/checkout@v3</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">ref:</span> <span class="string">dev</span></span><br><span class="line">          </span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Cache</span> <span class="string">dependencies</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">actions/cache@v3</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">path:</span> <span class="string">|</span></span><br><span class="line"><span class="string">            node_modules</span></span><br><span class="line"><span class="string">            public</span></span><br><span class="line"><span class="string"></span>          <span class="attr">key:</span> <span class="string">$&#123;&#123;</span> <span class="string">runner.os</span> <span class="string">&#125;&#125;-node-$&#123;&#123;</span> <span class="string">hashFiles(&#x27;**/package-lock.json&#x27;)</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          <span class="attr">restore-keys:</span> <span class="string">|</span></span><br><span class="line"><span class="string">            $&#123;&#123; runner.os &#125;&#125;-node-</span></span><br><span class="line"><span class="string"></span>            </span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Use</span> <span class="string">Node.js</span> <span class="string">$&#123;&#123;</span> <span class="string">matrix.node_version</span> <span class="string">&#125;&#125;</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">actions/setup-node@v3</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">version:</span> <span class="string">$&#123;&#123;</span> <span class="string">matrix.node_version</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          </span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Add</span> <span class="string">SSH</span> <span class="string">key</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">webfactory/ssh-agent@v0.7.0</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">ssh-private-key:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.hexo_deploy_pri</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          </span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Setup</span> <span class="string">hexo</span></span><br><span class="line">        <span class="attr">run:</span> <span class="string">|</span></span><br><span class="line"><span class="string">          git config --global user.email &quot;jasonkayzk@gmail.com&quot;</span></span><br><span class="line"><span class="string">          git config --global user.name &quot;jasonkayzk&quot;</span></span><br><span class="line"><span class="string">          npm install hexo-cli -g</span></span><br><span class="line"><span class="string">          npm install</span></span><br><span class="line"><span class="string"></span>          </span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Hexo</span> <span class="string">deploy</span></span><br><span class="line">        <span class="attr">env:</span></span><br><span class="line">          <span class="attr">GIT_SSH_COMMAND:</span> <span class="string">ssh</span> <span class="string">-o</span> <span class="string">StrictHostKeyChecking=no</span></span><br><span class="line">        <span class="attr">run:</span> <span class="string">|</span></span><br><span class="line"><span class="string">          hexo clean</span></span><br><span class="line"><span class="string">          hexo g</span></span><br><span class="line"><span class="string">          hexo d</span></span><br></pre></td></tr></table></figure><p>随后在仓库的 <code>Secrets and variables</code> 设置中，添加 <code>Repository secrets</code>：</p><ul><li><strong>key为：<code>HEXO_DEPLOY_PRI</code>；</strong></li><li><strong>值为：你连接 Github 的私钥！（注意是私钥！）</strong></li></ul><p><strong>提交到 dev 分支后即可自动部署！</strong></p><br/><h3 id="2、使用新分支保存笔记"><a href="#2、使用新分支保存笔记" class="headerlink" title="2、使用新分支保存笔记"></a><strong>2、使用新分支保存笔记</strong></h3><p>同时，生成的内容可能会覆盖原本的笔记<strong>（<code>hexo d</code> 会强行覆盖部署分支！）</strong>：</p><ul><li><strong>我们只需要 checkout 到另外的一个分支去编写博客，然后部署到 main 分支即可！</strong></li></ul><p>例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git checkout -b dev</span><br><span class="line"></span><br><span class="line">git push</span><br></pre></td></tr></table></figure><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>新博客地址：</p><ul><li><a href="https://jasonkayzk.github.io/jp/">https://jasonkayzk.github.io/jp/</a></li></ul><p>源代码：</p><ul><li><a href="https://github.com/JasonkayZK/jp">https://github.com/JasonkayZK/jp</a></li><li><a href="https://github.com/anzhiyu-c/hexo-theme-anzhiyu">https://github.com/anzhiyu-c/hexo-theme-anzhiyu</a></li></ul><br/>]]></content>
    
    
    <summary type="html">之前一直都在这里发一些学习日语相关的内容。但是感觉这些可以单独开一个新的网站来总结；最近比较有时间，就开了一个新的坑；博客主题用的是：hexo-theme-anzhiyu，真的很酷！也是花了半个小时，使用hexo，从零搭建了一个博客；之前没有好好总结，这里就又简单记录了一下搭建的过程，如果你还没有博客，可以跟着我一步一步来搭建一个GithubPages博客！</summary>
    
    
    
    <category term="日本語" scheme="https://jasonkayzk.github.io/cn/categories/%E6%97%A5%E6%9C%AC%E8%AA%9E/"/>
    
    
    <category term="日本語" scheme="https://jasonkayzk.github.io/cn/tags/%E6%97%A5%E6%9C%AC%E8%AA%9E/"/>
    
    <category term="博客管理" scheme="https://jasonkayzk.github.io/cn/tags/%E5%8D%9A%E5%AE%A2%E7%AE%A1%E7%90%86/"/>
    
  </entry>
  
  <entry>
    <title>二、性能模型与逐元素优化</title>
    <link href="https://jasonkayzk.github.io/cn/2025/07/30/%E4%BA%8C%E3%80%81%E6%80%A7%E8%83%BD%E6%A8%A1%E5%9E%8B%E4%B8%8E%E9%80%90%E5%85%83%E7%B4%A0%E4%BC%98%E5%8C%96/"/>
    <id>https://jasonkayzk.github.io/cn/2025/07/30/%E4%BA%8C%E3%80%81%E6%80%A7%E8%83%BD%E6%A8%A1%E5%9E%8B%E4%B8%8E%E9%80%90%E5%85%83%E7%B4%A0%E4%BC%98%E5%8C%96/</id>
    <published>2025-07-30T03:14:50.000Z</published>
    <updated>2026-10-25T04:05:16.278Z</updated>
    
    <content type="html"><![CDATA[<br/><span id="more"></span><h1 id="二、性能模型与逐元素优化"><a href="#二、性能模型与逐元素优化" class="headerlink" title="二、性能模型与逐元素优化"></a><strong>二、性能模型与逐元素优化</strong></h1><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><br/>]]></content>
    
    
    <summary type="html">&lt;br/&gt;</summary>
    
    
    
    <category term="CUDA" scheme="https://jasonkayzk.github.io/cn/categories/CUDA/"/>
    
    
    <category term="CUDA" scheme="https://jasonkayzk.github.io/cn/tags/CUDA/"/>
    
    <category term="GPU" scheme="https://jasonkayzk.github.io/cn/tags/GPU/"/>
    
    <category term="并行计算" scheme="https://jasonkayzk.github.io/cn/tags/%E5%B9%B6%E8%A1%8C%E8%AE%A1%E7%AE%97/"/>
    
  </entry>
  
  <entry>
    <title>一、并行编程导论与CUDA入门</title>
    <link href="https://jasonkayzk.github.io/cn/2025/07/29/%E4%B8%80%E3%80%81%E5%B9%B6%E8%A1%8C%E7%BC%96%E7%A8%8B%E5%AF%BC%E8%AE%BA%E4%B8%8ECUDA%E5%85%A5%E9%97%A8/"/>
    <id>https://jasonkayzk.github.io/cn/2025/07/29/%E4%B8%80%E3%80%81%E5%B9%B6%E8%A1%8C%E7%BC%96%E7%A8%8B%E5%AF%BC%E8%AE%BA%E4%B8%8ECUDA%E5%85%A5%E9%97%A8/</id>
    <published>2025-07-29T09:41:50.000Z</published>
    <updated>2026-10-25T04:05:16.276Z</updated>
    
    <content type="html"><![CDATA[<p>随着人工智能的发展，科学计算（尤其是矩阵/张量计算）越来越重要；因此，基于CUDA的张量编程也越来越重要。</p><p>在<a href="https://github.com/JasonkayZK/high-performance-computing-learn/blob/main/cuda/0-an-even-easier-intro-to-cuda.ipynb">上一篇笔记</a>中翻译了<a href="https://developer.nvidia.com/blog/even-easier-introduction-cuda/">《An Even Easier Introduction to CUDA》</a>，但是感觉作者写的不是很好；</p><p>这里重新写了一篇。同时，也作为CUDA和并行编程的开篇。</p><p>源代码：</p><ul><li><a href="https://github.com/JasonkayZK/high-performance-computing-learn/blob/main/cuda/1_introduction_to_parallel_programming_and_cuda.ipynb">https://github.com/JasonkayZK/high-performance-computing-learn/blob/main/cuda/1_introduction_to_parallel_programming_and_cuda.ipynb</a></li></ul><br/><span id="more"></span><h1 id="一、并行编程导论与CUDA入门"><a href="#一、并行编程导论与CUDA入门" class="headerlink" title="一、并行编程导论与CUDA入门"></a><strong>一、并行编程导论与CUDA入门</strong></h1><blockquote><p><strong>温馨提示：本文章配合 Colab 一同执行学习效果更佳：</strong></p><ul><li><a href="https://colab.research.google.com/github/JasonkayZK/high-performance-computing-learn/blob/main/cuda/1_introduction_to_parallel_programming_and_cuda.ipynb">https://colab.research.google.com/github/JasonkayZK/high-performance-computing-learn/blob/main/cuda/1_introduction_to_parallel_programming_and_cuda.ipynb</a></li></ul></blockquote><h2 id="（一）、CUDA编程概述"><a href="#（一）、CUDA编程概述" class="headerlink" title="（一）、CUDA编程概述"></a><strong>（一）、CUDA编程概述</strong></h2><h3 id="1、什么是CUDA"><a href="#1、什么是CUDA" class="headerlink" title="1、什么是CUDA"></a><strong>1、什么是CUDA</strong></h3><p>CUDA 是 NVIDIA 开发的并行计算平台和编程模型；</p><p>具有以下特点：</p><ul><li>C/C++ 语法；</li><li>SIMT（Single Instruction Multiple Threads）模式：<strong>一个指令会被多个线程同时执行！</strong></li><li>需要与CPU协作：CPU负责整理结果、处理逻辑；</li><li>自动调度：根据设定的执行参数，自动调度；</li></ul><br/><h3 id="2、CUDA-运算硬件单元"><a href="#2、CUDA-运算硬件单元" class="headerlink" title="2、CUDA 运算硬件单元"></a><strong>2、CUDA 运算硬件单元</strong></h3><h4 id="（1）SM-单元"><a href="#（1）SM-单元" class="headerlink" title="（1）SM 单元"></a><strong>（1）SM 单元</strong></h4><p>下面是一个 GPU 硬件单元：</p><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/cuda-1.png" alt="cuda-1.png"></p><p>每个核心中包含了多个 SM（Stream Multi-processor），任务在 SM 中处理；</p><p>SM 中包含了：</p><ul><li><strong>CUDA Core/SP</strong>：进行并行的加减法等计算；</li><li><strong>Tensor Core：</strong>张量计算</li><li>……</li></ul><br/><h4 id="（2）CPU与GPU协作"><a href="#（2）CPU与GPU协作" class="headerlink" title="（2）CPU与GPU协作"></a><strong>（2）CPU与GPU协作</strong></h4><p>CPU 与 GPU 协同工作的流程如下：</p><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/cuda-2.png" alt="cuda-2.png"></p><p>首先，习惯上将：</p><ul><li>CPU 所在端称为：Host 端，对应内存为 RAM；</li><li>GPU 所在称为：Device 端，对应内存为 Global Memory（通常对应 GPU RAM，显存）；</li></ul><blockquote><p>  通常，Global Memory 在其范围和生命周期中是全局的！</p><p>  <strong>也就是说，每个在<a href="https://modal.com/gpu-glossary/device-software/thread-block-grid">thread block grid</a> 中的 <a href="https://modal.com/gpu-glossary/device-software/thread">thread</a> 都可以访问Global Memory，并且生命周期与程序的执行时间一样长！</strong></p><p>  <strong>更多内容：</strong></p><ul><li><a href="https://modal.com/gpu-glossary/device-software/global-memory">https://modal.com/gpu-glossary/device-software/global-memory</a></li></ul></blockquote><p>CUDA 程序执行时主要分为以下几个步骤：</p><ul><li><strong>CPU 准备（CPU Prepare）</strong>：在主机端（Host ，包含 CPU 和 RAM 主存 ），CPU 负责初始化数据、设置计算参数等准备工作，为后续在 GPU 上的运算任务做铺垫，确定要处理的数据和运算逻辑；</li><li><strong>CPU 传输数据至 GPU（CPU Transfers Data to GPU）</strong>：通过总线（Bus），CPU 把主存（RAM）中准备好的数据传输到 GPU 端的全局内存（Global Memory ，GM），因为 GPU 运算需要的数据要先存放到其可访问的内存空间；</li><li><strong>从 GM 读数据（Read Data from GM）</strong>：GPU（如 NVIDIA A100 ）从自身的全局内存中读取需要参与运算的数据，将数据加载到运算单元可处理的位置；</li><li><strong>运算（Compute）</strong>：NVIDIA A100 等 GPU 设备利用自身的并行运算核心，对读取的数据执行 CUDA 核函数定义的运算操作，发挥 GPU 并行计算优势，高效处理大规模数据计算任务；</li><li><strong>写回 GM（Write Back to GM）</strong>：运算完成后，GPU 将运算结果写回到全局内存中，暂存运算产出的数据；</li><li><strong>GPU 传输数据至 CPU（GPU Transfers Data to CPU）</strong>：再次通过总线，GPU 把全局内存中存储的运算结果传输回主机端的主存（RAM），供 CPU 进一步处理（如数据展示、后续其他主机端逻辑运算等 ），完成一次 CUDA 编程的计算流程；</li></ul><p>CUDA 这种流程实现了 CPU 与 GPU 协同，让 GPU 承担并行计算 heavy - lifting ，提升计算密集型任务效率，广泛用于深度学习训练推理、科学计算等场景！</p><br/><h2 id="（二）、CUDA运算示例：加法"><a href="#（二）、CUDA运算示例：加法" class="headerlink" title="（二）、CUDA运算示例：加法"></a><strong>（二）、CUDA运算示例：加法</strong></h2><h3 id="1、CPU加法"><a href="#1、CPU加法" class="headerlink" title="1、CPU加法"></a><strong>1、CPU加法</strong></h3><p>add_cpu.cpp</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;cmath&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Step 2: Define add function</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">add_cpu</span><span class="params">(std::vector&lt;<span class="type">float</span>&gt; &amp;c, <span class="type">const</span> std::vector&lt;<span class="type">float</span>&gt; &amp;a, <span class="type">const</span> std::vector&lt;<span class="type">float</span>&gt; &amp;b)</span> </span>&#123;</span><br><span class="line">    <span class="comment">// CPU use loop to calculate</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i &lt; a.<span class="built_in">size</span>(); i++) &#123;</span><br><span class="line">        c[i] = a[i] + b[i];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">// Step 1: Prepare &amp; initialize data</span></span><br><span class="line">    <span class="keyword">constexpr</span> <span class="type">size_t</span> N = <span class="number">1</span> &lt;&lt; <span class="number">20</span>; <span class="comment">// ~1M elements</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// Initialize data</span></span><br><span class="line">    <span class="function"><span class="type">const</span> std::vector&lt;<span class="type">float</span>&gt; <span class="title">a</span><span class="params">(N, <span class="number">1</span>)</span></span>;</span><br><span class="line">    <span class="function"><span class="type">const</span> std::vector&lt;<span class="type">float</span>&gt; <span class="title">b</span><span class="params">(N, <span class="number">2</span>)</span></span>;</span><br><span class="line">    <span class="function">std::vector&lt;<span class="type">float</span>&gt; <span class="title">c</span><span class="params">(N, <span class="number">0</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Step 3: Call the cpu addition function</span></span><br><span class="line">    <span class="built_in">add_cpu</span>(c, a, b);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// Step 4: Check for errors (all values should be 3.0f)</span></span><br><span class="line">    <span class="type">float</span> maxError = <span class="number">0.0f</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; N; i++) &#123;</span><br><span class="line">        maxError = <span class="built_in">fmax</span>(maxError, <span class="built_in">fabs</span>(c[i] - <span class="number">3.0f</span>));</span><br><span class="line">    &#125;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;Max error: &quot;</span> &lt;&lt; maxError &lt;&lt; std::endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>主要分为以下几个步骤：</p><ul><li>准备和初始化数据；</li><li>定义加法函数<ul><li>靠<strong>循环</strong>来进行所有的元素加法</li></ul></li><li>调用函数</li><li>验证结果</li></ul><br/><h3 id="2、修改为GPU加法（重点！）"><a href="#2、修改为GPU加法（重点！）" class="headerlink" title="2、修改为GPU加法（重点！）"></a><strong>2、修改为GPU加法（重点！）</strong></h3><p>分为以下几个步骤：</p><ul><li><strong>修改文件名为 <code>*.cu</code></strong>：例如<code>add_cuda.cu</code>（表示 CUDA 程序）</li><li><strong>准备和初始化数据（CPU）</strong>：使用 vector 等进行 Host 端的 RAM 分配；</li><li><strong>数据传输到 GPU</strong>：使用 <code>cudaMalloc</code> 分配显存、使用 <code>cudaMemcpy</code> 复制数据等；</li><li><strong>GPU 从 GM 中读取并计算后写回（调用核（kernel）函数计算）</strong>：<ul><li>修改核函数声明：</li><li>修改调用方式：</li></ul></li><li><strong>将 GPU 数据传输回 CPU</strong>：</li><li>验证结果</li></ul><p>下面分别来看；</p><br/><h4 id="（1）修改文件名为-cu"><a href="#（1）修改文件名为-cu" class="headerlink" title="（1）修改文件名为 *.cu"></a>（1）修改文件名为 <code>*.cu</code></h4><p>CUDA 规定其文件扩展名为 <code>*.cu</code>，语法和 C++ 类似！</p><br/><h4 id="（2）准备和初始化数据（CPU）"><a href="#（2）准备和初始化数据（CPU）" class="headerlink" title="（2）准备和初始化数据（CPU）"></a><strong>（2）准备和初始化数据（CPU）</strong></h4><p>这步比较简单：</p><p>add_cuda.cu</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Step 1: Prepare &amp; initialize data</span></span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">size_t</span> N = <span class="number">1</span> &lt;&lt; <span class="number">20</span>; <span class="comment">// ~1M elements</span></span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">size_t</span> size_bytes = <span class="keyword">sizeof</span>(<span class="type">float</span>) * N;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Initialize data</span></span><br><span class="line"><span class="function"><span class="type">const</span> std::vector&lt;<span class="type">float</span>&gt; <span class="title">h_a</span><span class="params">(N, <span class="number">1</span>)</span></span>;</span><br><span class="line"><span class="function"><span class="type">const</span> std::vector&lt;<span class="type">float</span>&gt; <span class="title">h_b</span><span class="params">(N, <span class="number">2</span>)</span></span>;</span><br><span class="line"><span class="function">std::vector&lt;<span class="type">float</span>&gt; <span class="title">h_c</span><span class="params">(N, <span class="number">0</span>)</span></span>;</span><br></pre></td></tr></table></figure><p>此时在 Host 端的 RAM 分配内存；</p><br/><h4 id="（3）数据传输到-GPU"><a href="#（3）数据传输到-GPU" class="headerlink" title="（3）数据传输到 GPU"></a><strong>（3）数据传输到 GPU</strong></h4><p>数据传输到 GPU 使用 CUDA 提供的函数：</p><ul><li>使用 <code>cudaMalloc</code> 分配显存；</li><li>使用 <code>cudaMemcpy</code> 复制数据；</li></ul><p>add_cuda.cu</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">float</span> *d_a, *d_b, *d_c;</span><br><span class="line"><span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMalloc</span>(&amp;d_a, size_bytes));</span><br><span class="line"><span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMalloc</span>(&amp;d_b, size_bytes));</span><br><span class="line"><span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMalloc</span>(&amp;d_c, size_bytes));</span><br><span class="line"></span><br><span class="line"><span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMemcpy</span>(d_a, h_a.<span class="built_in">data</span>(), size_bytes, cudaMemcpyHostToDevice));</span><br><span class="line"><span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMemcpy</span>(d_b, h_b.<span class="built_in">data</span>(), size_bytes, cudaMemcpyHostToDevice));</span><br><span class="line"><span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMemcpy</span>(d_c, h_c.<span class="built_in">data</span>(), size_bytes, cudaMemcpyHostToDevice));</span><br></pre></td></tr></table></figure><p>这里使用了：</p><ul><li><code>CUDA_CHECK</code> 宏进行校验；</li><li><code>cudaMemcpyHostToDevice</code> 指定数据流方向；</li></ul><p>CUDA_CHECK 宏定义如下：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> CUDA_CHECK(call) \</span></span><br><span class="line"><span class="meta">&#123; \</span></span><br><span class="line"><span class="meta">    cudaError_t err = call; \</span></span><br><span class="line"><span class="meta">    <span class="keyword">if</span> (err != cudaSuccess) &#123; \</span></span><br><span class="line"><span class="meta">        std::cerr &lt;&lt; <span class="string">&quot;CUDA Error at &quot;</span> &lt;&lt; __FILE__ &lt;&lt; <span class="string">&quot;:&quot;</span> &lt;&lt; __LINE__ \</span></span><br><span class="line"><span class="meta">        &lt;&lt; <span class="string">&quot; - &quot;</span> &lt;&lt; cudaGetErrorString(err) &lt;&lt; std::endl; \</span></span><br><span class="line"><span class="meta">    &#125; \</span></span><br><span class="line"><span class="meta">&#125;</span></span><br></pre></td></tr></table></figure><br/><h4 id="（4：补）CUDA层级结构"><a href="#（4：补）CUDA层级结构" class="headerlink" title="（4：补）CUDA层级结构"></a><strong>（4：补）CUDA层级结构</strong></h4><h5 id="i-线程层级结构"><a href="#i-线程层级结构" class="headerlink" title="i.线程层级结构"></a><strong>i.线程层级结构</strong></h5><p>在 CPU 中，使用<strong>循环</strong>进行执行；</p><p><strong>而在 GPU 中，使用的是 <code>SIMT</code>，即：<code>一条命令会同时被多个线程执行！</code></strong></p><p><strong>此时需要指挥每个线程：组织结构和编号！</strong></p><p>在 CUDA 中，包含：</p><ul><li>Grid：</li><li>Block：</li><li>Thread：</li></ul><p>如下图：</p><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/cuda-3.png" alt="cuda-3.png"></p><p>其中：<strong>每一个 Grid 中包含多个已编号的 Block，而每一个 Block 中包含多个已编号的 Thread！</strong></p><p>同时，<strong>每个 Block 中包含的线程数是一样的！</strong></p><p><strong>一共有：<code>0~N-1</code>个Thread（假设每个 Block 包含 N 个 Thread）；</strong></p><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/cuda-4.png" alt="cuda-4.png"></p><br/><h5 id="ii-线程索引计算方法"><a href="#ii-线程索引计算方法" class="headerlink" title="ii.线程索引计算方法"></a><strong>ii.线程索引计算方法</strong></h5><p>在 CUDA 中：</p><ul><li>每个线程都有 <strong>独一无二</strong> 的编号索引(idx)；</li><li><code>idx = BlockID * BlockSize + ThreadID</code>；</li></ul><p>如下图：</p><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/cuda-5.png" alt="cuda-5.png"></p><br/><h4 id="（4）编写和调用核函数"><a href="#（4）编写和调用核函数" class="headerlink" title="（4）编写和调用核函数"></a><strong>（4）编写和调用核函数</strong></h4><p>相对于 CPU 中使用循环的方式执行，<strong>在 GPU 中主要使用的是：<code>多线程并行</code>；</strong></p><p>步骤如下：</p><ul><li>定义 block 的数量和大小来指挥线程、进行/并行计算；</li><li>定义 GPU 上的加法函数（核函数）；</li><li>结合定义的信息调用 GPU 加法函数；</li></ul><p>层级结构定义：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Set up kernel configuration</span></span><br><span class="line"><span class="function">dim3 <span class="title">block_dim</span><span class="params">(<span class="number">256</span>)</span></span>;</span><br><span class="line"><span class="function">dim3 <span class="title">grid_dim</span><span class="params">((N + block_dim.x - <span class="number">1</span>) / block_dim.x)</span></span>;</span><br></pre></td></tr></table></figure><p>核函数定义：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span></span><br><span class="line"><span class="function">__global__ <span class="type">void</span> <span class="title">add_kernel</span><span class="params">(T *c, <span class="type">const</span> T *a, <span class="type">const</span> T *b, <span class="type">int</span> n)</span> </span>&#123;</span><br><span class="line">    <span class="type">int</span> idx = blockIdx.x * blockDim.x + threadIdx.x;</span><br><span class="line">    <span class="keyword">if</span> (idx &lt; n) &#123;</span><br><span class="line">        c[idx] = a[idx] + b[idx];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>  <strong>只能通过指针的方式传递！</strong></p><p>  <font color="#f00"><strong>因为像是 vector 等数据结构，都是在 Host 端定义的，并不能在 Global Memory 中分配！</strong></font></p></blockquote><p>核函数调用：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Call cuda add kernel</span></span><br><span class="line">add_kernel&lt;&lt;&lt;grid_dim, block_dim&gt;&gt;&gt;(d_c, d_a, d_b, N);</span><br></pre></td></tr></table></figure><p>其中：</p><ul><li><code>dim3</code>：CUDA 表示线程层级结构的类型（包括：x、y、z 三个维度）；</li><li><code>&lt;&lt;&lt;&gt;&gt;&gt;</code>：传递线程层级信息给核函数；</li><li><code>核函数(kernel)</code>：设备侧的入口函数；</li><li><code>__global__</code>：表示这是个核函数；</li><li><code>blockldx</code>：表示 block 的编号，第几个 block；</li><li><code>blockDim</code>：表示 block 的大小，一个 block 多少个线程；</li><li><code>threadldx</code>：表示 thread 的编号，表示第几个 thread；</li></ul><br/><h4 id="（5）将-GPU-数据传输回-CPU"><a href="#（5）将-GPU-数据传输回-CPU" class="headerlink" title="（5）将 GPU 数据传输回 CPU"></a><strong>（5）将 GPU 数据传输回 CPU</strong></h4><p>同样，使用 <code>cudaMemcpy</code>：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMemcpy</span>(h_c.<span class="built_in">data</span>(), d_c, size_bytes, cudaMemcpyDeviceToHost));</span><br></pre></td></tr></table></figure><br/><h4 id="（6）验证结果，释放内存"><a href="#（6）验证结果，释放内存" class="headerlink" title="（6）验证结果，释放内存"></a><strong>（6）验证结果，释放内存</strong></h4><p>验证结果使用已经复制到 <code>h_c</code> 中的数据；</p><p>释放内存使用 <code>cudaFree</code>：</p><p>add_cuda.cu</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">float</span> maxError = <span class="number">0.0f</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; N; i++) &#123;</span><br><span class="line">    maxError = <span class="built_in">fmax</span>(maxError, <span class="built_in">fabs</span>(h_c[i] - <span class="number">3.0f</span>));</span><br><span class="line">&#125;</span><br><span class="line">std::cout &lt;&lt; <span class="string">&quot;Max error: &quot;</span> &lt;&lt; maxError &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (d_a) &#123;</span><br><span class="line">    <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaFree</span>(d_a));</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (d_b) &#123;</span><br><span class="line">    <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaFree</span>(d_b));</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (d_c) &#123;</span><br><span class="line">    <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaFree</span>(d_c));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br/><h3 id="3、编译-amp-运行CUDA程序"><a href="#3、编译-amp-运行CUDA程序" class="headerlink" title="3、编译&amp;运行CUDA程序"></a><strong>3、编译&amp;运行CUDA程序</strong></h3><p>需要使用 <code>NVCC（NIVIDEA CUDA Compiler）</code> 的编译器来编译程序；</p><blockquote><p>  NVCC 是 CUDA Toolkit 的一部分：</p><ul><li><a href="https://developer.nvidia.com/cuda-toolkit">https://developer.nvidia.com/cuda-toolkit</a></li></ul></blockquote><br/><h4 id="（1）编译流程"><a href="#（1）编译流程" class="headerlink" title="（1）编译流程"></a><strong>（1）编译流程</strong></h4><p>如下图所示：</p><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/cuda-6.png" alt="cuda-6.png"></p><p>流程如下：</p><ol><li><strong>每个 cu</strong>：Host 代码与 Device 代码分离（部分在CPU执行、部分在GPU执行）</li><li><strong>每个虚拟架构：</strong>Device 代码编译出 fatbin</li><li>Host 端使用系统的 C++ 编译器(如 g++)</li><li>链接（device，host）</li><li>最终获得可使用 GPU 的可执行二进制文件</li></ol><br/><h5 id="补：GPU虚拟架构"><a href="#补：GPU虚拟架构" class="headerlink" title="补：GPU虚拟架构"></a><strong>补：GPU虚拟架构</strong></h5><p>NVIDIA 不同年代生产的GPU可能有不同的架构，如下图所示：</p><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/cuda-7.png" alt="cuda-7.png"></p><p>以 A100 为例，A100 为 Ampere 架构；同时，各个架构间有区别；</p><p>因此提出：Compute Capability (CC)</p><ul><li>类似版本，表示能支持的功能和指令集合</li><li>A100 (Ampere 架构)是：cc8.0</li></ul><blockquote><p>  <strong>虽然 A100 举例，但从 CUDA 编程的角度目前各种架构没有本质区别！</strong></p><p>  <font color="#f00"><strong>正因为如此，所以说CUDA是一个编程平台</strong></font></p></blockquote><p>同时，在编译时也可以指定架构编译选项：</p><ul><li><code>-arch</code>：指定虚拟架构，PTX生成目标。决定代码中可使用的CUDA 功能；</li><li><code>-code</code>：指定实际架构，生成针对特定 GPU 硬件的二进制机器码(cubin)；</li></ul><br/><h4 id="（2）编译命令"><a href="#（2）编译命令" class="headerlink" title="（2）编译命令"></a><strong>（2）编译命令</strong></h4><p>通过：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nvcc add_cuda.cu -o add_cuda</span><br></pre></td></tr></table></figure><p>即可编译！</p><p>运行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./add_cuda</span><br></pre></td></tr></table></figure><br/><h2 id="（三）、GPU性能测试"><a href="#（三）、GPU性能测试" class="headerlink" title="（三）、GPU性能测试"></a>（三）、GPU性能测试</h2><p>可以通过：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nvidia-smi</span><br></pre></td></tr></table></figure><p>观察 GPU 利用率！</p><h3 id="1、并行加法性能对比"><a href="#1、并行加法性能对比" class="headerlink" title="1、并行加法性能对比"></a><strong>1、并行加法性能对比</strong></h3><p>分别对比：</p><ul><li>CPU；</li><li><code>&lt;&lt;&lt;1,1&gt;&gt;&gt;</code>；</li><li><code>&lt;&lt;&lt;256，256&gt;&gt;&gt;</code>；</li><li>GPU 满载；</li></ul><p>代码如下：</p><p>add_cuda_profiling.cu</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;cmath&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> CUDA_CHECK(call) \</span></span><br><span class="line"><span class="meta">&#123; \</span></span><br><span class="line"><span class="meta">    cudaError_t err = call; \</span></span><br><span class="line"><span class="meta">    <span class="keyword">if</span> (err != cudaSuccess) &#123; \</span></span><br><span class="line"><span class="meta">        std::cerr &lt;&lt; <span class="string">&quot;CUDA Error at &quot;</span> &lt;&lt; __FILE__ &lt;&lt; <span class="string">&quot;:&quot;</span> &lt;&lt; __LINE__ \</span></span><br><span class="line"><span class="meta">        &lt;&lt; <span class="string">&quot; - &quot;</span> &lt;&lt; cudaGetErrorString(err) &lt;&lt; std::endl; \</span></span><br><span class="line"><span class="meta">    &#125; \</span></span><br><span class="line"><span class="meta">&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Step 3: Define add kernel</span></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span></span><br><span class="line"><span class="function">__global__ <span class="type">void</span> <span class="title">add_kernel</span><span class="params">(T *c, <span class="type">const</span> T *a, <span class="type">const</span> T *b, <span class="type">const</span> <span class="type">size_t</span> n, <span class="type">const</span> <span class="type">size_t</span> step)</span> </span>&#123;</span><br><span class="line">    <span class="type">int</span> idx = blockIdx.x * blockDim.x + threadIdx.x + step;</span><br><span class="line">    <span class="keyword">if</span> (idx &lt; n) &#123;</span><br><span class="line">        c[idx] = a[idx] + b[idx];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">vector_add</span><span class="params">(T *c, <span class="type">const</span> T *a, <span class="type">const</span> T *b, <span class="type">size_t</span> n, <span class="type">const</span> dim3&amp; grid_dim, <span class="type">const</span> dim3&amp; block_dim)</span> </span>&#123;</span><br><span class="line">    <span class="type">size_t</span> step = grid_dim.x * block_dim.x;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i &lt; n; i += step) &#123;</span><br><span class="line">        add_kernel&lt;&lt;&lt;grid_dim, block_dim&gt;&gt;&gt;(c, a, b, n, i);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">// Step 1: Prepare &amp; initialize data</span></span><br><span class="line">    <span class="keyword">constexpr</span> <span class="type">size_t</span> N = <span class="number">1</span> &lt;&lt; <span class="number">20</span>; <span class="comment">// ~1M elements</span></span><br><span class="line">    <span class="keyword">constexpr</span> <span class="type">size_t</span> size_bytes = <span class="keyword">sizeof</span>(<span class="type">float</span>) * N;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Initialize data</span></span><br><span class="line">    <span class="function"><span class="type">const</span> std::vector&lt;<span class="type">float</span>&gt; <span class="title">h_a</span><span class="params">(N, <span class="number">1</span>)</span></span>;</span><br><span class="line">    <span class="function"><span class="type">const</span> std::vector&lt;<span class="type">float</span>&gt; <span class="title">h_b</span><span class="params">(N, <span class="number">2</span>)</span></span>;</span><br><span class="line">    <span class="function">std::vector&lt;<span class="type">float</span>&gt; <span class="title">h_c</span><span class="params">(N, <span class="number">0</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Step 2: Allocate device memory &amp; transfer to global memory</span></span><br><span class="line">    <span class="type">float</span> *d_a, *d_b, *d_c;</span><br><span class="line">    <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMalloc</span>(&amp;d_a, size_bytes));</span><br><span class="line">    <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMalloc</span>(&amp;d_b, size_bytes));</span><br><span class="line">    <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMalloc</span>(&amp;d_c, size_bytes));</span><br><span class="line"></span><br><span class="line">    <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMemcpy</span>(d_a, h_a.<span class="built_in">data</span>(), size_bytes, cudaMemcpyHostToDevice));</span><br><span class="line">    <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMemcpy</span>(d_b, h_b.<span class="built_in">data</span>(), size_bytes, cudaMemcpyHostToDevice));</span><br><span class="line">    <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMemcpy</span>(d_c, h_c.<span class="built_in">data</span>(), size_bytes, cudaMemcpyHostToDevice));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Step 4: Call the cpu addition function</span></span><br><span class="line">    <span class="comment">// Set up kernel configuration</span></span><br><span class="line">    <span class="function">dim3 <span class="title">block_dim</span><span class="params">(<span class="number">1</span>)</span></span>;</span><br><span class="line">    <span class="function">dim3 <span class="title">grid_dim</span><span class="params">(<span class="number">1</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Call cuda add kernel</span></span><br><span class="line">    <span class="built_in">vector_add</span>(d_c, d_a, d_b, N, block_dim, grid_dim);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Step 5: Transfer data from global mem to host mem</span></span><br><span class="line">    <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaMemcpy</span>(h_c.<span class="built_in">data</span>(), d_c, size_bytes, cudaMemcpyDeviceToHost));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Step 6: Check for errors (all values should be 3.0f)</span></span><br><span class="line">    <span class="type">float</span> sumError = <span class="number">0.0f</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; N; i++) &#123;</span><br><span class="line">        sumError += <span class="built_in">fabs</span>(h_c[i] - <span class="number">3.0f</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;Sum error: &quot;</span> &lt;&lt; sumError &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (d_a) &#123;</span><br><span class="line">        <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaFree</span>(d_a));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (d_b) &#123;</span><br><span class="line">        <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaFree</span>(d_b));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (d_c) &#123;</span><br><span class="line">        <span class="built_in">CUDA_CHECK</span>(<span class="built_in">cudaFree</span>(d_c));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>  可以修改其中的：</p>  <figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">dim3 <span class="title">block_dim</span><span class="params">(<span class="number">1</span>)</span></span>;</span><br><span class="line"><span class="function">dim3 <span class="title">grid_dim</span><span class="params">(<span class="number">1</span>)</span></span>;</span><br></pre></td></tr></table></figure></blockquote><p>不同情况下的性能如下：</p><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/cuda-8.png" alt="cuda-8.png"></p><p>可以使用 Nsight Systems（nsys，NVIDIA系统级性能分析工具）来分析；</p><p>启动 profiling：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nsys profile -t cuda,nvtx,osrt -o add_cuda_profiling -f <span class="literal">true</span> ./add_cuda_profiling</span><br></pre></td></tr></table></figure><p>解析并统计性能信息：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">nsys stats add_cuda_profiling.nsys-rep</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> ** OS Runtime Summary (osrt_sum):</span><br><span class="line"></span><br><span class="line"> Time (%)  Total Time (ns)  Num Calls    Avg (ns)       Med (ns)      Min (ns)    Max (ns)     StdDev (ns)            Name         </span><br><span class="line"> --------  ---------------  ---------  -------------  -------------  ----------  -----------  -------------  ----------------------</span><br><span class="line">     56.2    7,592,724,284         84   90,389,574.8  100,130,776.0       2,330  370,626,986   45,049,255.4  poll                  </span><br><span class="line">     42.4    5,736,493,727         26  220,634,374.1  189,702,756.5  41,077,614  752,975,386  124,762,585.8  sem_wait              </span><br><span class="line">      1.2      164,252,099        543      302,490.1       13,509.0         529  111,402,991    4,818,716.4  ioctl                 </span><br><span class="line">      0.1       14,968,499         38      393,907.9      131,267.0         135    5,539,804      890,642.6  pthread_rwlock_wrlock                 </span><br><span class="line">......</span><br><span class="line"></span><br><span class="line"> ** CUDA API Summary (cuda_api_sum):</span><br><span class="line"></span><br><span class="line"> Time (%)  Total Time (ns)  Num Calls    Avg (ns)     Med (ns)    Min (ns)   Max (ns)     StdDev (ns)            Name         </span><br><span class="line"> --------  ---------------  ---------  ------------  -----------  --------  -----------  -------------  ----------------------</span><br><span class="line">     96.9    6,504,565,162  1,048,576       6,203.2      5,159.0     2,928   37,814,020       99,097.6  cudaLaunchKernel      </span><br><span class="line">      3.0      203,141,797          3  67,713,932.3    103,908.0    73,162  202,964,727  117,130,625.1  cudaMalloc            </span><br><span class="line">      0.1        4,017,591          4   1,004,397.8  1,012,632.0   941,545    1,050,782       45,652.8  cudaMemcpy            </span><br><span class="line">      0.0          524,788          3     174,929.3    136,182.0   122,785      265,821       78,999.0  cudaFree              </span><br><span class="line">      0.0            2,584          1       2,584.0      2,584.0     2,584        2,584            0.0  cuModuleGetLoadingMode</span><br><span class="line"></span><br><span class="line">......</span><br></pre></td></tr></table></figure><p>各个类型 API Summary 分析结果如下：</p><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/cuda-9.png" alt="cuda-9.png"></p><p>可以看到：<code>&lt;&lt;&lt;1,1&gt;&gt;&gt;</code> cudaLaunchKernel 占比非常高这是由于：</p><p><strong>核函数调用有开销，在外面多次循环调用开销巨大！</strong></p><p>因此，需要进行优化！</p><br/><h3 id="2、将循环放入核函数（Grid-strided-loop）"><a href="#2、将循环放入核函数（Grid-strided-loop）" class="headerlink" title="2、将循环放入核函数（Grid-strided loop）"></a><strong>2、将循环放入核函数（Grid-strided loop）</strong></h3><p>由于在循环中频繁的调用核函数具有巨大的性能开销，因此可以将循环放入核函数中：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span></span><br><span class="line"><span class="function">__global__ <span class="type">void</span> <span class="title">add_kernel_inner_loop</span><span class="params">(T *c, <span class="type">const</span> T *a, <span class="type">const</span> T *b, <span class="type">const</span> <span class="type">size_t</span> n, <span class="type">const</span> <span class="type">size_t</span> step)</span> </span>&#123;</span><br><span class="line">    <span class="type">int</span> idx = blockIdx.x * blockDim.x + threadIdx.x;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">size_t</span> i = idx; i &lt; n; i += step) &#123;</span><br><span class="line">        <span class="keyword">if</span> (i &lt; n) &#123;</span><br><span class="line">            c[i] = a[i] + b[i];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">vector_add</span><span class="params">(T *c, <span class="type">const</span> T *a, <span class="type">const</span> T *b, <span class="type">size_t</span> n, <span class="type">const</span> dim3&amp; grid_dim, <span class="type">const</span> dim3&amp; block_dim)</span> </span>&#123;</span><br><span class="line">    <span class="type">size_t</span> step = grid_dim.x * block_dim.x;</span><br><span class="line">    add_kernel_inner_loop&lt;&lt;&lt;grid_dim, block_dim&gt;&gt;&gt;(c, a, b, n, step);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>分析后结果如下图：</p><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/cuda-10.png" alt="cuda-10.png"></p><p>同时使用 nsys 分析：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">** CUDA API Summary (cuda_api_sum):</span><br><span class="line"></span><br><span class="line">Time (%)  Total Time (ns)  Num Calls    Avg (ns)     Med (ns)    Min (ns)   Max (ns)     StdDev (ns)            Name         </span><br><span class="line">--------  ---------------  ---------  ------------  -----------  --------  -----------  -------------  ----------------------</span><br><span class="line">    55.4      204,935,456          3  68,311,818.7    104,741.0    79,097  204,751,618  118,160,333.0  cudaMalloc            </span><br><span class="line">    44.4      164,057,041          4  41,014,260.3  1,000,521.5   926,775  161,129,223   80,076,651.2  cudaMemcpy            </span><br><span class="line">     0.2          653,441          3     217,813.7    204,732.0   194,409      254,300       32,016.9  cudaFree              </span><br><span class="line">     0.1          264,055          1     264,055.0    264,055.0   264,055      264,055            0.0  cudaLaunchKernel      </span><br><span class="line">     0.0            2,429          1       2,429.0      2,429.0     2,429        2,429            0.0  cuModuleGetLoadingMode</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>可以看到 cudaLaunchKernel 的确少了很多！ </p><blockquote><p>  这说明：</p><p>  <font color="#f00"><strong>核函数的发射数量减少，因此总体执行时间降低！</strong></font></p></blockquote><br/><h3 id="3、CUDA并行加法性能评估（加速比）"><a href="#3、CUDA并行加法性能评估（加速比）" class="headerlink" title="3、CUDA并行加法性能评估（加速比）"></a><strong>3、CUDA并行加法性能评估（加速比）</strong></h3><p>指标：</p><p>加速比 = T<sub>cpu</sub> / T<sub>gpu</sub></p><p>其中：</p><ul><li><strong>T_cpu</strong> 是任务在 CPU 上的执行时间；</li><li><strong>T_gpu</strong> 是任务在 GPU 上的执行时间；</li></ul><blockquote><p>  <strong>理想加速比与实际加速比</strong></p><ol><li><strong>理想加速比</strong>：当任务完全并行化且没有任何开销时，加速比等于处理器核心数之比。例如，一个具有 1000 个 CUDA 核心的 GPU 理论上可以实现 1000 倍的加速（相对于单核 CPU）。</li><li><strong>实际加速比</strong>：由于以下因素，实际加速比通常远低于理想值：<ul><li>任务中存在无法并行化的串行部分</li><li>数据在 CPU 和 GPU 之间的传输开销</li><li>线程同步和内存访问延迟</li><li>算法在 GPU 架构上的效率低下</li></ul></li></ol></blockquote><h4 id="为什么-lt-lt-lt-1-1-gt-gt-gt-比-CPU慢？"><a href="#为什么-lt-lt-lt-1-1-gt-gt-gt-比-CPU慢？" class="headerlink" title="为什么&lt;&lt;&lt;1,1&gt;&gt;&gt; 比 CPU慢？"></a><strong>为什么<code>&lt;&lt;&lt;1,1&gt;&gt;&gt;</code> 比 CPU慢？</strong></h4><p>这是由于，单个 GPU 的核心实际上要比 CPU 的能力要弱！</p><p>实际上，GPU 是由于干活的人多，所以快！</p><br/><h3 id="4、CUDA并行加法性能评估（总耗时）"><a href="#4、CUDA并行加法性能评估（总耗时）" class="headerlink" title="4、CUDA并行加法性能评估（总耗时）"></a><strong>4、CUDA并行加法性能评估（总耗时）</strong></h3><p>实际上观察 nsys 的输出结果：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"> ** CUDA GPU Kernel Summary (cuda_gpu_kern_sum):</span><br><span class="line"></span><br><span class="line"> Time (%)  Total Time (ns)  Instances    Avg (ns)       Med (ns)      Min (ns)     Max (ns)    StdDev (ns)                                              Name                                             </span><br><span class="line"> --------  ---------------  ---------  -------------  -------------  -----------  -----------  -----------  ---------------------------------------------------------------------------------------------</span><br><span class="line">    100.0      160,054,287          1  160,054,287.0  160,054,287.0  160,054,287  160,054,287          0.0  void add_kernel_inner_loop&lt;<span class="built_in">float</span>&gt;(T1 *, const T1 *, const T1 *, unsigned long, unsigned long)</span><br><span class="line"></span><br><span class="line">Processing [add_cuda_profiling2.sqlite] with [/usr/local/cuda-12.1/nsight-systems-2023.1.2/host-linux-x64/reports/cuda_gpu_mem_time_sum.py]... </span><br><span class="line"></span><br><span class="line"> ** CUDA GPU MemOps Summary (by Time) (cuda_gpu_mem_time_sum):</span><br><span class="line"></span><br><span class="line"> Time (%)  Total Time (ns)  Count  Avg (ns)   Med (ns)   Min (ns)  Max (ns)  StdDev (ns)      Operation     </span><br><span class="line"> --------  ---------------  -----  ---------  ---------  --------  --------  -----------  ------------------</span><br><span class="line">     78.4        2,318,310      3  772,770.0  763,159.0   761,400   793,751     18,191.4  [CUDA memcpy HtoD]</span><br><span class="line">     21.6          640,473      1  640,473.0  640,473.0   640,473   640,473          0.0  [CUDA memcpy DtoH]</span><br></pre></td></tr></table></figure><p>总体的耗时应当是三个部分：</p><ul><li><strong>总耗时 = T<sub>H2D</sub> + T<sub>kernel</sub> + T<sub>D2H</sub></strong></li></ul><p>并且，对于 <code>&lt;&lt;&lt;256,256&gt;&gt;&gt;</code> 来说：<strong>HtoD 和 DtoH 的耗时会远大于 kernel 的运行时间！</strong></p><blockquote><p>  <strong>这就说明，来回的移动和复制数据比计算更消耗时间！</strong></p></blockquote><p>能否对这一部分进行优化呢？</p><p>后面的文章中会讲解！</p><br/><h2 id="（四）、设备信息"><a href="#（四）、设备信息" class="headerlink" title="（四）、设备信息"></a><strong>（四）、设备信息</strong></h2><p>对于 GPU 而言：<strong>越多的线程 =&gt; 越大的并行度 =&gt; 越好的性能</strong></p><p>GPU 最大可以启动的线程数可以参考：</p><ul><li>官网查询硬件：<a href="https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#features-and-technical-specifications">https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#features-and-technical-specifications</a></li><li>代码动态获取（cudaDeivceProp）：<a href="https://docs.nvidia.com/cuda/cuda-runtime-api/index.html">https://docs.nvidia.com/cuda/cuda-runtime-api/index.html</a></li></ul><blockquote><p>  也可以参考：</p><ul><li><a href="https://www.nvidia.cn/docs/IO/51635/NVIDIA_CUDA_Programming_Guide_1.1_chs.pdf">https://www.nvidia.cn/docs/IO/51635/NVIDIA_CUDA_Programming_Guide_1.1_chs.pdf</a></li></ul></blockquote><br/><h3 id="1、cudaDeivceProp"><a href="#1、cudaDeivceProp" class="headerlink" title="1、cudaDeivceProp"></a><strong>1、cudaDeivceProp</strong></h3><p>重点的几个参数：</p><ul><li><strong>maxGridSize（int[3]）</strong>：x、y、z三个方向分别最多可支持的 block 数；</li><li><strong>maxBlockSize（int[3]）</strong>：每个 Block中x、y、z三个方向分别最多可支持的线程数；</li><li><strong>maxThreadsPerBlock（int）</strong>：每个 block 中最多可有的线程数</li></ul><blockquote><p>  <strong>其中：Blocksize 需同时满足这两组条件：maxBlockSize、maxThreadsPerBlock：</strong></p><ul><li>x、y、z加起来不超过：maxThreadsPerBlock；</li><li>x、y、z各个方向不超过：maxBlockSize；</li></ul></blockquote><br/><h3 id="2、CUDA版本"><a href="#2、CUDA版本" class="headerlink" title="2、CUDA版本"></a><strong>2、CUDA版本</strong></h3><p>查看 CUDA 版本使用：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># CUDA版本</span></span><br><span class="line">nvcc --version</span><br><span class="line"></span><br><span class="line">nvcc: NVIDIA (R) Cuda compiler driver</span><br><span class="line">Copyright (c) 2005-2023 NVIDIA Corporation</span><br><span class="line">Built on Tue_Feb__7_19:32:13_PST_2023</span><br><span class="line">Cuda compilation tools, release 12.1, V12.1.66</span><br><span class="line">Build cuda_12.1.r12.1/compiler.32415258_0</span><br></pre></td></tr></table></figure><blockquote><p>  可以看到 CUDA 为 12.1！</p></blockquote><p>而 <code>nvidia-smi</code> 命令输出的是：<strong>驱动支持的的最高版本，而非实际正在使用的版本！</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">Tue Jul 29 09:30:09 2025       </span><br><span class="line">+-----------------------------------------------------------------------------------------+</span><br><span class="line">| NVIDIA-SMI 550.54.15              Driver Version: 550.54.15      CUDA Version: 12.4     |</span><br><span class="line">|-----------------------------------------+------------------------+----------------------+</span><br><span class="line">| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |</span><br><span class="line">| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |</span><br><span class="line">|                                         |                        |               MIG M. |</span><br><span class="line">|=========================================+========================+======================|</span><br><span class="line">|   0  Tesla T4                       Off |   00000000:00:04.0 Off |                    0 |</span><br><span class="line">| N/A   38C    P8             10W /   70W |       0MiB /  15360MiB |      0%      Default |</span><br><span class="line">|                                         |                        |                  N/A |</span><br><span class="line">+-----------------------------------------+------------------------+----------------------+</span><br><span class="line">                                                                                         </span><br><span class="line">+-----------------------------------------------------------------------------------------+</span><br><span class="line">| Processes:                                                                              |</span><br><span class="line">|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |</span><br><span class="line">|        ID   ID                                                               Usage      |</span><br><span class="line">|=========================================================================================|</span><br><span class="line">|  No running processes found                                                             |</span><br><span class="line">+-----------------------------------------------------------------------------------------+</span><br></pre></td></tr></table></figure><blockquote><p>  <strong>可以看到，最高支持 12.4！</strong></p></blockquote><br/><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a><strong>后记</strong></h2><p>更加详细的内容，可以看：</p><ul><li><a href="https://qiankunli.github.io/2025/03/22/cuda.html">https://qiankunli.github.io/2025/03/22/cuda.html</a></li></ul><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>源代码：</p><ul><li><a href="https://github.com/JasonkayZK/high-performance-computing-learn/blob/main/cuda/1_introduction_to_parallel_programming_and_cuda.ipynb">https://github.com/JasonkayZK/high-performance-computing-learn/blob/main/cuda/1_introduction_to_parallel_programming_and_cuda.ipynb</a></li></ul><p>参考文章：</p><ul><li><a href="https://beta.infinitensor.com/camp/summer2025/stage/1/course/cuda-programming">https://beta.infinitensor.com/camp/summer2025/stage/1/course/cuda-programming</a></li><li><a href="https://qiankunli.github.io/2025/03/22/cuda.html#simd%E5%92%8Csimt">https://qiankunli.github.io/2025/03/22/cuda.html#simd%E5%92%8Csimt</a></li><li><a href="https://www.nvidia.cn/docs/IO/51635/NVIDIA_CUDA_Programming_Guide_1.1_chs.pdf">https://www.nvidia.cn/docs/IO/51635/NVIDIA_CUDA_Programming_Guide_1.1_chs.pdf</a></li></ul><br/>]]></content>
    
    
    <summary type="html">随着人工智能的发展，科学计算（尤其是矩阵/张量计算）越来越重要；因此，基于CUDA的张量编程也越来越重要。在上一篇文章中翻译了《An Even Easier Introduction to CUDA》，但是感觉作者写的不是很好；这里重新写了一篇。同时，也作为CUDA和并行编程的开篇。</summary>
    
    
    
    <category term="CUDA" scheme="https://jasonkayzk.github.io/cn/categories/CUDA/"/>
    
    
    <category term="CUDA" scheme="https://jasonkayzk.github.io/cn/tags/CUDA/"/>
    
    <category term="GPU" scheme="https://jasonkayzk.github.io/cn/tags/GPU/"/>
    
    <category term="并行计算" scheme="https://jasonkayzk.github.io/cn/tags/%E5%B9%B6%E8%A1%8C%E8%AE%A1%E7%AE%97/"/>
    
  </entry>
  
  <entry>
    <title>一些免费的GPU资源</title>
    <link href="https://jasonkayzk.github.io/cn/2025/07/24/%E4%B8%80%E4%BA%9B%E5%85%8D%E8%B4%B9%E7%9A%84GPU%E8%B5%84%E6%BA%90/"/>
    <id>https://jasonkayzk.github.io/cn/2025/07/24/%E4%B8%80%E4%BA%9B%E5%85%8D%E8%B4%B9%E7%9A%84GPU%E8%B5%84%E6%BA%90/</id>
    <published>2025-07-24T07:37:04.000Z</published>
    <updated>2026-10-25T04:05:16.277Z</updated>
    
    <content type="html"><![CDATA[<p>在学习AI时，经常需要用到GPU资源；而有些时候我们手头并没有老黄的显卡，或者显卡已经不支持进行人工智能的学习了；</p><p>本文总结了一些常用的GPU资源；</p><p>同时，后续也会在博客更新一些和并行计算、人工智能相关的内容，敬请期待！</p><br/><span id="more"></span><h1 id="一些免费的GPU资源"><a href="#一些免费的GPU资源" class="headerlink" title="一些免费的GPU资源"></a><strong>一些免费的GPU资源</strong></h1><h2 id="一、Google-Colab（推荐）"><a href="#一、Google-Colab（推荐）" class="headerlink" title="一、Google Colab（推荐）"></a><strong>一、Google Colab（推荐）</strong></h2><p>网址：</p><ul><li><a href="https://colab.research.google.com/notebooks/">https://colab.research.google.com/notebooks/</a></li></ul><p>特点：</p><ul><li>提供 <strong>NVIDIA T4/P100/V100/A100</strong>（具体型号随机分配）；</li><li>免费用户每天最多可使用 12 小时（可能因资源调度而中断）；</li><li>可升级至 <strong>Colab Pro（9.99 美元/月）</strong>或 <strong>Colab Pro+（49.99 美元/月）</strong>，享受更长运行时间和优惠优先级；</li><li>集成 Jupyter Notebook 环境，适合深度学习和机器学习任务</li></ul><br/><h2 id="二、Kaggle"><a href="#二、Kaggle" class="headerlink" title="二、Kaggle"></a><strong>二、Kaggle</strong></h2><p>网址：</p><ul><li><a href="https://www.kaggle.com/">https://www.kaggle.com/</a></li></ul><p>特点：</p><ul><li><strong>GPU小时数</strong>：每周30小时。</li><li><strong>GPU</strong>：提供Tesla P100，与Google Colab的T4相当。</li><li><strong>使用质量</strong>：非常好，很少断连。</li><li><strong>CPU和内存</strong>：提供四个CPU和29GB RAM。</li><li><strong>易用性</strong>：易用，有类似笔记本的界面。</li><li><strong>存储</strong>：无持久性存储。</li></ul><br/><h2 id="三、Paperspace-Gradient"><a href="#三、Paperspace-Gradient" class="headerlink" title="三、Paperspace Gradient"></a><strong>三、Paperspace Gradient</strong></h2><p>网址：</p><ul><li><a href="https://www.paperspace.com/">https://www.paperspace.com/</a></li></ul><p>特点：</p><ul><li><strong>GPU小时数</strong>：无具体限制，质量不佳。</li><li><strong>存储</strong>：有持久性存储，数据不会丢失。</li><li><strong>GPU</strong>：提供M4000 GPU，质量低于Google Colab的T4。</li></ul><br/><h2 id="四、其他"><a href="#四、其他" class="headerlink" title="四、其他"></a><strong>四、其他</strong></h2><h3 id="1、AWS-Sagemaker-Studio-Lab"><a href="#1、AWS-Sagemaker-Studio-Lab" class="headerlink" title="1、AWS Sagemaker Studio Lab"></a><strong>1、AWS Sagemaker Studio Lab</strong></h3><p>特点：</p><ul><li><strong>GPU小时数</strong>：每天4小时，CPU小时数12小时。</li><li><strong>GPU</strong>：提供T4 GPU，与Google Colab相同。</li><li><strong>使用质量</strong>：非常好，很少断连。</li><li><strong>易用性</strong>：需要在网站上注册。</li><li><strong>存储</strong>：有持久性存储。</li></ul><br/><h3 id="2、Lightning-AI"><a href="#2、Lightning-AI" class="headerlink" title="2、Lightning AI"></a><strong>2、Lightning AI</strong></h3><p>网址：</p><ul><li><a href="https://lightning.ai/">https://lightning.ai/</a></li></ul><p>特点：</p><ul><li><strong>GPU小时数</strong>：每月22小时。</li><li><strong>CPU</strong>：提供一个Studio，4个CPU完全免费。</li><li><strong>使用质量</strong>：非常好，连接稳定。</li><li><strong>易用性</strong>：非常好，提供VS Code界面。</li></ul><br/><h3 id="3、百度-AI-Studio"><a href="#3、百度-AI-Studio" class="headerlink" title="3、百度 AI Studio"></a><strong>3、百度 AI Studio</strong></h3><p>网址：</p><ul><li><a href="https://aistudio.baidu.com/index">https://aistudio.baidu.com/index</a></li></ul><p>特点：</p><ul><li>免费提供 GPU 运行环境，支持常见型号（如 T4、P40 等，具体配置可能随时调整）；</li><li>集成 PaddlePaddle 以及 TensorFlow、PyTorch 等主流深度学习框架；</li><li>类似 Jupyter Notebook 的在线编程环境，适合快速上手、学习和实验；</li></ul><br/><h3 id="4、云平台注册赠费"><a href="#4、云平台注册赠费" class="headerlink" title="4、云平台注册赠费"></a><strong>4、云平台注册赠费</strong></h3><ul><li><strong>Google Cloud Free Tier</strong><ul><li>新用户可获得 300 美元免费试用额度（90 天内有效），体验包括 GPU 实例在内的众多云服务</li><li>用户可自行创建 NVIDIA T4/V100/A100 GPU 实例（需手动配置）</li><li>适用于大规模机器学习和 AI 训练</li><li>注册时需绑定信用卡，但试用期间不会产生扣费</li></ul></li><li><strong>Microsoft Azure Free Tier</strong><ul><li>新用户可获得 200 美元免费试用额度（30 天内有效），支持 GPU 虚拟机（如 NC/ND 系列）</li><li>适用于 AI 深度学习训练和企业级应用开发</li><li>需要信用卡验证，但试用期间不收费</li></ul></li><li><strong>AWS Free Tier（Amazon Web Services）</strong><ul><li>免费层主要提供 750 小时 t2.micro 实例（不含 GPU），部分新用户可额外申请 GPU 实例（如 p3/g4 系列）</li><li>提供 Amazon SageMaker 平台，支持机器学习项目的快速部署</li><li>注册需绑定信用卡，确保试用过程不产生费用</li></ul></li></ul><blockquote><p>  其他资源：</p><ul><li><a href="https://www.reddit.com/r/KoboldAI/comments/13taldr/google_colabs_possible_alternatives/">https://www.reddit.com/r/KoboldAI/comments/13taldr/google_colabs_possible_alternatives/</a></li><li><a href="https://deepnote.com/compare/alternatives/colab">https://deepnote.com/compare/alternatives/colab</a></li></ul></blockquote><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>参考文章：</p><ul><li><a href="https://zhuanlan.zhihu.com/p/1906295351289308808">https://zhuanlan.zhihu.com/p/1906295351289308808</a></li><li><a href="https://www.bilibili.com/read/cv34465418/">https://www.bilibili.com/read/cv34465418/</a></li><li><a href="https://www.reddit.com/r/KoboldAI/comments/13taldr/google_colabs_possible_alternatives/">https://www.reddit.com/r/KoboldAI/comments/13taldr/google_colabs_possible_alternatives/</a></li><li><a href="https://deepnote.com/compare/alternatives/colab">https://deepnote.com/compare/alternatives/colab</a></li></ul><br/>]]></content>
    
    
    <summary type="html">在学习AI时，经常需要用到GPU资源；而有些时候我们手头并没有老黄的显卡，或者显卡已经不支持进行人工智能的学习了；本文总结了一些常用的GPU资源；同时，后续也会在博客更新一些和并行计算、人工智能相关的内容，敬请期待！</summary>
    
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/categories/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/tags/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    <category term="人工智能" scheme="https://jasonkayzk.github.io/cn/tags/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/"/>
    
  </entry>
  
  <entry>
    <title>debian12部署kubernetes-1.28集群</title>
    <link href="https://jasonkayzk.github.io/cn/2025/07/21/debian12%E9%83%A8%E7%BD%B2kubernetes-1-28%E9%9B%86%E7%BE%A4/"/>
    <id>https://jasonkayzk.github.io/cn/2025/07/21/debian12%E9%83%A8%E7%BD%B2kubernetes-1-28%E9%9B%86%E7%BE%A4/</id>
    <published>2025-07-21T02:41:07.000Z</published>
    <updated>2026-10-25T04:05:16.273Z</updated>
    
    <content type="html"><![CDATA[<p>由于暑假到了以及天气原因，学校的k8s集群暂时关闭了，但是目前还是有使用k8s的需求，花了2个小时又重新搭了一下；</p><p>由于国内网络的问题，导致github包、镜像都很难拉下来，因此本文的内容更适合国内需求环境。</p><p>源代码：</p><ul><li><a href="https://github.com/JasonkayZK/kubernetes-learn">https://github.com/JasonkayZK/kubernetes-learn</a></li></ul><br/><span id="more"></span><h1 id="debian12部署kubernetes-1-28集群"><a href="#debian12部署kubernetes-1-28集群" class="headerlink" title="debian12部署kubernetes-1.28集群"></a><strong>debian12部署kubernetes-1.28集群</strong></h1><h2 id="零、前置工作"><a href="#零、前置工作" class="headerlink" title="零、前置工作"></a><strong>零、前置工作</strong></h2><h3 id="0、环境校验"><a href="#0、环境校验" class="headerlink" title="0、环境校验"></a><strong>0、环境校验</strong></h3><p>该部分内容来自于 <a href="https://kubernetes.io/zh-cn/docs/setup/production-environment/tools/kubeadm/install-kubeadm/"><code>K8S</code> 官方文档</a>：</p><ul><li>一台兼容的 <code>Linux</code> 主机。<code>Kubernetes</code> 项目为基于 <code>Debian</code> 和 <code>Red Hat</code> 的 <code>Linux</code> 发行版以及一些不提供包管理器的发行版提供通用的指令。</li><li>每台机器 <code>2 GB</code> 或更多的 <code>RAM</code>（如果少于这个数字将会影响你应用的运行内存）。</li><li><code>CPU 2</code> 核心及以上。</li><li>集群中的所有机器的网络彼此均能相互连接（公网和内网都可以）。</li><li>节点之中不可以有重复的主机名、<code>MAC</code> 地址或 <code>product_uuid</code>。</li></ul><br/><h3 id="1、准备虚拟机"><a href="#1、准备虚拟机" class="headerlink" title="1、准备虚拟机"></a><strong>1、准备虚拟机</strong></h3><table><thead><tr><th>IP Address</th><th>Hostname</th><th>CPU</th><th>Memory</th><th>Storage</th><th>OS Release</th><th>Role</th></tr></thead><tbody><tr><td>192.168.117.200</td><td>k1</td><td>4C</td><td>8G</td><td>100GB</td><td>Debian 12</td><td>Master</td></tr><tr><td>192.168.117.201</td><td>k2</td><td>4C</td><td>8G</td><td>100GB</td><td>Debian 12</td><td>Worker</td></tr><tr><td>192.168.117.202</td><td>k3</td><td>4C</td><td>8G</td><td>100GB</td><td>Debian 12</td><td>Worker</td></tr></tbody></table><p>虚拟机安装、配置部分不再赘述了！</p><p>主要包括下面几个方面：</p><ul><li>配置软件源；</li><li>配置静态IP；</li><li>配置 hosts 解析；</li><li>配置 SSH 免密登录；</li><li>安装必要工具：net-tools、wget、curl、htop等；</li></ul><blockquote><p>  参考：</p><ul><li><a href="/cn/2021/08/21/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E6%90%AD%E5%BB%BA%E5%A4%A7%E6%95%B0%E6%8D%AE%E9%95%9C%E5%83%8F-1/">《从零开始搭建大数据镜像-1》</a></li></ul></blockquote><br/><h3 id="2、卸载docker（如有）"><a href="#2、卸载docker（如有）" class="headerlink" title="2、卸载docker（如有）"></a><strong>2、卸载docker（如有）</strong></h3><p>新版本的 k8s 和 docker 底层都依赖 containerd 容易造成冲突，直接卸载docker：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras</span><br><span class="line"></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">rm</span> -rf /var/lib/docker</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">rm</span> -rf /var/lib/containerd</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">rm</span> -rf /etc/docker</span><br></pre></td></tr></table></figure><br/><h3 id="3、设置系统时区和时间同步"><a href="#3、设置系统时区和时间同步" class="headerlink" title="3、设置系统时区和时间同步"></a><strong>3、设置系统时区和时间同步</strong></h3><p>使用阿里云的时钟源：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">timedatectl set-timezone Asia/Shanghai</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 chrony</span></span><br><span class="line">apt-get install -y chrony</span><br><span class="line"></span><br><span class="line"><span class="comment"># 修改为阿里的时钟源</span></span><br><span class="line">sed -i <span class="string">&quot;s/pool 2.debian.pool.ntp.org iburst/server ntp.aliyun.com iburst/g&quot;</span> /etc/chrony/chrony.conf</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启用并立即启动 chrony 服务</span></span><br><span class="line">systemctl restart chrony</span><br><span class="line">systemctl <span class="built_in">enable</span> chrony</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看与 chrony 服务器同步的时间源</span></span><br><span class="line">chronyc sources</span><br></pre></td></tr></table></figure><br/><h3 id="4、安装ipvs工具"><a href="#4、安装ipvs工具" class="headerlink" title="4、安装ipvs工具"></a><strong>4、安装ipvs工具</strong></h3><p>在 <code>Kubernetes</code> 中，<code>ipset</code> 和 <code>ipvsadm</code> 的用途：</p><ul><li><code>ipset</code> 主要用于支持 <code>Service</code> 的负载均衡和网络策略。它可以帮助实现高性能的数据包过滤和转发，以及对 <code>IP</code> 地址和端口进行快速匹配。</li><li><code>ipvsadm</code> 主要用于配置和管理 <code>IPVS</code> 负载均衡器，以实现 <code>Service</code> 的负载均衡。</li></ul><p>执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt-get install -y ipset ipvsadm </span><br></pre></td></tr></table></figure><br/><h3 id="5、关闭服务"><a href="#5、关闭服务" class="headerlink" title="5、关闭服务"></a><strong>5、关闭服务</strong></h3><p>关闭 swap、防火墙等：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 关闭所有已激活的 swap 分区</span></span><br><span class="line">swapoff -a</span><br><span class="line"></span><br><span class="line"><span class="comment"># 禁用系统启动时自动挂载 swap 分区</span></span><br><span class="line">sed -i <span class="string">&#x27;/ swap / s/^\(.*\)$/#\1/g&#x27;</span> /etc/fstab</span><br><span class="line"></span><br><span class="line"><span class="comment"># 停止 AppArmor 服务</span></span><br><span class="line">systemctl stop apparmor.service</span><br><span class="line"></span><br><span class="line"><span class="comment"># 禁用 AppArmor 服务</span></span><br><span class="line">systemctl <span class="built_in">disable</span> apparmor.service</span><br><span class="line"></span><br><span class="line"><span class="comment"># 禁用 Uncomplicated Firewall（ufw）</span></span><br><span class="line">ufw <span class="built_in">disable</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 停止 ufw 服务</span></span><br><span class="line">systemctl stop ufw.service</span><br><span class="line"></span><br><span class="line"><span class="comment"># 禁用 ufw 服务</span></span><br><span class="line">systemctl <span class="built_in">disable</span> ufw.service</span><br></pre></td></tr></table></figure><br/><h3 id="6、内核优化"><a href="#6、内核优化" class="headerlink" title="6、内核优化"></a><strong>6、内核优化</strong></h3><p>创建一个名为 kubernetes.conf 的内核配置文件，并写入以下配置内容：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &gt; /etc/sysctl.d/kubernetes.conf &lt;&lt; <span class="string">EOF</span></span><br><span class="line"><span class="string"># 允许 IPv6 转发请求通过iptables进行处理（如果禁用防火墙或不是iptables，则该配置无效）</span></span><br><span class="line"><span class="string">net.bridge.bridge-nf-call-ip6tables = 1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># 允许 IPv4 转发请求通过iptables进行处理（如果禁用防火墙或不是iptables，则该配置无效）</span></span><br><span class="line"><span class="string">net.bridge.bridge-nf-call-iptables = 1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># 启用IPv4数据包的转发功能</span></span><br><span class="line"><span class="string">net.ipv4.ip_forward = 1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># 禁用发送 ICMP 重定向消息</span></span><br><span class="line"><span class="string">net.ipv4.conf.all.send_redirects = 0</span></span><br><span class="line"><span class="string">net.ipv4.conf.default.send_redirects = 0</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># 提高 TCP 连接跟踪的最大数量</span></span><br><span class="line"><span class="string">net.netfilter.nf_conntrack_max = 1000000</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># 提高连接追踪表的超时时间</span></span><br><span class="line"><span class="string">net.netfilter.nf_conntrack_tcp_timeout_established = 86400</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># 提高监听队列大小</span></span><br><span class="line"><span class="string">net.core.somaxconn = 1024</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># 防止 SYN 攻击</span></span><br><span class="line"><span class="string">net.ipv4.tcp_syncookies = 1</span></span><br><span class="line"><span class="string">net.ipv4.tcp_max_syn_backlog = 2048</span></span><br><span class="line"><span class="string">net.ipv4.tcp_synack_retries = 2</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># 提高文件描述符限制</span></span><br><span class="line"><span class="string">fs.file-max = 65536</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># 设置虚拟内存交换（swap）的使用策略为0，减少对磁盘的频繁读写</span></span><br><span class="line"><span class="string">vm.swappiness = 0</span></span><br><span class="line"><span class="string">EOF</span></span><br></pre></td></tr></table></figure><p>加载或启动内核模块 br_netfilter，该模块提供了网络桥接所需的网络过滤功能</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">modprobe br_netfilter</span><br></pre></td></tr></table></figure><p>查看是否已成功加载模块：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">lsmod | grep br_netfilter</span><br></pre></td></tr></table></figure><p>将读取该文件中的参数设置，并将其应用到系统的当前运行状态中：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sysctl -p /etc/sysctl.d/kubernetes.conf</span><br></pre></td></tr></table></figure><blockquote><p>  参考：</p><ul><li><a href="https://isekiro.com/linux操作系统-内核优化/">Linux操作系统-内核优化</a></li></ul></blockquote><br/><h3 id="7、内核模块配置"><a href="#7、内核模块配置" class="headerlink" title="7、内核模块配置"></a><strong>7、内核模块配置</strong></h3><p>将自定义在系统引导时自动加载的内核模块：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 将自定义在系统引导时自动加载的内核模块</span></span><br><span class="line"><span class="built_in">cat</span> &gt; /etc/modules-load.d/kubernetes.conf &lt;&lt; <span class="string">EOF</span></span><br><span class="line"><span class="string"># /etc/modules-load.d/kubernetes.conf</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># Linux 网桥支持</span></span><br><span class="line"><span class="string">br_netfilter</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># IPVS 加载均衡器</span></span><br><span class="line"><span class="string">ip_vs</span></span><br><span class="line"><span class="string">ip_vs_rr</span></span><br><span class="line"><span class="string">ip_vs_wrr</span></span><br><span class="line"><span class="string">ip_vs_sh</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># IPv4 连接跟踪</span></span><br><span class="line"><span class="string">nf_conntrack_ipv4</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"># IP 表规则</span></span><br><span class="line"><span class="string">ip_tables</span></span><br><span class="line"><span class="string">EOF</span></span><br></pre></td></tr></table></figure><p>添加可执行权限：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> a+x /etc/modules-load.d/kubernetes.conf</span><br></pre></td></tr></table></figure><br/><h3 id="8、安装containerd运行时"><a href="#8、安装containerd运行时" class="headerlink" title="8、安装containerd运行时"></a><strong>8、安装containerd运行时</strong></h3><blockquote><p>  <strong>以下指令适用于 Kubernetes 1.28！</strong></p></blockquote><h4 id="（1）安装"><a href="#（1）安装" class="headerlink" title="（1）安装"></a><strong>（1）安装</strong></h4><p>安装 containerd：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># cri-containerd 比 containerd 多了 runc</span></span><br><span class="line">wget https://github.com/containerd/containerd/releases/download/v1.7.21/cri-containerd-1.7.21-linux-amd64.tar.gz</span><br><span class="line"></span><br><span class="line">tar xf cri-containerd-1.7.21-linux-amd64.tar.gz -C /</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建目录，该目录用于存放 containerd 配置文件</span></span><br><span class="line"><span class="built_in">mkdir</span> /etc/containerd</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建一个默认的 containerd 配置文件</span></span><br><span class="line">containerd config default &gt; /etc/containerd/config.toml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 修改配置文件中使用的沙箱镜像版本</span></span><br><span class="line">sed -i <span class="string">&#x27;s#registry.k8s.io/pause:3.8#registry.aliyuncs.com/google_containers/pause:3.9#&#x27;</span> /etc/containerd/config.toml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置容器运行时（containerd + CRI）在创建容器时使用 Systemd Cgroups 驱动</span></span><br><span class="line">sed -i <span class="string">&#x27;/SystemdCgroup/s/false/true/&#x27;</span> /etc/containerd/config.toml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 修改存储目录</span></span><br><span class="line"><span class="comment"># mkdir /data1/containerd</span></span><br><span class="line"><span class="comment"># sed -i &#x27;s#root = &quot;/var/lib/containerd&quot;#root = &quot;/data1/containerd&quot;#&#x27; /etc/containerd/config.toml</span></span><br></pre></td></tr></table></figure><br/><h4 id="（2）配置脚本"><a href="#（2）配置脚本" class="headerlink" title="（2）配置脚本"></a><strong>（2）配置脚本</strong></h4><p>配置启动脚本：</p><p>/lib/systemd/system/containerd.service</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[Unit]</span></span><br><span class="line"><span class="attr">Description</span>=containerd container runtime</span><br><span class="line"><span class="attr">Documentation</span>=https://containerd.io</span><br><span class="line"><span class="attr">After</span>=network.target local-fs.target</span><br><span class="line"></span><br><span class="line"><span class="section">[Service]</span></span><br><span class="line"><span class="attr">ExecStartPre</span>=-/sbin/modprobe overlay</span><br><span class="line"><span class="attr">ExecStart</span>=/usr/local/bin/containerd</span><br><span class="line"></span><br><span class="line"><span class="attr">Type</span>=notify</span><br><span class="line"><span class="attr">Delegate</span>=<span class="literal">yes</span></span><br><span class="line"><span class="attr">KillMode</span>=process</span><br><span class="line"><span class="attr">Restart</span>=always</span><br><span class="line"><span class="attr">RestartSec</span>=<span class="number">5</span></span><br><span class="line"></span><br><span class="line"><span class="attr">LimitNPROC</span>=infinity</span><br><span class="line"><span class="attr">LimitCORE</span>=infinity</span><br><span class="line"></span><br><span class="line"><span class="attr">TasksMax</span>=infinity</span><br><span class="line"><span class="attr">OOMScoreAdjust</span>=-<span class="number">999</span></span><br><span class="line"></span><br><span class="line"><span class="section">[Install]</span></span><br><span class="line"><span class="attr">WantedBy</span>=multi-user.target</span><br></pre></td></tr></table></figure><p>执行配置：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 启用并立即启动 containerd 服务</span></span><br><span class="line">systemctl <span class="built_in">enable</span> --now containerd.service</span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查 containerd 服务的当前状态</span></span><br><span class="line">systemctl status containerd.service</span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查 containerd crictl runc 的版本</span></span><br><span class="line">containerd --version</span><br><span class="line">crictl --version</span><br><span class="line">runc --version</span><br><span class="line"></span><br><span class="line">crictl config runtime-endpoint unix:///run/containerd/containerd.sock</span><br></pre></td></tr></table></figure><br/><h2 id="一、安装组件"><a href="#一、安装组件" class="headerlink" title="一、安装组件"></a><strong>一、安装组件</strong></h2><p>更新 apt 包索引并安装使用 Kubernetes apt 仓库所需要的包：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt-get update</span><br><span class="line"></span><br><span class="line"><span class="comment"># apt-transport-https 可能是一个虚拟包（dummy package）；如果是的话，你可以跳过安装这个包</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get install -y apt-transport-https ca-certificates curl gpg</span><br><span class="line"></span><br><span class="line"><span class="comment">#下载用于 Kubernetes 软件包仓库的公共签名密钥。所有仓库都使用相同的签名密钥，因此你可以忽略URL中的版本：</span></span><br><span class="line">curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | <span class="built_in">sudo</span> gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg</span><br><span class="line"></span><br><span class="line"><span class="comment">#添加 Kubernetes apt 仓库。 请注意，此仓库仅包含适用于 Kubernetes 1.28 的软件包； 对于其他 Kubernetes 次要版本，则需要更改 URL 中的 Kubernetes 次要版本以匹配你所需的次要版本 （你还应该检查正在阅读的安装文档是否为你计划安装的 Kubernetes 版本的文档）。</span></span><br><span class="line"><span class="comment"># 此操作会覆盖 /etc/apt/sources.list.d/kubernetes.list 中现存的所有配置。</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /&#x27;</span> | <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/apt/sources.list.d/kubernetes.list</span><br><span class="line"></span><br><span class="line"><span class="comment">#更新 apt 包索引，安装 kubelet、kubeadm 和 kubectl，并锁定其版本：</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get update</span><br><span class="line"><span class="built_in">sudo</span> apt-get install -y kubelet=1.28.13-1.1 kubeadm=1.28.13-1.1 kubectl=1.28.13-1.1</span><br><span class="line"></span><br><span class="line"><span class="comment">#锁定版本</span></span><br><span class="line"><span class="built_in">sudo</span> apt-mark hold kubelet kubeadm kubectl</span><br><span class="line"></span><br><span class="line"><span class="comment">#说明：在 Debian 12 和 Ubuntu 22.04 之前的早期版本中，默认情况下不存在 /etc/apt/keyrings 目录； 你可以通过运行 sudo mkdir -m 755 /etc/apt/keyrings 来创建它。</span></span><br></pre></td></tr></table></figure><p>配置 kubelet 开机启动：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl <span class="built_in">enable</span> kubelet</span><br></pre></td></tr></table></figure><br/><h2 id="二、初始化集群"><a href="#二、初始化集群" class="headerlink" title="二、初始化集群"></a><strong>二、初始化集群</strong></h2><h3 id="1、初始化集群（Master节点执行）"><a href="#1、初始化集群（Master节点执行）" class="headerlink" title="1、初始化集群（Master节点执行）"></a><strong>1、初始化集群（Master节点执行）</strong></h3><blockquote><p>  <strong>本小节在 master 节点执行！</strong></p></blockquote><p>生成配置文件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubeadm config <span class="built_in">print</span> init-defaults &gt; kubeadm.yaml</span><br></pre></td></tr></table></figure><p>配置文件如下：</p><p>kubeadm.yaml</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">kubeadm.k8s.io/v1beta3</span></span><br><span class="line"><span class="attr">bootstrapTokens:</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">groups:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">system:bootstrappers:kubeadm:default-node-token</span></span><br><span class="line">  <span class="attr">token:</span> <span class="string">abcdef.0123456789abcdef</span></span><br><span class="line">  <span class="attr">ttl:</span> <span class="string">24h0m0s</span></span><br><span class="line">  <span class="attr">usages:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">signing</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">authentication</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">InitConfiguration</span></span><br><span class="line"><span class="comment">#localAPIEndpoint:</span></span><br><span class="line"><span class="comment">#  advertiseAddress: 192.168.2.232</span></span><br><span class="line"><span class="comment">#  bindPort: 6443</span></span><br><span class="line"><span class="attr">nodeRegistration:</span></span><br><span class="line">  <span class="attr">criSocket:</span> <span class="string">unix:///run/containerd/containerd.sock</span></span><br><span class="line">  <span class="attr">imagePullPolicy:</span> <span class="string">IfNotPresent</span></span><br><span class="line"><span class="comment">#  name: node</span></span><br><span class="line">  <span class="attr">taints:</span> <span class="literal">null</span></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">apiServer:</span></span><br><span class="line">  <span class="attr">timeoutForControlPlane:</span> <span class="string">4m0s</span></span><br><span class="line"><span class="attr">apiVersion:</span> <span class="string">kubeadm.k8s.io/v1beta3</span></span><br><span class="line"><span class="attr">certificatesDir:</span> <span class="string">/etc/kubernetes/pki</span></span><br><span class="line"><span class="attr">clusterName:</span> <span class="string">kubernetes</span></span><br><span class="line"><span class="attr">controllerManager:</span> &#123;&#125;</span><br><span class="line"><span class="attr">dns:</span> &#123;&#125;</span><br><span class="line"><span class="attr">etcd:</span></span><br><span class="line">  <span class="attr">local:</span></span><br><span class="line">    <span class="attr">dataDir:</span> <span class="string">/var/lib/etcd</span></span><br><span class="line"><span class="comment"># 指定阿里云镜像以及k8s版本</span></span><br><span class="line"><span class="attr">imageRepository:</span> <span class="string">registry.cn-hangzhou.aliyuncs.com/google_containers</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">ClusterConfiguration</span></span><br><span class="line"><span class="attr">kubernetesVersion:</span> <span class="number">1.28</span><span class="number">.13</span></span><br><span class="line"><span class="comment"># 新增</span></span><br><span class="line"><span class="attr">controlPlaneEndpoint:</span> <span class="number">192.168</span><span class="number">.117</span><span class="number">.200</span><span class="string">:6443</span> <span class="comment"># 修改为masterIP！</span></span><br><span class="line"><span class="attr">networking:</span></span><br><span class="line">  <span class="attr">dnsDomain:</span> <span class="string">cluster.local</span></span><br><span class="line">  <span class="attr">serviceSubnet:</span> <span class="number">10.254</span><span class="number">.0</span><span class="number">.0</span><span class="string">/16</span></span><br><span class="line">  <span class="attr">podSubnet:</span> <span class="number">10.255</span><span class="number">.0</span><span class="number">.0</span><span class="string">/16</span>  <span class="comment"># 指定pod网段</span></span><br><span class="line"><span class="attr">scheduler:</span> &#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 新增如下：</span></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">apiVersion:</span> <span class="string">kubelet.config.k8s.io/v1beta1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">KubeletConfiguration</span></span><br><span class="line"><span class="attr">cgroupDriver:</span> <span class="string">systemd</span></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">apiVersion:</span> <span class="string">kubeproxy.config.k8s.io/v1alpha1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">KubeProxyConfiguration</span></span><br><span class="line"><span class="attr">mode:</span> <span class="string">ipvs</span></span><br></pre></td></tr></table></figure><p>验证镜像仓配置是否生效。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubeadm config images list --config=kubeadm.yaml</span><br></pre></td></tr></table></figure><p>提前拉取镜像。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubeadm config images pull --config=kubeadm.yaml</span><br></pre></td></tr></table></figure><p>查看镜像是否下载。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">crictl images</span><br></pre></td></tr></table></figure><p>开始初始化。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubeadm init --config=kubeadm.yaml</span><br></pre></td></tr></table></figure><p>安装完会有加入集群的相关指令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">You should now deploy a pod network to the cluster.</span><br><span class="line">Run <span class="string">&quot;kubectl apply -f [podnetwork].yaml&quot;</span> with one of the options listed at:</span><br><span class="line">  https://kubernetes.io/docs/concepts/cluster-administration/addons/</span><br><span class="line"></span><br><span class="line">You can now <span class="built_in">join</span> any number of control-plane nodes by copying certificate authorities</span><br><span class="line">and service account keys on each node and <span class="keyword">then</span> running the following as root:</span><br><span class="line"></span><br><span class="line">  kubeadm <span class="built_in">join</span> 192.168.117.200:6443 --token abcdef.0123456789abcdef \</span><br><span class="line">        --discovery-token-ca-cert-hash sha256:91a2398cbadf3967950dc6900e7411d5319e82ad30e139a1163896f9a8c61234 \</span><br><span class="line">        --control-plane </span><br><span class="line"></span><br><span class="line">Then you can <span class="built_in">join</span> any number of worker nodes by running the following on each as root:</span><br><span class="line"></span><br><span class="line">kubeadm <span class="built_in">join</span> 192.168.117.200:6443 --token abcdef.0123456789abcdef \</span><br><span class="line">        --discovery-token-ca-cert-hash sha256:91a2398cbadf3967950dc6900e7411d5319e82ad30e139a1163896f9a8c61234</span><br></pre></td></tr></table></figure><br/><h3 id="2、Worker加入集群（Worker节点）"><a href="#2、Worker加入集群（Worker节点）" class="headerlink" title="2、Worker加入集群（Worker节点）"></a><strong>2、Worker加入集群（Worker节点）</strong></h3><blockquote><p>  <strong>此小节在 worker 节点执行！</strong></p></blockquote><p>执行加入脚本：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kubeadm <span class="built_in">join</span> 192.168.117.200:6443 --token abcdef.0123456789abcdef \</span><br><span class="line">        --discovery-token-ca-cert-hash sha256:91a2398cbadf3967950dc6900e7411d5319e82ad30e139a1163896f9a8c61234</span><br></pre></td></tr></table></figure><p>等待后即可加入！</p><br/><h3 id="3、Master节点污点（可选）"><a href="#3、Master节点污点（可选）" class="headerlink" title="3、Master节点污点（可选）"></a><strong>3、Master节点污点（可选）</strong></h3><p>默认情况下 Master 节点为 <code>control-plane</code>，无法部署服务；</p><p>可以通过执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看污点</span></span><br><span class="line">kubectl describe node k1 |grep Taints</span><br><span class="line">Taints:    node-role.kubernetes.io/control-plane:NoSchedule</span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除污点</span></span><br><span class="line">kubectl taint node k1 node-role.kubernetes.io/control-plane:NoSchedule-</span><br></pre></td></tr></table></figure><p>启用 master 节点调度！</p><br/><h3 id="补：其他节点使用kubectl"><a href="#补：其他节点使用kubectl" class="headerlink" title="补：其他节点使用kubectl"></a><strong>补：其他节点使用kubectl</strong></h3><p>其他节点默认是无法直接使用 kubectl 管理集群的，我们只需要将配置文件复制到其他节点即可！</p><p><strong>方法一：拷贝master节点的/etc/kubernetes/admin.conf 到nodes节点中的同样的目录/etc/kubernetes/ ，然后再配置环境变量</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@k8s-node1 qq-5201351]# scp k8s-master:/etc/kubernetes/admin.conf /etc/kubernetes/admin.conf</span><br></pre></td></tr></table></figure><p>然后再配置环境变量：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export KUBECONFIG=/etc/kubernetes/admin.conf&#x27;</span> &gt;&gt; ~/.bash_profile</span><br><span class="line"><span class="built_in">source</span> ~/.bash_profile</span><br></pre></td></tr></table></figure> <br/><p><strong>方法二：拷贝master节点的/etc/kubernetes/admin.conf 到nodes节点的$HOME/.kube目录，并且命名为config</strong></p><p>因为默认是没有 <code>$HOME/.kube</code> 目录的，先进行创建：</p><ul><li><strong>mkdir -p $HOME/.kube</strong></li><li><strong>scp k8s-master:/etc/kubernetes/admin.conf $HOME/.kube/config</strong></li></ul><br/><h2 id="三、网络插件"><a href="#三、网络插件" class="headerlink" title="三、网络插件"></a><strong>三、网络插件</strong></h2><h3 id="1、安装Calico"><a href="#1、安装Calico" class="headerlink" title="1、安装Calico"></a><strong>1、安装Calico</strong></h3><p>k8s 部署完成后还不能使用，需要配置网络插件，从而为 Pod 分配 IP，打通网络等等。</p><blockquote><p>  Calico是 <strong>目前开源的最成熟的纯三层网络框架之一</strong>， 是一种广泛采用、久经考验的开源网络和网络安全解决方案，适用于 Kubernetes、虚拟机和裸机工作负载。 Calico 为云原生应用提供两大服务：工作负载之间的网络连接和工作负载之间的网络安全策略。</p><p>  Calico 访问链接：<a href="https://link.juejin.cn/?target=https%3A%2F%2Fprojectcalico.docs.tigera.io%2Fabout%2Fabout-calico">projectcalico.docs.tigera.io/about/</a></p></blockquote><p>在这里使用 calico 来做为集群的网络插件，官网提供2种安装方式：</p><ul><li>operator 的方式修改镜像比较麻烦，这里不使用；</li><li>通过yaml配置文件的方式；</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/calico.yaml -O</span><br></pre></td></tr></table></figure><p><strong>配置：</strong></p><ul><li><strong>修改 <code>CALICO_IPV4POOL_CIDR</code> 为我们的网段（本文为：<code>10.254.0.0/16</code>）</strong></li><li><strong>修改 <code>CALICO_IPV4POOL_IPIP</code> 为 <code>Always</code> 启用 ipip 协议；</strong></li></ul><figure class="highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="deletion">- # - name: CALICO_IPV4POOL_CIDR</span></span><br><span class="line"><span class="deletion">- #   value: &quot;192.168.0.0/16&quot;</span></span><br><span class="line"><span class="addition">+ - name: CALICO_IPV4POOL_CIDR</span></span><br><span class="line"><span class="addition">+   value: &quot;10.254.0.0/16&quot;</span></span><br><span class="line"></span><br><span class="line"># Enable IPIP</span><br><span class="line"><span class="addition">+ - name: CALICO_IPV4POOL_IPIP</span></span><br><span class="line"><span class="addition">+   value: &quot;Always&quot;</span></span><br></pre></td></tr></table></figure><p><strong>修改镜像地址：</strong></p><p>搜索 <code>image:</code> 将镜像修改：</p><figure class="highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="deletion">- image: docker.io/calico/cni:v3.28.1</span></span><br><span class="line"><span class="addition">+ image: registry.cn-hangzhou.aliyuncs.com/jasonkay/cni:v3.28.1</span></span><br><span class="line"></span><br><span class="line"><span class="deletion">- image: docker.io/calico/node:v3.28.1</span></span><br><span class="line"><span class="addition">+ image: registry.cn-hangzhou.aliyuncs.com/jasonkay/node:v3.28.1</span></span><br><span class="line"></span><br><span class="line"><span class="deletion">- image: docker.io/calico/kube-controllers:v3.28.1</span></span><br><span class="line"><span class="addition">+ image: registry.cn-hangzhou.aliyuncs.com/jasonkay/kube-controllers:v3.28.1</span></span><br></pre></td></tr></table></figure><blockquote><p>  <strong>即，将：<code>docker.io/calico</code> 替换为 <code>registry.cn-hangzhou.aliyuncs.com/jasonkay</code> （我在阿里云上同步的镜像）！</strong></p></blockquote><p>随后执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f calico.yaml</span><br></pre></td></tr></table></figure><p>等待部署完成即可！</p><br/><h3 id="2、验证"><a href="#2、验证" class="headerlink" title="2、验证"></a><strong>2、验证</strong></h3><p>验证 coredns dns 转发是否正常：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装dns工具</span></span><br><span class="line">apt install -y dnsutils</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取dns ip地址</span></span><br><span class="line">kubectl get svc -n kube-system</span><br><span class="line">NAME       TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE</span><br><span class="line">kube-dns   ClusterIP   10.254.0.10   &lt;none&gt;        53/UDP,53/TCP,9153/TCP   15h</span><br><span class="line"></span><br><span class="line"><span class="comment"># 测试能够解析</span></span><br><span class="line">dig -t a www.baidu.com @10.254.0.10</span><br></pre></td></tr></table></figure><br/><h2 id="四、部署应用测试"><a href="#四、部署应用测试" class="headerlink" title="四、部署应用测试"></a><strong>四、部署应用测试</strong></h2><p>部署 nginx 进行测试：</p><p>nginx-deploy.yaml</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">apps/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Deployment</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">nginx-deployment</span></span><br><span class="line">  <span class="attr">labels:</span></span><br><span class="line">    <span class="attr">app:</span> <span class="string">nginx</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">replicas:</span> <span class="number">3</span></span><br><span class="line">  <span class="attr">selector:</span></span><br><span class="line">    <span class="attr">matchLabels:</span></span><br><span class="line">      <span class="attr">app:</span> <span class="string">nginx</span></span><br><span class="line">  <span class="attr">template:</span></span><br><span class="line">    <span class="attr">metadata:</span></span><br><span class="line">      <span class="attr">labels:</span></span><br><span class="line">        <span class="attr">app:</span> <span class="string">nginx</span></span><br><span class="line">    <span class="attr">spec:</span></span><br><span class="line">      <span class="attr">containers:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line">        <span class="attr">image:</span> <span class="string">registry.cn-hangzhou.aliyuncs.com/jasonkay/nginx:latest</span></span><br><span class="line">        <span class="attr">ports:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">containerPort:</span> <span class="number">80</span></span><br><span class="line"></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Service</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">nginx-service</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">type:</span> <span class="string">NodePort</span></span><br><span class="line">  <span class="attr">selector:</span></span><br><span class="line">    <span class="attr">app:</span> <span class="string">nginx</span></span><br><span class="line">  <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">protocol:</span> <span class="string">TCP</span></span><br><span class="line">      <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line">      <span class="attr">targetPort:</span> <span class="number">80</span></span><br><span class="line">      <span class="attr">nodePort:</span> <span class="number">31080</span></span><br></pre></td></tr></table></figure><p>应用：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f nginx-deploy.yaml</span><br></pre></td></tr></table></figure><p>然后访问 <code>k8s-ip:31080</code>，能够正常访问 Nginx！</p><br/><h2 id="五、安装Helm"><a href="#五、安装Helm" class="headerlink" title="五、安装Helm"></a><strong>五、安装Helm</strong></h2><p>Helm 是 Kubernetes 的一个包管理工具，类似于 Linux 的 Apt 或 Yum；</p><p>这个工具能帮助开发者和系统管理员更方便地管理在 Kubernetes 集群上部署、更新、卸载应用。</p><p><code>Helm</code> 中的三个主要概念：</p><table><thead><tr><th>概念</th><th>描述</th></tr></thead><tbody><tr><td>Chart</td><td>在 Kubernetes 集群上部署应用所需的所有资源定义的包</td></tr><tr><td>Release</td><td>在 Kubernetes 集群上部署的 Chart 的实例</td></tr><tr><td>Repository</td><td>Chart 的存储位置，类似软件仓库，用于分发和分享 Chart</td></tr></tbody></table><p>安装脚本：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">1. 添加 Helm 的官方 GPG key</span><br><span class="line">root@k8s-master:~# curl https://baltocdn.com/helm/signing.asc | gpg --dearmor -o /usr/share/keyrings/helm-keyring.gpg</span><br><span class="line"></span><br><span class="line">2. 添加 Helm 的官方 APT 仓库</span><br><span class="line">root@k8s-master:~# <span class="built_in">echo</span> <span class="string">&quot;deb [signed-by=/usr/share/keyrings/helm-keyring.gpg] https://baltocdn.com/helm/stable/debian/ all main&quot;</span> | <span class="built_in">tee</span> /etc/apt/sources.list.d/helm-stable-debian.list</span><br><span class="line"></span><br><span class="line">3. 更新 apt 源</span><br><span class="line">root@k8s-master:~# apt-get update</span><br><span class="line"></span><br><span class="line">4. 安装 Helm</span><br><span class="line">root@k8s-master:~# apt-get install -y helm</span><br><span class="line"></span><br><span class="line">5. 检查 Helm 是否已正确安装</span><br><span class="line">root@k8s-master:~# helm version</span><br><span class="line">version.BuildInfo&#123;Version:<span class="string">&quot;v3.13.3&quot;</span>, GitCommit:<span class="string">&quot;c8b948945e52abba22ff885446a1486cb5fd3474&quot;</span>, GitTreeState:<span class="string">&quot;clean&quot;</span>, GoVersion:<span class="string">&quot;go1.20.11&quot;</span>&#125;</span><br></pre></td></tr></table></figure><br/><h2 id="六、安装面板KubeSphere"><a href="#六、安装面板KubeSphere" class="headerlink" title="六、安装面板KubeSphere"></a><strong>六、安装面板KubeSphere</strong></h2><p>官方提供的面板不太好用，这里推荐使用 KubeSphere；</p><p>配置下载区域：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> KKZONE=cn</span><br></pre></td></tr></table></figure><p>安装也很简单，使用 helm 即可，而且支持国内：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">helm upgrade --install -n kubesphere-system \</span><br><span class="line">  --create-namespace ks-core \</span><br><span class="line">  https://charts.kubesphere.com.cn/main/ks-core-1.1.4.tgz \</span><br><span class="line">  --debug --<span class="built_in">wait</span> \</span><br><span class="line">  --<span class="built_in">set</span> global.imageRegistry=swr.cn-southwest-2.myhuaweicloud.com/ks \</span><br><span class="line">  --<span class="built_in">set</span> extension.imageRegistry=swr.cn-southwest-2.myhuaweicloud.com/ks</span><br></pre></td></tr></table></figure><p>等待所有 Pod 就绪后，安装完成，显示：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">NOTES:</span><br><span class="line">Thank you for choosing KubeSphere Helm Chart.</span><br><span class="line"></span><br><span class="line">Please be patient and wait for several seconds for the KubeSphere deployment to complete.</span><br><span class="line"></span><br><span class="line">1. Wait for Deployment Completion</span><br><span class="line"></span><br><span class="line">    Confirm that all KubeSphere components are running by executing the following command:</span><br><span class="line"></span><br><span class="line">    kubectl get pods -n kubesphere-system</span><br><span class="line"></span><br><span class="line">2. Access the KubeSphere Console</span><br><span class="line"></span><br><span class="line">    Once the deployment is complete, you can access the KubeSphere console using the following URL:</span><br><span class="line"></span><br><span class="line">    http://192.168.6.10:30880</span><br><span class="line"></span><br><span class="line">3. Login to KubeSphere Console</span><br><span class="line"></span><br><span class="line">    Use the following credentials to log in:</span><br><span class="line"></span><br><span class="line">    Account: admin</span><br><span class="line">    Password: P@88w0rd</span><br><span class="line"></span><br><span class="line">NOTE: It is highly recommended to change the default password immediately after the first login.</span><br><span class="line"></span><br><span class="line">For additional information and details, please visit https://kubesphere.io.</span><br></pre></td></tr></table></figure><p>执行以下命令检查 Pod 状态。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get pods -n kubesphere-system</span><br></pre></td></tr></table></figure><p>当 Pod 状态都为 <strong>Running</strong> 时，使用默认的账户和密码 (admin/P@88w0rd) 通过 <code>&lt;NodeIP&gt;:30880</code> 访问 KubeSphere Web 控制台！</p><br/><h2 id="七、工具推荐"><a href="#七、工具推荐" class="headerlink" title="七、工具推荐"></a><strong>七、工具推荐</strong></h2><h3 id="1、kubectx"><a href="#1、kubectx" class="headerlink" title="1、kubectx"></a><strong>1、kubectx</strong></h3><p>推荐安装 kubectx，可以切换k8s上下文（管理多个集群）；</p><p>并且 kubectx 自带了另一个工具：kubens，可以方便切换默认的 namespace；</p><p>安装：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt install -y kubectx</span><br></pre></td></tr></table></figure><br/><h3 id="2、nerdctl"><a href="#2、nerdctl" class="headerlink" title="2、nerdctl"></a><strong>2、nerdctl</strong></h3><p>nerdctl 可以提供在宿主机上类 docker 的操作（操作 containerd），可以提升用户体验：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /tmp</span><br><span class="line">wget https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-1.7.6-linux-amd64.tar.gz</span><br><span class="line">tar xf nerdctl-1.7.6-linux-amd64.tar.gz</span><br><span class="line"><span class="built_in">mv</span> nerdctl /usr/sbin</span><br></pre></td></tr></table></figure><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>参考文章：</p><ul><li><a href="https://isekiro.com/kubernetes%E5%9F%BA%E7%A1%80-debian-%E9%83%A8%E7%BD%B2k8s-1.28/">https://isekiro.com/kubernetes%E5%9F%BA%E7%A1%80-debian-%E9%83%A8%E7%BD%B2k8s-1.28/</a></li><li><a href="https://juejin.cn/post/7300419978486169641">https://juejin.cn/post/7300419978486169641</a></li><li><a href="https://www.cnblogs.com/5201351/p/17407406.html">https://www.cnblogs.com/5201351/p/17407406.html</a></li><li><a href="https://kubesphere.io/zh/docs/v4.1/02-quickstart/01-install-kubesphere/">https://kubesphere.io/zh/docs/v4.1/02-quickstart/01-install-kubesphere/</a></li></ul><p>源代码：</p><ul><li><a href="https://github.com/JasonkayZK/kubernetes-learn">https://github.com/JasonkayZK/kubernetes-learn</a></li></ul><br/>]]></content>
    
    
    <summary type="html">由于暑假到了以及天气原因，学校的k8s集群暂时关闭了，但是目前还是有使用k8s的需求，花了2个小时又重新搭了一下。由于国内网络的问题，导致github包、镜像都很难拉下来，因此本文的内容更适合国内需求环境。</summary>
    
    
    
    <category term="Kubernetes" scheme="https://jasonkayzk.github.io/cn/categories/Kubernetes/"/>
    
    
    <category term="Kubernetes" scheme="https://jasonkayzk.github.io/cn/tags/Kubernetes/"/>
    
    <category term="VMWare" scheme="https://jasonkayzk.github.io/cn/tags/VMWare/"/>
    
    <category term="Debian" scheme="https://jasonkayzk.github.io/cn/tags/Debian/"/>
    
  </entry>
  
  <entry>
    <title>分享两个服务器实用脚本：xsync和xcall</title>
    <link href="https://jasonkayzk.github.io/cn/2025/07/21/%E5%88%86%E4%BA%AB%E4%B8%A4%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%AE%9E%E7%94%A8%E8%84%9A%E6%9C%AC%EF%BC%9Axsync%E5%92%8Cxcall/"/>
    <id>https://jasonkayzk.github.io/cn/2025/07/21/%E5%88%86%E4%BA%AB%E4%B8%A4%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%AE%9E%E7%94%A8%E8%84%9A%E6%9C%AC%EF%BC%9Axsync%E5%92%8Cxcall/</id>
    <published>2025-07-21T02:20:51.000Z</published>
    <updated>2026-10-25T04:05:16.284Z</updated>
    
    <content type="html"><![CDATA[<p>如果同时需要维护多台服务器，可能会需要在多台服务器之间同步文件、执行命令。</p><p>本文介绍了两个简单的脚本实现这一功能！</p><p>源代码：</p><ul><li><a href="https://gist.github.com/JasonkayZK/e8bbe840d4b4d9d0ed15d4385e1c0a07">https://gist.github.com/JasonkayZK/e8bbe840d4b4d9d0ed15d4385e1c0a07</a></li><li><a href="https://gist.github.com/JasonkayZK/6847064a739bd08232e2da938d5e34ef">https://gist.github.com/JasonkayZK/6847064a739bd08232e2da938d5e34ef</a></li></ul><br/><span id="more"></span><h1 id="分享两个服务器实用脚本：xsync和xcall"><a href="#分享两个服务器实用脚本：xsync和xcall" class="headerlink" title="分享两个服务器实用脚本：xsync和xcall"></a><strong>分享两个服务器实用脚本：xsync和xcall</strong></h1><h2 id="文件同步：xsync"><a href="#文件同步：xsync" class="headerlink" title="文件同步：xsync"></a><strong>文件同步：xsync</strong></h2><h3 id="1、前置依赖"><a href="#1、前置依赖" class="headerlink" title="1、前置依赖"></a><strong>1、前置依赖</strong></h3><p>xsync 依赖于 rsync 工具，可以通过 yum 或者 apt 简单的安装：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt或yum install -y rsync</span><br></pre></td></tr></table></figure><p><strong>此外，还需要配置 SSH 无密码登录！</strong></p><br/><h3 id="2、编写脚本"><a href="#2、编写脚本" class="headerlink" title="2、编写脚本"></a><strong>2、编写脚本</strong></h3><p>脚本内容：</p><p>xsync</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># Dependency:</span></span><br><span class="line"><span class="comment">#  1. rsync: yum/apt install -y rsync</span></span><br><span class="line"><span class="comment">#  2. password-less SSH login</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 0. Define server list</span></span><br><span class="line">servers=(<span class="string">&quot;server-1&quot;</span> <span class="string">&quot;server-2&quot;</span> <span class="string">&quot;server-3&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 1. check param num</span></span><br><span class="line"><span class="keyword">if</span> [ <span class="variable">$#</span> -lt 1 ]; <span class="keyword">then</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;Not Enough Arguement!&quot;</span></span><br><span class="line">  <span class="built_in">exit</span> 1</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. traverse all machines</span></span><br><span class="line"><span class="keyword">for</span> host <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;servers[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;====================  <span class="variable">$host</span>  ====================&quot;</span></span><br><span class="line">  <span class="comment"># 3. traverse dir for each file</span></span><br><span class="line">  <span class="keyword">for</span> file <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$@</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">    <span class="comment"># 4. check file exist</span></span><br><span class="line">    <span class="keyword">if</span> [ -e <span class="string">&quot;<span class="variable">$file</span>&quot;</span> ]; <span class="keyword">then</span></span><br><span class="line">      <span class="comment"># 5. get parent dir</span></span><br><span class="line">      pdir=$(<span class="built_in">cd</span> -P <span class="string">&quot;<span class="subst">$(dirname <span class="string">&quot;<span class="variable">$file</span>&quot;</span>)</span>&quot;</span> &amp;&amp; <span class="built_in">pwd</span>)</span><br><span class="line">      <span class="comment"># 6. get file name</span></span><br><span class="line">      fname=$(<span class="built_in">basename</span> <span class="string">&quot;<span class="variable">$file</span>&quot;</span>)</span><br><span class="line">      ssh <span class="string">&quot;<span class="variable">$host</span>&quot;</span> <span class="string">&quot;mkdir -p <span class="variable">$pdir</span>&quot;</span></span><br><span class="line">      rsync -av <span class="string">&quot;<span class="variable">$pdir</span>/<span class="variable">$fname</span>&quot;</span> <span class="string">&quot;<span class="variable">$host</span>:<span class="variable">$pdir</span>&quot;</span></span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      <span class="built_in">echo</span> <span class="string">&quot;<span class="variable">$file</span> does not exist!&quot;</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">  <span class="keyword">done</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure><blockquote><p>  <strong>使用时，上面的文件中 servers 数组中的配置，为你服务器集群！</strong></p></blockquote><br/><h3 id="3、使用"><a href="#3、使用" class="headerlink" title="3、使用"></a><strong>3、使用</strong></h3><p>增加可执行权限、并将文件放在 PATH 下；</p><p>然后直接使用，例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xsync ~/.bashrc</span><br></pre></td></tr></table></figure><br/><h2 id="命令执行：xcall"><a href="#命令执行：xcall" class="headerlink" title="命令执行：xcall"></a><strong>命令执行：xcall</strong></h2><p>和 xsync 类似，编写：</p><p>xcall</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># Dependency: password-less SSH login</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Define server array (easily extensible)</span></span><br><span class="line">servers=(</span><br><span class="line">  <span class="string">&quot;server-1&quot;</span></span><br><span class="line">  <span class="string">&quot;server-2&quot;</span></span><br><span class="line">  <span class="string">&quot;server-3&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Check if command arguments are provided</span></span><br><span class="line"><span class="keyword">if</span> [ <span class="variable">$#</span> -eq 0 ]; <span class="keyword">then</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;Error: Please provide a command to execute&quot;</span> &gt;&amp;2</span><br><span class="line">  <span class="built_in">exit</span> 1</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Execute command across all servers</span></span><br><span class="line"><span class="keyword">for</span> server <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;servers[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;--------- <span class="variable">$server</span> ----------&quot;</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment"># Execute remote command and handle errors</span></span><br><span class="line">  <span class="keyword">if</span> ssh <span class="string">&quot;<span class="variable">$server</span>&quot;</span> <span class="string">&quot;$*&quot;</span>; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;✓ Command executed successfully&quot;</span></span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;✗ Command failed on server: <span class="variable">$server</span>&quot;</span> &gt;&amp;2</span><br><span class="line">    <span class="comment"># Uncomment below line to exit script on first failure</span></span><br><span class="line">    <span class="comment"># exit 1</span></span><br><span class="line">  <span class="keyword">fi</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure><p>使用也是类似：</p><p>增加可执行权限、并将文件放在 PATH 下；</p><p>然后直接使用，例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xcall <span class="built_in">ls</span></span><br></pre></td></tr></table></figure><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>源代码：</p><ul><li><a href="https://gist.github.com/JasonkayZK/e8bbe840d4b4d9d0ed15d4385e1c0a07">https://gist.github.com/JasonkayZK/e8bbe840d4b4d9d0ed15d4385e1c0a07</a></li><li><a href="https://gist.github.com/JasonkayZK/6847064a739bd08232e2da938d5e34ef">https://gist.github.com/JasonkayZK/6847064a739bd08232e2da938d5e34ef</a></li></ul><br/>]]></content>
    
    
    <summary type="html">如果同时需要维护多台服务器，可能会需要在多台服务器之间同步文件、执行命令。本文介绍了两个简单的脚本实现这一功能！</summary>
    
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/categories/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/tags/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
  </entry>
  
  <entry>
    <title>RSS订阅工具Folo使用</title>
    <link href="https://jasonkayzk.github.io/cn/2025/07/15/RSS%E8%AE%A2%E9%98%85%E5%B7%A5%E5%85%B7Folo%E4%BD%BF%E7%94%A8/"/>
    <id>https://jasonkayzk.github.io/cn/2025/07/15/RSS%E8%AE%A2%E9%98%85%E5%B7%A5%E5%85%B7Folo%E4%BD%BF%E7%94%A8/</id>
    <published>2025-07-15T13:30:21.000Z</published>
    <updated>2026-10-25T04:05:16.268Z</updated>
    
    <content type="html"><![CDATA[<p>之前一直使用的是Inoreader，也早就听说并且下载了Folo，但是一直没有时间切换；</p><p>今天有时间切换到了Folo，聊一下感受！</p><p>源代码：</p><ul><li><a href="https://github.com/RSSNext/Folo">https://github.com/RSSNext/Folo</a></li></ul><br/><span id="more"></span><h1 id="RSS订阅工具Folo使用"><a href="#RSS订阅工具Folo使用" class="headerlink" title="RSS订阅工具Folo使用"></a><strong>RSS订阅工具Folo使用</strong></h1><h2 id="零、Folo介绍"><a href="#零、Folo介绍" class="headerlink" title="零、Folo介绍"></a><strong>零、Folo介绍</strong></h2><p>Follow 是一款新兴且创新的 RSS 订阅工具；</p><p>除了具备传统 RSS 订阅器的所有基本功能外，Follow 还提供了一些额外的特色功能。</p><p>类似于 Inoreader，可以订阅 RSS，查看属于自己独一无二的信息流；</p><blockquote><p>  <strong>如果你还不了解 RSS，可以简单认为类似于将网页内容转为微信公众号订阅！</strong></p></blockquote><br/><h2 id="一、使用方法"><a href="#一、使用方法" class="headerlink" title="一、使用方法"></a><strong>一、使用方法</strong></h2><h3 id="1、下载-amp-注册"><a href="#1、下载-amp-注册" class="headerlink" title="1、下载&amp;注册"></a><strong>1、下载&amp;注册</strong></h3><p>Web 版：</p><ul><li><a href="https://app.follow.is/">https://app.follow.is/</a></li></ul><p>Mac、Win、Android：</p><ul><li><a href="https://github.com/RSSNext/Folo/releases">https://github.com/RSSNext/Folo/releases</a></li></ul><br/><h3 id="2、使用"><a href="#2、使用" class="headerlink" title="2、使用"></a><strong>2、使用</strong></h3><p>添加订阅即可！</p><p>添加方法：</p><ul><li>（1）搜索：输入关键词进行搜索；</li><li>（2）RSS订阅：输入RSS URL进行订阅；</li><li>（3）RSSHub订阅；</li><li>（4）RSS3</li></ul><ol start="5"><li>（5）UID：可以直接搜索订阅正在使用Follow的用户，输入对方的UID（在个人资料里设置的唯一标识）即可订阅；</li></ol><ul><li>（6）通过导入OPML文件（如Inoreader）订阅；</li></ul><blockquote><p>  <strong>强烈建议配合RSSHub使用（网页插件，可以探索当前页面的RSS源）：</strong></p><ul><li><a href="https://docs.rsshub.app/">https://docs.rsshub.app/</a></li></ul></blockquote><br/><h2 id="二、从Inoreader迁移"><a href="#二、从Inoreader迁移" class="headerlink" title="二、从Inoreader迁移"></a><strong>二、从Inoreader迁移</strong></h2><p>如果你根据 Folo 提供的：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">打开 https://www.inoreader.com/preferences/content</span><br><span class="line">切换到 &quot;SYSTEM FOLDERS&quot; 标签。</span><br><span class="line">点击 &quot;Newsfeed&quot; 右侧的 &quot;OPML&quot; 按钮。</span><br></pre></td></tr></table></figure><p>会要求你开通会员才能导出；</p><p>可以在设置的 <code>账号</code> 中，选择 <code>导出和备份</code>，此时会导出 xml 格式的文件！</p><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/inoreader-export-1.jpg" alt="inoreader-export-1.jpg"></p><p>随后，在导入时选择 <code>所有文件</code>，即可导入！</p><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/inoreader-export-2.jpg" alt="inoreader-export-2.jpg"></p><blockquote><p>  <strong>目前最多支持500个订阅，比 Inoreader 的150 个多很多了！</strong></p></blockquote><br/><h2 id="三、RSS所有者认证"><a href="#三、RSS所有者认证" class="headerlink" title="三、RSS所有者认证"></a><strong>三、RSS所有者认证</strong></h2><p>认证自己的订阅源。</p><h3 id="1、获取认证码"><a href="#1、获取认证码" class="headerlink" title="1、获取认证码"></a><strong>1、获取认证码</strong></h3><p>你在 Follow 中订阅自己的博客，再在 Follow 中右键点击订阅源，申请 Claim，便可以获取到认证码，例如：</p><p>This message is used to verify that this feed (feedId:57983956538829824) belongs to me (userId:81890745999218688). Join me in enjoying the next generation information browser <a href="https://folo.is">https://folo.is</a>.</p><h3 id="2、验证认证码"><a href="#2、验证认证码" class="headerlink" title="2、验证认证码"></a><strong>2、验证认证码</strong></h3><p>在你的博客，写入一篇文章，贴入认证码并发布；然后在 Follow 中再次申请 Claim 即可认证。 认证过后，认证码的信息便可以删除；此处予以修改、保留，方便其他读者认证时参考使用。 </p><p>当然，你也可以通过一个 Telegram 频道，来进行 Follow 的认证。</p><br/><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a><strong>后记</strong></h2><p>更多的内容可以阅读：</p><ul><li><a href="https://yinji.org/5317.html">《使用 Follow 的第 50 天：RSS 迎来又一春？》</a></li></ul><p>后续也会在博客分享一些我的订阅源，敬请期待～</p><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>源代码：</p><ul><li><a href="https://github.com/RSSNext/Folo">https://github.com/RSSNext/Folo</a></li></ul><p>RSS相关服务：</p><ul><li><a href="https://link.zhihu.com/?target=https%3A//docs.rsshub.app/">RSSHub</a></li><li><a href="https://link.zhihu.com/?target=https%3A//tg.i-c-a.su/">Telegram RSS / JSON generator</a></li><li><a href="https://link.zhihu.com/?target=https%3A//github.com/damoeb/rss-proxy">RSS-proxy</a></li><li><a href="https://link.zhihu.com/?target=https%3A//github.com/firmianay/yarb">yarb (Yet Another Rss Bot)</a></li><li><a href="https://link.zhihu.com/?target=https%3A//github.com/aboutrss/ALL-about-RSS">ALL-about-RSS</a></li><li><a href="https://link.zhihu.com/?target=https%3A//rss.lilydjwg.me/">各种转 RSS 服务</a></li><li><a href="https://link.zhihu.com/?target=https%3A//diff.blog/">diff.blog</a></li><li><a href="https://link.zhihu.com/?target=https%3A//kill-the-newsletter.com/">Kill the Newsletter</a></li></ul><p>参考文章：</p><ul><li><a href="https://zhuanlan.zhihu.com/p/781349659">https://zhuanlan.zhihu.com/p/781349659</a></li><li><a href="https://yinji.org/5317.html">https://yinji.org/5317.html</a></li></ul><br/>]]></content>
    
    
    <summary type="html">之前一直使用的是Inoreader，也早就听说并且下载了Folo，但是一直没有时间切换。今天有时间切换到了Folo，聊一下感受！</summary>
    
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/categories/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/tags/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    <category term="RSS" scheme="https://jasonkayzk.github.io/cn/tags/RSS/"/>
    
  </entry>
  
  <entry>
    <title>多平台消息推送工具ntfy使用</title>
    <link href="https://jasonkayzk.github.io/cn/2025/07/15/%E5%A4%9A%E5%B9%B3%E5%8F%B0%E6%B6%88%E6%81%AF%E6%8E%A8%E9%80%81%E5%B7%A5%E5%85%B7ntfy%E4%BD%BF%E7%94%A8/"/>
    <id>https://jasonkayzk.github.io/cn/2025/07/15/%E5%A4%9A%E5%B9%B3%E5%8F%B0%E6%B6%88%E6%81%AF%E6%8E%A8%E9%80%81%E5%B7%A5%E5%85%B7ntfy%E4%BD%BF%E7%94%A8/</id>
    <published>2025-07-15T08:52:51.000Z</published>
    <updated>2026-10-25T04:05:16.287Z</updated>
    
    <content type="html"><![CDATA[<p>ntfy是一个开源的多平台消息推送工具，可以通过HTTP请求发送通知到手机或桌面。</p><p>本文总结了ntfy的安装、配置和使用方法。</p><p>官方仓库：</p><ul><li><a href="https://github.com/binwiederhier/ntfy">https://github.com/binwiederhier/ntfy</a></li></ul><br/><span id="more"></span><h1 id="ntfy使用"><a href="#ntfy使用" class="headerlink" title="ntfy使用"></a><strong>ntfy使用</strong></h1><h2 id="一、简介"><a href="#一、简介" class="headerlink" title="一、简介"></a><strong>一、简介</strong></h2><p>ntfy（发音为“notify”）是一个简单的基于HTTP的发布-订阅通知服务。通过ntfy，可以使用PUT/POST请求从任何计算机的脚本发送通知到手机或桌面，而无需注册或支付费用。</p><p>同时ntfy是开源的，可以轻松自托管。</p><p>ntfy提供免费的公共实例：ntfy.sh，也有Android和iOS应用可用；</p><p>主要特点：</p><ul><li><strong>简单易用</strong>：通过curl等工具发送通知。</li><li><strong>自托管</strong>：可以部署自己的实例。</li><li><strong>多平台</strong>：支持Android、iOS、Web等。</li><li><strong>访问控制</strong>：支持用户认证和ACL。</li></ul><br/><h2 id="二、使用"><a href="#二、使用" class="headerlink" title="二、使用"></a><strong>二、使用</strong></h2><h3 id="1、发送通知"><a href="#1、发送通知" class="headerlink" title="1、发送通知"></a><strong>1、发送通知</strong></h3><p>使用curl：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -d <span class="string">&quot;Hello from ntfy&quot;</span> ntfy.sh/mytopic</span><br></pre></td></tr></table></figure><h3 id="2、订阅主题"><a href="#2、订阅主题" class="headerlink" title="2、订阅主题"></a><strong>2、订阅主题</strong></h3><p>在APP或Web订阅主题接收通知。</p><br/><h2 id="三、自部署"><a href="#三、自部署" class="headerlink" title="三、自部署"></a><strong>三、自部署</strong></h2><p>参考：</p><ul><li><a href="https://blog.xiaoz.org/archives/20400">https://blog.xiaoz.org/archives/20400</a></li><li><a href="https://k1r.in/posts/notify-ntfy/">https://k1r.in/posts/notify-ntfy/</a></li></ul><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>参考：</p><ul><li><a href="https://github.com/binwiederhier/ntfy">https://github.com/binwiederhier/ntfy</a></li><li><a href="https://k1r.in/posts/notify-ntfy/">https://k1r.in/posts/notify-ntfy/</a></li><li><a href="https://blog.7theaven.top/2023/06/11/%E4%BD%BF%E7%94%A8-ntfy-%E8%87%AA%E5%BB%BA%E6%B6%88%E6%81%AF%E6%8E%A8%E9%80%81%E6%9C%8D%E5%8A%A1/#toc-head-1">https://blog.7theaven.top/2023/06/11/%E4%BD%BF%E7%94%A8-ntfy-%E8%87%AA%E5%BB%BA%E6%B6%88%E6%81%AF%E6%8E%A8%E9%80%81%E6%9C%8D%E5%8A%A1/#toc-head-1</a></li><li><a href="https://blog.xiaoz.org/archives/20400">https://blog.xiaoz.org/archives/20400</a></li></ul><br/>]]></content>
    
    
    <summary type="html">ntfy是一个开源的多平台消息推送工具，可以通过HTTP请求发送通知到手机或桌面。本文总结了ntfy的安装、配置和使用方法。</summary>
    
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/categories/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/tags/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    <category term="推送" scheme="https://jasonkayzk.github.io/cn/tags/%E6%8E%A8%E9%80%81/"/>
    
    <category term="ntfy" scheme="https://jasonkayzk.github.io/cn/tags/ntfy/"/>
    
  </entry>
  
  <entry>
    <title>AppleScript介绍与简单实战</title>
    <link href="https://jasonkayzk.github.io/cn/2025/07/15/AppleScript%E4%BB%8B%E7%BB%8D%E4%B8%8E%E7%AE%80%E5%8D%95%E5%AE%9E%E6%88%98/"/>
    <id>https://jasonkayzk.github.io/cn/2025/07/15/AppleScript%E4%BB%8B%E7%BB%8D%E4%B8%8E%E7%AE%80%E5%8D%95%E5%AE%9E%E6%88%98/</id>
    <published>2025-07-15T06:23:25.000Z</published>
    <updated>2026-10-25T04:05:16.253Z</updated>
    
    <content type="html"><![CDATA[<p>AppleScript是macOS内置的脚本语言，可以自动化操作应用程序。本文介绍了AppleScript的基本概念、语法和一个简单实战示例。</p><br/><span id="more"></span><h1 id="AppleScript介绍与简单实战"><a href="#AppleScript介绍与简单实战" class="headerlink" title="AppleScript介绍与简单实战"></a><strong>AppleScript介绍与简单实战</strong></h1><h2 id="一、什么是AppleScript"><a href="#一、什么是AppleScript" class="headerlink" title="一、什么是AppleScript"></a><strong>一、什么是AppleScript</strong></h2><p>AppleScript是苹果公司推出的一种脚本语言，内置于macOS中，可以直接操作和控制macOS及其应用程序。它是一个实现macOS自动化的强大工具，AppleScript的前身是HyperCard所使用的脚本语言HyperTalk。</p><p>与其他脚本语言如Python和JavaScript相比，AppleScript最显著的特点是能够控制其他macOS上的应用程序。通过AppleScript，我们可以完成一些繁琐重复的工作。其语法简单，接近自然语言，就像在和系统对话一样。此外，系统提供了语法查询字典，方便查询语法。</p><br/><h2 id="二、基础语法"><a href="#二、基础语法" class="headerlink" title="二、基础语法"></a><strong>二、基础语法</strong></h2><p>按照惯例，用AppleScript写一个Hello World：</p><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">display dialog</span> <span class="string">&quot;Hello, world!&quot;</span></span><br></pre></td></tr></table></figure><p>命令行执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">osascript -e <span class="string">&#x27;display dialog &quot;Hello, world!&quot;&#x27;</span></span><br></pre></td></tr></table></figure><p>运行后，系统会弹出“Hello, world!”的弹窗。</p><br/><p>下面介绍几种常用语法：</p><h3 id="1、告诉应用做某事"><a href="#1、告诉应用做某事" class="headerlink" title="1、告诉应用做某事"></a><strong>1、告诉应用做某事</strong></h3><p>AppleScript的语法接近自然语言，例如：</p><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">tell</span> <span class="built_in">application</span> <span class="string">&quot;Safari&quot;</span></span><br><span class="line">    <span class="built_in">activate</span></span><br><span class="line">    open location <span class="string">&quot;https://qq.com/&quot;</span></span><br><span class="line"><span class="keyword">end</span> <span class="keyword">tell</span></span><br></pre></td></tr></table></figure><p>这告诉Safari启动并打开指定网址。</p><h3 id="2、设置变量"><a href="#2、设置变量" class="headerlink" title="2、设置变量"></a><strong>2、设置变量</strong></h3><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">set</span> qq <span class="keyword">to</span> <span class="string">&quot;https://qq.com/&quot;</span></span><br><span class="line"><span class="keyword">tell</span> <span class="built_in">application</span> <span class="string">&quot;Safari&quot;</span></span><br><span class="line">    <span class="built_in">activate</span></span><br><span class="line">    open location qq</span><br><span class="line"><span class="keyword">end</span> <span class="keyword">tell</span></span><br></pre></td></tr></table></figure><br/><h3 id="3、条件语句"><a href="#3、条件语句" class="headerlink" title="3、条件语句"></a><strong>3、条件语句</strong></h3><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> num &gt; <span class="number">2</span> <span class="keyword">then</span></span><br><span class="line">    // ...</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">    // ...</span><br><span class="line"><span class="keyword">end</span> <span class="keyword">if</span></span><br></pre></td></tr></table></figure><br/><h3 id="4、循环语句"><a href="#4、循环语句" class="headerlink" title="4、循环语句"></a><strong>4、循环语句</strong></h3><figure class="highlight applescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">repeat</span> <span class="keyword">with</span> num <span class="keyword">in</span> &#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>&#125;</span><br><span class="line">    <span class="built_in">display dialog</span> <span class="string">&quot;hello, world&quot;</span></span><br><span class="line"><span class="keyword">end</span> <span class="keyword">repeat</span></span><br></pre></td></tr></table></figure><br/><h3 id="5、模拟点击和输入"><a href="#5、模拟点击和输入" class="headerlink" title="5、模拟点击和输入"></a><strong>5、模拟点击和输入</strong></h3><p>可以使用<code>click</code>命令模拟点击，或<code>keystroke</code>输入文本。</p><br/><h2 id="三、简单实战：命令完成后显示通知"><a href="#三、简单实战：命令完成后显示通知" class="headerlink" title="三、简单实战：命令完成后显示通知"></a><strong>三、简单实战：命令完成后显示通知</strong></h2><p>执行以下命令可以展示一条通知：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">osascript -e <span class="string">&#x27;display notification &quot;The command finished&quot; with title &quot;Success&quot;&#x27;</span></span><br></pre></td></tr></table></figure><p>在.zshrc中定义一个函数：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">notifyResult</span></span> () &#123;</span><br><span class="line">  <span class="keyword">if</span> [ $? -eq 0 ]; <span class="keyword">then</span></span><br><span class="line">    osascript -e <span class="string">&#x27;display notification &quot;The command finished&quot; with title &quot;Success&quot;&#x27;</span></span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    osascript -e <span class="string">&#x27;display notification &quot;The command failed&quot; with title &quot;Failed&quot;&#x27;</span></span><br><span class="line">  <span class="keyword">fi</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>运行长时间命令时：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">some_program; notifyResult</span><br></pre></td></tr></table></figure><p>执行完后会收到通知是否执行成功！</p><blockquote><p>  可以设置通知音效：</p><ul><li><a href="https://strdr4605.com/mac-os-notify-when-the-terminal-command-is-finished">MacOS: notify when the terminal command is finished</a></li></ul></blockquote><br/><h2 id="四、一些常用脚本"><a href="#四、一些常用脚本" class="headerlink" title="四、一些常用脚本"></a><strong>四、一些常用脚本</strong></h2><h3 id="1、通过参数发送系统通知"><a href="#1、通过参数发送系统通知" class="headerlink" title="1、通过参数发送系统通知"></a><strong>1、通过参数发送系统通知</strong></h3><blockquote><p>  源代码：</p><ul><li><a href="https://gist.github.com/JasonkayZK/c32cc4af8582b12d785619f6c999999f">https://gist.github.com/JasonkayZK/c32cc4af8582b12d785619f6c999999f</a></li></ul></blockquote><p>代码如下：</p><p>sys-notify</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 帮助函数</span></span><br><span class="line"><span class="function"><span class="title">show_help</span></span>() &#123;</span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;Usage: <span class="variable">$0</span> [Option] [message]&quot;</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;Show system notification&quot;</span></span><br><span class="line">    <span class="built_in">echo</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;Option:&quot;</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;  -h, --help         Show help info&quot;</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;  -t, --title TITLE  Set notification title (Default: Notify)&quot;</span></span><br><span class="line">    <span class="built_in">exit</span> 0</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 默认值</span></span><br><span class="line">title=<span class="string">&quot;Notify&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 解析命令行参数</span></span><br><span class="line"><span class="keyword">while</span> [[ <span class="variable">$#</span> -gt 0 ]]; <span class="keyword">do</span></span><br><span class="line">    <span class="keyword">case</span> <span class="string">&quot;<span class="variable">$1</span>&quot;</span> <span class="keyword">in</span></span><br><span class="line">        -h|--<span class="built_in">help</span>)</span><br><span class="line">            show_help</span><br><span class="line">            ;;</span><br><span class="line">        -t|--title)</span><br><span class="line">            <span class="keyword">if</span> [[ -z <span class="string">&quot;<span class="variable">$2</span>&quot;</span> ]]; <span class="keyword">then</span></span><br><span class="line">                <span class="built_in">echo</span> <span class="string">&quot;错误: --title 需要一个参数&quot;</span> &gt;&amp;2</span><br><span class="line">                <span class="built_in">exit</span> 1</span><br><span class="line">            <span class="keyword">fi</span></span><br><span class="line">            title=<span class="string">&quot;<span class="variable">$2</span>&quot;</span></span><br><span class="line">            <span class="built_in">shift</span> 2</span><br><span class="line">            ;;</span><br><span class="line">        *)</span><br><span class="line">            <span class="comment"># 第一个非选项参数视为消息内容</span></span><br><span class="line">            message=<span class="string">&quot;<span class="variable">$1</span>&quot;</span></span><br><span class="line">            <span class="built_in">shift</span></span><br><span class="line">            <span class="built_in">break</span></span><br><span class="line">            ;;</span><br><span class="line">    <span class="keyword">esac</span></span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 如果没有提供消息内容，则从标准输入读取</span></span><br><span class="line"><span class="keyword">if</span> [[ -z <span class="string">&quot;<span class="variable">$message</span>&quot;</span> ]]; <span class="keyword">then</span></span><br><span class="line">    <span class="keyword">if</span> [[ -t 0 ]]; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&quot;错误: 没有提供消息内容&quot;</span> &gt;&amp;2</span><br><span class="line">        show_help</span><br><span class="line">        <span class="built_in">exit</span> 1</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        message=$(<span class="built_in">cat</span>)</span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 发送通知</span></span><br><span class="line"><span class="keyword">case</span> <span class="string">&quot;<span class="subst">$(uname -s)</span>&quot;</span> <span class="keyword">in</span></span><br><span class="line">    Darwin)</span><br><span class="line">        <span class="comment"># macOS 使用 AppleScript</span></span><br><span class="line">        osascript -e <span class="string">&quot;display notification \&quot;<span class="variable">$message</span>\&quot; with title \&quot;<span class="variable">$title</span>\&quot;&quot;</span></span><br><span class="line">        ;;</span><br><span class="line">    Linux)</span><br><span class="line">        <span class="comment"># Linux 使用 notify-send (libnotify)</span></span><br><span class="line">        <span class="keyword">if</span> <span class="built_in">command</span> -v notify-send &amp;&gt;/dev/null; <span class="keyword">then</span></span><br><span class="line">            notify-send <span class="string">&quot;<span class="variable">$title</span>&quot;</span> <span class="string">&quot;<span class="variable">$message</span>&quot;</span></span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            <span class="built_in">echo</span> <span class="string">&quot;错误: 未找到 notify-send 命令。请安装 libnotify 包。&quot;</span> &gt;&amp;2</span><br><span class="line">            <span class="built_in">exit</span> 1</span><br><span class="line">        <span class="keyword">fi</span></span><br><span class="line">        ;;</span><br><span class="line">    *)</span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&quot;错误: 不支持的操作系统&quot;</span> &gt;&amp;2</span><br><span class="line">        <span class="built_in">exit</span> 1</span><br><span class="line">        ;;</span><br><span class="line"><span class="keyword">esac</span>    </span><br></pre></td></tr></table></figure><p>准备：</p><ul><li>编写 <code>sys-notify</code>；</li><li>增加可执行权限 <code>chmod +x sys-notify</code>；</li><li>加入到 PATH 环境变量；</li></ul><p>使用方法：</p><ul><li>基本用法：<code>sys-notify &quot;操作已完成&quot;</code></li><li>自定义标题：<code>sys-notify -t &quot;操作结果&quot; &quot;操作已完成&quot;</code></li><li>从标准输入读取内容：<code>echo &quot;操作已完成&quot; | sys-notify -t &quot;操作结果&quot;</code></li></ul><br/><h3 id="2、命令完成后展示结果"><a href="#2、命令完成后展示结果" class="headerlink" title="2、命令完成后展示结果"></a><strong>2、命令完成后展示结果</strong></h3><blockquote><p>  源代码：</p><ul><li><a href="https://gist.github.com/JasonkayZK/d5c4e3adadf3478ded5896becf01f08c">https://gist.github.com/JasonkayZK/d5c4e3adadf3478ded5896becf01f08c</a></li></ul></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">notifyResult</span></span> () &#123;</span><br><span class="line">  <span class="keyword">if</span> [ $? -eq 0 ]; <span class="keyword">then</span></span><br><span class="line">    osascript -e <span class="string">&#x27;display notification &quot;The command finished&quot; with title &quot;Success&quot;&#x27;</span></span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    osascript -e <span class="string">&#x27;display notification &quot;The command failed&quot; with title &quot;Failed&quot;&#x27;</span></span><br><span class="line">  <span class="keyword">fi</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在运行某些需要比较长时间的程序时，执行以下命令：</p><figure class="highlight node-repl"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">some_program; notifyResult</span><br></pre></td></tr></table></figure><br/><h2 id="五、后记"><a href="#五、后记" class="headerlink" title="五、后记"></a><strong>五、后记</strong></h2><p>AppleScript是一个简单而强大的工具，能自动化macOS操作；</p><p>更多内容可参考附录链接；</p><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>源代码：</p><ul><li><a href="https://gist.github.com/JasonkayZK/c32cc4af8582b12d785619f6c999999f">https://gist.github.com/JasonkayZK/c32cc4af8582b12d785619f6c999999f</a></li><li><a href="https://gist.github.com/JasonkayZK/d5c4e3adadf3478ded5896becf01f08c">https://gist.github.com/JasonkayZK/d5c4e3adadf3478ded5896becf01f08c</a></li></ul><p>官方文档：</p><ul><li><a href="https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/introduction/ASLR_intro.html">https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/introduction/ASLR_intro.html</a></li></ul><p>参考文章：</p><ul><li><a href="https://zhuanlan.zhihu.com/p/149893274">https://zhuanlan.zhihu.com/p/149893274</a></li><li><a href="https://ameow.xyz/archives/display-notification-after-command-finishes-macos">https://ameow.xyz/archives/display-notification-after-command-finishes-macos</a></li></ul><br/>]]></content>
    
    
    <summary type="html">AppleScript是MacOS内置的脚本语言，可以自动化操作应用程序。本文介绍了AppleScript的基本概念、语法和一个简单实战示例。</summary>
    
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/categories/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/tags/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    <category term="AppleScript" scheme="https://jasonkayzk.github.io/cn/tags/AppleScript/"/>
    
    <category term="MacOS" scheme="https://jasonkayzk.github.io/cn/tags/MacOS/"/>
    
  </entry>
  
  <entry>
    <title>uv使用</title>
    <link href="https://jasonkayzk.github.io/cn/2025/07/14/uv%E4%BD%BF%E7%94%A8/"/>
    <id>https://jasonkayzk.github.io/cn/2025/07/14/uv%E4%BD%BF%E7%94%A8/</id>
    <published>2025-07-14T06:02:30.000Z</published>
    <updated>2026-10-25T04:05:16.274Z</updated>
    
    <content type="html"><![CDATA[<p><code>uv</code> 是一个用 Rust 编写的、速度极快的 Python 包和项目管理工具，由 <code>ruff</code> 的作者开发。它的目标是成为 <code>pip</code>、<code>venv</code>、<code>virtualenv</code> 和 <code>pip-tools</code> 等工具的直接替代品，提供一个统一、快速且易于使用的体验。</p><p>本文总结了如何安装和使用 <code>uv</code>。</p><p>官方仓库：</p><ul><li><a href="https://github.com/astral-sh/uv">https://github.com/astral-sh/uv</a></li></ul><br/><span id="more"></span><h1 id="uv使用"><a href="#uv使用" class="headerlink" title="uv使用"></a><strong>uv使用</strong></h1><h2 id="一、简介"><a href="#一、简介" class="headerlink" title="一、简介"></a><strong>一、简介</strong></h2><p>如果你对 Python 的包管理生态有所了解，你可能用过 <code>pip</code> 来安装包，用 <code>venv</code> 或 <code>virtualenv</code> 来创建虚拟环境，用 <code>pip-tools</code> 来锁定依赖。这些工具各司其职，但组合使用起来有时会显得有些繁琐。</p><p><code>uv</code> 的出现就是为了解决这个问题。它将包安装、虚拟环境管理和依赖解析等功能集成到了一个单一的命令行工具中，并且性能极高。</p><p><strong>主要特点：</strong></p><ul><li><strong>极速：</strong> <code>uv</code> 利用了先进的依赖解析算法和全局缓存，安装和解析包的速度比 <code>pip</code> 快得多。</li><li><strong>一体化：</strong> 无需在 <code>pip</code> 和 <code>venv</code> 之间切换，<code>uv</code> 提供了统一的命令来处理大多数包和环境管理任务。</li><li><strong>直接替代：</strong> <code>uv</code> 的命令设计与 <code>pip</code> 非常相似（例如 <code>uv pip install</code>），使得迁移成本非常低。</li><li><strong>依赖锁定：</strong> 内置了类似 <code>pip-tools</code> 的功能，可以从 <code>pyproject.toml</code> 或 <code>requirements.in</code> 文件编译生成锁定的 <code>requirements.txt</code> 文件。</li></ul><br/><h2 id="二、安装"><a href="#二、安装" class="headerlink" title="二、安装"></a><strong>二、安装</strong></h2><p><code>uv</code> 提供了多种安装方式：</p><h4 id="macOS-和-Linux"><a href="#macOS-和-Linux" class="headerlink" title="macOS 和 Linux"></a><strong>macOS 和 Linux</strong></h4><p>使用 <code>curl</code>:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -LsSf https://astral.sh/uv/install.sh | sh</span><br></pre></td></tr></table></figure><h4 id="Windows"><a href="#Windows" class="headerlink" title="Windows"></a><strong>Windows</strong></h4><p>使用 PowerShell:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">powershell -ExecutionPolicy ByPass -c <span class="string">&quot;irm https://astral.sh/uv/install.ps1 | iex&quot;</span></span><br></pre></td></tr></table></figure><h4 id="其他方式"><a href="#其他方式" class="headerlink" title="其他方式"></a><strong>其他方式</strong></h4><p>也可以通过 <code>pip</code>、<code>brew</code> 等包管理器安装：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 通过 pip</span></span><br><span class="line">pip install uv</span><br><span class="line"></span><br><span class="line"><span class="comment"># 通过 Homebrew</span></span><br><span class="line">brew install uv</span><br></pre></td></tr></table></figure><p>安装完成后，可以通过 <code>uv --version</code> 来验证是否成功。</p><br/><h2 id="三、基本使用"><a href="#三、基本使用" class="headerlink" title="三、基本使用"></a><strong>三、基本使用</strong></h2><p><code>uv</code> 的使用非常直观，特别是对于熟悉 <code>pip</code> 和 <code>venv</code> 的用户。</p><h3 id="1、管理python版本"><a href="#1、管理python版本" class="headerlink" title="1、管理python版本"></a><strong>1、管理python版本</strong></h3><p>使用如下命令，显示出当前环境中所有可用的python版本（包括已经安装的和可以安装的）</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv python list</span><br></pre></td></tr></table></figure><p>如果需要安装其他版本的python，使用如下命令</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv python install 3.12</span><br></pre></td></tr></table></figure><p>除了标准python之外，还可以安装其他的Python实现，比如PyPy实现的python：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv python install pypy@3.10</span><br></pre></td></tr></table></figure><p>查找某个python版本的路径：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">❯ uv python find 3.10</span><br><span class="line">/Library/Frameworks/Python.framework/Versions/3.10/bin/python3.10</span><br></pre></td></tr></table></figure><br/><h2 id="四、单个脚本使用"><a href="#四、单个脚本使用" class="headerlink" title="四、单个脚本使用"></a><strong>四、单个脚本使用</strong></h2><blockquote><p>  参考：</p><ul><li><a href="https://github.com/astral-sh/uv?tab=readme-ov-file#scripts">https://github.com/astral-sh/uv?tab=readme-ov-file#scripts</a></li></ul></blockquote><p>uv 可以管理单文件脚本的依赖项和环境；</p><p>例如：创建一个新脚本并添加内联元数据来声明其依赖项：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">echo</span> <span class="string">&#x27;import requests; print(requests.get(&quot;https://astral.sh&quot;))&#x27;</span> &gt; example.py</span><br><span class="line"></span><br><span class="line">$ uv add --script example.py requests</span><br><span class="line">Updated `example.py`</span><br></pre></td></tr></table></figure><p>然后，在隔离的虚拟环境中运行脚本：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ uv run example.py</span><br><span class="line">Reading inline script metadata from: example.py</span><br><span class="line">Installed 5 packages <span class="keyword">in</span> 12ms</span><br><span class="line">&lt;Response [200]&gt;</span><br></pre></td></tr></table></figure><br/><h2 id="五、项目中使用"><a href="#五、项目中使用" class="headerlink" title="五、项目中使用"></a><strong>五、项目中使用</strong></h2><h3 id="1、选用python版本"><a href="#1、选用python版本" class="headerlink" title="1、选用python版本"></a><strong>1、选用python版本</strong></h3><p>在具体的某个项目中，进入项目目录，使用如下命令指定选用的python版本：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv python pin 版本号</span><br></pre></td></tr></table></figure><p>这个命令会在指定目录下创建一个<code>.python-version</code>文件，内容如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">❯ uv python pin 3.10                                    </span><br><span class="line">Pinned `.python-version` to `3.10`</span><br><span class="line"></span><br><span class="line">❯ <span class="built_in">cat</span> .python-version  </span><br><span class="line">3.10</span><br></pre></td></tr></table></figure><blockquote><p>   <strong>注意：这里选用的python版本只和uv管理的虚拟环境有关系，和我们全局的python、python3命令都没有关系！</strong></p></blockquote><br/><h3 id="2、创建虚拟环境"><a href="#2、创建虚拟环境" class="headerlink" title="2、创建虚拟环境"></a>2、创建虚拟环境</h3><p>创建项目有两种方式，第一种方式，先创建好项目目录，然后设置python版本并初始化uv虚拟环境：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">uv python pin 3.10</span><br><span class="line">uv init <span class="comment"># 初始化</span></span><br></pre></td></tr></table></figure><p>执行了uv init之后，会在当前目录下创建几个文件，同时也会在当前目录下执行git init创建出一个新的git仓库来：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">❯ uv python pin 3.13</span><br><span class="line">Pinned `.python-version` to `3.13`</span><br><span class="line"></span><br><span class="line">❯ uv init</span><br><span class="line">Initialized project `test-code`</span><br><span class="line">                                         </span><br><span class="line">❯ <span class="built_in">ls</span></span><br><span class="line">README.md      main.py        pyproject.toml</span><br></pre></td></tr></table></figure><p>另外一个方式是在init之后添加一个项目名，会自动创建项目文件夹</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv init 项目名</span><br></pre></td></tr></table></figure><blockquote><p>  <strong>如果需要指定特定python版本，建议使用第一种方式来创建项目；</strong></p><p>  <strong>否则还需要手动修改pyproject.toml配置文件里面需要的python版本。</strong></p></blockquote><br/><h3 id="3、添加依赖"><a href="#3、添加依赖" class="headerlink" title="3、添加依赖"></a><strong>3、添加依赖</strong></h3><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv add 依赖项</span><br></pre></td></tr></table></figure><p>比如添加requests库：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv add requests</span><br></pre></td></tr></table></figure><p>还可以指定具体版本：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv add requests==版本号</span><br></pre></td></tr></table></figure><p>执行了这个命令后，会在当前目录下创建<code>.venv</code>虚拟环境目录（在vscode里面可以选择这个目录作为虚拟环境，否则代码解析会有问题）；</p><p>并添加我们要的依赖项，同时会新增一个uv.lock文件，用于存放依赖项版本相关的信息。</p><p>pyproject.toml文件中的dependencies字段也会包含需要的依赖项：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">❯ uv add requests</span><br><span class="line">Using CPython 3.13.1 interpreter at: /opt/homebrew/opt/python@3.13/bin/python3.13</span><br><span class="line">Creating virtual environment at: .venv</span><br><span class="line">Resolved 6 packages <span class="keyword">in</span> 13.85s</span><br><span class="line">Prepared 5 packages <span class="keyword">in</span> 5.55s</span><br><span class="line">Installed 5 packages <span class="keyword">in</span> 13ms</span><br><span class="line"> + certifi==2025.1.31</span><br><span class="line"> + charset-normalizer==3.4.1</span><br><span class="line"> + idna==3.10</span><br><span class="line"> + requests==2.32.3</span><br><span class="line"> + urllib3==2.4.0</span><br></pre></td></tr></table></figure><p>而且，从这个输出中也能看到，它自动使用了<code>.python-version</code>指定的3.13版本的python；</p><p>和当前全局配置下的python3指向什么版本没有关系（全局python3指向的是3.10版本）；</p><br/><h3 id="4、运行程序"><a href="#4、运行程序" class="headerlink" title="4、运行程序"></a>4、运行程序</h3><p>依赖添加好后，就可以使用uv来运行python程序了</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv run 程序文件名 [命令行参数]</span><br></pre></td></tr></table></figure><p>uv会自动按照我们的配置来运行程序，无序我们手动维护依赖项，也不需要手动去source各式各样的虚拟环境！</p><br/><h3 id="5、其他机器中配置环境"><a href="#5、其他机器中配置环境" class="headerlink" title="5、其他机器中配置环境"></a><strong>5、其他机器中配置环境</strong></h3><p>在其他机器拉取代码后，也需要配置虚拟环境、下载项目依赖；</p><p>如果使用 uv 进行管理只需要一步：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv <span class="built_in">sync</span></span><br></pre></td></tr></table></figure><p>即可同步环境，随后使用：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv run 程序文件名 [命令行参数]</span><br></pre></td></tr></table></figure><p>即可运行！</p><br/><h2 id="六、uvx命令"><a href="#六、uvx命令" class="headerlink" title="六、uvx命令"></a><strong>六、uvx命令</strong></h2><p>随着uv下载的还有一个uvx命令，和 <code>pipx</code> 类似；</p><p>使用 uvx 命令可以执行或安装一些使用 Python 编写的命令行工具；</p><blockquote><p>  参考：</p><ul><li><a href="https://github.com/astral-sh/uv?tab=readme-ov-file#tools">https://github.com/astral-sh/uv?tab=readme-ov-file#tools</a></li></ul></blockquote><h3 id="1、临时使用命令"><a href="#1、临时使用命令" class="headerlink" title="1、临时使用命令"></a><strong>1、临时使用命令</strong></h3><p>例如，在一个临时环境中执行一个工具：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">➜  blog git:(save) ✗ uvx pycowsay <span class="string">&#x27;hello world!&#x27;</span></span><br><span class="line">Installed 1 package <span class="keyword">in</span> 6ms</span><br><span class="line">/Users/zk/.cache/uv/archive-v0/C-520Z4yR2_MYfgN_xvWl/lib/python3.12/site-packages/pycowsay/main.py:23: SyntaxWarning: invalid escape sequence <span class="string">&#x27;\ &#x27;</span></span><br><span class="line">  <span class="string">&quot;&quot;</span><span class="string">&quot;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">  ------------</span></span><br><span class="line"><span class="string">&lt; hello world! &gt;</span></span><br><span class="line"><span class="string">  ------------</span></span><br><span class="line"><span class="string">   \   ^__^</span></span><br><span class="line"><span class="string">    \  (oo)\_______</span></span><br><span class="line"><span class="string">       (__)\       )\/\</span></span><br><span class="line"><span class="string">           ||----w |</span></span><br><span class="line"><span class="string">           ||     ||</span></span><br></pre></td></tr></table></figure><p>可以看到，工具会被临时下载到 <code>~/.cache/uv</code> 中！</p><br/><h3 id="2、全局安装工具"><a href="#2、全局安装工具" class="headerlink" title="2、全局安装工具"></a><strong>2、全局安装工具</strong></h3><p>也可以全局安装一个工具：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">$ uv tool install ruff</span><br><span class="line">Resolved 1 package <span class="keyword">in</span> 6ms</span><br><span class="line">Installed 1 package <span class="keyword">in</span> 2ms</span><br><span class="line"> + ruff==0.5.0</span><br><span class="line">Installed 1 executable: ruff</span><br><span class="line"></span><br><span class="line">$ ruff --version</span><br><span class="line">ruff 0.5.0</span><br></pre></td></tr></table></figure><blockquote><p>  参考：</p><ul><li><a href="https://docs.astral.sh/uv/guides/tools/">tools documentation</a></li></ul></blockquote><br/><p>uvx命令本质上是uv tool run命令的别名：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">uvx python main.py</span><br><span class="line"><span class="comment"># 等价于</span></span><br><span class="line">uv run main.py</span><br><span class="line"><span class="comment"># 等价于</span></span><br><span class="line">uv tool run main.py</span><br></pre></td></tr></table></figure><p>实际例子，如下这两个命令是等价的：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">❯ uvx --directory ~/data/code/python/test_code python main.py</span><br><span class="line">Hello from test-code!</span><br><span class="line">    </span><br><span class="line">❯ uv tool run --directory ~/data/code/python/test_code python main.py</span><br><span class="line">Hello from test-code!</span><br></pre></td></tr></table></figure><br/><h2 id="七、配置"><a href="#七、配置" class="headerlink" title="七、配置"></a><strong>七、配置</strong></h2><h3 id="1、依赖镜像源配置"><a href="#1、依赖镜像源配置" class="headerlink" title="1、依赖镜像源配置"></a><strong>1、依赖镜像源配置</strong></h3><blockquote><p>  参考：</p><ul><li><a href="https://blog.csdn.net/qq_41472205/article/details/145686414">https://blog.csdn.net/qq_41472205/article/details/145686414</a></li></ul></blockquote><h4 id="（1）项目级"><a href="#（1）项目级" class="headerlink" title="（1）项目级"></a><strong>（1）项目级</strong></h4><p>uv下载第三方库本质上也是通过pypi源下载的，所以在国内网络环境中默认链接速度会很慢，可以在项目目录的pyproject.toml中添加如下内容来使用清华源：</p><figure class="highlight toml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[[tool.uv.index]]</span></span><br><span class="line"><span class="attr">url</span> = <span class="string">&quot;https://pypi.tuna.tsinghua.edu.cn/simple&quot;</span></span><br><span class="line"><span class="attr">default</span> = <span class="literal">true</span></span><br></pre></td></tr></table></figure><h4 id="（2）命令行级"><a href="#（2）命令行级" class="headerlink" title="（2）命令行级"></a><strong>（2）命令行级</strong></h4><p>运行uv add命令的时候也可以指定镜像源</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uv add --default-index https://pypi.tuna.tsinghua.edu.cn/simple requests</span><br></pre></td></tr></table></figure><h4 id="（3）全局"><a href="#（3）全局" class="headerlink" title="（3）全局"></a><strong>（3）全局</strong></h4><p>uv也提供了全局的配置项，可以通过环境变量<code>UV_DEFAULT_INDEX</code>配置镜像源</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> UV_DEFAULT_INDEX=https://pypi.tuna.tsinghua.edu.cn/simple</span><br></pre></td></tr></table></figure><blockquote><p>  <strong>注意：全局的配置项优先级低于pyproject.toml中配置的镜像源；</strong></p></blockquote><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p><strong>官方仓库:</strong></p><ul><li><a href="https://github.com/astral-sh/uv">https://github.com/astral-sh/uv</a></li></ul><p><strong>官方文档:</strong></p><ul><li><a href="https://docs.astral.sh/uv/">https://docs.astral.sh/uv/</a></li></ul><p><strong>参考文章:</strong></p><ul><li><a href="https://blog.csdn.net/muxuen/article/details/147544307">https://blog.csdn.net/muxuen/article/details/147544307</a></li></ul><br/>]]></content>
    
    
    <summary type="html">uv是一个Python项目管理工具，类似于pip、venv、virtualenv和pip-tools的组合体，但它非常快。本文总结了如何安装和使用uv。</summary>
    
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/categories/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/tags/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    <category term="Python" scheme="https://jasonkayzk.github.io/cn/tags/Python/"/>
    
    <category term="uv" scheme="https://jasonkayzk.github.io/cn/tags/uv/"/>
    
  </entry>
  
  <entry>
    <title>gemini-cli使用</title>
    <link href="https://jasonkayzk.github.io/cn/2025/07/14/gemini-cli%E4%BD%BF%E7%94%A8/"/>
    <id>https://jasonkayzk.github.io/cn/2025/07/14/gemini-cli%E4%BD%BF%E7%94%A8/</id>
    <published>2025-07-14T05:17:01.000Z</published>
    <updated>2026-10-25T04:05:16.273Z</updated>
    
    <content type="html"><![CDATA[<p>有一段时间没有写博客了，这两年AI的发展日新月异，真是可怕。最近终于把学校的一摊子事忙完了，接下来还有个创新大赛、八月份又要去广州参加国培，不可谓不忙；</p><p>本文介绍了如何使用 Google 最新出的 gemini-cli：</p><ul><li><a href="https://github.com/google-gemini/gemini-cli">https://github.com/google-gemini/gemini-cli</a></li></ul><br/><span id="more"></span><h1 id="gemini-cli使用"><a href="#gemini-cli使用" class="headerlink" title="gemini-cli使用"></a><strong>gemini-cli使用</strong></h1><h2 id="一、简介"><a href="#一、简介" class="headerlink" title="一、简介"></a><strong>一、简介</strong></h2><p>目前大家可能用的都是 Cursor 或者 VSCode 里的插件（如 Cline）、阿里的通义灵码，以及腾讯的 CodeBuddy 这类界面化的 AI 编码交互方式。</p><p>而 <a href="https://github.com/google-gemini/gemini-cli">gemini-cli</a> 是一个让你可以在命令行使用和上面功能类似的命令行工具！</p><p>功能特点：</p><ul><li><strong>AI 编程伙伴：</strong> 你可以直接在终端里问它编程问题、让它帮你写代码、解释错误信息或者优化现有代码。</li><li><strong>多功能助手：</strong> 不仅仅是代码，你还可以向它提问各种问题，甚至可以发图片（比如错误截图）给它看，让它帮你分析。</li><li><strong>简化工作：</strong> 对于开发者和技术人员来说，这意味着不用离开熟悉的终端界面，就能快速获得 AI 的帮助，从而提高工作效率。</li><li><strong>开源免费：</strong> 它是开源的，并且在预览期间为个人开发者提供了非常慷慨的免费使用额度。</li></ul><br/><h2 id="二、安装"><a href="#二、安装" class="headerlink" title="二、安装"></a><strong>二、安装</strong></h2><p>直接使用 npm 全局安装即可：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g @google/gemini-cli</span><br></pre></td></tr></table></figure><br/><h2 id="三、使用"><a href="#三、使用" class="headerlink" title="三、使用"></a><strong>三、使用</strong></h2><p>直接在命令行输入：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gemini</span><br></pre></td></tr></table></figure><p>即可打开：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">➜  blog git:(save) ✗ gemini</span><br><span class="line"></span><br><span class="line"> ███            █████████  ██████████ ██████   ██████ █████ ██████   █████ █████</span><br><span class="line">░░░███         ███░░░░░███░░███░░░░░█░░██████ ██████ ░░███ ░░██████ ░░███ ░░███</span><br><span class="line">  ░░░███      ███     ░░░  ░███  █ ░  ░███░█████░███  ░███  ░███░███ ░███  ░███</span><br><span class="line">    ░░░███   ░███          ░██████    ░███░░███ ░███  ░███  ░███░░███░███  ░███</span><br><span class="line">     ███░    ░███    █████ ░███░░█    ░███ ░░░  ░███  ░███  ░███ ░░██████  ░███</span><br><span class="line">   ███░      ░░███  ░░███  ░███ ░   █ ░███      ░███  ░███  ░███  ░░█████  ░███</span><br><span class="line"> ███░         ░░█████████  ██████████ █████     █████ █████ █████  ░░█████ █████</span><br><span class="line">░░░            ░░░░░░░░░  ░░░░░░░░░░ ░░░░░     ░░░░░ ░░░░░ ░░░░░    ░░░░░ ░░░░░</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Tips for getting started:</span><br><span class="line">1. Ask questions, edit files, or run commands.</span><br><span class="line">2. Be specific for the best results.</span><br><span class="line">3. Create GEMINI.md files to customize your interactions with Gemini.</span><br><span class="line">4. /help for more information.</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">╭─────────────────────────────────────────────────────────────────────────────────────────────╮</span><br><span class="line">│ &gt;   Type your message or @path/to/file                                                      │</span><br><span class="line">╰─────────────────────────────────────────────────────────────────────────────────────────────╯</span><br><span class="line"></span><br><span class="line">~/workspace/blog (save*)       no sandbox (see /docs)        gemini-2.5-pro (100% context left)</span><br></pre></td></tr></table></figure><p>首次运行时，它会引导完成几个设置步骤：</p><ul><li><strong>选择主题风格：</strong> 为界面选择一个喜欢的颜色主题。</li><li><strong>授权登录：</strong> 它会提示您通过 Google 账户进行登录授权。这通常会生成一个链接，需要在浏览器中打开并授权。</li></ul><blockquote><p>  <strong>授权后，就可以享受免费的调用额度（预览版期间每天有 1000 次请求）。</strong></p></blockquote><br/><h2 id="四、配置API登陆"><a href="#四、配置API登陆" class="headerlink" title="四、配置API登陆"></a><strong>四、配置API登陆</strong></h2><p>如果你没有配置 API，每次运行 gemini-cli 都要重新登陆一次，可以配置 API 修改登录方式；</p><h3 id="1、访问-Google-AI-Studio"><a href="#1、访问-Google-AI-Studio" class="headerlink" title="1、访问 Google AI Studio"></a><strong>1、访问 Google AI Studio</strong></h3><p>在浏览器中打开网址：</p><ul><li><strong><a href="https://aistudio.google.com/app/apikey">https://aistudio.google.com/app/apikey</a></strong></li></ul><h3 id="2、创建或获取密钥"><a href="#2、创建或获取密钥" class="headerlink" title="2、创建或获取密钥"></a><strong>2、创建或获取密钥</strong></h3><ul><li>如果尚未登录，请使用您的 Google 账户登录。</li><li>点击 <strong>“Create API key”</strong> (创建 API 密钥) 按钮。</li><li>系统会生成一个新的 API 密钥。这是一个很长的字符串。</li></ul><h3 id="3、复制并妥善保管"><a href="#3、复制并妥善保管" class="headerlink" title="3、复制并妥善保管"></a><strong>3、复制并妥善保管</strong></h3><ul><li>立即点击密钥旁边的复制，复制 key；</li></ul><h3 id="4、引入环境变量"><a href="#4、引入环境变量" class="headerlink" title="4、引入环境变量"></a><strong>4、引入环境变量</strong></h3><p>配置：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> GEMINI_API_KEY=<span class="string">&quot;YOUR_API_KEY&quot;</span></span><br></pre></td></tr></table></figure><p>将你复制的内容替换 <code>YOUR_API_KEY</code>；</p><blockquote><p>  有关 Google Gemini API 的使用也可以看这篇文章：</p><ul><li><a href="http://apifox.com/apiskills/how-to-use-gemini-api/">Google Gemini API 接口调用教程，图文讲解</a></li></ul></blockquote><h3 id="5、生效"><a href="#5、生效" class="headerlink" title="5、生效"></a><strong>5、生效</strong></h3><p>运行 <code>source ~/.zshrc</code> 或重启终端；</p><p>随后在登录选项中选择 API Key 的方式即可！</p><br/><h2 id="五、其他说明"><a href="#五、其他说明" class="headerlink" title="五、其他说明"></a><strong>五、其他说明</strong></h2><p>启动 gemini 后，引用本地文件 可以使用 <code>@</code> 来选择文件；</p><p>更多内容可以通过 <code>/help</code> 获取：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">Basics:                                                                                     │</span><br><span class="line">│ Add context: Use @ to specify files <span class="keyword">for</span> context (e.g., @src/myFile.ts) to target specific   │</span><br><span class="line">│ files or folders.                                                                           │</span><br><span class="line">│ Shell mode: Execute shell commands via ! (e.g., !npm run start) or use natural language     │</span><br><span class="line">│ (e.g. start server).                                                                        │</span><br><span class="line">│                                                                                             │</span><br><span class="line">│ Commands:                                                                                   │</span><br><span class="line">│  /clear - clear the screen and conversation <span class="built_in">history</span>                                         │</span><br><span class="line">│  /help - <span class="keyword">for</span> <span class="built_in">help</span> on gemini-cli                                                             │</span><br><span class="line">│  /memory - Commands <span class="keyword">for</span> interacting with memory.                                            │</span><br><span class="line">│    show - Show the current memory contents.                                                 │</span><br><span class="line">│    add - Add content to the memory.                                                         │</span><br><span class="line">│    refresh - Refresh the memory from the <span class="built_in">source</span>.                                            │</span><br><span class="line">│  /theme - change the theme                                                                  │</span><br><span class="line">│  /docs - open full Gemini CLI documentation <span class="keyword">in</span> your browser                                 │</span><br><span class="line">│  /auth - change the auth method                                                             │</span><br><span class="line">│  /editor - <span class="built_in">set</span> external editor preference                                                   │</span><br><span class="line">│  /privacy - display the privacy notice                                                      │</span><br><span class="line">│  /stats - check session stats. Usage: /stats [model|tools]                                  │</span><br><span class="line">│  /mcp - list configured MCP servers and tools                                               │</span><br><span class="line">│  /extensions - list active extensions                                                       │</span><br><span class="line">│  /tools - list available Gemini CLI tools                                                   │</span><br><span class="line">│  /about - show version info                                                                 │</span><br><span class="line">│  /bug - submit a bug report                                                                 │</span><br><span class="line">│  /chat - Manage conversation <span class="built_in">history</span>. Usage: /chat &lt;list|save|resume&gt; &lt;tag&gt;                 │</span><br><span class="line">│  /quit - <span class="built_in">exit</span> the cli                                                                       │</span><br><span class="line">│  /compress - Compresses the context by replacing it with a summary.                         │</span><br><span class="line">│  ! - shell <span class="built_in">command</span>                                                                          │</span><br><span class="line">│                                                                                             │</span><br><span class="line">│ Keyboard Shortcuts:                                                                         │</span><br><span class="line">│ Enter - Send message                                                                        │</span><br><span class="line">│ Ctrl+J - New line                                                                           │</span><br><span class="line">│ Up/Down - Cycle through your prompt <span class="built_in">history</span>                                                 │</span><br><span class="line">│ Alt+Left/Right - Jump through words <span class="keyword">in</span> the input                                            │</span><br><span class="line">│ Shift+Tab - Toggle auto-accepting edits                                                     │</span><br><span class="line">│ Ctrl+Y - Toggle YOLO mode                                                                   │</span><br><span class="line">│ Esc - Cancel operation                                                                      │</span><br><span class="line">│ Ctrl+C - Quit application</span><br></pre></td></tr></table></figure><p>官方也提供了大量的经典案例：</p><ul><li><a href="https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#popular-tasks">https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#popular-tasks</a></li></ul><br/><h2 id="六、后记"><a href="#六、后记" class="headerlink" title="六、后记"></a><strong>六、后记</strong></h2><p>实际上和<a href="https://wiki.eryajf.net/">这位博主</a>一样，我最开始也不喜欢使用命令行：</p><blockquote><p>  由于先入为主的一些体验，我一直习惯于使用像 Cursor 或者 VSCode 里的插件（如 Cline）、阿里的通义灵码，以及腾讯的 CodeBuddy 这类界面化的 AI 编码交互方式。相比之下，对于 Claude cli、Gemini cli 这类基于终端、命令行的交互方式，我一直提不起兴趣。</p><p>  直到最近，我体验了几次 Claude cli 的编码功能，这才让我对以往的成见有了一些改变。过去我之所以更习惯插件式的交互方式，是因为它们的操作更为直观。无论是选择代码段、文件，还是插入图片，都非常直接简单。因此，我一直认为这种交互方式就是最优雅的 AI 编码方式。</p><p>  正因为这种先入为主的心态，我始终对 Cli 这类交互方式有些抵触。我一直不太能理解，在编辑器里写代码，却要用终端来进行 AI 编码，这到底是一种怎样的交互逻辑？总觉得这种方式很割裂，与 AI 的交互以及 AI 的编码过程变成了一种黑盒，很不直观。这也是我迟迟没有尝试这种编码方式的原因。</p></blockquote><p>但是在安装并且体验了之后，发现确实要方便很多！</p><p>他最后的总结也是我的体验以及一些个人感想：</p><blockquote><p>  <font color="#f00"><strong>这让我意识到，很多时候限制我们接受新事物的，并不是事物本身的缺点。那些所谓的缺点，或许只是我们自己想象出来的。真正阻碍我们发展的，往往是自己内心深处那些根深蒂固的成见。我们习惯于依赖以往成功的经验，固守在自己的舒适区，对不熟悉的方式和交互逻辑产生抵触情绪。而正是这种抵触，让我们与更美好的事物始终形同陌路。</strong></font></p><p>  <font color="#f00"><strong>这次 Claude cli 的体验给了我一个提醒：应该始终保持开放的心态，勇于尝试那些看似不符合直觉的新方法或新工具。也许这样能够带来许多意想不到的效率提升和全新的体验，要善于打破自己的成见，才能真正拥抱进步。</strong></font></p></blockquote><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>参考：</p><ul><li><a href="https://www.v2ex.com/t/1144487">https://www.v2ex.com/t/1144487</a></li><li><a href="https://wiki.eryajf.net/pages/d89910/">https://wiki.eryajf.net/pages/d89910/</a></li></ul><br/>]]></content>
    
    
    <summary type="html">有一段时间没有写博客了，这两年AI的发展日新月异，真是可怕。最近终于把学校的一摊子事忙完了，接下来还有个创新大赛、八月份又要去广州参加国培，不可谓不忙。本文介绍了如何使用 Google 最新出的 gemini-cli。</summary>
    
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/categories/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/tags/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    <category term="AI" scheme="https://jasonkayzk.github.io/cn/tags/AI/"/>
    
  </entry>
  
  <entry>
    <title>跑步一年多的一些总结和感想</title>
    <link href="https://jasonkayzk.github.io/cn/2025/05/04/%E8%B7%91%E6%AD%A5%E4%B8%80%E5%B9%B4%E5%A4%9A%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%BB%E7%BB%93%E5%92%8C%E6%84%9F%E6%83%B3/"/>
    <id>https://jasonkayzk.github.io/cn/2025/05/04/%E8%B7%91%E6%AD%A5%E4%B8%80%E5%B9%B4%E5%A4%9A%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%BB%E7%BB%93%E5%92%8C%E6%84%9F%E6%83%B3/</id>
    <published>2025-05-04T13:12:38.000Z</published>
    <updated>2026-10-25T04:05:16.296Z</updated>
    
    <content type="html"><![CDATA[<p>不知不觉跑步已经锻炼了有一年时间了，从最开始200米都跑不下来，到现在跑完半马，变化还是巨大的。</p><p>本文记录一些跑步的感想。</p><br/><span id="more"></span><HTML lang="en">    <div style="text-align: center;">   <iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=320 height=65 src="https://i.y.qq.com/n2/m/outchain/player/index.html?songid=1911822&songtype=0"></iframe></div></HTML><h1 id="跑步一年多的一些总结和感想"><a href="#跑步一年多的一些总结和感想" class="headerlink" title="跑步一年多的一些总结和感想"></a><strong>跑步一年多的一些总结和感想</strong></h1><h2 id="新的开始"><a href="#新的开始" class="headerlink" title="新的开始"></a><strong>新的开始</strong></h2><h3 id="契机"><a href="#契机" class="headerlink" title="契机"></a><strong>契机</strong></h3><p>最开始让我跑步的原因是当时刚刚告别程序员这个行业，体检的时候发现自己居然接近三高了：</p><ul><li>血压偏高</li><li>血脂偏高</li><li>尿酸偏高</li></ul><p>并且体重接近 90kg！</p><blockquote><p>  <strong>要知道上大学的时候，我还是易瘦体质，体重还没超过70kg！</strong></p></blockquote><p>正巧当时还没有确定好工作，空余时间比较多，加上膝盖已经出现了问题，所以就打算锻炼身体。</p><blockquote><p>  <strong>其实在此之前，在深圳、福州就已经开始断断续续的跑步了！</strong></p><p>  <strong>但是没有真正的把跑步当作一件事情认真对待，只是简单的跑一跑。</strong></p></blockquote><p>真正认真对待这件事还是回家之后，想跑一跑步，突然发现自己身体素质差的要命！</p><p>当时刚从南方回家，大概在十一月份，因为北方已经开始降温了，天气比较冷：</p><p>基本上遇到冷空气就要打喷嚏，并且几乎每个月都要感冒，身体差的不行；</p><p>再加上医院的体检结果也是非常吓人，很多指标都偏高！</p><p>但是实际上压死骆驼的最后一根稻草是：</p><p>我去运动场上试跑了一下，发现自己<strong>连200米都坚持不下来！</strong></p><blockquote><p>  <strong>这个对我来说印象十分深刻：</strong></p><p>  <strong>我至今都还能记得，自己跑了200米就开始大口大口喘气的感觉！</strong></p></blockquote><br/><hr><br/><h3 id="跑步训练-v0-1"><a href="#跑步训练-v0-1" class="headerlink" title="跑步训练-v0.1"></a><strong>跑步训练-v0.1</strong></h3><p>由于没有经验，最开始在跑步的时候是没有什么规划的，也不知道训练方法之类的；</p><p>基本上就是来到体育场，也没有热身，能跑多快跑多快；</p><p>这是最早的一张图（当时用的APP还是小米运动）：</p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/running-1.png" alt="image-20250505091951310" style="zoom: 25%;" /><p>基本上跑个400米就不行了。</p><p>而且因为没有热身，基本上跑完之后，第二天大腿、小腿还会疼；</p><br/><hr><br/><h3 id="跑步训练-v1-0"><a href="#跑步训练-v1-0" class="headerlink" title="跑步训练-v1.0"></a><strong>跑步训练-v1.0</strong></h3><p>实际上即使没有任何训练计划，跑了几天之后发现自己体力也是有明显进步的；</p><blockquote><p>  可能是因为原本的身体基础实在是太差、段位太低，所以提升的比较快！</p></blockquote><p>虽说是明显的进步，实际上也就是能坚持跑个1公里左右；</p><p>于是在这个时候开始准备一些更长的训练：</p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/running-2.png" alt="image-20250505091958741" style="zoom:25%;" /><p>这个阶段我的跑步策略是：</p><ul><li>先走一圈热身</li><li>然后再跑一公里</li><li>然后再走一圈</li><li>然后再跑一公里</li></ul><p>因为一开始根本是无法坚持跑完3公里的路程的，所以基本上只能分成3组，每组大概是1公里的样子；</p><p>中间穿插一小段热身缓和；</p><blockquote><p>  这个阶段大概持续了半年左右：</p><ul><li><strong>2023年11月-12月</strong></li><li><strong>2024年2月-7月</strong></li></ul></blockquote><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/running-3.png" alt="image-20250505092027429" style="zoom:25%;" /><br/><hr><br/><h3 id="跑步训练-v2-0"><a href="#跑步训练-v2-0" class="headerlink" title="跑步训练-v2.0"></a><strong>跑步训练-v2.0</strong></h3><p>上面的分阶段跑步大概持续了大半年左右，一直到了2024年的8月份；</p><p>这个时候训练从原来的3组1公里，慢慢变成了：3组1.5公里、4组1.5公里、一组5公里等等；</p><p>所以在这个阶段，慢慢开始考虑，是不是可以不再分组了，而是一口气跑下来5公里或者更长呢？</p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/running-4.png" alt="image-20250505092428629" style="zoom:25%;" /><p>于是从8月份开始，开始尝试5公里的跑步；</p><p>最开始的训练是非常痛苦的，因为5公里的长度对于我来说已经是非常长了，所以基本上是跑跑停停：</p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/running-5.png" alt="image-20250505092640311" style="zoom:25%;" /><br/><p>也是从这一阶段开始，我的跑步APP也从小米运动转到了 Keep；</p><p>同时也开始真正记录一些跑步数据、并且真正开始看和跑步相关的知识；</p><p>也许是之前训练了很长的时间，所以在这一阶段，5公里已经开始能跑出比较不错的成绩了！</p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/running-6.png" alt="image-20250505093052979" style="zoom:25%;" /><br/><p>当时也是迷上了一部动漫：</p><ul><li><a href="https://movie.douban.com/subject/30238385/">《風が強く吹いている》</a></li></ul><blockquote><p>  <strong>实际上这本书在我本科上学期间就已经读过了，非常推荐！</strong></p></blockquote><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/running-7.png" alt="image-20250505093337486" style="zoom:25%;" /><p>同时，也是在知乎上看到了这么一幅图：</p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/running-8.png" alt="image-20250505093407429" style="zoom:25%;" /><p>所以开始追求跑步的配速！</p><br/><p>同时也在 Github 搭建了：</p><ul><li><a href="/cn/running/">running-page</a></li></ul><blockquote><p>  <strong>感谢 <a href="https://github.com/yihong0618">yihong0618</a>！❤️</strong></p></blockquote><p>进一步激发了我的跑步热情！</p><br/><hr><br/><h3 id="跑步训练-v3-0"><a href="#跑步训练-v3-0" class="headerlink" title="跑步训练-v3.0"></a><strong>跑步训练-v3.0</strong></h3><p>经历了5公里洗礼之后，再继续跑步的时候，就想慢慢探索自己能否跑更长的距离；</p><p>也是这一时期，感觉自己可以开始试着准备准备半程马拉松了！</p><p>于是开始挑战10km这个距离；</p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/running-9.png" alt="image-20250505093926549" style="zoom:25%;" /><blockquote><p>  <strong>上面的这次跑步实际上只是为了看看自己1个小时究竟能跑多远！</strong></p></blockquote><p>说是挑战10公里，<strong>实际上要比我的第一个5公里要简单很多了！</strong></p><p>但是长距离带来了另外的问题，就是：</p><ul><li><strong>自己的脚底开始磨出水泡！</strong></li></ul><p>然后也开始慢慢意识到：</p><p><font color="#f00"><strong>即使跑步速度不快的情况下，时间或者距离足够长，实际上会将你的鞋底摩擦、衣服摩擦造成的影响给无限放大，导致出现短跑不会遇到的问题！</strong></font></p><p>也是这一阶段开始，自己开始注意在运动前保护自己：</p><ul><li><strong>跑前拉伸、热身1-2公里</strong></li><li><strong>注意检查自己的鞋是否存在磨脚等情况</strong></li><li><strong>跑步的状态等</strong></li></ul><br/><hr><br/><h3 id="跑步训练-v4-0"><a href="#跑步训练-v4-0" class="headerlink" title="跑步训练-v4.0"></a><strong>跑步训练-v4.0</strong></h3><p>4.0 版本实际上也就是目前的训练版本；</p><p>在今年的2月份，买了 Garmin 255 的手表，专门用来记录跑步！</p><p>同时，在跑步训练上也更加专注长距离的跑步，基本上每次训练都是10公里的量！</p><p>同时也是完成了半马挑战！</p><blockquote><p>  虽然成绩不是很好，哈哈。</p></blockquote><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/running-10.png" alt="image-20250505094746369" style="zoom:25%;" /><p>也是这几天，买了更加专业的跑鞋（李宁飞电6C）；</p><blockquote><p>  <font color="#f00"><strong>跑步装备越来越专业，实际上只是为了激励自己能更好的坚持跑下去！</strong></font></p><p>  <font color="#f00"><strong>不过我个人觉得，实际上更重要的是要能坚持迈开腿跑下去！装备并没有那么重要！</strong></font></p></blockquote><p>当然，后面也会挑战更多的半马；</p><p>上面年由于工作比较忙，所以也是希望下半年有机会参加郑开的半马！</p><br/><hr><br/><h2 id="一些收获和感想"><a href="#一些收获和感想" class="headerlink" title="一些收获和感想"></a><strong>一些收获和感想</strong></h2><h3 id="1、身体健康"><a href="#1、身体健康" class="headerlink" title="1、身体健康"></a><strong>1、身体健康</strong></h3><p>最大的收获当然是：<strong>自己的身体健康！</strong></p><p>坚持跑步以来，到目前为止，自己体检时的各项身体指标已经全部正常，并且处于中间位置；</p><p>高血压、高血脂、高尿酸全部不见了；</p><p>体重也从90公斤减到了70公斤！</p><p>目前为止，生病感冒等现象也没发生过了！</p><br/><h3 id="2、精神状态"><a href="#2、精神状态" class="headerlink" title="2、精神状态"></a><strong>2、精神状态</strong></h3><p>整个人的精神面貌也好了不少；</p><p>锻炼给人的感觉应该是要消耗大量的体力、导致身体疲惫。</p><p><font color="#f00"><strong>但是实际上，锻炼之后只是当时比较累，事后反而会让你精力充沛，这是比较反直觉的！</strong></font></p><br/><h3 id="3、其他"><a href="#3、其他" class="headerlink" title="3、其他"></a><strong>3、其他</strong></h3><p>除了以上这些之外，实际上自己对于距离、速度的掌控也变得精确。</p><p>同时<strong>对于长跑也不再那么恐惧</strong>，目前已经参加了：</p><ul><li>学校10公里微马拉松；</li><li>集团2次马拉松：团体赛、个人赛；</li></ul><p>同时觉得也更能掌控自己的身体！</p><br/><h2 id="跑步时我在做什么"><a href="#跑步时我在做什么" class="headerlink" title="跑步时我在做什么"></a><strong>跑步时我在做什么</strong></h2><p>实际上这来自于知乎的一个问题：</p><ul><li><a href="https://www.zhihu.com/question/25947722">《你跑步的时候在想什么？》</a></li></ul><p>那要问跑步时我在做什么，实际上答案当然是：跑步！</p><p>这里说的是除了跑步之外，我在做什么，包括：</p><ul><li>大脑在想什么；</li><li>耳朵在听什么；</li><li>眼睛在看什么；</li><li>……</li></ul><br/><h3 id="大脑在想什么"><a href="#大脑在想什么" class="headerlink" title="大脑在想什么"></a><strong>大脑在想什么</strong></h3><p>实际上脑子里在想的，和知乎上有些人写的差不多；</p><p>更多的是在思考：</p><ul><li>好痛苦啊？！</li><li>现在跑了多久了？</li><li>怎么还有5公里？！</li><li>速度怎么这么慢？</li><li>……</li></ul><blockquote><p>  <strong>我在跑步的时候是思考不了其他事情的，我也很佩服那些大脑是多核处理器的人；</strong></p><p>  <strong>能在跑步的同时思考一些其他时间，我是不行；</strong></p></blockquote><p><font color="#f00"><strong>这个过程对于我来说有点类似于冥想，只不过我是在匀速运动中冥想，而有的人是静止状态。</strong></font></p><br/><h3 id="耳朵在听什么"><a href="#耳朵在听什么" class="headerlink" title="耳朵在听什么"></a><strong>耳朵在听什么</strong></h3><p>大部分情况下都是在听自己的一些歌单；</p><blockquote><p>  <strong>关于这个歌单，后文会给大家介绍；</strong></p></blockquote><p>当然还有一些跑步的大牛会听一些播客；</p><p>不过和上面的原因一样，我感觉我听这些根本进不去脑子；</p><p>而且如果我听播客，我跑步的时候可能会很别扭。</p><p>所以我一般就是听歌曲；</p><br/><h3 id="眼睛在看什么"><a href="#眼睛在看什么" class="headerlink" title="眼睛在看什么"></a><strong>眼睛在看什么</strong></h3><p>我基本上都是在运动场跑步，所以一般情况下都不会是我自己；</p><p>在跑步的时候，可以观察一下其他也在跑步的朋友，他的：</p><ul><li>跑步姿势；</li><li>跑步速度；</li><li>跑了多久；</li><li>……</li></ul><p>然后感叹：我靠他怎么这么厉害、我跟不上他了；</p><blockquote><p>  <strong>不过相信我，如果你能在运动场跑个一个小时以上的时间，基本上至少能熬走2-3波来锻炼的人！</strong></p></blockquote><br/><h2 id="一些相关的推荐"><a href="#一些相关的推荐" class="headerlink" title="一些相关的推荐"></a><strong>一些相关的推荐</strong></h2><p>这里给大家分享一些我目前用到的一些工具等等；</p><br/><h3 id="歌单"><a href="#歌单" class="headerlink" title="歌单"></a><strong>歌单</strong></h3><p>我平时听的歌曲是一些节奏比较强烈的歌，尤其是鼓点最好能配上你的步频节奏那就更好了！</p><p>除此之外，我个人常听的一些歌是：</p><ul><li><font color="#f00"><strong>原神战斗bgm</strong></font></li></ul><p>例如：</p>  <iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=320 height=65 src="https://i.y.qq.com/n2/m/outchain/player/index.html?songid=414726056&songtype=0"></iframe><p><font color="#f00"><strong>虽然我已经好久都没玩原神了，但是听这些歌曲给我一种我自己正在游戏世界里奔跑游荡的感觉！</strong></font></p><br/><p>除此之外，你可以试试一些播客～</p><br/><h3 id="APP"><a href="#APP" class="headerlink" title="APP"></a><strong>APP</strong></h3><h4 id="一、跑步记录"><a href="#一、跑步记录" class="headerlink" title="一、跑步记录"></a><strong>一、跑步记录</strong></h4><p>跑步记录的 APP 我这里推荐几个；</p><h5 id="1、Keep"><a href="#1、Keep" class="headerlink" title="1、Keep"></a><strong>1、Keep</strong></h5><p>可以在 Keep 里面设置自定义的训练内容，比如 5公里、10公里、15公里等；</p><p>然后在每一公里处都设置播报，当然你的速度快了或者慢了，Keep 也都有提示；</p><p>总体来说还是比较方便的；</p><br/><h5 id="2、Garmin-Connect"><a href="#2、Garmin-Connect" class="headerlink" title="2、Garmin Connect"></a><strong>2、Garmin Connect</strong></h5><p>由于我目前用的是佳明的手表，所以一般情况下都是使用手表记录跑步，然后通过 Connect 同步到云端；</p><p>当然，如果你有其他的手表，比如：Coros、Apple Watch、华为、小米 等等，也是可以的！</p><br/><h4 id="二、听歌"><a href="#二、听歌" class="headerlink" title="二、听歌"></a><strong>二、听歌</strong></h4><p>我一般使用的是 QQ 音乐，因为充了会员，歌曲还是比较多的；</p><p>除此之外，也推荐大家使用汽水音乐，他是字节推出的一个听歌APP；</p><p>使用汽水音乐有一个好处就是：</p><ul><li><strong>他的交互模式类似于抖音，上划就能下一曲了，比其他APP切歌方便的多！</strong></li><li><strong>同时，他的歌曲推荐也还可以！</strong></li></ul><p>如果你的手表包含了歌曲功能，也是可以的！</p><br/><h3 id="网站"><a href="#网站" class="headerlink" title="网站"></a><strong>网站</strong></h3><h4 id="一、RunningPage（强烈推荐）"><a href="#一、RunningPage（强烈推荐）" class="headerlink" title="一、RunningPage（强烈推荐）"></a><strong>一、RunningPage（强烈推荐）</strong></h4><p>这个是一个可以自行部署并生成你的跑步记录的网站：</p><ul><li><a href="https://github.com/yihong0618/running_page">https://github.com/yihong0618/running_page</a></li></ul><p>支持许多的手表设备和平台；</p><blockquote><p>  <strong>包括 Keep！</strong></p></blockquote><p>下面的这个网站就是我搭建的：</p><ul><li><a href="https://jasonkayzk.github.io/running_page/">https://jasonkayzk.github.io/running_page/</a></li></ul><p><strong>搭建完成后，每天会自动获取你的运动数据，并且更新内容，非常的酷！</strong></p><br/><h4 id="二、Garmin-Connect"><a href="#二、Garmin-Connect" class="headerlink" title="二、Garmin Connect"></a><strong>二、Garmin Connect</strong></h4><p>这个是佳明手表提供的平台：</p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/running-11.png" alt="image-20250505104237203" style="zoom:33%;" /><p>同时，你也可以分享你的个人资料，比如下面是我个人的资料：</p><ul><li><a href="https://connect.garmin.cn/modern/profile/1fbb8b4a-ba06-4c4a-bd9b-fc29524ec46f">https://connect.garmin.cn/modern/profile/1fbb8b4a-ba06-4c4a-bd9b-fc29524ec46f</a></li></ul><blockquote><p>  <strong>佳明平台是分中国区和国际区的，数据是不同步的！</strong></p><p>  <strong>你可以使用下面这个仓库同步：</strong></p><ul><li><a href="https://github.com/gooin/dailysync-rev">https://github.com/gooin/dailysync-rev</a></li></ul></blockquote><br/><h4 id="三、Strava"><a href="#三、Strava" class="headerlink" title="三、Strava"></a><strong>三、Strava</strong></h4><p>Strave 是一个跑步运动的平台，许多的大牛都在这个平台上；</p><blockquote><p>  <strong>国内可能无法访问！</strong></p></blockquote><p>你可以在这个平台关注一些你喜欢的跑者、运动员，看他们每天的训练内容、计划等等！</p><p>下面是我的个人网站：</p><ul><li><a href="https://www.strava.com/athletes/145491210">https://www.strava.com/athletes/145491210</a></li></ul><blockquote><p>  Strava 中可以配置从其他平台同步数据（比如：佳明）！</p><p>  <strong>当然，只能同步国际区的佳明数据，可以通过上面介绍的同步国际区的方式同步数据1</strong></p></blockquote><br/><h3 id="博主"><a href="#博主" class="headerlink" title="博主"></a><strong>博主</strong></h3><p>这里我比较关注的有：</p><ul><li><a href="https://space.bilibili.com/38995440">黑影儿TV</a>：跑过100km！</li><li><a href="https://x.com/yihong0618">yihong0618</a>：坚持跑步好多年的大佬，RunningPage的作者</li><li></li></ul><blockquote><p>  其他：</p><ul><li><a href="https://www.reddit.com/r/AdvancedRunning/comments/1aiugyx/running_influencers/?tl=zh-hans">https://www.reddit.com/r/AdvancedRunning/comments/1aiugyx/running_influencers/?tl=zh-hans</a></li></ul></blockquote><br/><h3 id="装备"><a href="#装备" class="headerlink" title="装备"></a><strong>装备</strong></h3><ul><li>手表/手环：佳明、高驰、华为、小米都可以</li><li>手机</li><li>一双好的运动鞋</li></ul><br/><h3 id="动漫书籍"><a href="#动漫书籍" class="headerlink" title="动漫书籍"></a><strong>动漫书籍</strong></h3><p>动漫、电影、书籍都推荐：强风吹拂：</p><ul><li><a href="https://movie.douban.com/subject/30238385/">《風が強く吹いている》</a></li></ul><br/><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a><strong>后记</strong></h2><p>最后，说了这么多，实际上：<strong>一切的理论、装备都不如一份坚持重要。</strong></p><p>我最近参加了几个业余组的比赛就发现：</p><p>比赛刚开始的时候，大家都是兴致勃勃，但是超过一公里之后的每一段距离，都有一部分选手选择停下来；</p><p>但是对于长跑来说：</p><p><font color="#f00"><strong>重要的实际上并不是最开始或者最后的一公里，而是在开始前确定一个恒定的速度，然后按照这个恒定的速度一直坚持跑下去，像机器一样、节奏一直恒定的运行。</strong></font></p><p><strong>最后，也祝各位读者能够身体健康，每天突破自己的 PB！🎉</strong></p><br/>]]></content>
    
    
    <summary type="html">不知不觉跑步已经锻炼了有一年时间了，从最开始200米都跑不下来，到现在跑完半马，变化还是巨大的。本文记录一些跑步的感想。</summary>
    
    
    
    <category term="人生日记" scheme="https://jasonkayzk.github.io/cn/categories/%E4%BA%BA%E7%94%9F%E6%97%A5%E8%AE%B0/"/>
    
    
    <category term="人生日记" scheme="https://jasonkayzk.github.io/cn/tags/%E4%BA%BA%E7%94%9F%E6%97%A5%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>通过GithubActions拉取并推送Docker镜像到国内云</title>
    <link href="https://jasonkayzk.github.io/cn/2025/01/30/%E9%80%9A%E8%BF%87GithubActions%E6%8B%89%E5%8F%96%E5%B9%B6%E6%8E%A8%E9%80%81Docker%E9%95%9C%E5%83%8F%E5%88%B0%E5%9B%BD%E5%86%85%E4%BA%91/"/>
    <id>https://jasonkayzk.github.io/cn/2025/01/30/%E9%80%9A%E8%BF%87GithubActions%E6%8B%89%E5%8F%96%E5%B9%B6%E6%8E%A8%E9%80%81Docker%E9%95%9C%E5%83%8F%E5%88%B0%E5%9B%BD%E5%86%85%E4%BA%91/</id>
    <published>2025-01-30T03:13:54.000Z</published>
    <updated>2026-10-25T04:05:16.297Z</updated>
    
    <content type="html"><![CDATA[<p>自从DockerHub在国内被墙之后，Docker镜像在国内的拉取一直是一个问题。目前有许多解决方案，比如：使用公开的镜像站、或者通过Cloudflare自建镜像站等等。但是都存在访问不稳定、配置麻烦等问题。</p><p>实际上，Github提供的Actions服务器就是在海外，可以通过Actions拉取Docker镜像，并推送到国内的云厂商，实现稳定的访问！</p><p><a href="https://github.com/tech-shrimp/docker_image_pusher">tech-shrimp/docker_image_pusher</a> 库就实现了这个功能！</p><br/><span id="more"></span><h1 id="通过GithubActions拉取并推送Docker镜像到国内云"><a href="#通过GithubActions拉取并推送Docker镜像到国内云" class="headerlink" title="通过GithubActions拉取并推送Docker镜像到国内云"></a><strong>通过GithubActions拉取并推送Docker镜像到国内云</strong></h1><h2 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a><strong>使用方法</strong></h2><p>首先 fork 项目：</p><ul><li><a href="https://github.com/tech-shrimp/docker_image_pusher">https://github.com/tech-shrimp/docker_image_pusher</a></li></ul><p>到本地，然后基本上根据 README 文档来即可；</p><p>需要在 fork 后的仓库的配置中配置 Secrets：</p><ul><li>ALIYUN_NAME_SPACE：你创建的阿里云的命名空间</li><li>ALIYUN_REGISTRY：阿里云的地址</li><li>ALIYUN_REGISTRY_USER：阿里云的用户名</li><li>ALIYUN_REGISTRY_PASSWORD：阿里云的密码</li></ul><p><strong>配置完成后直接修改 <code>images.txt</code> 文件即可直接拉取镜像并推送到阿里云的容器仓库！</strong></p><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>源码仓库：</p><ul><li><a href="https://github.com/tech-shrimp/docker_image_pusher">https://github.com/tech-shrimp/docker_image_pusher</a></li></ul><br/>]]></content>
    
    
    <summary type="html">自从DockerHub在国内被墙之后，Docker镜像在国内的拉取一直是一个问题。目前有许多解决方案，比如：使用公开的镜像站、或者通过Cloudflare自建镜像站等等。但是都存在访问不稳定、配置麻烦等问题。实际上，Github提供的Actions服务器就是在海外，可以通过Actions拉取Docker镜像，并推送到国内的云厂商，实现稳定的访问！tech-shrimp/docker_image_pusher 库就实现了这个功能！</summary>
    
    
    
    <category term="Docker" scheme="https://jasonkayzk.github.io/cn/categories/Docker/"/>
    
    
    <category term="Docker" scheme="https://jasonkayzk.github.io/cn/tags/Docker/"/>
    
    <category term="Github" scheme="https://jasonkayzk.github.io/cn/tags/Github/"/>
    
  </entry>
  
  <entry>
    <title>使用AnythingLLM+SillconFlow+Milvus快速搭建个人云端知识库</title>
    <link href="https://jasonkayzk.github.io/cn/2025/01/29/%E4%BD%BF%E7%94%A8AnythingLLM-SillconFlow-Milvus%E5%BF%AB%E9%80%9F%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BA%E4%BA%91%E7%AB%AF%E7%9F%A5%E8%AF%86%E5%BA%93/"/>
    <id>https://jasonkayzk.github.io/cn/2025/01/29/%E4%BD%BF%E7%94%A8AnythingLLM-SillconFlow-Milvus%E5%BF%AB%E9%80%9F%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BA%E4%BA%91%E7%AB%AF%E7%9F%A5%E8%AF%86%E5%BA%93/</id>
    <published>2025-01-29T05:49:26.000Z</published>
    <updated>2026-10-25T04:05:16.278Z</updated>
    
    <content type="html"><![CDATA[<p>最近DeepSeek如火如荼，由于目前我也有自己搭建个人知识库的需求，因此结合最新的一些技术搭建了一下。主要是包括：</p><ul><li>AnythingLLM平台</li><li>SillconFlow提供免费的大模型API支持</li><li>私有部署的Milvus向量数据库供多个人使用</li></ul><p>源代码：</p><ul><li><a href="https://github.com/JasonkayZK/docker-repo/blob/master/anything-llm.sh">https://github.com/JasonkayZK/docker-repo/blob/master/anything-llm.sh</a></li><li><a href="https://github.com/JasonkayZK/docker-repo/tree/milvus-standalone">https://github.com/JasonkayZK/docker-repo/tree/milvus-standalone</a></li></ul><br/><span id="more"></span><h1 id="使用AnythingLLM-SillconFlow-Milvus快速搭建个人云端知识库"><a href="#使用AnythingLLM-SillconFlow-Milvus快速搭建个人云端知识库" class="headerlink" title="使用AnythingLLM+SillconFlow+Milvus快速搭建个人云端知识库"></a><strong>使用AnythingLLM+SillconFlow+Milvus快速搭建个人云端知识库</strong></h1><p>环境搭建部分完全使用 Docker：</p><p>首先部署 Milvus、然后部署 AnythingLLM 平台，最后注册 SillconFlow 并对平台进行配置。</p><br/><h2 id="部署Milvus"><a href="#部署Milvus" class="headerlink" title="部署Milvus"></a><strong>部署Milvus</strong></h2><h3 id="部署"><a href="#部署" class="headerlink" title="部署"></a><strong>部署</strong></h3><p>向量数据库 <a href="https://github.com/milvus-io/milvus">milvus</a> 的部署比较简单，直接通过 docker-compose 部署即可：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3.5&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">etcd:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">milvus-etcd</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">quay.io/coreos/etcd:v3.5.16</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">ETCD_AUTO_COMPACTION_MODE=revision</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">ETCD_AUTO_COMPACTION_RETENTION=1000</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">ETCD_QUOTA_BACKEND_BYTES=4294967296</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">ETCD_SNAPSHOT_COUNT=50000</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">$&#123;DOCKER_VOLUME_DIRECTORY:-.&#125;/volumes/etcd:/etcd</span></span><br><span class="line">    <span class="attr">command:</span> <span class="string">etcd</span> <span class="string">-advertise-client-urls=http://127.0.0.1:2379</span> <span class="string">-listen-client-urls</span> <span class="string">http://0.0.0.0:2379</span> <span class="string">--data-dir</span> <span class="string">/etcd</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;etcdctl&quot;</span>, <span class="string">&quot;endpoint&quot;</span>, <span class="string">&quot;health&quot;</span>]</span><br><span class="line">      <span class="attr">interval:</span> <span class="string">30s</span></span><br><span class="line">      <span class="attr">timeout:</span> <span class="string">20s</span></span><br><span class="line">      <span class="attr">retries:</span> <span class="number">3</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">minio:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">milvus-minio</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">registry.cn-hangzhou.aliyuncs.com/jasonkay/minio:RELEASE.2023-03-20T20-16-18Z</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">MINIO_ACCESS_KEY:</span> <span class="string">minioadmin</span></span><br><span class="line">      <span class="attr">MINIO_SECRET_KEY:</span> <span class="string">minioadmin</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;9001:9001&quot;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;9000:9000&quot;</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">$&#123;DOCKER_VOLUME_DIRECTORY:-.&#125;/volumes/minio:/minio_data</span></span><br><span class="line">    <span class="attr">command:</span> <span class="string">minio</span> <span class="string">server</span> <span class="string">/minio_data</span> <span class="string">--console-address</span> <span class="string">&quot;:9001&quot;</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;curl&quot;</span>, <span class="string">&quot;-f&quot;</span>, <span class="string">&quot;http://localhost:9000/minio/health/live&quot;</span>]</span><br><span class="line">      <span class="attr">interval:</span> <span class="string">30s</span></span><br><span class="line">      <span class="attr">timeout:</span> <span class="string">20s</span></span><br><span class="line">      <span class="attr">retries:</span> <span class="number">3</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">standalone:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">milvus-standalone</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">registry.cn-hangzhou.aliyuncs.com/jasonkay/milvus:v2.5.4</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br><span class="line">    <span class="attr">command:</span> [<span class="string">&quot;milvus&quot;</span>, <span class="string">&quot;run&quot;</span>, <span class="string">&quot;standalone&quot;</span>]</span><br><span class="line">    <span class="attr">security_opt:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">seccomp:unconfined</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">ETCD_ENDPOINTS:</span> <span class="string">etcd:2379</span></span><br><span class="line">      <span class="attr">MINIO_ADDRESS:</span> <span class="string">minio:9000</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">$&#123;DOCKER_VOLUME_DIRECTORY:-.&#125;/volumes/milvus:/var/lib/milvus</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;curl&quot;</span>, <span class="string">&quot;-f&quot;</span>, <span class="string">&quot;http://localhost:9091/healthz&quot;</span>]</span><br><span class="line">      <span class="attr">interval:</span> <span class="string">30s</span></span><br><span class="line">      <span class="attr">start_period:</span> <span class="string">90s</span></span><br><span class="line">      <span class="attr">timeout:</span> <span class="string">20s</span></span><br><span class="line">      <span class="attr">retries:</span> <span class="number">3</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;19530:19530&quot;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;9091:9091&quot;</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;etcd&quot;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;minio&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line">  <span class="attr">default:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">milvus</span></span><br></pre></td></tr></table></figure><blockquote><p>  <strong>镜像使用的是我在阿里云上的，国内也可以直接使用；</strong></p></blockquote><p>使用：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose up -d</span><br></pre></td></tr></table></figure><p>部署即可；</p><br/><h3 id="配置密码"><a href="#配置密码" class="headerlink" title="配置密码"></a><strong>配置密码</strong></h3><p>部署成功后，Milvus 的默认账号、密码为：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">root</span><br><span class="line">Milvus</span><br></pre></td></tr></table></figure><p>可以通过在部署的时候提供配置文件来配置账号密码，也可以部署后通过 Python 脚本部署；</p><p>例如：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pymilvus <span class="keyword">import</span> MilvusClient</span><br><span class="line"></span><br><span class="line">client = MilvusClient(</span><br><span class="line">    uri=<span class="string">&#x27;http://localhost:19530&#x27;</span>, <span class="comment"># replace with your own Milvus server address</span></span><br><span class="line">    token=<span class="string">&quot;root:Milvus&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">client.update_password(<span class="string">&#x27;root&#x27;</span>, <span class="string">&#x27;Milvus&#x27;</span>, <span class="string">&#x27;&lt;your-new-password&gt;&#x27;</span>, using=<span class="string">&#x27;default&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(client.list_users())</span><br></pre></td></tr></table></figure><blockquote><p>  参考：</p><ul><li><a href="https://www.milvus-io.com/adminGuide/authenticate">https://www.milvus-io.com/adminGuide/authenticate</a></li></ul></blockquote><br/><h3 id="备注"><a href="#备注" class="headerlink" title="备注"></a><strong>备注</strong></h3><p>在启动 standalone 类型的服务后， Web 界面会有 etcd unhealthy 的报错。</p><p>这个是正常现象，忽略即可；</p><blockquote><p>  参考：</p><ul><li><a href="https://github.com/milvus-io/milvus/issues/39417">milvus-io/milvus#39417</a></li></ul></blockquote><br/><h2 id="注册SiliconFlow"><a href="#注册SiliconFlow" class="headerlink" title="注册SiliconFlow"></a><strong>注册SiliconFlow</strong></h2><p>SiliconFlow 提供了各种大模型的 API，甚至有许多免费的版本；</p><p>可以通过下面的链接注册：</p><ul><li><a href="https://cloud.siliconflow.cn/i/zA7ywKdU">https://cloud.siliconflow.cn/i/zA7ywKdU</a></li></ul><blockquote><p>  <strong>链接包含我的邀请码，注册后可额外获得 2000w 的 token 额度。</strong></p></blockquote><p>注册成功后，可以在 <a href="https://cloud.siliconflow.cn/account/ak">API密钥</a> 生成密钥；</p><blockquote><p>  <strong>保存，后面会用到！</strong></p></blockquote><br/><h2 id="部署AnythingLLM"><a href="#部署AnythingLLM" class="headerlink" title="部署AnythingLLM"></a><strong>部署AnythingLLM</strong></h2><h3 id="部署-1"><a href="#部署-1" class="headerlink" title="部署"></a><strong>部署</strong></h3><p>可以通过 Docker 直接部署 AnythingLLM：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> STORAGE_LOCATION=<span class="variable">$HOME</span>/workspace/anythingllm &amp;&amp; \</span><br><span class="line"><span class="built_in">mkdir</span> -p <span class="variable">$STORAGE_LOCATION</span> &amp;&amp; \</span><br><span class="line"><span class="built_in">touch</span> <span class="string">&quot;<span class="variable">$STORAGE_LOCATION</span>/.env&quot;</span> &amp;&amp; \</span><br><span class="line"><span class="built_in">chmod</span> -R 0777 <span class="variable">$STORAGE_LOCATION</span> &amp;&amp; \</span><br><span class="line">docker run -d -p 3001:3001 \</span><br><span class="line">--restart=unless-stopped \</span><br><span class="line">--name my-anything-llm \</span><br><span class="line">--cap-add SYS_ADMIN \</span><br><span class="line">-v <span class="variable">$&#123;STORAGE_LOCATION&#125;</span>:/app/server/storage \</span><br><span class="line">-v <span class="variable">$&#123;STORAGE_LOCATION&#125;</span>/.env:/app/server/.env \</span><br><span class="line">-e STORAGE_DIR=<span class="string">&quot;/app/server/storage&quot;</span> \</span><br><span class="line">registry.cn-hangzhou.aliyuncs.com/jasonkay/anythingllm:latest</span><br></pre></td></tr></table></figure><p>这里需要注意：</p><p><strong>Docker挂载目录需要给权限 0777，否则可能会报错无权限（尤其是root用户操作）：</strong></p><blockquote><p>  <a href="https://github.com/Mintplex-Labs/anything-llm/issues/2564">https://github.com/Mintplex-Labs/anything-llm/issues/2564</a></p></blockquote><br/><h3 id="配置"><a href="#配置" class="headerlink" title="配置"></a><strong>配置</strong></h3><p>在配置 <code>LLM 提供商</code> 时，需要选择：<code>Generic OpenAI</code> 才能使用我们在 SiliconFlow 中的模型，随后配置：</p><ul><li>Base URL：<a href="https://api.siliconflow.cn">https://api.siliconflow.cn</a></li><li>API Key：你上面生成的API密钥</li><li>Chat Model Name：可在 <a href="https://cloud.siliconflow.cn/models">https://cloud.siliconflow.cn/models</a> 查找免费的模型（例如：<code>Qwen/Qwen2.5-7B-Instruct</code>）</li></ul><br/><p>在配置向量数据库时，可以直接使用 AnythingLLM 中内嵌的 LanceDB，此时无需配置；</p><p>当然，也可以使用我们上面已经部署好的 Milvus 数据库；</p><p>此时，只需要配置：</p><ul><li>Milvus DB Address：<a href="http://172.17.0.1">http://172.17.0.1</a> （可以使用 Docker 的gateway，也可以用其他的）</li><li>Username、Password：使用你配置的或者默认的即可！</li></ul><br/><h3 id="加载模型"><a href="#加载模型" class="headerlink" title="加载模型"></a><strong>加载模型</strong></h3><p>上面配置完成后，即可正常使用对话功能；</p><p>但是，如果想要通过上传文档、图片等形成个人知识库，则还需要对数据进行向量化等操作，此时需要加载模型；</p><p>在没有挂梯子的情况下，在上传文档时会报错：<code>fetch-failed-on-upload</code>：</p><ul><li><a href="https://docs.anythingllm.com/fetch-failed-on-upload#windows-visual-c-redistributable">https://docs.anythingllm.com/fetch-failed-on-upload#windows-visual-c-redistributable</a></li><li><a href="https://github.com/Mintplex-Labs/anything-llm/issues/821#issuecomment-1968382359">https://github.com/Mintplex-Labs/anything-llm/issues/821#issuecomment-1968382359</a></li></ul><p>此时大概率是一位模型无法下载；</p><p>可以通过手动下载并加载的方式来解决：</p><blockquote><p>  参考：</p><ul><li><a href="https://github.com/JasonkayZK/docker-repo/issues/4">https://github.com/JasonkayZK/docker-repo/issues/4</a></li></ul></blockquote><p>首先，在 <code>&lt;your-anythingllm-path&gt;/models/</code> 目录下创建 <code>Xenova</code> 目录；</p><p>随后下载模型压缩包，并上传到这个目录下：</p><ul><li><a href="https://github.com/user-attachments/files/18596293/all-MiniLM-L6-v2.zip">all-MiniLM-L6-v2.zip</a></li></ul><p>最后解压缩即可：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">unzip all-MiniLM-L6-v2.zip</span><br></pre></td></tr></table></figure><p>解压缩完成后效果：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">root@VM-12-16-debian:~/workspace/anythingllm/models/Xenova# tree .</span><br><span class="line">.</span><br><span class="line">└── all-MiniLM-L6-v2</span><br><span class="line">    ├── config.json</span><br><span class="line">    ├── onnx</span><br><span class="line">    │   └── model_quantized.onnx</span><br><span class="line">    ├── tokenizer_config.json</span><br><span class="line">    └── tokenizer.json</span><br><span class="line"></span><br><span class="line">2 directories, 4 files</span><br></pre></td></tr></table></figure><br/><h2 id="功能测试"><a href="#功能测试" class="headerlink" title="功能测试"></a><strong>功能测试</strong></h2><p>全部部署完成后，可以创建新的工作区，并且在工作区中创建 thread 进行新的对话；</p><p>同时在工作区中也可以上传文档，在对话时，AnythingLLM 会首先根据你的问题，在向量数据库中匹配，随后发给大模型作为 prompt 来生成对应回答！</p><br/><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a><strong>结语</strong></h2><p>除了使用 Docker 来部署 AnythingLLM 之外，也提供了桌面的版本；</p><p>Desktop 版本和 Web 版的配置非常类似，这里不再赘述！</p><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>源代码：</p><ul><li><a href="https://github.com/JasonkayZK/docker-repo/blob/master/anything-llm.sh">https://github.com/JasonkayZK/docker-repo/blob/master/anything-llm.sh</a></li><li><a href="https://github.com/JasonkayZK/docker-repo/tree/milvus-standalone">https://github.com/JasonkayZK/docker-repo/tree/milvus-standalone</a></li></ul><br/>]]></content>
    
    
    <summary type="html">最近DeepSeek如火如荼，由于目前我也有自己搭建个人知识库的需求，因此结合最新的一些技术搭建了一下。主要是包括AnythingLLM平台、SillconFlow提供免费的大模型API支持、私有部署的Milvus向量数据库供多个人使用！</summary>
    
    
    
    <category term="人工智能" scheme="https://jasonkayzk.github.io/cn/categories/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/"/>
    
    
    <category term="Docker" scheme="https://jasonkayzk.github.io/cn/tags/Docker/"/>
    
    <category term="人工智能" scheme="https://jasonkayzk.github.io/cn/tags/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/"/>
    
  </entry>
  
  <entry>
    <title>さよなら２０２４、こんにちは２０２５！</title>
    <link href="https://jasonkayzk.github.io/cn/2025/01/17/%E3%81%95%E3%82%88%E3%81%AA%E3%82%89%EF%BC%92%EF%BC%90%EF%BC%92%EF%BC%94%E3%80%81%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%EF%BC%92%EF%BC%90%EF%BC%92%EF%BC%95%EF%BC%81/"/>
    <id>https://jasonkayzk.github.io/cn/2025/01/17/%E3%81%95%E3%82%88%E3%81%AA%E3%82%89%EF%BC%92%EF%BC%90%EF%BC%92%EF%BC%94%E3%80%81%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%EF%BC%92%EF%BC%90%EF%BC%92%EF%BC%95%EF%BC%81/</id>
    <published>2025-01-17T05:45:11.000Z</published>
    <updated>2026-10-25T04:05:16.276Z</updated>
    
    <content type="html"><![CDATA[<p>又是新的一年了，最近放寒假，终于能抽出时间来总结一下2024年、再展望一下2025年！</p><br/><span id="more"></span><h1 id="さよなら２０２４、こんにちは２０２５！"><a href="#さよなら２０２４、こんにちは２０２５！" class="headerlink" title="さよなら２０２４、こんにちは２０２５！"></a><strong>さよなら２０２４、こんにちは２０２５！</strong></h1><h2 id="さよなら２０２４！"><a href="#さよなら２０２４！" class="headerlink" title="さよなら２０２４！"></a><strong>さよなら２０２４！</strong></h2><h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a><strong>前言</strong></h3><p>2024年对我个人来说，是转变极大的一年。</p><p>在这一年，我彻底放弃了程序员的职业，转而回家考取体制内，最终在八月份成为了一名家乡大专的计算机专业的老师。</p><p>除了职业上的转变，实际上也包含了心态上的转变。</p><p>在2024年的上半年，实际上花了很长时间继续去做一些技术上的突破，比如：</p><ul><li>学习了一些数据存储的格式，例如：bamboo；</li><li>学习了分布式系统相关的时钟逻辑，也用 rust 实现了一个：merkle-trie-clock；</li><li>学习了 CRDTs 相关的内容，用 rust 写了一个简单的 CRDTs 的demo；</li><li>看了数据库内核的相关实现，打算尝试去写一个基于 CRDTs 理论的分布式数据库；</li><li>……</li></ul><p>但是，后面发现对于技术的热情实际上是有所下降的。</p><blockquote><p>  <strong>与其说是对于技术的热情有所下降，不如说是更多是想分享知识，而非单纯的研究技术；</strong></p></blockquote><br/><p>当然，除了研究技术之外，上半年也准备了一下考试。</p><blockquote><p>  别忘了，我是学电气工程出身的！</p></blockquote><p>为了准备相关的考试，又重新复习了一下电气工程的相关书，包括：</p><ul><li>电网招聘考试书</li><li>注册电气工程师</li><li>原来本科的书</li><li>行测等</li><li>……</li></ul><p><img src="https://raw.gitmirror.com/JasonkayZK/blog_static/master/images/%E7%94%B5%E6%B0%94%E5%A4%8D%E4%B9%A0.jpg" alt="电气复习.jpg"></p><p>最后也是通过笔试第二、面试第一成功选择了学校的岗位。</p><blockquote><p>  <strong>有些人可能会奇怪，电气工程专业为啥当上了计算机的老师；</strong></p><p>  <strong>实际上我在去学校报道的时候，正好碰到了计算机学院的院长，然后就被拉到了计算机学院😁，巧了！</strong></p></blockquote><br/><h3 id="学校生活"><a href="#学校生活" class="headerlink" title="学校生活"></a><strong>学校生活</strong></h3><p>八月份入职之前，其实提前准备了一些教师相关的东西，比如：</p><ul><li>如何备课</li><li>如何上好一门课</li><li>上课期间站姿、手势、仪态等等</li></ul><p>但实际上刚入职的老师会被要求担任辅导员；</p><br/><h4 id="辅导员"><a href="#辅导员" class="headerlink" title="辅导员"></a><strong>辅导员</strong></h4><p>作为初入学校的「しろうと」来说，辅导员的挑战实际上是有的。</p><p>对于2024年新入学的学生来说，大致是在06年出生，和我相差大概10岁左右。</p><blockquote><p>  <strong>但是实际上，辅导员算是一个半管理岗位，为啥说是“半”呢？</strong></p><p>  <strong>因为，每天一睁眼，几十号人的吃喝拉撒基本上都要你管！</strong></p></blockquote><p>但是实际上会有些紧张，这个紧张一方面是：和一群「歳下」 的孩子们接触：</p><ul><li>如何和这些同学接触？</li><li>如何融入学生？</li><li>进一步，如何管理这些学生？（达成共识？解决冲突？）</li></ul><blockquote><p>  <strong>实际上，这些工作和程序员的工作思路是完全不同的事情！</strong></p></blockquote><p>另一方面是：如何正确的引导这些学生？</p><ul><li>思想上</li><li>三观上</li></ul><p>我自以为，老师和其他相关的职业有一个很大的不同在于：</p><p><font color="#f00"><strong>一个好的老师真的可以拯救学生，而一个不负责任的老师真的也能毁掉无数个学生</strong></font></p><blockquote><p>  <strong>我自认为自己还算是一个做事负责任的人吧！</strong></p></blockquote><p>实际上你的言行真的会影响到很多学生、尤其是刚刚成年的学生未来的三观。</p><p>但是对于如何做，实际上当时我是毫无头绪的！</p><p>但是当时我给自己定下了一个最低的底线：</p><ul><li><font color="#f00"><strong>一定不要成为自己最讨厌的那种老师！</strong></font></li></ul><blockquote><p>  <strong>现在看来，这个底线实际上也并不低！</strong></p></blockquote><br/><h5 id="首次接触学生"><a href="#首次接触学生" class="headerlink" title="首次接触学生"></a><strong>首次接触学生</strong></h5><p>我第一次接触学生实际上是在新生报道之前。</p><p>因为我之前是程序员的缘故，接触过不少云计算相关的内容，所以我的导师王老师让我来带一带竞赛的学生；</p><blockquote><p>  <strong>实际上这个决定让我首先小范围的接触了几位同学；</strong></p><p>  <strong>对我后面工作的开展获益匪浅；</strong></p></blockquote><p>所以，在还没开学之前就了解了目前这个年龄段的学生脑子里想的是什么，学生的层次、一些学校的规则制度、运行模式等等。</p><p>同时也能够小范围的先锻炼锻炼自己的表达能力…</p><blockquote><p>  <strong>关于竞赛的事情，后文再继续聊～</strong></p></blockquote><br/><h5 id="迎新活动"><a href="#迎新活动" class="headerlink" title="迎新活动"></a><strong>迎新活动</strong></h5><p>当新生辅导员的第一件事实际上是为全班的新生建群。</p><p>好在我带的班学生都比较积极，基本上一天之内就建好了！</p><p>到了24级正式开学的时候，实际上今年一共招了将近900号学生，要对这些学生进行信息采集、确认；</p><p>当时在学院楼外面坐了整整两天，说话说的嗓子都要哑了，最后也是顺利的把这些熊孩子给安置好了。</p><br/><h5 id="第一次带军训"><a href="#第一次带军训" class="headerlink" title="第一次带军训"></a><strong>第一次带军训</strong></h5><p>迎新结束之后，马不停蹄的就是学生的军训；</p><p>比起我当年的军训，个人觉得00后的军训强度要低太多了；</p><p>可能是身体素质整体都下滑，军训还没开始，刚刚站了十几分钟就已经有晕倒的了。</p><p>我带的班，军训的两个星期也是请假无数……；</p><p>总而言之，身体素质在00后这一代真的堪忧……。</p><br/><h5 id="第一次班会"><a href="#第一次班会" class="headerlink" title="第一次班会"></a><strong>第一次班会</strong></h5><p>在军训期间，要开一个班会，和班里的同学都见见面。</p><p>这也是我第一次以辅导员的身份站在讲台上；</p><p>其实刚开始还是有些紧张的，毕竟下面坐着几十个完全不认识的熊孩子；</p><p>需要做的实际上是提前准备班会的内容，可以先记在笔记本上，然后带过去讲就行；</p><blockquote><p>  <strong>后面发现，站上去之后讲的挺自然的，就不紧张了…</strong></p><p>  <strong>当然，现在在上面时间长了，早就没什么感觉了…</strong></p></blockquote><br/><h5 id="第一次出差"><a href="#第一次出差" class="headerlink" title="第一次出差"></a><strong>第一次出差</strong></h5><p>在九月底还没到十月份的时候，接到了通知要带几个学生去开封参加比赛，这也是我第一次带学生外出比赛；</p><p>比较好的是，来回的路途是由市政府安排的专车接送，所以不需要提前订票了；</p><p>但是当时的酒店我们希望能拼房，所以出来不小的问题，就是和我们拼房的人提前3天走了，导致我们无房可拼；</p><p>不过后面也是找到了开封市的人社局给解决了；</p><p>本次比赛的成绩可以说是非常惨淡：<strong>参与了3个赛项，无一获奖！</strong></p><p>实际上一个比较关键的原因是：竞赛的学生基本上都是靠自己自学，而没有老师带！</p><p>这些学生会浪费大量的时间在寻找学习材料和学习路径上，这是很可怕的事情！</p><blockquote><p>  <strong>这也让我感受到了，学校的竞赛之路，任重而道远啊！</strong></p></blockquote><br/><h5 id="一些其他的碎碎念"><a href="#一些其他的碎碎念" class="headerlink" title="一些其他的碎碎念"></a><strong>一些其他的碎碎念</strong></h5><p>除了上面的事情之外，实际上还有很多其他的事情，下面就简单列出一部分：</p><ul><li>学生宿舍值班</li><li>学生日常请假管理</li><li>学生心理问题排查</li><li>班级活动组织</li><li>……</li></ul><p>最后想再说一下：</p><p>我最开始以为，来到大专的学生大多数是对学习毫无兴趣的学生；</p><p>但是后面接触之后我发现，实际上这里大多数学生都来自农村、乡镇（至少我班里只有4、5个是城市户口）；</p><p>他们先天就没有特别好的教育环境。</p><p>以我带的竞赛的一个学生为例：这个学生白天的时候要去干农活、晚上在家做完饭之后，才能抽出时间来学习云计算；</p><p>我当时听完之后感觉到挺不可思议的。</p><blockquote><p>  <strong>当时我还戏称自己是“上山下乡”……</strong></p></blockquote><br/><h4 id="教学"><a href="#教学" class="headerlink" title="教学"></a><strong>教学</strong></h4><h5 id="竞赛培训"><a href="#竞赛培训" class="headerlink" title="竞赛培训"></a><strong>竞赛培训</strong></h5><p>作为一个老师而言，其实最基本的一个工作就是讲课；</p><p>分享的经验实际上在之前当程序员的时候是有的，当时有大量的技术分享会，而且我也参与过一次线上的直播分享；</p><p>但是实际上对于这些学生的水平，我是拿不准的，不知道这些学生对于知识的掌握程度，这个是很致命的！</p><p>好在有个学生掌握的还可以，但是没有老师带，实际上还是挺吃力的，一直在自己部署 OpenStack，对于 Docker、K8S 都不知道是什么；</p><p>我也是从 Github、git、一路讲到 Docker！</p><blockquote><p>  <strong>实际上，如果真正感兴趣、用心学的学生，他的学习能力是惊人的！</strong></p></blockquote><p>最后也是拿了省二等和国家三等奖的成绩。</p><blockquote><p>  <strong>实际上这个成绩只是个开始，后面还要继续努力！</strong></p></blockquote><br/><h5 id="第一次试讲"><a href="#第一次试讲" class="headerlink" title="第一次试讲"></a><strong>第一次试讲</strong></h5><p>关于这个试讲，这里说一下。</p><p>新入职的老师是不会直接参与讲课的，只有通过了：教研室、系部、学校，三个阶段的试讲才能上课。</p><p>试讲的内容是自己选择一门最拿手的课程，然后进行无生试讲，大概 15 分钟左右。</p><p>我的试讲内容实际上是云计算，讲的 Docker。</p><p>由于没有什么经验，同时备课准备的实际上不是很充分，所以课讲的稀烂……</p><blockquote><p>  <strong>甚至讲课的状态是我最讨厌的念 PPT 的方式……！</strong></p></blockquote><p>当时主任给我提了很多很实用的整改意见，我这里大概总结了几条：</p><ul><li><strong>PPT 的内容应该少文章多图片，这样比较生动；</strong></li><li><strong>讲课的时候应该多举一些生活中的例子，而不只是念ppt的内容；</strong></li><li><strong>在讲的过程中，声音应当抑扬顿挫，有节奏，类似于唱歌；</strong></li><li>……</li></ul><blockquote><p>  <font color="#f00"><strong>这里非常感谢主任给我提的这些意见，让我在后面找到了讲课的方向，慢慢摸索出了如何讲课！</strong></font></p><p>  <font color="#f00"><strong>实际上还有另外一个问题，就是：当时我刚来的时候就是给参与竞赛的学生讲，但是这些学生实际上水平、学习热情是远远高于一般的学生的！</strong></font></p><p>  <font color="#f00"><strong>实际上这也导致了，后面在真正上课的时候，一开始上课的内容实际上学生并不能很好的掌握（甚至部分学生别崩溃）！</strong></font></p></blockquote><p>后面，由于第一次试讲讲的并不是很好，所以后面又陆陆续续讲了几次试讲，进步其实是很明显的！</p><br/><h5 id="新生分享、社团分享"><a href="#新生分享、社团分享" class="headerlink" title="新生分享、社团分享"></a><strong>新生分享、社团分享</strong></h5><p>在第二次试讲之前，为了锻炼一下自己的讲课能力，参与了一些其他课程的讲授。</p><p>主要是几次的新生分享：</p><p>第一次是给24级新来的计算机专业的新生讲解目前一些新的主流技术，比如：云计算、大数据、人工智能相关的内容；</p><p>第二次是给学校的本科学生讲解：大学时间规划、考研等相关的内容；</p><p>相比于第一次分享，第二次是受到学校的另一个学院的院长邀请，形式上也比较正式，是在学校图书馆一楼的报告厅，大概有几百号学生参与；</p><p>实际上准备的并不是很充分，但是不知道是不是因为讲的都是自己的经历，反而没什么可紧张的，讲的过程也很顺利。</p><blockquote><p>  <strong>实际上，在台上看到下面坐着的许多学生心里还是几多感慨：</strong></p><p>  <strong>大概十年前，我和他们是一样的迷茫，不知道自己何去何从，不知道自己要干什么……</strong></p><p>  <strong>所以当时，上台之前，我想做的实际上就是分享自己的经历，包括好的和坏的。让这些学生有所借鉴，能走出属于这些孩子自己的一条路！</strong></p></blockquote><br/><p>同时，由于我是学校计算机社团的指导老师，在后面也给社团讲了一次课（大概2个小时的时间）。</p><p>主要是分享（或者说科普）一些计算机相关的内容。</p><p>来参与的学生实际上并不只是计算机专业的学生，但是除了基础的 Python 之外，我还是讲了一些其他的内容。</p><p>比如：</p><ul><li>人工智能的基本使用方法；</li><li>Github 网站</li><li>一些写代码的工具</li><li>……</li></ul><blockquote><p>  <strong>基本上每次分享，我都要讲上面的一些内容；</strong></p><p>  <strong>尤其是 Github，我觉得如果从事计算机专业，这个网站是必须要知道的！</strong></p><p>  <strong>但是国内很多高校的学生，甚至到毕业都不知道这个网站！</strong></p><p>  <strong>个人觉得，学会并使用 Github 是从事计算机行业最基本的一项内容！</strong></p></blockquote><br/><h5 id="第二次试讲"><a href="#第二次试讲" class="headerlink" title="第二次试讲"></a><strong>第二次试讲</strong></h5><p>第二次试讲来的比较匆忙，从通知到试讲实际上就间隔了两三天时间。</p><p>并且由于和之前第一次试讲间隔了太长的时间，实际上之前试讲的内容都忘的差不多了。</p><p>好在 “瘦死的骆驼比马大”！</p><p>所以最后还是顺利的拿下了。</p><p>当然，当时院长也提出了不少的意见，比如：</p><ul><li>讲课过程中，动作太多，一直来回走</li><li>PPT 的标题不统一</li><li>……</li></ul><br/><h5 id="紧急代课！"><a href="#紧急代课！" class="headerlink" title="紧急代课！"></a><strong>紧急代课！</strong></h5><p>十一月底的时候，由于有一位老师提前走了，他这学期有两门课需要我临时带，所以强度突然上来！</p><p>当时是周五的晚上通知我，下周一就要上课了！</p><p>由于是第一次正式上课，很多规矩都还不清楚，而且当时是临时代课，还不知道之前的内容。</p><p>所以花了一些时间将要做的按照先后顺序事情归了一下类：</p><ul><li>添加原来的老师、班委，询问课程进度</li><li>拿之前老师的教学资料</li><li>提前备课</li><li>询问上课的流程（包括如何签到、课前的点名、下课的内容等等）</li><li>……</li></ul><p>比较巧的是，我带的其中有一门课，在还没开学的时候，提前备过课，所以可以直接拿过来讲。</p><p>所以第一节课实际上马马虎虎，没有讲什么具体的操作内容，主要是对大数据的技术做了一个科普。</p><br/><p>但是后面的课程实际上是出了一些小状况的：</p><p>1、由于这些学生之前的基础没有打好，所以导致我在讲课的时候，班里一大半的学生根本不知道如何实操！</p><blockquote><p>  <strong>实际上，使用到的都是一些非常讲的的 Shell 命令！</strong></p><p>  <strong>对于我之前带的竞赛的学生来说是非常简单的，但是对于来上课的普通学生来说，感觉比登天还难！</strong></p></blockquote><p>所以后面又先带着“复习”了一下 Linux 的内容。</p><br/><p>2、另外一个状况是：在机房里面，实际上是没有部署相应的软件的，所以学生没办法跟着一起练习！</p><p>所以，我专门抽了一个下午的时间，做了一个 VMWare 的镜像给到学生，让学生们可以直接通过这个镜像练习！</p><blockquote><p>  最开始我做的是一个无图形界面的系统，但是发现这些学生不会用……</p><p>  所以没办法，又做了一个 Desktop 版本的……</p></blockquote><p>不管怎么样，最后也是把课、期末考试、教学材料跌跌撞撞的走完了！</p><p>虽然比较生涩，但是确实把：</p><ul><li>如何上课</li><li>如何设计课程</li><li>如何设计期末考试</li><li>如何整理教学材料</li><li>……</li></ul><p>在高强度之下快速的摸清楚了！</p><br/><h5 id="第三次试讲"><a href="#第三次试讲" class="headerlink" title="第三次试讲"></a><strong>第三次试讲</strong></h5><p>第三次试讲是由学校来组织的，来参与的都是新老师，但是还是收获满满。</p><p>我由于之前的很多经历，准备的比较充分，所以没什么可紧张的。</p><p>但是，在听其他老师试讲的过程中，实际上发现自己和他们还是有非常大的差距的！</p><p>尤其是有几个音乐专业的老师，讲的生动形象，我和他们比起来可以说是相形见绌……</p><blockquote><p>  <strong>并且，我在试讲的时候，写板书写了一分多钟，被评委给吐槽了……</strong></p></blockquote><br/><h3 id="一些工作上的总结"><a href="#一些工作上的总结" class="headerlink" title="一些工作上的总结"></a><strong>一些工作上的总结</strong></h3><h4 id="一些心得和分享"><a href="#一些心得和分享" class="headerlink" title="一些心得和分享"></a><strong>一些心得和分享</strong></h4><p>上面是半个学期的一些工作内容。实际上，除了上面列出的一些工作之外，还有很多其他的工作没有列出来。</p><p>可以说，虽然是一个新的老师，但是工作还是非常充实的！</p><p>下面列一些我觉得这学期工作的时候，比较实用的一些技巧和心得。</p><br/><h5 id="待办清单（小米云服务）"><a href="#待办清单（小米云服务）" class="headerlink" title="待办清单（小米云服务）"></a><strong>待办清单（小米云服务）</strong></h5><blockquote><p>  <strong>这个是我目前为止，基本上离不开的一个东西！</strong></p></blockquote><p>因为辅导员的事情实际上是非常多的，基本上每次开会都要安排十几件事情！</p><p>如果没有个待办清单，很多事情都会忘掉！</p><p>我之前尝试过一些其他的 TODO 应用，但是感觉还没有小米自带的好用。</p><p>小米的待办清单在 Windows 上有 <code>MIUI+</code> 可以同步，但是我用的是 Mac，没有这个软件。</p><p>但是有一个 <code>小米云服务</code>，所以可以曲线救国，用这个！</p><blockquote><p>  <strong>这里面唯一一个我用的功能就是待办清单！</strong></p><p>  顺便吐槽一下，MIUI+ 说了好多年适配 Mac 了，到现在还没有做出来……</p></blockquote><br/><h5 id="和学生打交道"><a href="#和学生打交道" class="headerlink" title="和学生打交道"></a><strong>和学生打交道</strong></h5><p>有的人可能会对辅导员这个职业比较抗拒，但是实际上我倒是觉得这是为数不多比较暖心的工作了…</p><p>可能是因为我和这些孩子们的年龄差距不大，所以并没有那么多代沟，所以沟通起来还是比较轻松的。</p><p>而且也都经历过学生时代，对于这些学生心里是怎么想的、比较反感的东西实际上是一清二楚的。</p><p>当时给自己定的目标就是：</p><ul><li><strong>从群众中来，到群众中去！</strong></li><li><strong>学生们的事情尽量身体力行的去做！</strong></li><li><strong>不要成为自己讨厌的那一类辅导员！</strong></li></ul><p>基本上每周六晚上我值班的时候，都会和班里的学生打打篮球。</p><p>然后时不时的在班级群里吹吹牛啥的，也挺欢乐。</p><p>但是确实，有的事情确实是没有办法，dddd……</p><br/><h5 id="讲课"><a href="#讲课" class="headerlink" title="讲课"></a><strong>讲课</strong></h5><p>对于讲课来说，是一个老师的基本功。</p><p>一个感受比较深的点就是：</p><p><strong>一定要备课！</strong></p><p><strong>一定要备课！</strong></p><p><strong>一定要备课！</strong></p><blockquote><p>  <strong>不备课的课和备过课的课上起来是完全不一样的！</strong></p></blockquote><p>备课的时候，主要是记一下这节课的主要大纲，有哪些重点难点什么的。</p><p>然后就是提前准备一些和课程有关的例子，如果不熟悉可以提前先打印出来，然后用笔标注一下。</p><blockquote><p>  <strong>认真备课之后，讲出来的东西可能才是你想要表达的；</strong></p><p>  <strong>如果不备课，虽然很多东西都是你用到的很基础的内容，当时实际上有的时候也很难讲出来！</strong></p></blockquote><p>我刚来学校的时候，主任和我分享的一句话就是：</p><p><font color="#f00"><strong>备课实际上是备学生，你要了解你上课的班的学生的整体状态！</strong></font></p><br/><h4 id="需要继续加强的地方"><a href="#需要继续加强的地方" class="headerlink" title="需要继续加强的地方"></a><strong>需要继续加强的地方</strong></h4><p>首先就是做事方面：</p><p>很多事情不懂得推脱，基本上只要有能帮忙的地方，都会去揽活来做，把自己搞得比较累。</p><p>有些时候如果自己比较忙，实际上是可以拒绝的！</p><br/><p>另外就是讲课方面：</p><p>基本上现在很多课程都还需要很长的时间备课，同时讲课的能力方面实际上还有很大的进步空间。</p><br/><p>心态方面：</p><p>很多事情在做的时候，还是会比较急，心态容易出问题。</p><p>这可能在未来的工作中还需要进一步沉淀沉淀！</p><br/><h2 id="こんにちは２０２５！"><a href="#こんにちは２０２５！" class="headerlink" title="こんにちは２０２５！"></a><strong>こんにちは２０２５！</strong></h2><p>聊完了已经过去的 2024 年，下面是我对于 2025 年的一些规划：</p><ul><li><p>证书：</p><ul><li><input checked="" disabled="" type="checkbox"> <p>高校教师资格证 + 普通话证</p></li><li><input disabled="" type="checkbox"> <p>通过软考中级（软件设计师）</p></li><li><input disabled="" type="checkbox"> <p>日语N2证书</p></li><li><input disabled="" type="checkbox"> <p>雅思证书（待定）</p></li></ul></li><li><p>跑步：</p><ul><li><input disabled="" type="checkbox"> 年跑量 1000km</li><li><input disabled="" type="checkbox"> 参加一次半马</li></ul></li><li><p>旅游：</p><ul><li><input disabled="" type="checkbox"> 去一次日本旅游</li></ul></li><li><p>购物：</p><ul><li><input disabled="" type="checkbox"> 40系 N 卡</li><li><input checked="" disabled="" type="checkbox"> 佳明 255 跑表</li></ul></li></ul><p>内容可能不是很多，但是是一些目前我能够想到的东西；</p><p>如果后面有新加入的内容，也会再加进来！</p><p>最后，祝愿各位在新的一年都能顺顺利利，无限进步！</p><p><strong>今年も、よろしくお願いします！</strong></p><br/>]]></content>
    
    
    <summary type="html">又是新的一年了，最近放寒假，终于能抽出时间来总结一下2024年、再展望一下2025年！</summary>
    
    
    
    <category term="人生日记" scheme="https://jasonkayzk.github.io/cn/categories/%E4%BA%BA%E7%94%9F%E6%97%A5%E8%AE%B0/"/>
    
    
    <category term="人生日记" scheme="https://jasonkayzk.github.io/cn/tags/%E4%BA%BA%E7%94%9F%E6%97%A5%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>Excel通过身份证号列计算性别</title>
    <link href="https://jasonkayzk.github.io/cn/2024/09/11/Excel%E9%80%9A%E8%BF%87%E8%BA%AB%E4%BB%BD%E8%AF%81%E5%8F%B7%E5%88%97%E8%AE%A1%E7%AE%97%E6%80%A7%E5%88%AB/"/>
    <id>https://jasonkayzk.github.io/cn/2024/09/11/Excel%E9%80%9A%E8%BF%87%E8%BA%AB%E4%BB%BD%E8%AF%81%E5%8F%B7%E5%88%97%E8%AE%A1%E7%AE%97%E6%80%A7%E5%88%AB/</id>
    <published>2024-09-11T02:28:56.000Z</published>
    <updated>2026-10-25T04:05:16.256Z</updated>
    
    <content type="html"><![CDATA[<p>Excel统计信息中有身份证号，可以通过身份证号直接生成性别列；</p><br/><span id="more"></span><h1 id="Excel通过身份证号列计算性别"><a href="#Excel通过身份证号列计算性别" class="headerlink" title="Excel通过身份证号列计算性别"></a><strong>Excel通过身份证号列计算性别</strong></h1><p>例如，B2 列为身份证号所在列，则可以在性别列（如D2列）填写：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">=IF(MOD(MID(B2, 17, 1), 2) = 1, &quot;男&quot;, &quot;女&quot;)</span><br></pre></td></tr></table></figure><p>输入后回车计算结果即为性别；</p><p>可以下拉直接生成全部结果！</p><br/><p>参考：</p><ul><li><a href="https://jingyan.baidu.com/article/5553fa8291d46b65a2393432.html">https://jingyan.baidu.com/article/5553fa8291d46b65a2393432.html</a></li></ul><br/>]]></content>
    
    
    <summary type="html">Excel统计信息中有身份证号，可以通过身份证号直接生成性别列；</summary>
    
    
    
    <category term="办公" scheme="https://jasonkayzk.github.io/cn/categories/%E5%8A%9E%E5%85%AC/"/>
    
    
    <category term="办公" scheme="https://jasonkayzk.github.io/cn/tags/%E5%8A%9E%E5%85%AC/"/>
    
    <category term="Excel" scheme="https://jasonkayzk.github.io/cn/tags/Excel/"/>
    
  </entry>
  
  <entry>
    <title>开源的个人书籍管理系统Talebook</title>
    <link href="https://jasonkayzk.github.io/cn/2024/08/22/%E5%BC%80%E6%BA%90%E7%9A%84%E4%B8%AA%E4%BA%BA%E4%B9%A6%E7%B1%8D%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9FTalebook/"/>
    <id>https://jasonkayzk.github.io/cn/2024/08/22/%E5%BC%80%E6%BA%90%E7%9A%84%E4%B8%AA%E4%BA%BA%E4%B9%A6%E7%B1%8D%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9FTalebook/</id>
    <published>2024-08-22T02:19:57.000Z</published>
    <updated>2026-10-25T04:05:16.288Z</updated>
    
    <content type="html"><![CDATA[<p>我平时看的都是PDF电子书籍，但是之前没有用书籍管理，所以书籍比较乱；</p><p>比较有名的书籍管理系统有Calibre，但是Talebook支持OPDS，同时能从豆瓣导入信息，比较好用；</p><p>本文介绍了如何部署和配置Talebook；</p><p>源代码：</p><ul><li><a href="https://github.com/JasonkayZK/docker-repo/tree/talebook">https://github.com/JasonkayZK/docker-repo/tree/talebook</a></li></ul><br/><span id="more"></span><h1 id="开源的个人书籍管理系统Talebook"><a href="#开源的个人书籍管理系统Talebook" class="headerlink" title="开源的个人书籍管理系统Talebook"></a><strong>开源的个人书籍管理系统Talebook</strong></h1><h2 id="部署"><a href="#部署" class="headerlink" title="部署"></a><strong>部署</strong></h2><p>项目地址如下：</p><ul><li><a href="https://github.com/talebook/talebook">https://github.com/talebook/talebook</a></li></ul><p>DockerHub地址：</p><ul><li><a href="https://hub.docker.com/r/talebook/talebook">https://hub.docker.com/r/talebook/talebook</a></li></ul><p>B站上也有UP主对Talebook做了介绍：</p><ul><li><a href="https://www.bilibili.com/video/BV1AT411S7c3/">https://www.bilibili.com/video/BV1AT411S7c3/</a></li></ul><p>部署起来也是非常简单，先把镜像拉下来，然后 docker-compose 就行：</p><p>docker-compose.yml</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&quot;3&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">talebook:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">talebook</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">talebook/talebook:v3.8.1</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/data/talebook:/data</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">       <span class="bullet">-</span> <span class="string">&quot;80:80&quot;</span></span><br><span class="line">       <span class="bullet">-</span> <span class="string">&quot;443:443&quot;</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">PUID=1000</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">PGID=1000</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">TZ=Asia/Shanghai</span></span><br><span class="line">      <span class="comment"># 调整为『SSR=ON』可开启「服务器端渲染」模式，对于搜索引擎更友好，同时更消耗服务器性能</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">SSR=OFF</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">douban-rs-api</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">      </span><br><span class="line">  <span class="attr">douban-rs-api:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">douban-rs-api</span></span><br><span class="line">    <span class="comment"># https://github.com/cxfksword/douban-api-rs</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">ghcr.io/cxfksword/douban-api-rs:latest</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br></pre></td></tr></table></figure><p>配置都比较简单，目录挂载、端口映射直接根据自己的需求修改即可！</p><br/><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a><strong>配置</strong></h2><p>基本的配置，上面的B站UP基本上都讲了；</p><p>需要注意的是：</p><p><font color="#f00"><strong>配置豆瓣的时候，url 结尾的 <code>/</code> 要删除！否则会无法使用！</strong></font></p><blockquote><p>  参考：</p><ul><li><a href="https://github.com/talebook/talebook/issues/340#issuecomment-2097703672">https://github.com/talebook/talebook/issues/340#issuecomment-2097703672</a></li></ul></blockquote><br/><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a><strong>其他</strong></h2><p>支持 OPDS 的 APP 推荐：</p><ul><li>安卓：静读天下</li><li>iOS、MacOS：Yomu、KyBook</li></ul><blockquote><p>  参考：</p><ul><li><a href="https://gameapp.club/post/2022-12-25-ebooks/">https://gameapp.club/post/2022-12-25-ebooks/</a></li></ul></blockquote><p>需要注意的是：</p><p><strong>如果要使用 OPDS，需要配置：</strong></p><ul><li><strong>关闭「私人图书馆」模式。</strong></li><li><strong>打开「允许任意下载」（访客无需注册或登录）</strong></li></ul><blockquote><p>  参考：</p><ul><li><a href="https://github.com/talebook/talebook/blob/master/document/README.zh_CN.md#%E9%9D%99%E8%AF%BB%E5%A4%A9%E4%B8%8Bapp%E9%87%8C%E8%AE%BF%E9%97%AE%E4%B9%A6%E5%BA%93%E4%BC%9A%E5%A4%B1%E8%B4%A5%E6%80%8E%E4%B9%88%E5%8A%9E">https://github.com/talebook/talebook/blob/master/document/README.zh_CN.md#%E9%9D%99%E8%AF%BB%E5%A4%A9%E4%B8%8Bapp%E9%87%8C%E8%AE%BF%E9%97%AE%E4%B9%A6%E5%BA%93%E4%BC%9A%E5%A4%B1%E8%B4%A5%E6%80%8E%E4%B9%88%E5%8A%9E</a></li></ul></blockquote><p><strong>Enjoy!</strong></p><br/><h1 id="附录"><a href="#附录" class="headerlink" title="附录"></a><strong>附录</strong></h1><p>源代码：</p><ul><li><a href="https://github.com/JasonkayZK/docker-repo/tree/talebook">https://github.com/JasonkayZK/docker-repo/tree/talebook</a></li></ul><p>参考：</p><ul><li><a href="https://www.bilibili.com/video/BV1AT411S7c3/">https://www.bilibili.com/video/BV1AT411S7c3/</a></li><li><a href="https://blog.hsu.life/2024/01/14/%E6%89%8B%E6%9C%BA%E5%A6%82%E4%BD%95%E6%96%B9%E4%BE%BF%E7%9A%84%E4%BD%BF%E7%94%A8%E4%B9%A6%E5%BA%93/index.html">https://blog.hsu.life/2024/01/14/%E6%89%8B%E6%9C%BA%E5%A6%82%E4%BD%95%E6%96%B9%E4%BE%BF%E7%9A%84%E4%BD%BF%E7%94%A8%E4%B9%A6%E5%BA%93/index.html</a></li><li><a href="https://gameapp.club/post/2022-12-25-ebooks/">https://gameapp.club/post/2022-12-25-ebooks/</a></li></ul><br/>]]></content>
    
    
    <summary type="html">我平时看的都是PDF电子书籍，但是之前没有用书籍管理，所以书籍比较乱；比较有名的书籍管理系统有Calibre，但是Talebook支持OPDS，同时能从豆瓣导入信息，比较好用；本文介绍了如何部署和配置Talebook；</summary>
    
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/categories/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    
    <category term="工具分享" scheme="https://jasonkayzk.github.io/cn/tags/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    <category term="软件推荐" scheme="https://jasonkayzk.github.io/cn/tags/%E8%BD%AF%E4%BB%B6%E6%8E%A8%E8%8D%90/"/>
    
  </entry>
  
</feed>
