<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>娃娃Code</title>
  
  <subtitle>Blog</subtitle>
  <link href="https://blog.dollcode.cn/atom.xml" rel="self"/>
  
  <link href="https://blog.dollcode.cn/"/>
  <updated>2025-06-27T06:34:56.453Z</updated>
  <id>https://blog.dollcode.cn/</id>
  
  <author>
    <name>娃娃Code</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>小米路由器BE7000的Docker权限不足问题解决</title>
    <link href="https://blog.dollcode.cn/xiaomiBE7000-dockerup.html"/>
    <id>https://blog.dollcode.cn/xiaomiBE7000-dockerup.html</id>
    <published>2024-12-09T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.453Z</updated>
    
    <content type="html"><![CDATA[<p>Error response from daemon: authorization denied by plugin opa-docker-authz: request rejected by administrative policy。<br>小米路由器BE7000，docker run 权限提升问题解决方案。</p><p>手上有一台MiWiFi For Xiaomi路由器BE7000 稳定版。这个路由器硬件配置还不错，而且支持Docker。刚好从网上看到有解锁SSH的教程。(SSH教程，在恩山找就行)<br>于是在开启SSH之后，尝试跑几个docker容器，结果遇到了这个错误：Error response from daemon: authorization denied by plugin opa-docker-authz: request rejected by administrative policy。</p><p>原来这个路由器默认的docker初始化加入了opa权限插件。这个插件opa-docker-authz 是一个使用 Open Policy Agent (OPA) 实现的 Docker 容器授权插件，用于对 Docker 守护进程的 API 请求进行访问控制。它允许管理员定义细粒度的访问控制策略，以决定哪些操作可以执行，哪些不可以。</p><p>首先我们找到·初始化的配置信息，关闭这个插件即可。文件在 <strong>&#x2F;etc&#x2F;config&#x2F;mi_docker</strong></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></pre></td><td class="code"><pre><span class="line">// 查看文件</span><br><span class="line"><span class="built_in">cat</span> /etc/config/mi_docker</span><br><span class="line"></span><br><span class="line">// 编辑文件</span><br><span class="line">vi /etc/config/mi_docker</span><br></pre></td></tr></table></figure><p>把文件中这一行 list authorization_plugins ‘opa-docker-authz’<br>将引号中的内容删掉，只保留引号就可以了<br>list authorization_plugins ‘’</p><p><img src="/img/article/20241209201126.png"></p><p>然后重启路由器就可以了</p><p>这样docker权限提升就完成了！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Error response from daemon: authorization denied by plugin opa-docker-authz: request rejected by administrative policy。&lt;br&gt;小米路由器BE7000，do</summary>
      
    
    
    
    <category term="生活琐事" scheme="https://blog.dollcode.cn/categories/%E7%94%9F%E6%B4%BB%E7%90%90%E4%BA%8B/"/>
    
    
    <category term="Linux" scheme="https://blog.dollcode.cn/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>cloudflare ddns通过API更新动态IP域名解析</title>
    <link href="https://blog.dollcode.cn/cloudflare-ddns.html"/>
    <id>https://blog.dollcode.cn/cloudflare-ddns.html</id>
    <published>2024-11-04T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.453Z</updated>
    
    <content type="html"><![CDATA[<p>Cloudflare的DDNS功能使用，通过Linux定时任务配合shell脚本，完成动态IP的域名解析。适用于家庭网络公网IP不固定的情况。</p><h1 id="创建一个API密钥"><a href="#创建一个API密钥" class="headerlink" title="创建一个API密钥"></a>创建一个API密钥</h1><p>登录Cloudflare之后 -&gt; 点击页面右上角的个人中心 -&gt; 进入My Profile -&gt; 进入API token<br>也可以直接访问链接：<a href="https://dash.cloudflare.com/profile/api-tokens">https://dash.cloudflare.com/profile/api-tokens</a></p><p>创建一个Token，选择模板Edit zone DNS<br><img src="/img/article/20241104140608.png"><br><img src="/img/article/20241104141241.png"></p><blockquote><p>点击 提交确认之后，复制token并保存起来. (<strong>注意这个Token只会展示这一次，忘记了就只能重新创建一个Token</strong>)</p></blockquote><h1 id="编写脚本，验证流程"><a href="#编写脚本，验证流程" class="headerlink" title="编写脚本，验证流程"></a>编写脚本，验证流程</h1><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># Cloudflare API令牌</span></span><br><span class="line">API_TOKEN=<span class="string">&quot;填token&quot;</span></span><br><span class="line"><span class="comment"># Cloudflare Zone ID</span></span><br><span class="line">ZONE_ID=<span class="string">&quot;填Zone ID&quot;</span></span><br><span class="line"><span class="comment"># DNS记录ID（需要更新的记录ID）</span></span><br><span class="line">RECORD_ID=<span class="string">&quot;填DNS记录ID&quot;</span></span><br><span class="line"><span class="comment"># 需要更新的域名，subdomain.example.com</span></span><br><span class="line">RECORD_NAME=<span class="string">&quot;填域名&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取当前公网IP</span></span><br><span class="line">CURRENT_IP=$(curl -s http://ipv4.icanhazip.com)</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;当前公网IP: <span class="variable">$CURRENT_IP</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取现有的DNS记录IP</span></span><br><span class="line">DNS_RECORD_RESPONSE=$(curl -s -X GET <span class="string">&quot;https://api.cloudflare.com/client/v4/zones/<span class="variable">$&#123;ZONE_ID&#125;</span>/dns_records/<span class="variable">$&#123;RECORD_ID&#125;</span>&quot;</span> \</span><br><span class="line">     -H <span class="string">&quot;Authorization: Bearer <span class="variable">$&#123;API_TOKEN&#125;</span>&quot;</span> \</span><br><span class="line">     -H <span class="string">&quot;Content-Type: application/json&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 提取现有DNS记录的IP地址</span></span><br><span class="line">DNS_RECORD_IP=$(<span class="built_in">echo</span> <span class="string">&quot;<span class="variable">$DNS_RECORD_RESPONSE</span>&quot;</span> | sed -n <span class="string">&#x27;s/.*&quot;content&quot;:&quot;\([^&quot;]*\)&quot;.*/\1/p&#x27;</span>)</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;提取到的DNS记录IP: <span class="variable">$DNS_RECORD_IP</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查IP是否需要更新</span></span><br><span class="line"><span class="keyword">if</span> [ <span class="string">&quot;<span class="variable">$CURRENT_IP</span>&quot;</span> == <span class="string">&quot;<span class="variable">$DNS_RECORD_IP</span>&quot;</span> ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;IP地址未改变，无需更新&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;IP地址已改变，开始更新DNS记录&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 更新DNS记录</span></span><br><span class="line">    RESPONSE=$(curl -s -X PUT <span class="string">&quot;https://api.cloudflare.com/client/v4/zones/<span class="variable">$&#123;ZONE_ID&#125;</span>/dns_records/<span class="variable">$&#123;RECORD_ID&#125;</span>&quot;</span> \</span><br><span class="line">         -H <span class="string">&quot;Authorization: Bearer <span class="variable">$&#123;API_TOKEN&#125;</span>&quot;</span> \</span><br><span class="line">         -H <span class="string">&quot;Content-Type: application/json&quot;</span> \</span><br><span class="line">         --data <span class="string">&quot;&#123;\&quot;type\&quot;:\&quot;A\&quot;,\&quot;name\&quot;:\&quot;<span class="variable">$&#123;RECORD_NAME&#125;</span>\&quot;,\&quot;content\&quot;:\&quot;<span class="variable">$&#123;CURRENT_IP&#125;</span>\&quot;,\&quot;ttl\&quot;:120,\&quot;proxied\&quot;:false&#125;&quot;</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> <span class="built_in">echo</span> <span class="string">&quot;<span class="variable">$RESPONSE</span>&quot;</span> | grep -q <span class="string">&quot;\&quot;success\&quot;:true&quot;</span>; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&quot;DNS记录已成功更新为新IP: <span class="variable">$&#123;CURRENT_IP&#125;</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;更新DNS记录失败：<span class="variable">$RESPONSE</span>&quot;</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line"><span class="keyword">fi</span></span><br></pre></td></tr></table></figure><p>首先在控制台新增一条对应的域名DNS解析记录，用于后续API动态修改。<br><img src="/img/article/20241104144310.png"></p><p>解释一下脚本中的几个变量：</p><ol><li>API_TOKEN：就是上面创建的token</li><li>ZONE_ID：在控制台websites列表页面-进入你的域名页面-在右侧可以看到API Zone ID</li><li>RECORD_ID：就是你需要更新的那一条解析记录的ID，可以用下面的API接口查看<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></pre></td><td class="code"><pre><span class="line">curl -X GET <span class="string">&quot;https://api.cloudflare.com/client/v4/zones/你的ZONE_ID/dns_records?type=A&amp;name=你的解析域名&quot;</span> \</span><br><span class="line">     -H <span class="string">&quot;Authorization: Bearer 你的API_TOKEN&quot;</span> \</span><br><span class="line">     -H <span class="string">&quot;Content-Type: application/json&quot;</span></span><br></pre></td></tr></table></figure><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">// 返回的响应结果如下，第一个id字段，就是这条域名解析记录的ID</span><br><span class="line">&#123;&quot;result&quot;:[&#123;&quot;id&quot;:&quot;3995e7cd0ee84056abe3e0c2d191cf62&quot;,&quot;zone_id&quot;:&quot;04dbfb40755d415ba7c2f40f562e357e&quot;,&quot;zone_name&quot;:&quot;dollcode.cn&quot;,&quot;name&quot;:&quot;blog.dollcode.cn&quot;,&quot;type&quot;:&quot;A&quot;,&quot;content&quot;:&quot;114.114.114.114&quot;,&quot;proxiable&quot;:true,&quot;proxied&quot;:false,&quot;ttl&quot;:120,&quot;settings&quot;:&#123;&#125;..............</span><br></pre></td></tr></table></figure></li><li>RECORD_NAME：填自己的域名就行了</li></ol><p>根据实际情况替换变量为自己的，然后保存脚本。命名为<code>cfddns.sh</code>，然后执行如下命令验证效果</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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 赋予可执行权限</span></span><br><span class="line"><span class="built_in">chmod</span> +x /opt/ddns/cfddns.sh</span><br><span class="line"><span class="comment"># 执行验证</span></span><br><span class="line">/opt/ddns/cfddns.sh</span><br></pre></td></tr></table></figure><p>就可以看到对应的日志信息了！</p><h1 id="注册为定时任务"><a href="#注册为定时任务" class="headerlink" title="注册为定时任务"></a>注册为定时任务</h1><p>接下来就是注册定时任务，每十分钟执行一次，完成自动动态更新解析</p><p>使用 cron 定时执行该脚本。编辑 cron 配置：</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">crontab -e</span><br></pre></td></tr></table></figure><p>添加如下内容，使其每10分钟执行一次：</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">*/10 * * * * /opt/ddns/cfddns.sh &gt;&gt; /opt/ddns/ddnsupdate.log 2&gt;&amp;1</span><br></pre></td></tr></table></figure><p>wq保存退出</p><p>注意目录替换为实际路径。并检查&#x2F;opt&#x2F;ddns&#x2F;ddnsupdate.log 中的日志输出即可！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Cloudflare的DDNS功能使用，通过Linux定时任务配合shell脚本，完成动态IP的域名解析。适用于家庭网络公网IP不固定的情况。&lt;/p&gt;
&lt;h1 id=&quot;创建一个API密钥&quot;&gt;&lt;a href=&quot;#创建一个API密钥&quot; class=&quot;headerlink&quot; ti</summary>
      
    
    
    
    <category term="Web技术" scheme="https://blog.dollcode.cn/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Linux" scheme="https://blog.dollcode.cn/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>新版FRP内网穿透搭建使用</title>
    <link href="https://blog.dollcode.cn/linux-newfrp.html"/>
    <id>https://blog.dollcode.cn/linux-newfrp.html</id>
    <published>2024-09-07T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.453Z</updated>
    
    <content type="html"><![CDATA[<p>新版的配置文件有比较大的改动，这里记录一下安装部署过程，官网文档在这里 <a href="https://gofrp.org/zh-cn/docs/setup">https://gofrp.org/zh-cn/docs/setup</a><br>下载安装地址 <a href="https://github.com/fatedier/frp/releases">https://github.com/fatedier/frp/releases</a><br>当前最新版0.60.0</p><h1 id="服务端安装"><a href="#服务端安装" class="headerlink" title="服务端安装"></a>服务端安装</h1><p>首先是服务端，需要在一台公网机器上部署。<br>这里我们自己下载 选择自己机器对应平台的压缩包 我这里选<a href="https://github.com/fatedier/frp/releases/download/v0.60.0/frp_0.60.0_linux_amd64.tar.gz">https://github.com/fatedier/frp/releases/download/v0.60.0/frp_0.60.0_linux_amd64.tar.gz</a></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">// 下载</span><br><span class="line">wget https://github.com/fatedier/frp/releases/download/v0.60.0/frp_0.60.0_linux_amd64.tar.gz</span><br><span class="line">// 解压</span><br><span class="line">tar zxvf frp_0.60.0_linux_amd64.tar.gz</span><br><span class="line">// 进入目录</span><br><span class="line"><span class="built_in">cd</span> frp_0.60.0_linux_amd64</span><br><span class="line">// 设置可执行权限</span><br><span class="line"><span class="built_in">chmod</span> +x frps</span><br></pre></td></tr></table></figure><p>可以看到目录下有两对执行文件和配置文件， 分别对应客户端(frpc)和服务端(frps)。</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></pre></td><td class="code"><pre><span class="line">LICENSE</span><br><span class="line">frpc</span><br><span class="line">frpc.toml </span><br><span class="line">frps      </span><br><span class="line">frps.toml</span><br></pre></td></tr></table></figure><h2 id="编辑配置文件"><a href="#编辑配置文件" class="headerlink" title="编辑配置文件"></a>编辑配置文件</h2><p><code>vim frps.toml</code>  加入如下配置</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><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"><span class="comment"># 服务端监听端口(需要开放安全组端口)</span></span><br><span class="line"><span class="attr">bindPort</span> = <span class="number">7000</span></span><br><span class="line"><span class="comment"># 服务端监听HTTP端口(需要开放安全组端口)</span></span><br><span class="line"><span class="attr">vhostHTTPPort</span> = <span class="number">8080</span></span><br><span class="line"><span class="comment"># 鉴权方式为token</span></span><br><span class="line"><span class="attr">auth.method</span> = <span class="string">&quot;token&quot;</span></span><br><span class="line"><span class="comment"># 设置Token，(安全重要) 建议设置复杂一点，对应客户端需要设置一样才能鉴权通过</span></span><br><span class="line"><span class="attr">auth.token</span> = <span class="string">&quot;abcdefg&quot;</span></span><br><span class="line"><span class="comment"># 日志文件最多保留天数，默认为 3 天。</span></span><br><span class="line"><span class="attr">log.maxDays</span> = <span class="number">7</span></span><br><span class="line"><span class="comment"># 日志级别，可选值为 trace, debug, info, warn, error，默认级别为 info</span></span><br><span class="line"><span class="attr">log.level</span> = <span class="string">&quot;info&quot;</span></span><br><span class="line"><span class="comment"># 日志输出文件路径 (根据自己的实际目录填写)</span></span><br><span class="line"><span class="attr">log.to</span> = <span class="string">&quot;/home/blog/frp_0.60.0_linux_amd64/info.log&quot;</span></span><br></pre></td></tr></table></figure><h2 id="设置开机自启"><a href="#设置开机自启" class="headerlink" title="设置开机自启"></a>设置开机自启</h2><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">vim /etc/systemd/system/frps.service</span><br></pre></td></tr></table></figure><p><strong>加入如下内容(注意替换自己的实际路径)</strong></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></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line">Description = frp server</span><br><span class="line">After = network.target syslog.target</span><br><span class="line">Wants = network.target</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">Type = simple</span><br><span class="line"># 启动frps的命令，需修改为您的frps的安装路径</span><br><span class="line">ExecStart = /home/blog/frp_0.60.0_linux_amd64/frps -c /home/blog/frp_0.60.0_linux_amd64/frps.toml</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy = multi-user.target</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">// 启动FRP服务并设置开机自启</span><br><span class="line">systemctl enable --now frps</span><br><span class="line">// 查看运行状态</span><br><span class="line">systemctl status frps</span><br></pre></td></tr></table></figure><p>** 看到如下日志就服务端启动就OK了 **</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></pre></td><td class="code"><pre><span class="line">● frps.service - frp server</span><br><span class="line">   Loaded: loaded (/etc/systemd/system/frps.service; enabled; vendor preset: disabled)</span><br><span class="line">   Active: active (running) since Sat 2024-09-09 11:37:27 CST; 5h 9min ago</span><br><span class="line"> Main PID: 2677050 (frps)</span><br><span class="line">    Tasks: 5</span><br><span class="line">   Memory: 13.0M</span><br><span class="line">   CGroup: /system.slice/frps.service</span><br><span class="line">           └─2677050 /home/blog/frp_0.60.0_linux_amd64/frps -c /home/blog/frp_0.60.0_linux_amd64/frps.toml</span><br></pre></td></tr></table></figure><h1 id="客户端安装"><a href="#客户端安装" class="headerlink" title="客户端安装"></a>客户端安装</h1><blockquote><p>下载的还是同一个压缩包，这些步骤就不重复说明了。<br>我这里连安装目录也都放的和服务机器一致。 解压之后，赋予客户端可执行权限</p></blockquote><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">// 设置可执行权限</span><br><span class="line"><span class="built_in">chmod</span> +x frpc</span><br></pre></td></tr></table></figure><h2 id="编辑配置文件-1"><a href="#编辑配置文件-1" class="headerlink" title="编辑配置文件"></a>编辑配置文件</h2><p>编辑客户端配置文件<br><code>vim frpc.toml</code>  有如下几种配置场景。可以直接看官网文档！挺详细的 <a href="https://gofrp.org/zh-cn/docs/examples/">https://gofrp.org/zh-cn/docs/examples/</a></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><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="comment"># 填服务端机器的公网IP</span></span><br><span class="line"><span class="attr">serverAddr</span> = <span class="string">&quot;x.x.x.x&quot;</span></span><br><span class="line"><span class="comment"># 和服务端保持一致</span></span><br><span class="line"><span class="attr">bindPort</span> = <span class="number">7000</span></span><br><span class="line"><span class="comment"># 和服务端保持一致</span></span><br><span class="line"><span class="attr">vhostHTTPPort</span> = <span class="number">8080</span></span><br><span class="line"><span class="comment"># 鉴权方式为token</span></span><br><span class="line"><span class="attr">auth.method</span> = <span class="string">&quot;token&quot;</span></span><br><span class="line"><span class="comment"># TOKEN 客户端需要设置和服务端一样才能鉴权通过</span></span><br><span class="line"><span class="attr">auth.token</span> = <span class="string">&quot;abcdefg&quot;</span></span><br><span class="line"><span class="comment"># 日志文件最多保留天数，默认为 3 天。</span></span><br><span class="line"><span class="attr">log.maxDays</span> = <span class="number">7</span></span><br><span class="line"><span class="comment"># 日志级别，可选值为 trace, debug, info, warn, error，默认级别为 info</span></span><br><span class="line"><span class="attr">log.level</span> = <span class="string">&quot;info&quot;</span></span><br><span class="line"><span class="comment"># 日志输出文件路径 (根据自己的实际目录填写)</span></span><br><span class="line"><span class="attr">log.to</span> = <span class="string">&quot;/home/blog/frp_0.60.0_linux_amd64/info.log&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 公众号调试代理 </span></span><br><span class="line"><span class="section">[[proxies]]</span></span><br><span class="line"><span class="attr">name</span> = <span class="string">&quot;mp-web&quot;</span></span><br><span class="line"><span class="attr">type</span> = <span class="string">&quot;http&quot;</span></span><br><span class="line"><span class="attr">localPort</span> = <span class="number">8080</span></span><br><span class="line"><span class="attr">customDomains</span> = [<span class="string">&quot;temptest.blog.dollcode.cn&quot;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># SSH登录代理</span></span><br><span class="line"><span class="section">[[proxies]]</span></span><br><span class="line"><span class="attr">name</span> = <span class="string">&quot;ssh&quot;</span></span><br><span class="line"><span class="attr">type</span> = <span class="string">&quot;tcp&quot;</span></span><br><span class="line"><span class="attr">localIP</span> = <span class="string">&quot;127.0.0.1&quot;</span></span><br><span class="line"><span class="attr">localPort</span> = <span class="number">22</span></span><br><span class="line"><span class="attr">remotePort</span> = <span class="number">6000</span></span><br></pre></td></tr></table></figure><h2 id="设置开机自启-1"><a href="#设置开机自启-1" class="headerlink" title="设置开机自启"></a>设置开机自启</h2><blockquote><p>方法和在服务端机器操作一模一样，仅仅需要修改 frps 为 frpc 即可</p></blockquote><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">vim /etc/systemd/system/frpc.service</span><br></pre></td></tr></table></figure><p><strong>加入如下内容(注意替换自己的实际路径)</strong></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></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line">Description = frp server</span><br><span class="line">After = network.target syslog.target</span><br><span class="line">Wants = network.target</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">Type = simple</span><br><span class="line"># 启动frps的命令，需修改为您的frps的安装路径</span><br><span class="line">ExecStart = /home/blog/frp_0.60.0_linux_amd64/frpc -c /home/blog/frp_0.60.0_linux_amd64/frpc.toml</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy = multi-user.target</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">// 启动FRP服务并设置开机自启</span><br><span class="line">systemctl enable --now frpc</span><br><span class="line">// 查看运行状态</span><br><span class="line">systemctl status frpc</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;新版的配置文件有比较大的改动，这里记录一下安装部署过程，官网文档在这里 &lt;a href=&quot;https://gofrp.org/zh-cn/docs/setup&quot;&gt;https://gofrp.org/zh-cn/docs/setup&lt;/a&gt;&lt;br&gt;下载安装地址 &lt;a href</summary>
      
    
    
    
    <category term="Web技术" scheme="https://blog.dollcode.cn/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Linux" scheme="https://blog.dollcode.cn/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>Docker搭建gitlab-runner利用CICD部署Springboot微服务到K8s集群</title>
    <link href="https://blog.dollcode.cn/docker-gitlab-runner.html"/>
    <id>https://blog.dollcode.cn/docker-gitlab-runner.html</id>
    <published>2024-08-19T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.453Z</updated>
    
    <content type="html"><![CDATA[<p>在DevOps工作流中，CICD持续集成持续部署是重要的一环。GitLab CI&#x2F;CD 是 GitLab 的一部分，因此不需要单独安装。<br>如果你已经在使用 GitLab 进行代码管理，GitLab CI&#x2F;CD 无缝集成，直接在同一个平台上管理代码、审查合并请求、自动化测试和部署。<br>这种集成度简化了开发流程，使用起来非常方便。</p><blockquote><p>前提条件：已经在使用Gitlab做代码管理、机器已安装Docker环境<br>目标：Docker搭建gitlab-runner，用gitgitlab-ci.yml脚本、Maven打包Springboot微服务、上传到Docker镜像仓库、远程部署到K8s集群</p></blockquote><h1 id="docker安装gitlab-runner"><a href="#docker安装gitlab-runner" class="headerlink" title="docker安装gitlab-runner"></a>docker安装gitlab-runner</h1><p>在Gitlab中Runner可以注册到 项目（Project）、群组（Group） 或 所有项目（All projects），这里注册到最大的，所有项目和组都可以用这个Runner<br><img src="/img/article/20240819105213.png"></p><p>还需要查看当前在用的Gitlab的安装版本，选择一致的版本。避免gitlab-runner版本跨度过大导致出现问题。</p><p><strong>1.先注册生成得到一个配置文件config.toml</strong></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">// 注意替换成自己的版本号，然后回车，开始注册runner到gitlab流程</span><br><span class="line">docker run --<span class="built_in">rm</span> -it -v $(<span class="built_in">pwd</span>)/runner-config:/etc/gitlab-runner gitlab/gitlab-runner:v16.11.3 register</span><br></pre></td></tr></table></figure><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><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></pre></td><td class="code"><pre><span class="line">// 第一步：输入gitlab的访问地址即可</span><br><span class="line">Enter the GitLab instance URL (<span class="keyword">for</span> example, https://gitlab.com/):</span><br><span class="line">http://192.168.168.168:8888</span><br><span class="line"></span><br><span class="line">// 第二步：输入 从gitlab管理页面上的复制token</span><br><span class="line">Enter the registration token:</span><br><span class="line">pAovXYzGHsy5EWF7zKiU</span><br><span class="line"></span><br><span class="line">// 第三步：输入runner名称 比如：docker-microservice-runner</span><br><span class="line">Enter a description <span class="keyword">for</span> the runner:</span><br><span class="line">[94030fed2ba3]: docker-microservice-runner</span><br><span class="line"></span><br><span class="line">// 第四步：输入Tag 比如：blog</span><br><span class="line">Enter tags <span class="keyword">for</span> the runner (comma-separated):</span><br><span class="line">blog</span><br><span class="line"></span><br><span class="line">// 第五步：输入说明备注 直接回车跳过</span><br><span class="line">Enter optional maintenance note <span class="keyword">for</span> the runner:</span><br><span class="line"></span><br><span class="line">WARNING: Support <span class="keyword">for</span> registration tokens and runner parameters <span class="keyword">in</span> the <span class="string">&#x27;register&#x27;</span> <span class="built_in">command</span> has been deprecated <span class="keyword">in</span> GitLab Runner 16.11 and will be replaced with support <span class="keyword">for</span> authentication tokens. For more information, see https://gitlab.com/gitlab-org/gitlab/-/issues/380872</span><br><span class="line">Registering runner... succeeded                     runner=pAovXYzG</span><br><span class="line"></span><br><span class="line">// 第六步：这个时候可以看到上面日志已经注册完成，选择执行器 docker</span><br><span class="line">Enter an executor: docker, parallels, virtualbox, docker+machine, docker-ssh+machine, instance, kubernetes, custom, docker-ssh, shell, ssh:</span><br><span class="line">docker</span><br><span class="line"></span><br><span class="line">// 第七步：选择默认基础镜像，这个镜像其实无所谓，因为我们在实际CICD中会指定镜像。这里就直接填 docker:24.0.2</span><br><span class="line">Enter the default Docker image (<span class="keyword">for</span> example, ruby:2.7):</span><br><span class="line">docker:24.0.2</span><br><span class="line">Runner registered successfully. Feel free to start it, but <span class="keyword">if</span> it<span class="string">&#x27;s running already the config should be automatically reloaded!</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">Configuration (with the authentication token) was saved in &quot;/etc/gitlab-runner/config.toml&quot;</span></span><br></pre></td></tr></table></figure><p>现在我们得到了配置文件，还需要修改一项重要配置（重要）！！！</p><blockquote><p>因为我们使用Docker部署的Runner，也就是使用 Docker-in-Docker (DinD) 模式进行部署。<br>需要挂载&#x2F;var&#x2F;run&#x2F;docker.sock，以允许容器内的 Docker 引擎访问宿主机的 Docker。</p></blockquote><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></pre></td><td class="code"><pre><span class="line">// 编辑配置文件 </span><br><span class="line">vim runner-config/config.toml</span><br><span class="line"></span><br><span class="line">// 修改volumes这一行，改为如下即可</span><br><span class="line">volumes = [<span class="string">&quot;/var/run/docker.sock:/var/run/docker.sock&quot;</span>, <span class="string">&quot;/cache&quot;</span>]</span><br></pre></td></tr></table></figure><p>保存之后，整个runner的配置文件就准备完成了！</p><p><strong>2.启动gitlab-runner</strong><br>配置文件OK之后，就可以启动Runner了，执行如下命令（注意所在目录需要跟上面保持一致）</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></pre></td><td class="code"><pre><span class="line">docker run -d --name gitlab-runner  \</span><br><span class="line">  -v $(<span class="built_in">pwd</span>)/runner-config:/etc/gitlab-runner \</span><br><span class="line">  -v /var/run/docker.sock:/var/run/docker.sock \</span><br><span class="line">  gitlab/gitlab-runner:v16.11.3</span><br></pre></td></tr></table></figure><p>启动之后，就可以在Gitlab上看到 Runner了。<br><img src="/img/article/20240819111552.png"></p><h1 id="构建JAVA微服务CICD"><a href="#构建JAVA微服务CICD" class="headerlink" title="构建JAVA微服务CICD"></a>构建JAVA微服务CICD</h1><p>整个流程：maven打包得到jar包 -&gt; Dockerfile构建镜像并上传仓库 -&gt; Kubectl部署到K8s集群<br>在这个过程中，牵扯到账号信息，为了安全方便可以配置成CICD变量。</p><h2 id="配置CICD变量"><a href="#配置CICD变量" class="headerlink" title="配置CICD变量"></a>配置CICD变量</h2><ul><li>DOCKER_REGISTRY  docker地址 比如:registry.cn-hangzhou.aliyuncs.com&#x2F;blog</li><li>DOCKER_REGISTRY_USER  docker登录名</li><li>DOCKER_REGISTRY_PASSWORD  docker密码</li><li>K8S_KUBECONFIG_TEST   k8s测试集群的config文件</li><li>K8S_KUBECONFIG_PROD   k8s生产集群的config文件</li><li>JAVA_MAVEN_SETTINGS   maven的setting.xml配置</li></ul><p><strong>注意K8sconfig变量类型为 File</strong> 文件内容就是集群的KubeConfig<br><img src="/img/article/20240819143506.png"><br><img src="/img/article/20240819145437.png"></p><p>Maven的setting.xml文件如下，需要替换成自己的私服即可。</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></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">settings</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/SETTINGS/1.0.0&quot;</span></span></span><br><span class="line"><span class="tag">          <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">          <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">mirrors</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">mirror</span>&gt;</span>  </span><br><span class="line">        <span class="tag">&lt;<span class="name">id</span>&gt;</span>nexus-aliyun<span class="tag">&lt;/<span class="name">id</span>&gt;</span>  </span><br><span class="line">        <span class="tag">&lt;<span class="name">mirrorOf</span>&gt;</span>central<span class="tag">&lt;/<span class="name">mirrorOf</span>&gt;</span>    </span><br><span class="line">        <span class="tag">&lt;<span class="name">name</span>&gt;</span>Nexus aliyun<span class="tag">&lt;/<span class="name">name</span>&gt;</span>  </span><br><span class="line">        <span class="tag">&lt;<span class="name">url</span>&gt;</span>http://maven.aliyun.com/nexus/content/groups/public<span class="tag">&lt;/<span class="name">url</span>&gt;</span>  </span><br><span class="line">      <span class="tag">&lt;/<span class="name">mirror</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;/<span class="name">mirrors</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="name">settings</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="增加部署文件"><a href="#增加部署文件" class="headerlink" title="增加部署文件"></a>增加部署文件</h2><p>进入springboot项目仓库，创建 Dockerfile 、k8sdeploy_test.yaml 、k8sdeploy_prod.yaml<br>项目结构如下：</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></pre></td><td class="code"><pre><span class="line">项目名称</span><br><span class="line"> ├── src/main</span><br><span class="line"> │   └── java</span><br><span class="line"> │   └── resources</span><br><span class="line"> ├── pom.xml</span><br><span class="line"> ├── Dockerfile</span><br><span class="line"> ├── k8sdeploy_test.yaml</span><br><span class="line"> ├── k8sdeploy_prod.yaml</span><br></pre></td></tr></table></figure><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><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="keyword">FROM</span> registry.cn-hangzhou.aliyuncs.com/blog/jre17</span><br><span class="line"><span class="keyword">MAINTAINER</span> dollcode</span><br><span class="line"><span class="keyword">ARG</span> JAR_FILE</span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> <span class="variable">$&#123;JAR_FILE&#125;</span> app.jar</span></span><br><span class="line"><span class="keyword">EXPOSE</span> <span class="number">8080</span></span><br><span class="line"><span class="keyword">ENTRYPOINT</span><span class="language-bash"> [<span class="string">&quot;java&quot;</span>,<span class="string">&quot;-jar&quot;</span>,<span class="string">&quot;/app.jar&quot;</span>]</span></span><br></pre></td></tr></table></figure><blockquote><p>k8sdeploy_test.yaml 内容如下：</p></blockquote><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">APPLICATIONNAME</span></span><br><span class="line">  <span class="attr">namespace:</span> <span class="string">blog</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">replicas:</span> <span class="number">1</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">APPLICATIONNAME</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">APPLICATIONNAME</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">APPLICATIONNAME</span></span><br><span class="line">          <span class="attr">image:</span> <span class="string">APPLICATIONIMAGE</span></span><br><span class="line">          <span class="attr">imagePullPolicy:</span> <span class="string">Always</span></span><br><span class="line">          <span class="attr">env:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">SPRING_PROFILES_ACTIVE</span></span><br><span class="line">              <span class="attr">value:</span> <span class="string">test</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="string">APPLICATIONPORT</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">APPLICATIONNAME-svc</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">ports:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">port:</span> <span class="string">APPLICATIONPORT</span></span><br><span class="line">      <span class="attr">protocol:</span> <span class="string">TCP</span></span><br><span class="line">      <span class="attr">targetPort:</span> <span class="string">APPLICATIONPORT</span></span><br><span class="line">  <span class="attr">selector:</span></span><br><span class="line">    <span class="attr">app:</span> <span class="string">APPLICATIONNAME</span></span><br><span class="line">  <span class="attr">type:</span> <span class="string">ClusterIP</span></span><br></pre></td></tr></table></figure><blockquote><p>k8sdeploy_prod.yaml 内容差不多 只是环境不一样，就不贴了。</p></blockquote><h2 id="编写CICD脚本"><a href="#编写CICD脚本" class="headerlink" title="编写CICD脚本"></a>编写CICD脚本</h2><p>依次点击 CICD -&gt; Editor 编辑脚本内容如下</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><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">stages:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">maven_build</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">docker_build</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">deploy_k8s</span></span><br><span class="line"></span><br><span class="line"><span class="attr">variables:</span></span><br><span class="line">  <span class="comment"># 指定项目的端口和代码版本</span></span><br><span class="line">  <span class="attr">PROJECT_PORT:</span> <span class="string">&quot;8080&quot;</span></span><br><span class="line">  <span class="attr">PROJECT_VERSION:</span> <span class="string">&quot;1.0&quot;</span></span><br><span class="line">  <span class="comment"># 指定maven-build配置路径</span></span><br><span class="line">  <span class="attr">MAVEN_CLI_OPTS:</span> <span class="string">&quot;-s /root/.m2/settings.xml&quot;</span></span><br><span class="line">  <span class="comment"># 定义docker镜像的tag命名</span></span><br><span class="line">  <span class="attr">REGISTRY_TAG:</span> <span class="string">&quot;ci-$CI_PIPELINE_ID&quot;</span></span><br><span class="line">  <span class="comment"># 定义docker镜像的命名  </span></span><br><span class="line">  <span class="attr">REGISTRY_APPNAME:</span> <span class="string">&quot;$DOCKER_REGISTRY/blog/$CI_PROJECT_NAME&quot;</span></span><br><span class="line">  <span class="comment"># 全局环境</span></span><br><span class="line">  <span class="attr">DEPLOY_ENV:</span> <span class="string">&quot;dev&quot;</span></span><br><span class="line">  <span class="comment"># K8s命名空间</span></span><br><span class="line">  <span class="attr">K8S_NAMESPACE:</span> <span class="string">&quot;default&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 前置脚本：设置不同分支使用不同的配置和镜像地址，部署到不同的K8s集群</span></span><br><span class="line"><span class="comment"># dev分支为测试环境部署：registry.cn-hangzhou.aliyuncs.com/blog_test/spring-service:ci-101</span></span><br><span class="line"><span class="comment"># dev分支为测试环境部署：registry.cn-hangzhou.aliyuncs.com/blog_prod/spring-service:ci-101</span></span><br><span class="line"><span class="attr">before_script:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">mkdir</span> <span class="string">-p</span> <span class="string">.m2/repository</span> <span class="string">~/.kube</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">if</span> [ <span class="string">&quot;$CI_COMMIT_BRANCH&quot;</span> <span class="string">==</span> <span class="string">&quot;dev&quot;</span> ]<span class="string">;</span> <span class="string">then</span></span><br><span class="line">      <span class="string">export</span> <span class="string">DEPLOY_ENV=test;</span></span><br><span class="line">      <span class="string">mv</span> <span class="string">$K8S_KUBECONFIG_TEST</span>  <span class="string">$HOME/.kube/config;</span></span><br><span class="line">    <span class="string">elif</span> [ <span class="string">&quot;$CI_COMMIT_BRANCH&quot;</span> <span class="string">==</span> <span class="string">&quot;main&quot;</span> ]<span class="string">;</span> <span class="string">then</span></span><br><span class="line">      <span class="string">export</span> <span class="string">DEPLOY_ENV=prod;</span></span><br><span class="line">      <span class="string">mv</span> <span class="string">$K8S_KUBECONFIG_PROD</span>  <span class="string">$HOME/.kube/config;</span></span><br><span class="line">    <span class="string">else</span></span><br><span class="line">      <span class="string">echo</span> <span class="string">&quot;This branch is not configured for deployment.&quot;</span><span class="string">;</span></span><br><span class="line">      <span class="string">exit</span> <span class="number">1</span><span class="string">;</span></span><br><span class="line">    <span class="string">fi</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">export</span> <span class="string">REGISTRY_APPNAME=$DOCKER_REGISTRY/blog_$DEPLOY_ENV/$CI_PROJECT_NAME;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># maven打包，注意image要改为自己项目JDK对应版本 如maven:3.8.6-jdk-11、 maven:3.8.6-jdk-8</span></span><br><span class="line"><span class="attr">mavenjar_job:</span></span><br><span class="line">  <span class="attr">stage:</span> <span class="string">maven_build</span></span><br><span class="line">  <span class="attr">image:</span> <span class="string">maven:3.8.6-jdk-11</span></span><br><span class="line">  <span class="comment"># maven依赖做缓存</span></span><br><span class="line">  <span class="attr">cache:</span></span><br><span class="line">    <span class="attr">key:</span> <span class="string">global-cache</span></span><br><span class="line">    <span class="attr">paths:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">.m2/repository</span></span><br><span class="line">    <span class="attr">policy:</span> <span class="string">pull-push</span></span><br><span class="line">  <span class="attr">script:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">mkdir</span> <span class="string">-p</span> <span class="string">~/.m2</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">echo</span> <span class="string">&quot;$JAVA_MAVEN_SETTINGS&quot;</span> <span class="string">&gt;</span> <span class="string">~/.m2/settings.xml</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">mvn</span> <span class="string">$MAVEN_CLI_OPTS</span> <span class="string">clean</span> <span class="string">package</span> <span class="string">-DskipTests</span> <span class="string">-Dmaven.repo.local=.m2/repository</span></span><br><span class="line">  <span class="attr">artifacts:</span></span><br><span class="line">    <span class="attr">paths:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">target/$CI_PROJECT_NAME-$PROJECT_VERSION.jar</span></span><br><span class="line">  <span class="attr">tags:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">blog</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Docker镜像打包上传</span></span><br><span class="line"><span class="attr">container_job:</span></span><br><span class="line">  <span class="attr">stage:</span> <span class="string">docker_build</span></span><br><span class="line">  <span class="attr">image:</span> <span class="string">docker:24.0.2</span></span><br><span class="line">  <span class="attr">script:</span></span><br><span class="line">    <span class="comment"># build镜像 并一个命名当前版本，一个命名latest</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">docker</span> <span class="string">build</span> <span class="string">--build-arg</span> <span class="string">JAR_FILE=&quot;target/$CI_PROJECT_NAME-$PROJECT_VERSION.jar&quot;</span> <span class="string">--tag</span> <span class="string">$REGISTRY_APPNAME:$REGISTRY_TAG</span> <span class="string">--tag</span> <span class="string">$REGISTRY_APPNAME:latest</span> <span class="string">.</span></span><br><span class="line">    <span class="comment"># 登录docker私服仓库</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">docker</span> <span class="string">login</span> <span class="string">-u</span> <span class="string">&quot;$DOCKER_REGISTRY_USER&quot;</span> <span class="string">-p</span> <span class="string">&quot;$DOCKER_REGISTRY_PASSWORD&quot;</span> <span class="string">$DOCKER_REGISTRY</span></span><br><span class="line">    <span class="comment"># 推送镜像</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">docker</span> <span class="string">push</span> <span class="string">$REGISTRY_APPNAME:$REGISTRY_TAG</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">docker</span> <span class="string">push</span> <span class="string">$REGISTRY_APPNAME:latest</span></span><br><span class="line">  <span class="attr">tags:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">blog</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 部署K8S</span></span><br><span class="line"><span class="attr">deploy_job:</span></span><br><span class="line">  <span class="attr">stage:</span> <span class="string">deploy_k8s</span></span><br><span class="line">  <span class="attr">image:</span></span><br><span class="line">    <span class="comment"># 版本号要和K8s集群版本一致</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">bitnami/kubectl:1.28</span></span><br><span class="line">    <span class="attr">entrypoint:</span> [<span class="string">&quot;&quot;</span>]</span><br><span class="line">  <span class="attr">script:</span></span><br><span class="line">    <span class="comment"># 替换对应环境yaml中的项目端口、项目名称、项目镜像</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">sed</span> <span class="string">-i</span> <span class="string">s/APPLICATIONPORT/$PROJECT_PORT/</span> <span class="string">k8sdeploy_$DEPLOY_ENV.yaml</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">sed</span> <span class="string">-i</span> <span class="string">s/APPLICATIONNAME/$CI_PROJECT_NAME/</span> <span class="string">k8sdeploy_$DEPLOY_ENV.yaml</span></span><br><span class="line">    <span class="comment"># 因为镜像名称中包含特殊字符(/),所以使用%代替分隔符</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">sed</span> <span class="string">-i</span> <span class="string">s%APPLICATIONIMAGE%$REGISTRY_APPNAME:$REGISTRY_TAG%</span> <span class="string">k8sdeploy_$DEPLOY_ENV.yaml</span></span><br><span class="line">    <span class="comment"># 部署</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">kubectl</span> <span class="string">apply</span> <span class="string">-f</span> <span class="string">k8sdeploy_$DEPLOY_ENV.yaml</span> <span class="string">--namespace</span> <span class="string">$K8S_NAMESPACE</span></span><br><span class="line">  <span class="attr">tags:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">blog</span></span><br></pre></td></tr></table></figure><h2 id="部署"><a href="#部署" class="headerlink" title="部署"></a>部署</h2><p>提交代码 或者 手动触发 部署完成！！！<br><img src="/img/article/20240819162335.png"></p><h1 id="踩坑汇总"><a href="#踩坑汇总" class="headerlink" title="踩坑汇总"></a>踩坑汇总</h1><h2 id="Maven依赖缓存"><a href="#Maven依赖缓存" class="headerlink" title="Maven依赖缓存"></a>Maven依赖缓存</h2><p>如果没有设置依赖缓存，每一次都会重新拉取依赖jar。而Springboot的依赖是非常多的，每次拉取超级耗时。<br>这里有一个坑：<strong>gitlab CICD只能缓存项目工作空间下的目录。</strong>所以需要创建.m2&#x2F;repository 并且在maven build命令中指定目录</p><h2 id="bitnami-x2F-kubectl无法执行命令"><a href="#bitnami-x2F-kubectl无法执行命令" class="headerlink" title="bitnami&#x2F;kubectl无法执行命令"></a>bitnami&#x2F;kubectl无法执行命令</h2><p>在deploy_job执行中，日志报错如下：</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></pre></td><td class="code"><pre><span class="line">Using docker image sha256:be85f4da59a1c49507de843111579c94b9adf3 for bitnami/kubectl:1.28 with digest bitnami/kubectl@sha256:9657fd84779759711e59a51f4993567562 ...</span><br><span class="line">E0816 09:35:39.752914       1 run.go:120] &quot;command failed&quot; err=&quot;unknown command \&quot;sh\&quot; for \&quot;kubectl\&quot;\n\nDid you mean this?\n\tset\n\tcp\n&quot;</span><br><span class="line">Cleaning up project directory and file based variables</span><br><span class="line">00:01</span><br><span class="line">ERROR: Job failed: exit code 1</span><br></pre></td></tr></table></figure><p>因为bitnami&#x2F;kubectl 镜像的默认入口点是 kubectl，因此执行 sh 命令时，它会认为这是一个 kubectl 的子命令，而不是一个 Shell 命令。<br>必须要显式覆盖镜像的入口点或命令，以便运行 sh。所以需要指定<code> entrypoint: [&quot;&quot;]</code></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在DevOps工作流中，CICD持续集成持续部署是重要的一环。GitLab CI&amp;#x2F;CD 是 GitLab 的一部分，因此不需要单独安装。&lt;br&gt;如果你已经在使用 GitLab 进行代码管理，GitLab CI&amp;#x2F;CD 无缝集成，直接在同一个平台上管理代码、</summary>
      
    
    
    
    <category term="服务器" scheme="https://blog.dollcode.cn/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
    
    <category term="Linux" scheme="https://blog.dollcode.cn/tags/Linux/"/>
    
    <category term="Springboot" scheme="https://blog.dollcode.cn/tags/Springboot/"/>
    
    <category term="Docker" scheme="https://blog.dollcode.cn/tags/Docker/"/>
    
  </entry>
  
  <entry>
    <title>ngrok内网穿透注册使用无需实名</title>
    <link href="https://blog.dollcode.cn/dashboard-ngrok.html"/>
    <id>https://blog.dollcode.cn/dashboard-ngrok.html</id>
    <published>2024-08-08T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.453Z</updated>
    
    <content type="html"><![CDATA[<p>开箱即用的内网穿透的工具有很多很多，但是由于国内环境需要实名认证劝退了。发现dashboard.ngrok.com注册即用，带https。而且控制台体验特别好，简直是傻瓜式。引导做的太棒了！！！<br>所以这里简单记录一下，因为控制台的交互设计已经非常完善了。</p><h1 id="注册ngrok-com"><a href="#注册ngrok-com" class="headerlink" title="注册ngrok.com"></a>注册ngrok.com</h1><p>打开官网：<a href="https://dashboard.ngrok.com/">https://dashboard.ngrok.com</a> 用邮箱注册，然后邮件激活账号即可。</p><blockquote><p>最新情况： HTTP隧道可以直接用，TCP隧道需要绑卡</p></blockquote><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">You must add a credit or debit card before you can use TCP endpoints on a free account. </span><br><span class="line">We require a valid card as a way to combat abuse and keep the internet a safe place. </span><br><span class="line">This card will NOT be charged. Add a card to your account here: https://dashboard.ngrok.com/settings#id-verification</span><br></pre></td></tr></table></figure><h1 id="下载安装客户端"><a href="#下载安装客户端" class="headerlink" title="下载安装客户端"></a>下载安装客户端</h1><p>进入控制台之后，选择自己对应的平台客户端下载。这里以 Linux举例<br><img src="/img/article/20240808104856.png"><br><img src="/img/article/20240808105419.png"></p><p>将下载的客户端传输到机器上，解压并安装。</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></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> tar -xvzf ngrok-v3-stable-linux-amd64.tgz -C /usr/local/bin</span><br><span class="line"></span><br><span class="line">// 创建配置文件并授权token，命令直接在控制台复制即可，非常方便</span><br><span class="line">ngrok config add-authtoken xxxxxxxxxxxxxxxxxxx</span><br></pre></td></tr></table></figure><h1 id="直接启动穿透"><a href="#直接启动穿透" class="headerlink" title="直接启动穿透"></a>直接启动穿透</h1><p>可以直接使用客户端启动自己的穿透隧道，但是这样启动的域名是随机动态的。<br>每次都不一样，可以用下面的第二种方式生成一个固定的域名。</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></pre></td><td class="code"><pre><span class="line">// 启动http穿透80端口</span><br><span class="line">ngrok http http://localhost:80</span><br><span class="line">// 启动tcp穿透如ssh连接</span><br><span class="line">ngrok tcp 22</span><br></pre></td></tr></table></figure><h1 id="创建域名启动穿透"><a href="#创建域名启动穿透" class="headerlink" title="创建域名启动穿透"></a>创建域名启动穿透</h1><p>注意：免费用户只有一个域名额度！<br>创建一个Edges，选择自己的穿透类型 Web服务穿透选Http  SSH穿透选TCP。  并勾选生成域名<br><img src="/img/article/20240808111127.png"></p><p>再点击页面中的 -&gt; <strong>Start a Tunnel</strong> 蓝色按钮 -&gt; 会展示出启动命令，根据提示复制这个命令</p><h1 id="启动穿透隧道"><a href="#启动穿透隧道" class="headerlink" title="启动穿透隧道"></a>启动穿透隧道</h1><p>举例 WEB服务，启动一个nginx。端口80</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">ngrok tunnel --label edge=edghts_xxxxxxxx http://localhost:80</span><br></pre></td></tr></table></figure><p>执行之后会输出启动日志。浏览器访问控制台上的Endpoints域名，<br><img src="/img/article/20240808112624.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;开箱即用的内网穿透的工具有很多很多，但是由于国内环境需要实名认证劝退了。发现dashboard.ngrok.com注册即用，带https。而且控制台体验特别好，简直是傻瓜式。引导做的太棒了！！！&lt;br&gt;所以这里简单记录一下，因为控制台的交互设计已经非常完善了。&lt;/p&gt;
&lt;h</summary>
      
    
    
    
    <category term="Web技术" scheme="https://blog.dollcode.cn/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Software" scheme="https://blog.dollcode.cn/tags/Software/"/>
    
  </entry>
  
  <entry>
    <title>ubuntu设置grub密码实现加密开机启动</title>
    <link href="https://blog.dollcode.cn/ubuntu-grub-encrypt.html"/>
    <id>https://blog.dollcode.cn/ubuntu-grub-encrypt.html</id>
    <published>2024-08-02T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.453Z</updated>
    
    <content type="html"><![CDATA[<p>先看效果，在机器开机进入引导时会先进入一个用户名密码验证界面，通过之后才会进入启动流程。并且如果想操作引导其他项，也必须输入密码。类似于密钥启动验证的效果！<br><img src="/img/article/20240807153041.png"></p><blockquote><p>假设我们设置用户名为：dollcode 密码为：123456</p></blockquote><h1 id="步骤-1：生成加密密码"><a href="#步骤-1：生成加密密码" class="headerlink" title="步骤 1：生成加密密码"></a>步骤 1：生成加密密码</h1><p><img src="/img/article/20240807150314.png"></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></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> grub-mkpasswd-pbkdf2</span><br><span class="line">// 输入并二次确认密码后，会输出一个加密后的密码字符串，类似如下所示：</span><br><span class="line">PBKDF2 <span class="built_in">hash</span> of your password is grub.pbkdf2.sha512.10000.2932A1217B661566186EE6213A992F6296F947F44E2A52E01EC42B3C0DD079342363378E52A7C0307F78027595FDD9F72C4788E66B74F66D9B154957818CAE0D.FC379727A4D967F4F1C2A03B0284021E8F209253BA3380C6F9D04391C27FCB072DE367ADC64540B6EE809E261DF0EEB0EF0568CFA74FD383C77F2A05DD1EA50E</span><br></pre></td></tr></table></figure><p><em>复制这个字符串，只需要复制 <code>password is</code>后面的字符串密码，也就是从 grub 开始复制</em></p><h1 id="步骤-2：配置GRUB文件"><a href="#步骤-2：配置GRUB文件" class="headerlink" title="步骤 2：配置GRUB文件"></a>步骤 2：配置GRUB文件</h1><p>接下来，需要将生成的加密密码添加到 GRUB 配置文件中。设置用户名为：dollcode 密码为：123456<br><img src="/img/article/20240807152255.png"></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></pre></td><td class="code"><pre><span class="line">//1. 打开 /etc/grub.d/40_custom 文件进行编辑：</span><br><span class="line"><span class="built_in">sudo</span> vim /etc/grub.d/40_custom</span><br><span class="line">//2. 在文件尾部添加以下内容：设置用户和第一步的加密密码</span><br><span class="line"><span class="built_in">set</span> superusers=<span class="string">&quot;dollcode&quot;</span></span><br><span class="line">password_pbkdf2 dollcode grub.pbkdf2.sha512.10000.2932A1217B661566186EE6213A992F6296F947F44E2A52E01EC42B3C0DD079342363378E52A7C0307F78027595FDD9F72C4788E66B74F66D9B154957818CAE0D.FC379727A4D967F4F1C2A03B0284021E8F209253BA3380C6F9D04391C27FCB072DE367ADC64540B6EE809E261DF0EEB0EF0568CFA74FD383C77F2A05DD1EA50E</span><br></pre></td></tr></table></figure><p>保存并退出编辑器，然后更新 GRUB 配置：</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"><span class="built_in">sudo</span> update-grub</span><br></pre></td></tr></table></figure><p><img src="/img/article/20240807152654.png"></p><h1 id="步骤-3：重启系统并验证"><a href="#步骤-3：重启系统并验证" class="headerlink" title="步骤 3：重启系统并验证"></a>步骤 3：重启系统并验证</h1><p>只有输入配置的用户名和密码，才能进入引导系统。<br><img src="/img/article/20240807153041.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;先看效果，在机器开机进入引导时会先进入一个用户名密码验证界面，通过之后才会进入启动流程。并且如果想操作引导其他项，也必须输入密码。类似于密钥启动验证的效果！&lt;br&gt;&lt;img src=&quot;/img/article/20240807153041.png&quot;&gt;&lt;/p&gt;
&lt;blockq</summary>
      
    
    
    
    <category term="Web技术" scheme="https://blog.dollcode.cn/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Linux" scheme="https://blog.dollcode.cn/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>Docker自定义JDK17 JRE精简镜像</title>
    <link href="https://blog.dollcode.cn/jdk17-docker.html"/>
    <id>https://blog.dollcode.cn/jdk17-docker.html</id>
    <published>2024-08-01T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.453Z</updated>
    
    <content type="html"><![CDATA[<p>由于官方的openJDK17镜像近500MB，属于太大，不利于微服务镜像打包部署。<br>所以自定义基于alpine 3.18 和 openjdk 17 制作JRE镜像，构建Springboot项目镜像(JRE是java运行环境，不包含开发工具所以小)。<br>先看结论，一共测试了三种方式。</p><blockquote><p>注意：只编译java SE平台的Jre环境在运行Springboot项目会有问题，精简过头也不行，少了依赖。<br>！！！推荐用jre17all，这是完整的JRE环境包，测试是完全没问题的。</p></blockquote><ul><li>jre17se 只构建了javaSE平台模块包的JRE环境的镜像</li><li>jre17all 构建了所有包模块的JRE环境的镜像</li><li>jre17   直接用adoptium下载的JRE来创建的镜像</li><li>openjdk  官方的镜像</li></ul><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></pre></td><td class="code"><pre><span class="line">&gt;docker images</span><br><span class="line">jre17se          latest            cd9e997465f6        7 seconds ago      81MB</span><br><span class="line">jre17all         latest            8d7173e8cdd9        8 minutes ago      113MB</span><br><span class="line">jre17            latest            9c0b10d8c81d        1 hours ago        208MB</span><br><span class="line">openjdk          17                5f94f53bbced        2 hours ago        471MB</span><br></pre></td></tr></table></figure><blockquote><p>选型：</p></blockquote><ul><li>基础镜像apline 大小7MB</li><li>JDK17安装包有180MB，运行环境只需要JRE，所以这里直接从<a href="https://adoptium.net/">预编译OPENJDK</a>选 <a href="https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9/OpenJDK17U-jre_x64_alpine-linux_hotspot_17.0.9_9.tar.gz">JRE下载</a></li></ul><h1 id="第一种直接使用已有的JRE创建镜像"><a href="#第一种直接使用已有的JRE创建镜像" class="headerlink" title="第一种直接使用已有的JRE创建镜像"></a>第一种直接使用已有的JRE创建镜像</h1><p>这里我做了测试，直接用adoptium构建好的JRE包，去做镜像的话，最后的大小居然有<code>200MB</code>。虽然比官方的OPENJDK的<code>470MB</code>要小一半。但是还不够精简。</p><blockquote><blockquote><blockquote><p>所以后面还是自已编译构建JRE包，可以直接跳到第二种方案查看&lt;&lt;&lt;</p></blockquote></blockquote></blockquote><p><img src="/img/article/20240802143757.png"><br>首先创建一个目录，将下载的Jre压缩包放入。如果网络访问github正常的话，也可以直接下载</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">wget https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9/OpenJDK17U-jre_x64_alpine-linux_hotspot_17.0.9_9.tar.gz</span><br></pre></td></tr></table></figure><p>创建Dockerfile</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用Alpine 3.18作为基础镜像</span></span><br><span class="line">FROM alpine:3.18</span><br><span class="line"></span><br><span class="line"><span class="comment"># 复制JDK压缩包到镜像中</span></span><br><span class="line">COPY OpenJDK17U-jre_x64_alpine-linux_hotspot_17.0.9_9.tar.gz /tmp/openjdk.tar.gz</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置环境变量</span></span><br><span class="line">ENV JAVA_HOME=/opt/jdk</span><br><span class="line">ENV PATH=<span class="variable">$JAVA_HOME</span>/bin:<span class="variable">$PATH</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 更新Alpine的软件源为阿里云</span></span><br><span class="line">RUN <span class="built_in">echo</span> <span class="string">&quot;https://mirrors.aliyun.com/alpine/v3.18/main&quot;</span> &gt; /etc/apk/repositories \</span><br><span class="line">    &amp;&amp; <span class="built_in">echo</span> <span class="string">&quot;https://mirrors.aliyun.com/alpine/v3.18/community&quot;</span> &gt;&gt; /etc/apk/repositories</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装必要的软件包，包括时区设置和字体支持</span></span><br><span class="line">RUN apk add --no-cache fontconfig libretls ttf-dejavu tzdata \</span><br><span class="line">    &amp;&amp; <span class="built_in">rm</span> -rf /var/cache/apk/* \</span><br><span class="line">    &amp;&amp; <span class="built_in">echo</span> <span class="string">&quot;Asia/Shanghai&quot;</span> &gt; /etc/timezone \</span><br><span class="line">    &amp;&amp; <span class="built_in">ln</span> -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime</span><br><span class="line"></span><br><span class="line"><span class="comment"># 解压JDK并清理无用文件</span></span><br><span class="line">RUN <span class="built_in">set</span> -eux; \</span><br><span class="line">    <span class="built_in">mkdir</span> -p <span class="string">&quot;<span class="variable">$JAVA_HOME</span>&quot;</span>; \</span><br><span class="line">    tar --extract \</span><br><span class="line">        --file /tmp/openjdk.tar.gz \</span><br><span class="line">        --directory <span class="string">&quot;<span class="variable">$JAVA_HOME</span>&quot;</span> \</span><br><span class="line">        --strip-components 1 \</span><br><span class="line">        --no-same-owner \</span><br><span class="line">    &amp;&amp; <span class="built_in">rm</span> -f /tmp/openjdk.tar.gz \</span><br><span class="line">    &amp;&amp; find <span class="string">&quot;<span class="variable">$JAVA_HOME</span>&quot;</span> -name <span class="string">&#x27;*.diz&#x27;</span> -delete \</span><br><span class="line">    &amp;&amp; find <span class="string">&quot;<span class="variable">$JAVA_HOME</span>&quot;</span> -name <span class="string">&#x27;*.txt&#x27;</span> -delete \</span><br><span class="line">    &amp;&amp; <span class="built_in">rm</span> -rf <span class="string">&quot;<span class="variable">$JAVA_HOME</span>&quot;</span>/man \</span><br><span class="line">    &amp;&amp; <span class="built_in">rm</span> -rf <span class="string">&quot;<span class="variable">$JAVA_HOME</span>&quot;</span>/legal</span><br><span class="line"></span><br><span class="line"><span class="comment"># 清理缓存和临时文件</span></span><br><span class="line">RUN <span class="built_in">rm</span> -rf /var/cache/apk/* \</span><br><span class="line">    &amp;&amp; <span class="built_in">rm</span> -rf /tmp/*</span><br><span class="line"></span><br><span class="line"><span class="comment"># 可选：打印Java版本信息</span></span><br><span class="line">CMD [<span class="string">&quot;sh&quot;</span>, <span class="string">&quot;-c&quot;</span>, <span class="string">&quot;echo &#x27;Java version:&#x27; &amp;&amp; java -version &amp;&amp; echo &#x27;Current date and time:&#x27; &amp;&amp; date&quot;</span>]</span><br></pre></td></tr></table></figure><p>执行build，并启动容器验证</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">docker build -t jre17 .</span><br></pre></td></tr></table></figure><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">// 执行会打印JAVA版本信息和时间信息</span><br><span class="line">docker run --<span class="built_in">rm</span> jre17</span><br></pre></td></tr></table></figure><p>这种方式构建的是最全的，但是感觉还是有点大，所以还是自定义吧！</p><h1 id="第二种自己构建JRE环境包"><a href="#第二种自己构建JRE环境包" class="headerlink" title="第二种自己构建JRE环境包"></a>第二种自己构建JRE环境包</h1><p>思路：首先用JDK包构建自定义的JRE环境包，再将JRE包制作到镜像里。需要采用Docker的多阶段构建，可以减少镜像大小。<br>老样子 <em>先下载对应Alpine平台的的包，放到同级目录。</em>如下：<br><img src="/img/article/20240802141717.png"><br>Dockerfile文件内容如下</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 第一阶段：使用基础镜像来下载和安装JDK</span></span><br><span class="line">FROM alpine:3.18 as builder</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置 JDK并复制本地压缩包</span></span><br><span class="line">ARG JDK_DIR=/usr/lib/jvm/java17</span><br><span class="line">COPY OpenJDK17U-jdk_x64_alpine-linux_hotspot_17.0.12_7.tar.gz ./jdk.tar.gz</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装必要的工具，binutils 是使用 jlink 所需的工具</span></span><br><span class="line">RUN <span class="built_in">set</span> -eux; \</span><br><span class="line">    apk add --no-cache tar gzip binutils;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 解压 JDK</span></span><br><span class="line">RUN <span class="built_in">set</span> -eux; \</span><br><span class="line">    <span class="built_in">mkdir</span> -p <span class="variable">$&#123;JDK_DIR&#125;</span>; \</span><br><span class="line">    tar --extract \</span><br><span class="line">        --file jdk.tar.gz \</span><br><span class="line">        --directory <span class="variable">$&#123;JDK_DIR&#125;</span> \</span><br><span class="line">        --strip-components 1 \</span><br><span class="line">        --no-same-owner;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置环境变量</span></span><br><span class="line">ENV JAVA_HOME=<span class="variable">$&#123;JDK_DIR&#125;</span></span><br><span class="line">ENV PATH=<span class="variable">$JAVA_HOME</span>/bin:<span class="variable">$PATH</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用 jlink 创建自定义JRE --add-modules这个参数传全部模块：ALL-MODULE-PATH 或者指定只包含JAVA SE平台下的模块：java.se</span></span><br><span class="line">RUN <span class="built_in">set</span> -eux; \</span><br><span class="line">    <span class="variable">$JAVA_HOME</span>/bin/jlink \</span><br><span class="line">         --module-path <span class="variable">$&#123;JAVA_HOME&#125;</span>/jmods \</span><br><span class="line">         --add-modules ALL-MODULE-PATH \</span><br><span class="line">         --strip-debug \</span><br><span class="line">         --no-man-pages \</span><br><span class="line">         --no-header-files \</span><br><span class="line">         --compress=2 \</span><br><span class="line">         --output /jre17;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 第二阶段：创建最终镜像</span></span><br><span class="line">FROM alpine:3.18</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置 JDK 安装目录</span></span><br><span class="line">ARG JDK_HOME_DIR=/opt/java/jdk17</span><br><span class="line"></span><br><span class="line"><span class="comment"># 复制自定义 JRE 到新镜像</span></span><br><span class="line">COPY --from=builder /jre17 <span class="variable">$&#123;JDK_HOME_DIR&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置环境变量</span></span><br><span class="line">ENV JAVA_HOME=<span class="variable">$&#123;JDK_HOME_DIR&#125;</span></span><br><span class="line">ENV PATH=<span class="variable">$JAVA_HOME</span>/bin:<span class="variable">$PATH</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置其它环境变量</span></span><br><span class="line">ENV TZ=<span class="string">&#x27;Asia/Shanghai&#x27;</span></span><br><span class="line">ENV LANG=C.UTF-8</span><br><span class="line"></span><br><span class="line"><span class="comment"># 更新 Alpine 的软件源为阿里云</span></span><br><span class="line">RUN <span class="built_in">echo</span> <span class="string">&quot;https://mirrors.aliyun.com/alpine/v3.18/main&quot;</span> &gt; /etc/apk/repositories \</span><br><span class="line">    &amp;&amp; <span class="built_in">echo</span> <span class="string">&quot;https://mirrors.aliyun.com/alpine/v3.18/community&quot;</span> &gt;&gt; /etc/apk/repositories</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装必要的软件包，包括时区设置和字体支持</span></span><br><span class="line">RUN apk add --no-cache fontconfig libretls ttf-dejavu tzdata musl-locales musl-locales-lang ca-certificates p11-kit-trust \</span><br><span class="line">    &amp;&amp; <span class="built_in">rm</span> -rf /var/cache/apk/*</span><br><span class="line"></span><br><span class="line"><span class="comment"># 测试 Java 安装和显示当前时间 不需要可以删除这一行</span></span><br><span class="line">CMD [<span class="string">&quot;sh&quot;</span>, <span class="string">&quot;-c&quot;</span>, <span class="string">&quot;echo &#x27;Java version:&#x27; &amp;&amp; java -version &amp;&amp; echo &#x27;Current date and time:&#x27; &amp;&amp; date&quot;</span>]</span><br></pre></td></tr></table></figure><h1 id="部署并验证"><a href="#部署并验证" class="headerlink" title="部署并验证"></a>部署并验证</h1><p>执行build，并启动容器验证</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">docker build -t jre17all .</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">// 执行会打印JAVA版本信息和时间信息</span><br><span class="line">docker run --<span class="built_in">rm</span> jre17all</span><br><span class="line">// 打标签 上传到私有镜像仓库</span><br><span class="line">docker tag jre17all registry.cn-hangzhou.aliyuncs.com/blog/jre17</span><br><span class="line">docker push registry.cn-hangzhou.aliyuncs.com/blog/jre17</span><br></pre></td></tr></table></figure><p>然后拿一个Springboot微服务验证一下<br>修改微服务Dockerfile首行的基础镜像为自定义的JRE <code>from registry.cn-hangzhou.aliyuncs.com/blog/jre17</code></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></pre></td><td class="code"><pre><span class="line">FROM registry.cn-hangzhou.aliyuncs.com/blog/jre17</span><br><span class="line">MAINTAINER dollcode</span><br><span class="line">ARG JAR_FILE</span><br><span class="line">COPY <span class="variable">$&#123;JAR_FILE&#125;</span> app.jar</span><br><span class="line">EXPOSE 8080</span><br><span class="line">ENTRYPOINT [<span class="string">&quot;java&quot;</span>,<span class="string">&quot;-jar&quot;</span>,<span class="string">&quot;/app.jar&quot;</span>]</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;由于官方的openJDK17镜像近500MB，属于太大，不利于微服务镜像打包部署。&lt;br&gt;所以自定义基于alpine 3.18 和 openjdk 17 制作JRE镜像，构建Springboot项目镜像(JRE是java运行环境，不包含开发工具所以小)。&lt;br&gt;先看结论，一</summary>
      
    
    
    
    <category term="Web技术" scheme="https://blog.dollcode.cn/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Java" scheme="https://blog.dollcode.cn/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>docker-compose一键部署yapi接口文档</title>
    <link href="https://blog.dollcode.cn/docker-yapi.html"/>
    <id>https://blog.dollcode.cn/docker-yapi.html</id>
    <published>2024-05-24T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://github.com/YMFE/yapi">yapi</a> 已经很久没人更新和维护，但界面和功能还是挺不错的，支持从Swagger快速导入更新接口，适合团队接口文档管理和存档。<br>官方并没有直接封装docker镜像，但是有一个二次开发的 <a href="https://github.com/yapi-pro/yapi">YAPIPro镜像</a>。<a href="https://hub.docker.com/r/yapipro/yapi">https://hub.docker.com/r/yapipro/yapi</a> 提供了部署文档，但是步骤有点多。于是动手自定义了docker-compose.yml实现快速部署。</p><h1 id="前提准备"><a href="#前提准备" class="headerlink" title="前提准备"></a>前提准备</h1><p>机器已安装docker-compose</p><p>创建一个目录，接下来安装操作都在这个目录下操作。目录名称就叫 <code>yapi</code> 吧</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"><span class="built_in">mkdir</span> yapi</span><br><span class="line"><span class="built_in">cd</span> yapi</span><br></pre></td></tr></table></figure><p>我们需要安装 <em>yapi</em> 和 <em>mongodb</em> 两个容器。并且需要提前创建mongodb的用户信息，并设置用户名和密码<br>所以需要准备一个脚本文件 <code>init-mongo.js</code></p><figure class="highlight js"><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">db = db.<span class="title function_">getSiblingDB</span>(<span class="string">&#x27;yapi&#x27;</span>);</span><br><span class="line"></span><br><span class="line">db.<span class="title function_">createUser</span>(&#123;</span><br><span class="line">  <span class="attr">user</span>: <span class="string">&quot;yapiblog&quot;</span>,</span><br><span class="line">  <span class="attr">pwd</span>: <span class="string">&quot;yapi666&quot;</span>,</span><br><span class="line">  <span class="attr">roles</span>: [&#123; <span class="attr">role</span>: <span class="string">&quot;dbAdmin&quot;</span>, <span class="attr">db</span>: <span class="string">&quot;yapi&quot;</span> &#125;,&#123; <span class="attr">role</span>: <span class="string">&quot;readWrite&quot;</span>, <span class="attr">db</span>: <span class="string">&quot;yapi&quot;</span> &#125;]</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>还需要准备yapi的配置文件 <code>config.json</code> </p><figure class="highlight json"><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="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;port&quot;</span><span class="punctuation">:</span> <span class="string">&quot;3000&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;adminAccount&quot;</span><span class="punctuation">:</span> <span class="string">&quot;hexiaohei1024@gmail.com&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;timeout&quot;</span><span class="punctuation">:</span><span class="number">120000</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;db&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;servername&quot;</span><span class="punctuation">:</span> <span class="string">&quot;mongodb&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;DATABASE&quot;</span><span class="punctuation">:</span> <span class="string">&quot;yapi&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;port&quot;</span><span class="punctuation">:</span> <span class="number">27017</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;user&quot;</span><span class="punctuation">:</span> <span class="string">&quot;yapiblog&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;pass&quot;</span><span class="punctuation">:</span> <span class="string">&quot;yapi666&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;authSource&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;mail&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;enable&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;host&quot;</span><span class="punctuation">:</span> <span class="string">&quot;smtp.gmail.com&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;port&quot;</span><span class="punctuation">:</span> <span class="number">465</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;from&quot;</span><span class="punctuation">:</span> <span class="string">&quot;*&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;auth&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;user&quot;</span><span class="punctuation">:</span> <span class="string">&quot;hexiaohei1024@gmail.com&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;pass&quot;</span><span class="punctuation">:</span> <span class="string">&quot;xxx&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></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></pre></td><td class="code"><pre><span class="line">yapi</span><br><span class="line"> ├── config.json</span><br><span class="line"> ├── docker-compose.yml</span><br><span class="line"> ├── init-mongo.js</span><br></pre></td></tr></table></figure><h1 id="部署脚本"><a href="#部署脚本" class="headerlink" title="部署脚本"></a>部署脚本</h1><p><strong>因为yapi流程需要先初始化数，再二次启动运行。所以yml中需要增加一个一次性容器用于初始化数据库</strong></p><p>docker-compose.yml 文件内容如下：</p><figure class="highlight yml"><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></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3&#x27;</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">mongodb:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">mongo:5.0.14</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">mongodb</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;27017:27017&quot;</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">MONGO_INITDB_DATABASE:</span> <span class="string">yapi</span></span><br><span class="line">      <span class="comment"># 设置ROOT用户和密码</span></span><br><span class="line">      <span class="attr">MONGO_INITDB_ROOT_USERNAME:</span> <span class="string">yapipro</span></span><br><span class="line">      <span class="attr">MONGO_INITDB_ROOT_PASSWORD:</span> <span class="string">yapipro1024</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./mongo-data:/data/db</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js</span></span><br><span class="line">    <span class="attr">command:</span> <span class="string">mongod</span> <span class="string">--auth</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 这个容器只需要执行一次即可</span></span><br><span class="line">  <span class="attr">yapi-init:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">yapipro/yapi:1.9.5</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">yapi-init</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">&quot;no&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">mongodb</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./config.json:/yapi/config.json</span></span><br><span class="line">    <span class="comment"># 设置延迟执行安装初始化</span></span><br><span class="line">    <span class="attr">entrypoint:</span> [<span class="string">&quot;sh&quot;</span>, <span class="string">&quot;-c&quot;</span>, <span class="string">&quot;sleep 15 &amp;&amp; node server/install.js&quot;</span>]</span><br><span class="line"></span><br><span class="line">  <span class="attr">yapi:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">yapipro/yapi:1.9.5</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">yapi</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">mongodb</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;3000:3000&quot;</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./config.json:/yapi/config.json</span></span><br><span class="line">    <span class="attr">entrypoint:</span> [<span class="string">&quot;sh&quot;</span>, <span class="string">&quot;-c&quot;</span>, <span class="string">&quot;sleep 30 &amp;&amp; node server/app.js&quot;</span>]</span><br></pre></td></tr></table></figure><h1 id="启动验证"><a href="#启动验证" class="headerlink" title="启动验证"></a>启动验证</h1><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">docker-compose up -d</span><br></pre></td></tr></table></figure><p>初始化管理员账号在上面的 config.json 配置中 <a href="mailto:&#x68;&#x65;&#x78;&#x69;&#97;&#111;&#104;&#x65;&#x69;&#x31;&#48;&#x32;&#x34;&#x40;&#103;&#x6d;&#x61;&#x69;&#108;&#46;&#99;&#x6f;&#109;">&#x68;&#x65;&#x78;&#x69;&#97;&#111;&#104;&#x65;&#x69;&#x31;&#48;&#x32;&#x34;&#x40;&#103;&#x6d;&#x61;&#x69;&#108;&#46;&#99;&#x6f;&#109;</a>，初始密码是 yapi.pro，<br>可以登录后进入个人中心修改。  访问 IP:3000登录即可！</p><p>关于MongoDB版本选择：长时间运行且对稳定性要求高的生产环境：推荐使用 MongoDB 4.4.x 或 5.0.x，这些版本经过了大量验证，社区反馈也较好</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/YMFE/yapi&quot;&gt;yapi&lt;/a&gt; 已经很久没人更新和维护，但界面和功能还是挺不错的，支持从Swagger快速导入更新接口，适合团队接口文档管理和存档。&lt;br&gt;官方并没有直接封装docker镜像，但是有一个二次开发</summary>
      
    
    
    
    <category term="服务器" scheme="https://blog.dollcode.cn/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
    
    <category term="Linux" scheme="https://blog.dollcode.cn/tags/Linux/"/>
    
    <category term="Docker" scheme="https://blog.dollcode.cn/tags/Docker/"/>
    
  </entry>
  
  <entry>
    <title>DB-GPT本地部署体验讯飞星火大模型V3.5</title>
    <link href="https://blog.dollcode.cn/dbgpt-xunfeispark.html"/>
    <id>https://blog.dollcode.cn/dbgpt-xunfeispark.html</id>
    <published>2024-04-19T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<h1 id=""><a href="#" class="headerlink" title=""></a></h1><p>首先我们从 DB-GPT官网，可以得到的<a href="https://docs.dbgpt.site/docs/latest/quickstart">https://docs.dbgpt.site/docs/latest/quickstart</a><br>DB-GPT是一个开源的AI原生数据应用开发框架(AI Native Data App Development framework with AWEL(Agentic Workflow Expression Language) and Agents)。目的是构建大模型领域的基础设施，通过开发多模型管理(SMMF)、Text2SQL效果优化、RAG框架以及优化、Multi-Agents框架协作、AWEL(智能体工作流编排)等多种技术能力，让围绕数据库构建大模型应用更简单，更方便。<br>数据3.0 时代，基于模型、数据库，企业&#x2F;开发者可以用更少的代码搭建自己的专属应用</p><p>本次 我们通过代理模型方式，使用讯飞星火大模型3.5版本，来进行验证部署。</p><blockquote><p>需要提前将Miniconda环境安装</p></blockquote><h1 id="环境配置"><a href="#环境配置" class="headerlink" title="环境配置"></a>环境配置</h1><p>首先根据官方文档说明，下载源码，并配置环境(python &gt;&#x3D; 3.10)</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></pre></td><td class="code"><pre><span class="line">// 拉取源码</span><br><span class="line">git <span class="built_in">clone</span> https://github.com/eosphoros-ai/DB-GPT.git</span><br><span class="line">// 进入项目目录</span><br><span class="line"><span class="built_in">cd</span> DB-GPT</span><br></pre></td></tr></table></figure><p>创建环境</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">// 创建环境</span><br><span class="line">conda create -n dbgpt_env python=3.10</span><br><span class="line">// 激活环境</span><br><span class="line">conda activate dbgpt_env</span><br><span class="line">// 安装依赖</span><br><span class="line">pip install -e <span class="string">&quot;.[default]&quot;</span></span><br><span class="line">// 复制环境配置文件</span><br><span class="line"><span class="built_in">cp</span> .env.template  .<span class="built_in">env</span></span><br></pre></td></tr></table></figure><h1 id="文本向量模型配置"><a href="#文本向量模型配置" class="headerlink" title="文本向量模型配置"></a>文本向量模型配置</h1><p>在项目目录下，创建一个models文件夹，用来存放模型文件</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"><span class="built_in">mkdir</span> models and <span class="built_in">cd</span> models</span><br></pre></td></tr></table></figure><blockquote><p>下载模型，国内访问不了<a href="https://huggingface.co/GanymedeNil/text2vec-large-chinese">https://huggingface.co/GanymedeNil/text2vec-large-chinese</a><br>可以替换为镜像站<a href="https://hf-mirror.com/GanymedeNil/text2vec-large-chinese">https://hf-mirror.com/GanymedeNil/text2vec-large-chinese</a></p></blockquote><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">git <span class="built_in">clone</span> https://hf-mirror.com/GanymedeNil/text2vec-large-chinese</span><br></pre></td></tr></table></figure><h1 id="配置星火3-5模型"><a href="#配置星火3-5模型" class="headerlink" title="配置星火3.5模型"></a>配置星火3.5模型</h1><p>因为源码中没有3.5的API，需要手动修改一下代码，主要需要修改<code>/DB-GPT/dbgpt/model/proxy/llms/spark.py</code><br><strong>直接将3.1改为3.5即可使用</strong><br><img src="/img/article/20240419-115307.png"><br><img src="/img/article/20240419-115418.png"></p><p>然后在<code>.env</code>文件中 将以下星火相关的配置替换即可</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></pre></td><td class="code"><pre><span class="line">LLM_MODEL=spark_proxyllm</span><br><span class="line">XUNFEI_SPARK_API_VERSION=v3.5</span><br><span class="line">XUNFEI_SPARK_APPID=xx</span><br><span class="line">XUNFEI_SPARK_API_KEY=xxx</span><br><span class="line">XUNFEI_SPARK_API_SECRET=xxx</span><br></pre></td></tr></table></figure><h1 id="启动项目"><a href="#启动项目" class="headerlink" title="启动项目"></a>启动项目</h1><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">python dbgpt/app/dbgpt_server.py</span><br></pre></td></tr></table></figure><p><img src="/img/article/20240419-171912.png"><br>看到日志输出启动完成，打开浏览器访问<a href="http://localhost:5670/">http://localhost:5670</a><br><img src="/img/article/20240420-153402.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;&quot;&gt;&lt;a href=&quot;#&quot; class=&quot;headerlink&quot; title=&quot;&quot;&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;首先我们从 DB-GPT官网，可以得到的&lt;a href=&quot;https://docs.dbgpt.site/docs/latest/quickstart&quot;&gt;h</summary>
      
    
    
    
    <category term="Web技术" scheme="https://blog.dollcode.cn/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
  </entry>
  
  <entry>
    <title>PostgreSQL UPSERT(insert on conflict do)和pgpass使用说明</title>
    <link href="https://blog.dollcode.cn/pgsql-insertup-new.html"/>
    <id>https://blog.dollcode.cn/pgsql-insertup-new.html</id>
    <published>2023-12-21T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<p>PostgreSQL INSERT INTO ON CONFLICT语法。UPSERT(insert on conflict do) 记录存在就更新，不存在就更新。<br>在某些业务场景中，需要把插入语句和更新组合到一起，一条SQL同时完成插入和更新逻辑。<br>这个时候就需要用到 <code>INSERT ON CONFLICT</code>语法特性了。可以实现根据主键或者唯一约束，来插入或指定条件更新。</p><h1 id="官方语法说明"><a href="#官方语法说明" class="headerlink" title="官方语法说明"></a>官方语法说明</h1><figure class="highlight sql"><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">Command:     <span class="keyword">INSERT</span>  </span><br><span class="line">Description: <span class="keyword">create</span> <span class="keyword">new</span> <span class="keyword">rows</span> <span class="keyword">in</span> a <span class="keyword">table</span>  </span><br><span class="line">Syntax:  </span><br><span class="line">[ <span class="keyword">WITH</span> [ <span class="keyword">RECURSIVE</span> ] with_query [, ...] ]  </span><br><span class="line"><span class="keyword">INSERT INTO</span> table_name [ <span class="keyword">AS</span> alias ] [ ( column_name [, ...] ) ]  </span><br><span class="line">    &#123; <span class="keyword">DEFAULT</span> <span class="keyword">VALUES</span> <span class="operator">|</span> <span class="keyword">VALUES</span> ( &#123; expression <span class="operator">|</span> <span class="keyword">DEFAULT</span> &#125; [, ...] ) [, ...] <span class="operator">|</span> query &#125;  </span><br><span class="line">    [ <span class="keyword">ON</span> CONFLICT [ conflict_target ] conflict_action ]  </span><br><span class="line">    [ RETURNING <span class="operator">*</span> <span class="operator">|</span> output_expression [ [ <span class="keyword">AS</span> ] output_name ] [, ...] ]  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">where</span> conflict_target can be <span class="keyword">one</span> <span class="keyword">of</span>:  </span><br><span class="line">  </span><br><span class="line">    ( &#123; index_column_name <span class="operator">|</span> ( index_expression ) &#125; [ <span class="keyword">COLLATE</span> <span class="keyword">collation</span> ] [ opclass ] [, ...] ) [ <span class="keyword">WHERE</span> index_predicate ]  </span><br><span class="line">    <span class="keyword">ON</span> <span class="keyword">CONSTRAINT</span> constraint_name  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">and</span> conflict_action <span class="keyword">is</span> <span class="keyword">one</span> <span class="keyword">of</span>:  </span><br><span class="line">  </span><br><span class="line">    DO NOTHING  </span><br><span class="line">    DO <span class="keyword">UPDATE</span> <span class="keyword">SET</span> &#123; column_name <span class="operator">=</span> &#123; expression <span class="operator">|</span> <span class="keyword">DEFAULT</span> &#125; <span class="operator">|</span>  </span><br><span class="line">                    ( column_name [, ...] ) <span class="operator">=</span> ( &#123; expression <span class="operator">|</span> <span class="keyword">DEFAULT</span> &#125; [, ...] ) <span class="operator">|</span>  </span><br><span class="line">                    ( column_name [, ...] ) <span class="operator">=</span> ( sub<span class="operator">-</span><span class="keyword">SELECT</span> )  </span><br><span class="line">                  &#125; [, ...]  </span><br><span class="line">              [ <span class="keyword">WHERE</span> <span class="keyword">condition</span> ]  </span><br></pre></td></tr></table></figure><p>假如我们有这样一张日志表，要同时实现写入和更新。</p><figure class="highlight sql"><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="keyword">CREATE TABLE</span> user_log_info (</span><br><span class="line">    log_id text <span class="keyword">NOT NULL</span>,</span><br><span class="line">    log_name text,</span><br><span class="line">    log_path text,</span><br><span class="line">    log_size <span class="type">bigint</span>,</span><br><span class="line">    log_time <span class="type">timestamp</span>,</span><br><span class="line">    create_time <span class="type">timestamp</span>,</span><br><span class="line">    <span class="keyword">PRIMARY KEY</span> (log_id,log_time)</span><br><span class="line">) </span><br></pre></td></tr></table></figure><h1 id="根据主键新增或更新"><a href="#根据主键新增或更新" class="headerlink" title="根据主键新增或更新"></a>根据主键新增或更新</h1><blockquote><p>符合写入日志时间比当前记录新，才执行写入更新</p></blockquote><figure class="highlight sql"><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="keyword">INSERT INTO</span> user_log_info</span><br><span class="line"><span class="keyword">VALUES</span></span><br><span class="line">( <span class="string">&#x27;demo001&#x27;</span>, <span class="string">&#x27;open1&#x27;</span>, <span class="string">&#x27;/logs/a.log&#x27;</span>, <span class="number">30</span>, TO_TIMESTAMP( <span class="number">1713509590</span> ), <span class="built_in">LOCALTIMESTAMP</span> ) <span class="keyword">ON</span> CONFLICT ( log_id, log_time ) DO</span><br><span class="line"><span class="keyword">UPDATE</span> </span><br><span class="line"><span class="keyword">SET</span> log_name <span class="operator">=</span> EXCLUDED.log_name,</span><br><span class="line">log_path <span class="operator">=</span> EXCLUDED.log_path,</span><br><span class="line">log_size <span class="operator">=</span> EXCLUDED.log_size,</span><br><span class="line">log_time <span class="operator">=</span> EXCLUDED.log_time,</span><br><span class="line">create_time <span class="operator">=</span> EXCLUDED.create_time </span><br><span class="line"><span class="keyword">WHERE</span></span><br><span class="line">EXCLUDED.log_time <span class="operator">&gt;</span> user_log_info.log_time</span><br></pre></td></tr></table></figure><h1 id="根据符合条件才更新"><a href="#根据符合条件才更新" class="headerlink" title="根据符合条件才更新"></a>根据符合条件才更新</h1><blockquote><p>举例：符合日志size大小，比之前大才会更新，SQL如下</p></blockquote><figure class="highlight sql"><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="keyword">INSERT INTO</span> user_log_info</span><br><span class="line"><span class="keyword">VALUES</span></span><br><span class="line">( <span class="string">&#x27;demo001&#x27;</span>, <span class="string">&#x27;open1&#x27;</span>, <span class="string">&#x27;/logs/a.log&#x27;</span>, <span class="number">30</span>, TO_TIMESTAMP( <span class="number">1713509590</span> ), <span class="built_in">LOCALTIMESTAMP</span> ) <span class="keyword">ON</span> CONFLICT ( log_id, log_time ) DO</span><br><span class="line"><span class="keyword">UPDATE</span> </span><br><span class="line"><span class="keyword">SET</span> log_name <span class="operator">=</span> EXCLUDED.log_name,</span><br><span class="line">log_path <span class="operator">=</span> EXCLUDED.log_path,</span><br><span class="line">log_size <span class="operator">=</span> EXCLUDED.log_size,</span><br><span class="line">log_time <span class="operator">=</span> EXCLUDED.log_time,</span><br><span class="line">create_time <span class="operator">=</span> EXCLUDED.create_time </span><br><span class="line"><span class="keyword">WHERE</span></span><br><span class="line">EXCLUDED.log_size <span class="operator">&gt;</span> user_log_info.log_size</span><br></pre></td></tr></table></figure><h1 id="实际应用场景"><a href="#实际应用场景" class="headerlink" title="实际应用场景"></a>实际应用场景</h1><p>相当于我们在写入数据时，可以像写查询一样 带上WHERE条件，实现符合条件才更新</p><h1 id="PGSQL定时任务实现"><a href="#PGSQL定时任务实现" class="headerlink" title="PGSQL定时任务实现"></a>PGSQL定时任务实现</h1><p>cron + pgpass<br>利用shell脚本 + Linux定时任务，去定时执行清理日志表</p><h2 id="首先配置命令行免密登录"><a href="#首先配置命令行免密登录" class="headerlink" title="首先配置命令行免密登录"></a>首先配置命令行免密登录</h2><p>根据Postgres的官方文档配置.pgpass。</p><blockquote><p>文件内容格式如下：127.0.0.1:5432:库名:用户:密码</p></blockquote><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></pre></td><td class="code"><pre><span class="line">登录服务器，在用户主目录中创建`.pgpass`文件配置</span><br><span class="line">vi .pgpass</span><br><span class="line">127.0.0.1:5432:demo_test:postgres:123456</span><br><span class="line"></span><br><span class="line">// 授权当前用户可见</span><br><span class="line"><span class="built_in">chmod</span> 600 .pgpass</span><br><span class="line"></span><br><span class="line">// 执行验证测试，查询连接用户数SQL</span><br><span class="line">/usr/pgsql-13/bin/psql -h 127.0.0.1 -p 5432 -d demo_test  -U postgres  -c <span class="string">&quot;select COUNT(*) from pg_stat_activity&quot;</span></span><br></pre></td></tr></table></figure><h2 id="编写shell脚本封装SQL"><a href="#编写shell脚本封装SQL" class="headerlink" title="编写shell脚本封装SQL"></a>编写shell脚本封装SQL</h2><p>vim pgcron.sh。文件内容如下</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><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"><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">execpgsql</span></span>()&#123;</span><br><span class="line">  <span class="built_in">echo</span> <span class="variable">$1</span></span><br><span class="line">  starttime=`<span class="built_in">date</span> +<span class="string">&quot;%Y-%m-%d %H:%M.%S&quot;</span>` </span><br><span class="line">  result=$(/usr/pgsql-13/bin/psql -h 127.0.0.1 -p 5432 -d demo_test  -U postgres  -c <span class="string">&quot;<span class="variable">$1</span>&quot;</span>)</span><br><span class="line">  endtime=`<span class="built_in">date</span> +<span class="string">&quot;%Y-%m-%d %H:%M.%S&quot;</span>`</span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;[开始执行:<span class="variable">$starttime</span>&quot;</span> <span class="string">&quot;执行结束:<span class="variable">$endtime</span>]&quot;</span> <span class="string">&quot;SQL:<span class="variable">$1</span>&quot;</span> <span class="string">&quot;结果:<span class="variable">$result</span>&quot;</span></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">sql=<span class="string">&quot;DROP TABLE user_log_info&quot;</span></span><br><span class="line">execpgsql <span class="string">&quot;<span class="variable">$sql</span>&quot;</span></span><br></pre></td></tr></table></figure><blockquote><p>再将这个脚本加入 crontab，并设定执行周期</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;PostgreSQL INSERT INTO ON CONFLICT语法。UPSERT(insert on conflict do) 记录存在就更新，不存在就更新。&lt;br&gt;在某些业务场景中，需要把插入语句和更新组合到一起，一条SQL同时完成插入和更新逻辑。&lt;br&gt;这个时候就</summary>
      
    
    
    
    <category term="Web技术" scheme="https://blog.dollcode.cn/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="数据库" scheme="https://blog.dollcode.cn/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>搭建PostgreSQL主从架构</title>
    <link href="https://blog.dollcode.cn/primary-or-secondary-postgresql.html"/>
    <id>https://blog.dollcode.cn/primary-or-secondary-postgresql.html</id>
    <published>2023-08-23T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<p>PostgreSQL是一个功能非常强大的、源代码开放的客户&#x2F;服务器关系型数据库管理系统（RDBMS），被业界誉为“先进的开源数据库”，支持NoSQL数据类型，主要面向企业复杂查询SQL的OLTP业务场景。<br>并且提供PostGIS地理信息引擎，也是我本次使用它的原因。经常在网上看到“PostgreSQL —— 世界上最流行的数据库”<br>这一次 从零开始 搭建PG主从架构，做读写分离。</p><h1 id="1-配置PostgreSQL下载源"><a href="#1-配置PostgreSQL下载源" class="headerlink" title="1. 配置PostgreSQL下载源"></a>1. 配置PostgreSQL下载源</h1><p>首先准备两台服务器，安装PostgreSQL主从。版本选择这块，选了中间版本<code>13</code> (详细版本是：13.12)。各版本信息可以在官网查看：<a href="https://www.postgresql.org/docs/">https://www.postgresql.org/docs/</a><br><img src="/img/article/20230923155410.png"></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></pre></td><td class="code"><pre><span class="line">// 首先下载PostgreSQL的RPM文件包</span><br><span class="line">wget --no-check-certificate https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm</span><br><span class="line"></span><br><span class="line">// 安装RPM包</span><br><span class="line">rpm -ivh pgdg-redhat-repo-latest.noarch.rpm</span><br></pre></td></tr></table></figure><h1 id="2-安装PostgreSQL"><a href="#2-安装PostgreSQL" class="headerlink" title="2. 安装PostgreSQL"></a>2. 安装PostgreSQL</h1><p>根据自己业务需要，除了sever包之外，这里我还会多安装两个包。（如果不需要可以不装）</p><ul><li>postgresql13-server：数据库</li><li>postgresql13-contrib：自定义函数需要通过contrib模块进行扩展</li><li>pg_cron_13：PostgreSQL定时任务插件</li></ul><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">// 安装</span><br><span class="line">yum install postgresql13-server postgresql13-contrib pg_cron_13 -y</span><br></pre></td></tr></table></figure><h2 id="自定义数据存储目录"><a href="#自定义数据存储目录" class="headerlink" title="自定义数据存储目录"></a>自定义数据存储目录</h2><p>默认的存储目录是<code>/var/lib/pgsql/13/data</code>。可以修改为自定义</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">vim /usr/lib/systemd/system/postgresql-13.service</span><br></pre></td></tr></table></figure><p><img src="/img/article/20230914102117.png"><br>修改默认的存储目录，然后重新加载一次服务</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">systemctl daemon-reload</span><br></pre></td></tr></table></figure><h2 id="配置服务器postgres用户密码"><a href="#配置服务器postgres用户密码" class="headerlink" title="配置服务器postgres用户密码"></a>配置服务器postgres用户密码</h2><p>因为安装PG数据库之后 会自动创建postgres用户，可以设置一下密码</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">// 设置postgres用户密码，回车之后输入密码确认即可</span><br><span class="line">passwd postgres</span><br></pre></td></tr></table></figure><p><strong>至此 在两台机器上 都执行完成这些命令之后，准备工作就差不多完成了。</strong></p><h1 id="主库搭建"><a href="#主库搭建" class="headerlink" title="主库搭建"></a>主库搭建</h1><p>首先初始化数据库，并配置启动</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></pre></td><td class="code"><pre><span class="line">// 初始化数据库</span><br><span class="line">/usr/pgsql-13/bin/postgresql-13-setup initdb</span><br><span class="line">// 启动</span><br><span class="line">systemctl start postgresql-13.service</span><br><span class="line">// 设置服务开机自启动</span><br><span class="line">systemctl <span class="built_in">enable</span> postgresql-13.service</span><br></pre></td></tr></table></figure><h2 id="修改配置文件"><a href="#修改配置文件" class="headerlink" title="修改配置文件"></a>修改配置文件</h2><p>配置文件有很多选项需要优化，优化放到最后说，搭建我们只需要注意三个配置即可</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">// 编辑postgresql.conf</span><br><span class="line">vim /var/lib/pgsql/13/data/postgresql.conf</span><br></pre></td></tr></table></figure><p>listen_addresses为*，max_connections调大到500，wal_level决定多少信息写入到 WAL中。默认值是replica</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">listen_addresses = &#x27;*&#x27;</span><br><span class="line">max_connections = 500</span><br><span class="line">wal_level = replica</span><br></pre></td></tr></table></figure><h2 id="创建主从复制账号"><a href="#创建主从复制账号" class="headerlink" title="创建主从复制账号"></a>创建主从复制账号</h2><p>登录到PG，并创建用于主从复制的账号</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">// 登录postgres用户</span><br><span class="line">su - postgres</span><br><span class="line"></span><br><span class="line">// 当显示-bash-4.2$时表示成功登录，然后输入以下命令进入PostgreSQL交互终端</span><br><span class="line">psql</span><br><span class="line"></span><br><span class="line">// 为用户postgres设置密码</span><br><span class="line">ALTER USER postgres WITH PASSWORD <span class="string">&#x27;admin123&#x27;</span>;</span><br><span class="line"></span><br><span class="line">// 创建数据库账号slavereplica，并设置密码及登录权限和备份权限。</span><br><span class="line">CREATE ROLE slavereplica login replication encrypted password <span class="string">&#x27;slaver123&#x27;</span>;</span><br></pre></td></tr></table></figure><p>在pg_hba.conf 中增加一行从库节点机器IP段。自己查看服务器IP和内网网段。方法配置trust表示直接信任</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">vim /var/lib/pgsql/13/data/pg_hba.conf</span><br></pre></td></tr></table></figure><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">host    replication     slavereplica    192.168.0.0/16           trust</span><br></pre></td></tr></table></figure><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">// 全部配置完成之后重新启动</span><br><span class="line">systemctl restart postgresql-13.service</span><br></pre></td></tr></table></figure><p><strong>主库的配置就全部完成了，接下来是从库的操作了</strong></p><h1 id="从库搭建"><a href="#从库搭建" class="headerlink" title="从库搭建"></a>从库搭建</h1><p>从库的配置比较简单了，迁移主库数据就可以了</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">// 初始化数据库</span><br><span class="line">/usr/pgsql-13/bin/postgresql-13-setup initdb</span><br><span class="line"></span><br><span class="line">// 从节点 清空data 目录</span><br><span class="line"><span class="built_in">rm</span> -rf /var/lib/pgsql/13/date/*</span><br><span class="line"></span><br><span class="line">// 复制主节点data数据: IP为主库的机器IP</span><br><span class="line"><span class="built_in">sudo</span> -u postgres pg_basebackup -h 192.168.31.190 -p 5432 -U slavereplica -X stream -D /var/lib/pgsql/13/data -R -P</span><br></pre></td></tr></table></figure><blockquote><p>备份完成，会在数据库实例目录下自动生成standby.signal“信号”文件，并在postgresql.auto.conf文件写入了主库的连接信息</p></blockquote><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></pre></td><td class="code"><pre><span class="line">// 启动从库</span><br><span class="line">systemctl start postgresql-13.service</span><br><span class="line"></span><br><span class="line">// 验证是否为从节点，会得到t，即<span class="literal">true</span>，为从节点</span><br><span class="line"><span class="built_in">sudo</span> -u postgres /usr/pgsql-13/bin/psql -c <span class="string">&quot;select pg_is_in_recovery()&quot;</span></span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">pg_is_in_recovery </span><br><span class="line">-------------------</span><br><span class="line"> t</span><br><span class="line">(1 row)</span><br></pre></td></tr></table></figure><p>同时在主库机器执行以下命令 可以查看到集群状态</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"><span class="built_in">sudo</span> -u postgres /usr/pgsql-13/bin/psql -c <span class="string">&quot;select * from pg_stat_replication&quot;</span></span><br></pre></td></tr></table></figure><h1 id="用户访问权限配置"><a href="#用户访问权限配置" class="headerlink" title="用户访问权限配置"></a>用户访问权限配置</h1><p>如果需要外网访问，需要配置权限。<br>编辑pg_hba.conf文件，新增一行 允许所有用户所有库所有IP访问</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">host    all             all             0.0.0.0/0               scram-sha-256</span><br></pre></td></tr></table></figure><blockquote><p><strong>这是最省事的方法，但是不太安全，建议是单个用户单个配置</strong></p></blockquote><ul><li>第一列：类型 （host固定）</li><li>第二列：数据库 （all表示所有数据库，可以单独设置库名）</li><li>第三列：用户  （all表示所有用户，可以单独设置用户）</li><li>第四列：IP-CIDR表达式  （0.0.0.0&#x2F;0表示不限制）</li><li>第五列：认证方式 （scram-sha-256&#x3D;密码认证；trust&#x3D;直接信任）</li></ul><h1 id="postgresql-conf配置优化"><a href="#postgresql-conf配置优化" class="headerlink" title="postgresql.conf配置优化"></a>postgresql.conf配置优化</h1><p>数据库的配置，需要根据服务器性能合理配置。这里推荐一个参考项目：填入机器配置，可以自动生成对于的数据库配置信息(可以参考)<br>项目地址：<a href="https://pgtune.leopard.in.ua/">https://pgtune.leopard.in.ua</a><br><img src="/img/article/20230923170550.png"></p><h2 id="配置信息说明"><a href="#配置信息说明" class="headerlink" title="配置信息说明"></a>配置信息说明</h2><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></pre></td><td class="code"><pre><span class="line">max_connections = 1000# 最大连接数</span><br><span class="line">shared_buffers = 4GB# 建议的设置值为机器总内存大小的1/4</span><br><span class="line">effective_cache_size = 8GB # 缓存数据大小</span><br><span class="line"></span><br><span class="line">max_worker_processes = 8# 最大后台进程数</span><br></pre></td></tr></table></figure><h1 id="pgadmin管理端"><a href="#pgadmin管理端" class="headerlink" title="pgadmin管理端"></a>pgadmin管理端</h1><p>数据库管理工具这一块，可以使用pgadmin。用docker可以快速搭建好，这样就可以通过web端在游览器管理数据库了<br><a href="https://www.pgadmin.org/download/pgadmin-4-container/">https://www.pgadmin.org/download/pgadmin-4-container/</a></p><p>Docker命令如下：配置了管理员的登录邮箱和密码</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></pre></td><td class="code"><pre><span class="line">docker run --name <span class="string">&quot;pgadmin4&quot;</span> \</span><br><span class="line">-p 8080:80 \</span><br><span class="line">    -e <span class="string">&quot;PGADMIN_DEFAULT_EMAIL=admin@163.com&quot;</span> \</span><br><span class="line">    -e <span class="string">&quot;PGADMIN_DEFAULT_PASSWORD=admin123&quot;</span> \</span><br><span class="line">-e <span class="string">&quot;PGADMIN_LISTEN_ADDRESS=0.0.0.0&quot;</span> \</span><br><span class="line">    -d dpage/pgadmin4</span><br></pre></td></tr></table></figure><p>启动成功之后，登录pgadmin并配置数据库的连接信息之后，就可以在WEB端对数据库进行监控和管理了。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;PostgreSQL是一个功能非常强大的、源代码开放的客户&amp;#x2F;服务器关系型数据库管理系统（RDBMS），被业界誉为“先进的开源数据库”，支持NoSQL数据类型，主要面向企业复杂查询SQL的OLTP业务场景。&lt;br&gt;并且提供PostGIS地理信息引擎，也是我本次使用它</summary>
      
    
    
    
    <category term="Web技术" scheme="https://blog.dollcode.cn/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Linux" scheme="https://blog.dollcode.cn/tags/Linux/"/>
    
    <category term="PostgreSQL" scheme="https://blog.dollcode.cn/tags/PostgreSQL/"/>
    
  </entry>
  
  <entry>
    <title>K8s搭建Flink集群并用StreamPark管理</title>
    <link href="https://blog.dollcode.cn/k8s-flink-cluster.html"/>
    <id>https://blog.dollcode.cn/k8s-flink-cluster.html</id>
    <published>2023-06-08T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<p>前面文章中，成功搭建了K8s集群。这篇文章就开始来搭建组件了！</p><p>实时即未来 Apache Flink被普遍认为是下一代大数据流计算引擎。官网地址：<a href="https://flink.apache.org/">https://flink.apache.org</a><br><strong>Apache StreamPark</strong>之前也叫做 <strong>Streamx</strong>。是Flink开发利器。官网地址：<a href="https://streampark.apache.org/">https://streampark.apache.org</a></p><p>所以本文内容：K8s搭建Flink集群并用StreamX管理。</p><h1 id="前提说明"><a href="#前提说明" class="headerlink" title="前提说明"></a>前提说明</h1><p>官方文档地址如下：</p><ul><li>K8s Flink : <a href="https://nightlies.apache.org/flink/flink-docs-stable/docs/deployment/resource-providers/native_kubernetes">https://nightlies.apache.org/flink/flink-docs-stable/docs/deployment/resource-providers/native_kubernetes</a></li><li>StreamX : <a href="https://streampark.apache.org/zh-CN/docs/user-guide/deployment">https://streampark.apache.org/zh-CN/docs/user-guide/deployment</a></li></ul><p>依托于 <strong>StreamX一站式管理</strong> 和 <strong>K8s强大的调度管理</strong>。Flink集群的搭建算是比较简单了，按照官方文档一步一步就可以完成搭建。</p><p>K8s Flink 有要求 <strong>Kubernetes &gt;&#x3D; 1.9</strong> 前面装的1.22是满足的。</p><h1 id="部署Flink集群"><a href="#部署Flink集群" class="headerlink" title="部署Flink集群"></a>部署Flink集群</h1><h2 id="环境配置"><a href="#环境配置" class="headerlink" title="环境配置"></a>环境配置</h2><p>首先登录k8smaster节点机器，检查<code>kubectl</code>是否正常</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"><span class="comment"># 查看集群信息</span></span><br><span class="line">kubectl cluster-info</span><br></pre></td></tr></table></figure><p>输出集群信息，证明kubectl连接正常即可</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">Kubernetes control plane is running at https://192.168.31.190:6443</span><br><span class="line">CoreDNS is running at https://192.168.31.190:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy</span><br></pre></td></tr></table></figure><p>接下来Kubernetes RBAC配置</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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建命名空间</span></span><br><span class="line">kubectl create namespace flink-cluster</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建Flink角色权限，指定命名空间，默认k8s账户</span></span><br><span class="line">kubectl create clusterrolebinding flink-role-binding-default --clusterrole=edit --serviceaccount=flink-cluster:default</span><br></pre></td></tr></table></figure><p>这样K8s这边准备工作就全部完成了，是不是很简单。那是因为把所有的创建和管理全部用StreamX去承载了。</p><p>如果不使用StreamX。那么也可以直接使用Flink官方文档上的配置进行Flink安装，但是那样是需要用命令方式提交任务和管理的，不太方便。</p><h2 id="安装StreamX"><a href="#安装StreamX" class="headerlink" title="安装StreamX"></a>安装StreamX</h2><p>StreamX就直接安装在K8smaster所在机器上了，但需要提前准备一些环境：</p><ul><li>JAVA 1.8+（需要安装在部署机器上）</li><li>MySQL 5.6+（安装在部署机器或者其他机器已经有MySQL也行）</li><li>Flink版本必须是1.12.x或以上版本, scala版本必须是2.11</li></ul><p>下载安装包地址：<a href="https://github.com/apache/incubator-streampark/releases/download/v1.2.3/streamx-console-service_2.11-1.2.3.tar.gz">https://github.com/apache/incubator-streampark/releases/download/v1.2.3/streamx-console-service_2.11-1.2.3.tar.gz</a></p><p>解压缩之后，cd进入该目录，可以看到目录结构如下<br><img src="/img/article/20230608170210.png"></p><p>需要修改目录<code>conf/application.yml</code>文件中的三处<br>(Mysql连接信息、本地存储位置、docker仓库的命名空间)<br><img src="/img/article/20230608171040.png"><br><img src="/img/article/20230608171219.png"></p><p>接下来，在Mysql创建一个数据库<code>streamx</code>。并找到目录<code>script/final.sql</code> 执行这个SQL脚本。完成表和数据导入。</p><p>启动streamx</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">./bin/startup.sh</span><br></pre></td></tr></table></figure><p>会输出一连串启动日志，最后一行<code>[StreamX] StreamX start successful. pid: xxxx</code>。就证明启动成功了</p><p>游览器打开：IP:10000端口，访问，输入默认账号密码<strong>admin &#x2F; streamx</strong></p><h2 id="streamx配置"><a href="#streamx配置" class="headerlink" title="streamx配置"></a>streamx配置</h2><p>首先找到设置<br><img src="/img/article/20230608172451.png"></p><p>先配置系统设置，Flink搭建目前只需要配置 最下面的 <strong>Docker三项</strong></p><ul><li>Docker Register Address</li><li>Docker Register User</li><li>Docker Register Password</li></ul><p>再点击<code>Flink Home</code>配置，可以配置多个不同版本Flink</p><p>按照StreamX的环境要求，选择scala版本必须是2.11，大家可以自由选择版本，只需要改动地址中的版本号，即可进入对应版本文档</p><ul><li>1.17文档：<a href="https://nightlies.apache.org/flink/flink-docs-release-1.17/docs/deployment/resource-providers/native_kubernetes/">https://nightlies.apache.org/flink/flink-docs-release-1.17/docs/deployment/resource-providers/native_kubernetes/</a></li><li>1.13文档：<a href="https://nightlies.apache.org/flink/flink-docs-release-1.13/docs/deployment/resource-providers/native_kubernetes/">https://nightlies.apache.org/flink/flink-docs-release-1.13/docs/deployment/resource-providers/native_kubernetes/</a></li></ul><p>所以我这里下载1.13.6。下载地址:<a href="https://archive.apache.org/dist/flink/flink-1.13.6/">https://archive.apache.org/dist/flink/flink-1.13.6/</a><br><img src="/img/article/20230608190934.png"><br>解压缩之后放到<code>/opt/flinkpackages</code>目录下。以后其他版本也放到这里</p><p>填入名称 和 目录位置 再点击提交即可<br><img src="/img/article/20230608191119.png"></p><p>接下来开始配置集群信息，先创建一个Session集群，这里先简单配置一下，验证整个流程是否通顺<br><img src="/img/article/20230608191326.png"><br><img src="/img/article/20230608191443.png"></p><p>启动完成之后，点击 <code>小眼睛</code> 按钮 直接跳转到Flink UI。</p><h1 id="测试验证"><a href="#测试验证" class="headerlink" title="测试验证"></a>测试验证</h1><p>点击 Application 按钮，看到有一个自带的Demo，点击编辑按钮<br><img src="/img/article/20230608192002.png"></p><h2 id="测试session模式部署任务"><a href="#测试session模式部署任务" class="headerlink" title="测试session模式部署任务"></a>测试session模式部署任务</h2><p>选择刚刚启动的Session-test集群，其他下面配置不用改，直接点提交<br><img src="/img/article/20230608192147.png"></p><p>然后 点击第二个按钮Launch Application，等待编译完成之后 &gt; 再次点击就是Start Application。会弹出启动配置窗口 &gt; 关闭savepoint。再点击应用。<br>等待启动成功变为Running状态，点击<code>小眼睛</code> 按钮查看详细，可以跳转到Flink UI。<br><img src="/img/article/20230608193055.png"><br>可以在Flink UIk看到在运行，这个Demo一会就跑完了。然后会自动伸缩TaskManagers<br><img src="/img/article/20230608193248.png"></p><p>至此，整个Flink Session部署的流程就跑通了！</p><h2 id="测试application模式部署任务"><a href="#测试application模式部署任务" class="headerlink" title="测试application模式部署任务"></a>测试application模式部署任务</h2><blockquote><p>这里面有一个前提条件，需要预先在每台节点机器上登录docker私有仓库</p></blockquote><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"><span class="comment"># docker login命令用于登陆到一个Docker镜像仓库，如果未指定镜像仓库地址，默认为官方仓库DockerHub（hub.docker.com）。</span></span><br><span class="line">docker login --username=用户名 镜像仓库地址</span><br></pre></td></tr></table></figure><p>还是用上面的Flink SQL Demo，再次编辑，模式选择<code>kubernetes application</code> 自定义clusterId：<code>test123</code>，然后点提交。<br><img src="/img/article/20230609101936.png"></p><p>接下来就是和session集群一样的操作，点击第二个按钮Launch。等待docker镜像bulid完成并上传到docke仓库。就可以再次点击启动了</p><p>等待启动成功变为Running状态，点击<code>小眼睛</code> 按钮查看详细，可以跳转到Flink UI 进行查看。</p><p>至此，整个Flink application部署的流程也跑通了！</p><p>也可以直接在K8s Dashboard 查看，等待jobmanager和taskmanager都为running。<br><img src="/img/article/20230609141229.png"></p><h1 id="Flink-任务资源配置"><a href="#Flink-任务资源配置" class="headerlink" title="Flink 任务资源配置"></a>Flink 任务资源配置</h1><blockquote><p><strong>接下来就是根据任务来合理配置不同的部署模式。合理利用资源。</strong></p></blockquote><p>高效利用资源，让K8s合理分配，可以从Flink官方文档中了解Flink的整个配置说明。<br>地址：<a href="https://nightlies.apache.org/flink/flink-docs-release-1.13/docs/deployment/config/#kubernetes">https://nightlies.apache.org/flink/flink-docs-release-1.13/docs/deployment/config/#kubernetes</a></p><p>从文档中，我们可以看到所有配置项，可以直接在Streamx上直接对Flink集群进行配置 写在：“Dynamic Option” （一行一个配置，首位添加<code>-D</code>） 中 比如：<br><img src="/img/article/20230908110200.png"></p><ul><li>配置了一个TaskManger中有三个slot</li><li>配置了任务重启策略为固定间隔重启</li><li>配置了任务重启次数为10次</li><li>配置了K8s限制jobmangerCPU资源为0.5</li><li>配置了K8s限制taskmangerCPU资源为1</li></ul><p>这样在Flink集群启动时，就会按照配置加载，从Flink UI中也可以看到集群的详细配置<br><img src="/img/article/20230908110833.png"></p><h1 id="Flink镜像时区修改"><a href="#Flink镜像时区修改" class="headerlink" title="Flink镜像时区修改"></a>Flink镜像时区修改</h1><p>用Flink的官方镜像，时区不是东八区，从日志打印也可以看出来慢了8个小时。所以我们需要构建自定义镜像，修改时区为东八区<br>首先创建一个Dockerfile</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></pre></td><td class="code"><pre><span class="line">FROM apache/flink:1.13.6-scala_2.11</span><br><span class="line">RUN <span class="built_in">ln</span> -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime</span><br><span class="line">RUN <span class="built_in">echo</span> <span class="string">&#x27;Asia/Shanghai&#x27;</span> &gt; /etc/timezone</span><br></pre></td></tr></table></figure><p>在Dockerfil同级目录，执行build命令(注意命令最后有一点)，打成自定义镜像。</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">docker build -t streamx/flink:1.13.6-scala_2.11 .</span><br></pre></td></tr></table></figure><p>再推送到私服</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">docker push streamx/flink:1.13.6-scala_2.11</span><br></pre></td></tr></table></figure><p>接着修改集群设置中的镜像配置”Flink Base Docker Image”为新的自定义镜像，再次启动即可。</p><h1 id="Streamx中使用UDF函数"><a href="#Streamx中使用UDF函数" class="headerlink" title="Streamx中使用UDF函数"></a>Streamx中使用UDF函数</h1><p>在Flink SQL 中，会需要使用到自定义的UDF函数，来做一些复杂的计算。<br>首先我们创建一个Maven工程，Pom.xml引入基础的包，和业务需要的包即可</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><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- Flink基础包 --&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.flink<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>flink-table-common<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;flink.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">scope</span>&gt;</span>provided<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line">   <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">               <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">               <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-shade-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">               <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.2.4<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">               <span class="tag">&lt;<span class="name">executions</span>&gt;</span></span><br><span class="line">                   <span class="tag">&lt;<span class="name">execution</span>&gt;</span></span><br><span class="line">                       <span class="tag">&lt;<span class="name">phase</span>&gt;</span>package<span class="tag">&lt;/<span class="name">phase</span>&gt;</span></span><br><span class="line">                       <span class="tag">&lt;<span class="name">goals</span>&gt;</span></span><br><span class="line">                           <span class="tag">&lt;<span class="name">goal</span>&gt;</span>shade<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></span><br><span class="line">                       <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></span><br><span class="line">                       <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                           <span class="tag">&lt;<span class="name">transformers</span>&gt;</span></span><br><span class="line">                               <span class="tag">&lt;<span class="name">transformer</span> <span class="attr">implementation</span>=<span class="string">&quot;org.apache.maven.plugins.shade.resource.ManifestResourceTransformer&quot;</span>&gt;</span></span><br><span class="line">                                   <span class="tag">&lt;<span class="name">mainClass</span>&gt;</span>cn.dollcode.TestCalc<span class="tag">&lt;/<span class="name">mainClass</span>&gt;</span></span><br><span class="line">                               <span class="tag">&lt;/<span class="name">transformer</span>&gt;</span></span><br><span class="line">                           <span class="tag">&lt;/<span class="name">transformers</span>&gt;</span></span><br><span class="line">                       <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">                   <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></span><br><span class="line">               <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">               <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">               <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-compiler-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">               <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                   <span class="tag">&lt;<span class="name">source</span>&gt;</span>8<span class="tag">&lt;/<span class="name">source</span>&gt;</span></span><br><span class="line">                   <span class="tag">&lt;<span class="name">target</span>&gt;</span>8<span class="tag">&lt;/<span class="name">target</span>&gt;</span></span><br><span class="line">               <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br></pre></td></tr></table></figure><p>然后创建自定义函数类，并继承Flink的ScalarFunction类，这里举例就简单实现拼接函数</p><figure class="highlight java"><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="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestCalc</span> <span class="keyword">extends</span> <span class="title class_">ScalarFunction</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">eval</span><span class="params">(String value)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Hello&quot;</span> + value;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>将Maven工程打成Jar包，在Streamx中创建Flink SQL任务，并在Dependency一栏 选择 Upload Jar。<br><img src="/img/article/20230908114815.png"></p><p>同时需要在SQL中添加 注册函数</p><figure class="highlight sql"><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="keyword">CREATE TABLE</span> datagen (</span><br><span class="line">   f_sequence <span class="type">INT</span>,</span><br><span class="line">   f_random <span class="type">INT</span>,</span><br><span class="line">   f_random_str STRING,</span><br><span class="line">   ts <span class="keyword">AS</span> <span class="built_in">localtimestamp</span>,</span><br><span class="line">   WATERMARK <span class="keyword">FOR</span> ts <span class="keyword">AS</span> ts</span><br><span class="line"> ) <span class="keyword">WITH</span> (</span><br><span class="line">   <span class="string">&#x27;connector&#x27;</span> <span class="operator">=</span> <span class="string">&#x27;datagen&#x27;</span>,</span><br><span class="line">   <span class="comment">-- optional options --</span></span><br><span class="line">   <span class="string">&#x27;rows-per-second&#x27;</span><span class="operator">=</span><span class="string">&#x27;5&#x27;</span>,</span><br><span class="line">   <span class="string">&#x27;fields.f_sequence.kind&#x27;</span><span class="operator">=</span><span class="string">&#x27;sequence&#x27;</span>,</span><br><span class="line">   <span class="string">&#x27;fields.f_sequence.start&#x27;</span><span class="operator">=</span><span class="string">&#x27;1&#x27;</span>,</span><br><span class="line">   <span class="string">&#x27;fields.f_sequence.end&#x27;</span><span class="operator">=</span><span class="string">&#x27;500&#x27;</span>,</span><br><span class="line">   <span class="string">&#x27;fields.f_random.min&#x27;</span><span class="operator">=</span><span class="string">&#x27;1&#x27;</span>,</span><br><span class="line">   <span class="string">&#x27;fields.f_random.max&#x27;</span><span class="operator">=</span><span class="string">&#x27;500&#x27;</span>,</span><br><span class="line">   <span class="string">&#x27;fields.f_random_str.length&#x27;</span><span class="operator">=</span><span class="string">&#x27;10&#x27;</span></span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> <span class="keyword">CREATE TABLE</span> print_table (</span><br><span class="line">   f_sequence <span class="type">INT</span>,</span><br><span class="line">   f_random <span class="type">INT</span>,</span><br><span class="line">   f_random_str STRING</span><br><span class="line">   ) <span class="keyword">WITH</span> (</span><br><span class="line">   <span class="string">&#x27;connector&#x27;</span> <span class="operator">=</span> <span class="string">&#x27;print&#x27;</span></span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> <span class="keyword">CREATE</span> <span class="keyword">FUNCTION</span> TestCalc <span class="keyword">as</span> <span class="string">&#x27;cn.dollcode.TestCalc&#x27;</span>; <span class="comment">-- 注册函数，前面是定义函数名，后面是指定函数路径</span></span><br><span class="line"> </span><br><span class="line"> <span class="keyword">INSERT INTO</span> print_table </span><br><span class="line">   <span class="keyword">select</span> </span><br><span class="line">f_sequence,</span><br><span class="line">f_random,</span><br><span class="line">TestCalc(f_random_str) <span class="comment">-- 使用函数</span></span><br><span class="line"><span class="keyword">from</span> datagen;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;前面文章中，成功搭建了K8s集群。这篇文章就开始来搭建组件了！&lt;/p&gt;
&lt;p&gt;实时即未来 Apache Flink被普遍认为是下一代大数据流计算引擎。官网地址：&lt;a href=&quot;https://flink.apache.org/&quot;&gt;https://flink.apache.</summary>
      
    
    
    
    <category term="Web技术" scheme="https://blog.dollcode.cn/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Flink" scheme="https://blog.dollcode.cn/tags/Flink/"/>
    
    <category term="K8s" scheme="https://blog.dollcode.cn/tags/K8s/"/>
    
  </entry>
  
  <entry>
    <title>k8s集群管理面板dashboard部署</title>
    <link href="https://blog.dollcode.cn/k8s-dashboard.html"/>
    <id>https://blog.dollcode.cn/k8s-dashboard.html</id>
    <published>2023-06-02T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<p>在上一篇文章中，已经完成了K8s集群的搭建，现在再加上一个可视化的webUI来进行管理和方便查看。<br>这里选择<strong>kubernetes&#x2F;dashboard</strong> 通过官方的配置可以一键部署。<br><img src="/img/article/20230602102753.png"></p><h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><p>访问下载页面： <a href="https://github.com/kubernetes/dashboard/releases">https://github.com/kubernetes/dashboard/releases</a><br>选择自己K8s集群的兼容版本，进行安装<br><img src="/img/article/20230602104458.png"></p><p>执行安装命令</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">kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml</span><br></pre></td></tr></table></figure><p>查看启动状态</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">kubectl get pods -n=kubernetes-dashboard -o wide</span><br></pre></td></tr></table></figure><p>都为Running状态就可以了</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">NAME                                         READY   STATUS    RESTARTS   AGE     IP            NODE       NOMINATED NODE   READINESS GATES</span><br><span class="line">dashboard-metrics-scraper-7c857855d9-r6wh7   1/1     Running   0          4m31s   10.98.90.18   k8snode1   &lt;none&gt;           &lt;none&gt;</span><br><span class="line">kubernetes-dashboard-658b66597c-6rrzs        1/1     Running   0          4m31s   10.98.90.17   k8snode1   &lt;none&gt;           &lt;none&gt;</span><br></pre></td></tr></table></figure><p>官方说明上的API访问方式 需要本地配置config,并开启<code>kubectl proxy</code>，比较麻烦<br><img src="/img/article/20230602105240.png"></p><p>我们可以直接修改kubernetes-dashboard service的Type属性<br>将里面的type: ClusterIP改为type: NodePort</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">kubectl edit service kubernetes-dashboard -n=kubernetes-dashboard</span><br></pre></td></tr></table></figure><p><img src="/img/article/20230602110141.png"></p><p><code>:wq</code> 保存退出即可</p><p>等待更新完成之后，查看端口</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">kubectl get service kubernetes-dashboard -n=kubernetes-dashboard</span><br></pre></td></tr></table></figure><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">NAME                   TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE</span><br><span class="line">kubernetes-dashboard   NodePort   10.99.117.158   &lt;none&gt;        443:32576/TCP   19s</span><br></pre></td></tr></table></figure><p>打开游览器 输入IP:32576，访问成功，但是会有https证书警告。</p><h1 id="重新生成证书"><a href="#重新生成证书" class="headerlink" title="重新生成证书"></a>重新生成证书</h1><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><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#Step 1: 新建目录：</span></span><br><span class="line"><span class="built_in">mkdir</span> key &amp;&amp; <span class="built_in">cd</span> key</span><br><span class="line"></span><br><span class="line"><span class="comment">#Step 2: 生成 SSL 证书</span></span><br><span class="line">openssl genrsa -out dashboard.key 2048</span><br><span class="line"></span><br><span class="line"><span class="comment">#Step 3: 我这里写的自己的 node1 节点，因为我是通过 nodeport 访问的</span></span><br><span class="line">openssl req -new -out dashboard.csr -key dashboard.key -subj <span class="string">&#x27;/CN=192.168.31.190&#x27;</span></span><br><span class="line">openssl x509 -req -<span class="keyword">in</span> dashboard.csr -signkey dashboard.key -out dashboard.crt</span><br><span class="line"></span><br><span class="line"><span class="comment">#Step 4: 删除原有的证书 secret</span></span><br><span class="line">kubectl delete secret kubernetes-dashboard-certs -n kubernetes-dashboard</span><br><span class="line"></span><br><span class="line"><span class="comment">#Step 5: 创建新的证书 secret</span></span><br><span class="line">kubectl create secret generic kubernetes-dashboard-certs --from-file=dashboard.key --from-file=dashboard.crt -n kubernetes-dashboard</span><br><span class="line"></span><br><span class="line"><span class="comment">#Step 6: 查看 pod</span></span><br><span class="line">kubectl get pod -n kubernetes-dashboard</span><br><span class="line"></span><br><span class="line"><span class="comment">#Step 7: 重启 pod</span></span><br><span class="line">kubectl delete pod kubernetes-dashboard-7b5bf5d559-gn4ls  -n kubernetes-dashboard</span><br></pre></td></tr></table></figure><h1 id="创建认证Token"><a href="#创建认证Token" class="headerlink" title="创建认证Token"></a>创建认证Token</h1><p><img src="/img/article/20230602140614.png"><br>创建用户配置</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></pre></td><td class="code"><pre><span class="line"><span class="string">cat</span> <span class="string">&gt;&gt;</span> <span class="string">admin-user.yaml</span> <span class="string">&lt;&lt;</span> <span class="string">EOF</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">ServiceAccount</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">admin-user</span></span><br><span class="line">  <span class="attr">namespace:</span> <span class="string">kubernetes-dashboard</span></span><br><span class="line"><span class="string">EOF</span></span><br></pre></td></tr></table></figure><p>创建角色绑定关系配置</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></pre></td><td class="code"><pre><span class="line"><span class="string">cat</span> <span class="string">&gt;&gt;</span> <span class="string">admin-user.yaml</span> <span class="string">&lt;&lt;</span> <span class="string">EOF</span></span><br><span class="line"><span class="attr">apiVersion:</span> <span class="string">rbac.authorization.k8s.io/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">ClusterRoleBinding</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">admin-user</span></span><br><span class="line"><span class="attr">roleRef:</span></span><br><span class="line">  <span class="attr">apiGroup:</span> <span class="string">rbac.authorization.k8s.io</span></span><br><span class="line">  <span class="attr">kind:</span> <span class="string">ClusterRole</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">cluster-admin</span></span><br><span class="line"><span class="attr">subjects:</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">kind:</span> <span class="string">ServiceAccount</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">admin-user</span></span><br><span class="line">  <span class="attr">namespace:</span> <span class="string">kubernetes-dashboard</span></span><br><span class="line"><span class="string">EOF</span></span><br></pre></td></tr></table></figure><p>然后依次执行</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">kubectl create -f admin-user.yaml</span><br><span class="line">kubectl create -f admin-user-role-binding.yaml</span><br></pre></td></tr></table></figure><h2 id="获取Token"><a href="#获取Token" class="headerlink" title="获取Token"></a>获取Token</h2><p>获取Token命令如下，执行之后会输出token。可以看到是JWT形式的</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">kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk <span class="string">&#x27;&#123;print $1&#125;&#x27;</span>)</span><br></pre></td></tr></table></figure><h1 id="token方式登录"><a href="#token方式登录" class="headerlink" title="token方式登录"></a>token方式登录</h1><p>将Token复制到控制台，登录即可。不过默认的过期时间是15分钟。太短了不太方便。可以在容器加入参数配置，指定过期时效（单位:秒）<br><code>- --token-ttl=864000</code> 我这里直接设置了10天（不过为了安全，不建议设置这么久）</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">kubectl edit deployment kubernetes-dashboard -n=kubernetes-dashboard</span><br></pre></td></tr></table></figure><p><img src="/img/article/20230602154128.png"></p><p><img src="/img/article/20230602155135.png"><br>至此整个部署就完成了！！！</p><p>参考资源</p><ul><li><a href="https://developer.aliyun.com/article/856527">https://developer.aliyun.com/article/856527</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在上一篇文章中，已经完成了K8s集群的搭建，现在再加上一个可视化的webUI来进行管理和方便查看。&lt;br&gt;这里选择&lt;strong&gt;kubernetes&amp;#x2F;dashboard&lt;/strong&gt; 通过官方的配置可以一键部署。&lt;br&gt;&lt;img src=&quot;/img/arti</summary>
      
    
    
    
    <category term="Web技术" scheme="https://blog.dollcode.cn/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="K8s" scheme="https://blog.dollcode.cn/tags/K8s/"/>
    
  </entry>
  
  <entry>
    <title>使用kubeadm方式搭建K8s集群</title>
    <link href="https://blog.dollcode.cn/k8scluster-kubeadm.html"/>
    <id>https://blog.dollcode.cn/k8scluster-kubeadm.html</id>
    <published>2023-06-01T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<p>从零开始搭建K8s集群，一般网上的教程都会让大家提前准备三台机器，分别进行环境的安装。其实我们可以通过<code>VMware</code>虚拟机的<strong>克隆机制</strong>直接复制得到虚拟机。这样就只需要处理一台的环境即可。</p><h1 id="k8s环境安装并配置"><a href="#k8s环境安装并配置" class="headerlink" title="k8s环境安装并配置"></a>k8s环境安装并配置</h1><p><strong>VMware</strong>安装centos7之后， 用这台虚拟机用作master，安装并配置环境之后，再直接克隆出两个node即可</p><table><thead><tr><th>角色</th><th>IP</th><th>备注</th></tr></thead><tbody><tr><td>k8smaster</td><td>192.168.31.190</td><td>安装环境只做一次即可</td></tr><tr><td>k8snode1</td><td>192.168.31.191</td><td>克隆虚拟机，并改MAC地址、改hostname</td></tr><tr><td>k8snode2</td><td>192.168.31.192</td><td>克隆虚拟机，并改MAC地址、改hostname</td></tr></tbody></table><h2 id="环境配置"><a href="#环境配置" class="headerlink" title="环境配置"></a>环境配置</h2><h3 id="防火墙、selinux、swap"><a href="#防火墙、selinux、swap" class="headerlink" title="防火墙、selinux、swap"></a>防火墙、selinux、swap</h3><p>部署k8s，需要关闭防火墙、禁用selinux、swap</p><ul><li>关闭防火墙的原因（nftables后端兼容性问题，产生重复的防火墙规则）</li><li>禁用selinux的原因（关闭selinux以允许容器访问宿主机的文件系统）</li><li>禁用swap的原因（swap将部分内存数据存放到磁盘中，这样会使性能下降）</li></ul><p>依次执行下列命令</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><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="comment"># 关闭防火墙</span></span><br><span class="line">systemctl stop firewalld</span><br><span class="line"><span class="comment"># 禁用开机自启</span></span><br><span class="line">systemctl <span class="built_in">disable</span> firewalld</span><br><span class="line"></span><br><span class="line"><span class="comment"># 关闭selinux</span></span><br><span class="line">sed -i <span class="string">&#x27;s/enforcing/disabled/&#x27;</span> /etc/selinux/config</span><br><span class="line"></span><br><span class="line"><span class="comment"># 关闭swap</span></span><br><span class="line">sed -ri <span class="string">&#x27;s/.*swap.*/#&amp;/&#x27;</span> /etc/fstab</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置主机名称为k8smaster</span></span><br><span class="line">hostnamectl set-hostname k8smaster</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加hosts</span></span><br><span class="line"><span class="built_in">cat</span> &gt;&gt; /etc/hosts &lt;&lt; <span class="string">EOF</span></span><br><span class="line"><span class="string">192.168.31.190 k8smaster</span></span><br><span class="line"><span class="string">192.168.31.191 k8snode1</span></span><br><span class="line"><span class="string">192.168.31.192 k8snode2</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 将桥接的IPv4流量传递到iptables的链</span></span><br><span class="line"><span class="built_in">cat</span> &gt; /etc/sysctl.d/k8s.conf &lt;&lt; <span class="string">EOF</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">net.bridge.bridge-nf-call-iptables = 1</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 生效</span></span><br><span class="line">sysctl --system  </span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装ntpdate</span></span><br><span class="line">yum install ntpdate -y</span><br><span class="line"><span class="comment"># 执行时间同步</span></span><br><span class="line">ntpdate time.windows.com</span><br><span class="line"></span><br><span class="line"><span class="comment"># 全部执行完成之后，重启</span></span><br><span class="line">reboot</span><br></pre></td></tr></table></figure><h2 id="安装Docker"><a href="#安装Docker" class="headerlink" title="安装Docker"></a>安装Docker</h2><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><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"><span class="comment"># 添加Docker阿里镜像源</span></span><br><span class="line">wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看docker版本列表信息</span></span><br><span class="line">yum list docker-ce --showduplicates|grep <span class="string">&quot;^doc&quot;</span>|<span class="built_in">sort</span> -r</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装指定版本Docker</span></span><br><span class="line">yum -y install docker-ce-19.03.15-3.el7 docker-ce-cli-19.03.15-3.el7 containerd.io</span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置自己的阿里云镜像加速，同时配置Docker的cgroupdrvier和kubelet的cgroupdrver一致</span></span><br><span class="line"><span class="built_in">cat</span> &gt;&gt; /etc/docker/daemon.json &lt;&lt; <span class="string">EOF</span></span><br><span class="line"><span class="string">&#123;</span></span><br><span class="line"><span class="string">  &quot;registry-mirrors&quot;: [&quot;https://xxxx.mirror.aliyuncs.com&quot;], &quot;exec-opts&quot;: [&quot;native.cgroupdriver=systemd&quot;]</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置自启</span></span><br><span class="line">systemctl <span class="built_in">enable</span> docker</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动docker</span></span><br><span class="line">systemctl start docker</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看docker安装版本情况</span></span><br><span class="line">docker version</span><br></pre></td></tr></table></figure><p><strong>显示如下输出，docker安装就完成了</strong></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">Client: Docker Engine - Community</span><br><span class="line"> Version:           24.0.2</span><br><span class="line"> API version:       1.40 (downgraded from 1.43)</span><br><span class="line"> Go version:        go1.20.4</span><br><span class="line"> Git commit:        cb74dfc</span><br><span class="line"> Built:             Thu May 25 21:55:21 2023</span><br><span class="line"> OS/Arch:           linux/amd64</span><br><span class="line"> Context:           default</span><br><span class="line"></span><br><span class="line">Server: Docker Engine - Community</span><br><span class="line"> Engine:</span><br><span class="line">  Version:          19.03.15</span><br><span class="line">  API version:      1.40 (minimum version 1.12)</span><br><span class="line">  Go version:       go1.13.15</span><br><span class="line">  Git commit:       99e3ed8919</span><br><span class="line">  Built:            Sat Jan 30 03:16:33 2021</span><br><span class="line">  OS/Arch:          linux/amd64</span><br><span class="line">  Experimental:     false</span><br><span class="line"> containerd:</span><br><span class="line">  Version:          1.6.21</span><br><span class="line">  GitCommit:        3dce8eb055cbb6872793272b4f20ed16117344f8</span><br><span class="line"> runc:</span><br><span class="line">  Version:          1.1.7</span><br><span class="line">  GitCommit:        v1.1.7-0-g860f061</span><br><span class="line"> docker-init:</span><br><span class="line">  Version:          0.18.0</span><br><span class="line">  GitCommit:        fec3683</span><br></pre></td></tr></table></figure><h2 id="配置K8s环境"><a href="#配置K8s环境" class="headerlink" title="配置K8s环境"></a>配置K8s环境</h2><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><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"><span class="comment"># 添加阿里云Kubernetes yum镜像源</span></span><br><span class="line"><span class="built_in">cat</span> &gt; /etc/yum.repos.d/kubernetes.repo &lt;&lt; <span class="string">EOF</span></span><br><span class="line"><span class="string">[kubernetes]</span></span><br><span class="line"><span class="string">name=Kubernetes</span></span><br><span class="line"><span class="string">baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64</span></span><br><span class="line"><span class="string">enabled=1</span></span><br><span class="line"><span class="string">gpgcheck=0</span></span><br><span class="line"><span class="string">repo_gpgcheck=0</span></span><br><span class="line"><span class="string">gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装kubelet、kubeadm、kubectl(注意版本要和k8s的版本一致)</span></span><br><span class="line">yum -y install kubelet-1.22.0 kubeadm-1.22.0 kubectl-1.22.0</span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置kubelet的cgroupdrver与Docker一致</span></span><br><span class="line">vim /etc/sysconfig/kubelet</span><br><span class="line"><span class="comment"># 在属性后增加参数如下，然后:wq保存</span></span><br><span class="line">KUBELET_EXTRA_ARGS=<span class="string">&quot;--cgroup-driver=systemd&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 重载配置文件</span></span><br><span class="line">systemctl daemon-reload</span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置自启</span></span><br><span class="line">systemctl <span class="built_in">enable</span> kubelet</span><br></pre></td></tr></table></figure><h2 id="可能会出现的问题"><a href="#可能会出现的问题" class="headerlink" title="可能会出现的问题"></a>可能会出现的问题</h2><blockquote><p>kubeadm init执行的时候出现：unexpected kernel config: CONFIG_CGROUP_PIDS。这个问题需要升级Linux内核</p></blockquote><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><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="comment"># 查看当前默认启动内核</span></span><br><span class="line">grub2-editenv list</span><br><span class="line"></span><br><span class="line"><span class="comment"># 升级内核命令，依次执行</span></span><br><span class="line">rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org</span><br><span class="line">rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm</span><br><span class="line">yum --disablerepo=<span class="string">&quot;*&quot;</span> --enablerepo=<span class="string">&quot;elrepo-kernel&quot;</span> list available</span><br><span class="line">yum --enablerepo=elrepo-kernel install kernel-ml</span><br><span class="line"><span class="built_in">cp</span> /etc/default/grub  /etc/default/grub_bak</span><br><span class="line">grub2-mkconfig -o /boot/grub2/grub.cfg</span><br><span class="line">systemctl <span class="built_in">enable</span> docker.service</span><br><span class="line">reboot</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重启完成之后，查看已安装内核列表</span></span><br><span class="line"><span class="built_in">cat</span> /boot/grub2/grub.cfg | grep -v rescue | grep ^menuentry</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置默认启动内核</span></span><br><span class="line">grub2-set-default <span class="string">&#x27;CentOS Linux (6.3.5-1.el7.elrepo.x86_64) 7 (Core)&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 再次重启</span></span><br><span class="line">reboot</span><br><span class="line"></span><br></pre></td></tr></table></figure><h1 id="克隆虚拟机机"><a href="#克隆虚拟机机" class="headerlink" title="克隆虚拟机机"></a>克隆虚拟机机</h1><p>首先关闭虚拟机 - 设置 - 克隆（克隆之后需要修改两处：1.MAC地址 2.HostName）<br><img src="/img/article/20230601135626.png"><br><img src="/img/article/20230601135745.png"><br>选择完整克隆<br><img src="/img/article/20230601135806.png"><br>命名为k8snode1</p><p>然后记得 <strong>在虚拟机的 网络适配器高级设置 中修改MAC地址</strong><br>打开虚拟机之后，修改hostname</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></pre></td><td class="code"><pre><span class="line">hostnamectl set-hostname k8snode1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 然后重启</span></span><br><span class="line">reboot</span><br></pre></td></tr></table></figure><p>第三台也是一样的操作。</p><h1 id="master安装k8s"><a href="#master安装k8s" class="headerlink" title="master安装k8s"></a>master安装k8s</h1><p>用kubeadm init命令来安装，kubeadm的版本和kubernetes-version需要一致，如下都为1.22。</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">kubeadm init --apiserver-advertise-address=192.168.31.190 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.22.10 --service-cidr=10.96.0.0/12  --pod-network-cidr=10.244.0.0/16</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></pre></td><td class="code"><pre><span class="line">Your Kubernetes control-plane has initialized successfully!</span><br><span class="line">To start using your cluster, you need to run the following as a regular user:</span><br><span class="line">mkdir -p $HOME/.kube</span><br><span class="line">sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config</span><br><span class="line">sudo chown $(id -u):$(id -g) $HOME/.kube/config</span><br><span class="line">You should now deploy a pod network to the cluster .</span><br><span class="line">Run &quot;kubectl apply -f [podnetwork] .yamLu with one of the options listed at:</span><br><span class="line">https: / /kube rnetes. io/docs /concepts/cluster- administration/ addons I</span><br><span class="line">Then you can join any number of worker nodes by running the following on each as root:</span><br><span class="line">kubeadm join 192.168.31.190:6443 --token 2luxh6.uhhj74j5oj6xfdtv \</span><br><span class="line">--discovery-token-ca-cert-hash sha256:4f558182265bee13182b2480ba7180a867a5f3b93ab18c82c4a0d542a4c2poi1</span><br></pre></td></tr></table></figure><h2 id="配置kubectl工具"><a href="#配置kubectl工具" class="headerlink" title="配置kubectl工具"></a>配置kubectl工具</h2><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></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p <span class="variable">$HOME</span>/.kube</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">cp</span> -i /etc/kubernetes/admin.conf <span class="variable">$HOME</span>/.kube/config</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">chown</span> $(<span class="built_in">id</span> -u):$(<span class="built_in">id</span> -g) <span class="variable">$HOME</span>/.kube/config</span><br></pre></td></tr></table></figure><p>查看节点状态</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">kubectl get nodes</span><br></pre></td></tr></table></figure><p>能够看到，目前有一个master节点已经运行了，但是还处于未准备状态<br>下面我们还需要在Node节点执行其它的命令，将node1和node2加入到我们的master节点上</p><h2 id="node1加入集群"><a href="#node1加入集群" class="headerlink" title="node1加入集群"></a>node1加入集群</h2><p>复制 上面 master安装成功之后的输出的<code>kubeadm join</code>命令，默认的token有效期为24小时，当过期之后，该token就不能用了，这时可以使用如下的命令创建token</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"><span class="comment"># 生成一个永不过期的token</span></span><br><span class="line">kubeadm token create --ttl 0</span><br></pre></td></tr></table></figure><p>将该token替换上面的join命令中的token</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">kubeadm <span class="built_in">join</span> 192.168.31.190:6443 --token 7auxee.exh5uov0uorusyl \</span><br><span class="line">--discovery-token-ca-cert-hash sha256:4f558182265bee13182b2480ba7180a867a5f3b93ab18c82c4a0d542a4c2poi1</span><br></pre></td></tr></table></figure><h1 id="Master部署CNI网络插件"><a href="#Master部署CNI网络插件" class="headerlink" title="Master部署CNI网络插件"></a>Master部署CNI网络插件</h1><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">kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml</span><br></pre></td></tr></table></figure><p>如果网络访问不了，也可以先在自己电脑上下载完成之后，再传输到虚拟机上，执行<code>kubectl apply -f kube-flannel.yml</code></p><p>然后等待pod全部安装，进入running状态</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">kubectl get pods -n kube-system</span><br></pre></td></tr></table></figure><p><img src="/img/article/20230601143227.png"></p><p>这个时候，我们再次查看节点状态就都是Ready状态了<br><img src="/img/article/20230601143549.png"></p><h2 id="如果node节点还不是Ready状态"><a href="#如果node节点还不是Ready状态" class="headerlink" title="如果node节点还不是Ready状态"></a>如果node节点还不是Ready状态</h2><p>需要先删除节点，再重置<br>在master机器上删除node1</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">kubectl delete node k8snode1</span><br></pre></td></tr></table></figure><p>然后在node1机器上执行重置</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">kubeadm reset</span><br></pre></td></tr></table></figure><p>再次join</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">kubeadm <span class="built_in">join</span> 192.168.31.190:6443 --token 7auxee.exh5uov0uorusyl \</span><br><span class="line">--discovery-token-ca-cert-hash sha256:4f558182265bee13182b2480ba7180a867a5f3b93ab18c82c4a0d542a4c2poi1</span><br></pre></td></tr></table></figure><p>回到master机器上，再次查看node状态</p><h1 id="集群健康检查"><a href="#集群健康检查" class="headerlink" title="集群健康检查"></a>集群健康检查</h1><p>在master机器上执行健康检查状态</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">kubectl get cs</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></pre></td><td class="code"><pre><span class="line">NAME                 STATUS    MESSAGE                         ERROR</span><br><span class="line">scheduler            Healthy   ok                              </span><br><span class="line">controller-manager   Healthy   ok                              </span><br><span class="line">etcd-0               Healthy   &#123;&quot;health&quot;:&quot;true&quot;,&quot;reason&quot;:&quot;&quot;&#125;</span><br></pre></td></tr></table></figure><p>如果出现状态出现 Unhealthy，就需要删掉配置中<code>- --port=0</code> 这一行<br>vim &#x2F;etc&#x2F;kubernetes&#x2F;manifests&#x2F;kube-controller-manager.yaml<br>vim &#x2F;etc&#x2F;kubernetes&#x2F;manifests&#x2F;kube-scheduler.yaml<br><img src="/img/article/20230601152813.png"></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"><span class="comment"># 重启kubelet服务</span></span><br><span class="line">systemctl restart kubelet</span><br></pre></td></tr></table></figure><p>至此，整个搭建过程就完成了。</p><p>参考来源：</p><ul><li><a href="http://victorfengming.gitee.io/kubernetes/">http://victorfengming.gitee.io/kubernetes/</a></li><li><a href="https://www.cnblogs.com/xuweiweiwoaini/p/13884112.html">https://www.cnblogs.com/xuweiweiwoaini/p/13884112.html</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;从零开始搭建K8s集群，一般网上的教程都会让大家提前准备三台机器，分别进行环境的安装。其实我们可以通过&lt;code&gt;VMware&lt;/code&gt;虚拟机的&lt;strong&gt;克隆机制&lt;/strong&gt;直接复制得到虚拟机。这样就只需要处理一台的环境即可。&lt;/p&gt;
&lt;h1 id=&quot;k8s</summary>
      
    
    
    
    <category term="Web技术" scheme="https://blog.dollcode.cn/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="CentOS" scheme="https://blog.dollcode.cn/tags/CentOS/"/>
    
    <category term="Docker" scheme="https://blog.dollcode.cn/tags/Docker/"/>
    
    <category term="K8s" scheme="https://blog.dollcode.cn/tags/K8s/"/>
    
  </entry>
  
  <entry>
    <title>群晖7.0安装Transmission4.0挂PT(docker版)</title>
    <link href="https://blog.dollcode.cn/nas-transmission4.html"/>
    <id>https://blog.dollcode.cn/nas-transmission4.html</id>
    <published>2023-03-24T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<p>最近把NAS升级了一下，关于群晖7.0和docker安装Transmission4.0，这种最新版本的安装教程较少，同时Transmission4.0的配置和3.0是有很大区别的，汉化目录、WEB授权方式和路径都变了。所以在这里记录一下。</p><h2 id="群晖套件安装Docker"><a href="#群晖套件安装Docker" class="headerlink" title="群晖套件安装Docker"></a>群晖套件安装Docker</h2><p>这一步很简单，在套件中心，搜索Docker，安装即可</p><h2 id="下载Transmission镜像"><a href="#下载Transmission镜像" class="headerlink" title="下载Transmission镜像"></a>下载Transmission镜像</h2><p>选择第一个镜像下载，选择latest版本。从右上角可以点击跳转详细页面，能看到最新版就是4.0.2<br><img src="/img/article/20230324104435.png"><br><img src="/img/article/20230324104654.png"></p><h2 id="配置容器参数"><a href="#配置容器参数" class="headerlink" title="配置容器参数"></a>配置容器参数</h2><p>首先在docker目录下创建transmission文件夹。同时给予权限everyone<br><img src="/img/article/20230324114254.png"><br>然后在子目录下再创建三个目录 <code>downloads</code>，<code>config</code>，<code>watch</code> 分别挂载到容器的对应目录<br><img src="/img/article/20230324113326.png"></p><ul><li>&#x2F;downloads  ：下载目录</li><li>&#x2F;config     ：配置目录</li><li>&#x2F;watch      ：种子目录<br><img src="/img/article/20230324113650.png"></li></ul><h3 id="环境变量（重点）"><a href="#环境变量（重点）" class="headerlink" title="环境变量（重点）"></a>环境变量（重点）</h3><ul><li>TRANSMISSION_WEB_HOME ：自定义web页面目录</li><li>USER                  ：web页面的登录用户名</li><li>PASS                  ：web页面的登录密码<br><img src="/img/article/20230324144721.png"></li></ul><h3 id="端口映射"><a href="#端口映射" class="headerlink" title="端口映射"></a>端口映射</h3><p><img src="/img/article/20230324113720.png"></p><h3 id="汉化web页面"><a href="#汉化web页面" class="headerlink" title="汉化web页面"></a>汉化web页面</h3><p>transmission UI 汉化 GitHub项目地址：<a href="https://github.com/ronggang/transmission-web-control">https://github.com/ronggang/transmission-web-control</a><br>下载页面地址：<a href="https://github.com/ronggang/transmission-web-control/releases">https://github.com/ronggang/transmission-web-control/releases</a><br>下载ZIP包，解压得到src目录下的文件。<br><img src="/img/article/20230324115642.png"></p><p>然后在<code>config</code>目录下创建一个<code>web-control</code>目录。将刚刚解压出的整个放到目录下即可<br><img src="/img/article/20230324115859.png"></p><h2 id="启动容器"><a href="#启动容器" class="headerlink" title="启动容器"></a>启动容器</h2><p>启动容器之后，在游览器打开 IP:9091 端口进入web页面，输入 配置的用户名和密码即可。</p><p>可以看到系统信息4.0.2准确无误，功能也正常。<br><img src="/img/article/20230324150759.png"></p><p>大功告成！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;最近把NAS升级了一下，关于群晖7.0和docker安装Transmission4.0，这种最新版本的安装教程较少，同时Transmission4.0的配置和3.0是有很大区别的，汉化目录、WEB授权方式和路径都变了。所以在这里记录一下。&lt;/p&gt;
&lt;h2 id=&quot;群晖套件安</summary>
      
    
    
    
    <category term="服务器" scheme="https://blog.dollcode.cn/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
    
  </entry>
  
  <entry>
    <title>qbittorrent内网穿透解决端口阻塞</title>
    <link href="https://blog.dollcode.cn/qbittorrent-nat.html"/>
    <id>https://blog.dollcode.cn/qbittorrent-nat.html</id>
    <published>2022-12-01T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前提场景"><a href="#前提场景" class="headerlink" title="前提场景"></a>前提场景</h2><p>在qbittorrent没有公网IP，并且也开不了路由器端口转发的情况下，<strong>通过一台公网服务器中转</strong>，进行Socket5代理和内网穿透，解决qbittorrent端口阻塞问题。<br>主要用到以下软件：</p><ul><li><a href="https://github.com/fatedier/frp/releases">Frp内网穿透</a></li><li><a href="https://github.com/ginuerzh/gost/releases">gost代理</a></li></ul><h2 id="公网机器配置"><a href="#公网机器配置" class="headerlink" title="公网机器配置"></a>公网机器配置</h2><blockquote><p>公网机器 用来让内网中的qbittorrent客户端机器获取公网IP，同时转发客户端的端口流量。</p></blockquote><h3 id="启动gost"><a href="#启动gost" class="headerlink" title="启动gost"></a>启动gost</h3><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></pre></td><td class="code"><pre><span class="line">./gost -L=qbadmin:123456@blog.dollcode.cn:8081</span><br><span class="line"></span><br><span class="line">//执行之后会输出如下日志就是正常成功了</span><br><span class="line">2022/12/01 03:11:45 route.go:694: auto://blog.dollcode.cn:8081 on xxx.xxx.xxx.xxx:8081</span><br></pre></td></tr></table></figure><blockquote><p>配置说明：</p><ul><li>代表开启一个Socket5代理</li><li>用户名是：qbadmin；密码是：123456</li><li>IP是：blog.dollcode.cn(可以用域名也可以用IP)</li><li>端口是：8081</li></ul></blockquote><h3 id="启动frps"><a href="#启动frps" class="headerlink" title="启动frps"></a>启动frps</h3><p>frp有两个包：frps是服务器端；frpc是客户端。这里我们配置frps的配置</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></pre></td><td class="code"><pre><span class="line">[common]</span><br><span class="line"># 允许任意IP</span><br><span class="line">bind_addr = 0.0.0.0</span><br><span class="line"># udp端口</span><br><span class="line">bind_udp_port = 8080</span><br><span class="line"># tcp端口</span><br><span class="line">bind_port = 8080</span><br><span class="line"># 安全连接</span><br><span class="line">tls_only = true</span><br><span class="line"># 连接密钥</span><br><span class="line">token = dollcode</span><br><span class="line"># 日志文件路径</span><br><span class="line">log_file = ./frps.log</span><br><span class="line"># 日志级别</span><br><span class="line">log_level = info</span><br><span class="line"># 日志文件保存天数</span><br><span class="line">log_max_days = 3</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">// 执行启动命令</span><br><span class="line">./frps -c frps.conf</span><br><span class="line"></span><br><span class="line">// 查看启动日志，输出如下就是正常成功了</span><br><span class="line">2022/12/01 03:07:04 [I] [service.go:152] frps tcp listen on 0.0.0.0:8080</span><br><span class="line">2022/12/01 03:07:04 [I] [service.go:233] nat hole udp service listen on 0.0.0.0:8080</span><br><span class="line">2022/12/01 03:07:04 [I] [root.go:205] start frps success</span><br></pre></td></tr></table></figure><blockquote><p>上面指定的8080端口和8081端口，需要在服务器的防火墙中放开该端口</p></blockquote><h2 id="qbittorrent客户端机器配置"><a href="#qbittorrent客户端机器配置" class="headerlink" title="qbittorrent客户端机器配置"></a>qbittorrent客户端机器配置</h2><blockquote><p>内网客户端 用来qbittorrent下载</p></blockquote><h3 id="启动frpc"><a href="#启动frpc" class="headerlink" title="启动frpc"></a>启动frpc</h3><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></pre></td><td class="code"><pre><span class="line">[common]</span><br><span class="line"># 公网服务器的IP或域名</span><br><span class="line">server_addr = blog.dollcode.cn</span><br><span class="line"># 公网机器隧道端口</span><br><span class="line">server_port = 8080 </span><br><span class="line">tls_enable = true</span><br><span class="line">token = dollcode</span><br><span class="line"></span><br><span class="line"># 58736这个端口就是qbittorrent的连接端口</span><br><span class="line">[tcppt]</span><br><span class="line">type = tcp</span><br><span class="line">local_ip = 127.0.0.1</span><br><span class="line">local_port = 58736</span><br><span class="line">remote_port = 58736</span><br><span class="line"></span><br><span class="line">[udppt]</span><br><span class="line">type = udp</span><br><span class="line">local_ip = 127.0.0.1</span><br><span class="line">local_port = 58736</span><br><span class="line">remote_port = 58736</span><br></pre></td></tr></table></figure><p><img src="/img/article/20221201112108.png"></p><p>启动之后可以看到连接成功的日志<br><img src="/img/article/20221201111614.png"></p><h3 id="配置qbittorrent代理"><a href="#配置qbittorrent代理" class="headerlink" title="配置qbittorrent代理"></a>配置qbittorrent代理</h3><p>填入服务器gost设置的配置即可<br><img src="/img/article/20221201113249.png"></p><p>退出软件重新进入，就可以看到绿灯亮了<br><img src="/img/article/20221201113536.png"></p><p>至此，整个内网穿透和Socket5代理就全部完成了。可以开始愉快的下载啦！！！</p><h3 id="超时问题解决"><a href="#超时问题解决" class="headerlink" title="超时问题解决"></a>超时问题解决</h3><p><img src="/img/article/20221201112138.png"><br><strong>如果qbittorrent日志中出现连接超时，一般就是服务器防火墙端口没开，或者账号密码输错了，记得检查一下哦！</strong></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;前提场景&quot;&gt;&lt;a href=&quot;#前提场景&quot; class=&quot;headerlink&quot; title=&quot;前提场景&quot;&gt;&lt;/a&gt;前提场景&lt;/h2&gt;&lt;p&gt;在qbittorrent没有公网IP，并且也开不了路由器端口转发的情况下，&lt;strong&gt;通过一台公网服务器中转&lt;/stro</summary>
      
    
    
    
    <category term="服务器" scheme="https://blog.dollcode.cn/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
    
    <category term="Linux" scheme="https://blog.dollcode.cn/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>linux 软连接link的使用</title>
    <link href="https://blog.dollcode.cn/linux-lnlink.html"/>
    <id>https://blog.dollcode.cn/linux-lnlink.html</id>
    <published>2022-11-14T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<p>当我们需要在不同的目录，用到相同的文件场景中：我们不需要在每一个需要的目录下都放一个相同的文件，我们只要在其它的目录下用<strong>ln命令链接（link）</strong>就可以，不必重复的占用磁盘空间。<br>软连接是linux中一个常用命令，它的功能是为某一个文件在另外一个位置建立一个同不的链接。</p><h2 id="创建软链"><a href="#创建软链" class="headerlink" title="创建软链"></a>创建软链</h2><blockquote><p>命令：ln -s [源文件] [目标文件]</p></blockquote><p>比如：将存放在<code>/home/books</code>目录下的书籍，软链到<code>/opt/shu</code>目录，实现在<code>/opt/shu</code>下也能使用查看书籍，也可以创建多个软链。如下：shu、shu1、shu2三个软链。<br><img src="https://s2.loli.net/2022/11/14/KEmWDhp4b9wuZP1.png"></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><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">root@Blog:/home/books# <span class="built_in">ls</span></span><br><span class="line">三国.txt  水浒传.txt</span><br><span class="line">root@Blog:/home/books# <span class="built_in">ln</span> -s /home/books /opt/shu</span><br><span class="line">root@Blog:/home/books# <span class="built_in">cd</span> /opt/shu/</span><br><span class="line">root@Blog:/opt/shu# <span class="built_in">ls</span></span><br><span class="line">三国.txt  水浒传.txt</span><br><span class="line">root@Blog:/opt/shu# <span class="built_in">ln</span> -s /home/books /opt/shu1</span><br><span class="line">root@Blog:/opt/shu# <span class="built_in">ln</span> -s /home/books /opt/shu2</span><br><span class="line">root@Blog:/opt/shu# <span class="built_in">cd</span> /opt/shu1</span><br><span class="line">root@Blog:/opt/shu1# <span class="built_in">ls</span></span><br><span class="line">三国.txt  水浒传.txt</span><br><span class="line">root@Blog:/opt/shu1# <span class="built_in">cd</span> /opt/shu2</span><br><span class="line">root@Blog:/opt/shu2# <span class="built_in">ls</span></span><br><span class="line">三国.txt  水浒传.txt</span><br><span class="line">root@Blog:/opt/shu2#</span><br></pre></td></tr></table></figure><h2 id="删除软链"><a href="#删除软链" class="headerlink" title="删除软链"></a>删除软链</h2><blockquote><p>删除软链接与删除普通的文件是一样的，删除都是使用rm来进行操作。</p></blockquote><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">// 删除 /opt/shu2</span><br><span class="line"><span class="built_in">rm</span> -rf /opt/shu2</span><br></pre></td></tr></table></figure><p><img src="https://s2.loli.net/2022/11/14/KgdfvJwQI7lRWtX.png"></p><h2 id="修改软链"><a href="#修改软链" class="headerlink" title="修改软链"></a>修改软链</h2><blockquote><p>命令：ln –snf [新的源文件或目录] [目标文件或目录]</p></blockquote><p>修改&#x2F;opt&#x2F;shu1，指向别的新目录。比如：原来是books目录 现在改为music</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"><span class="built_in">ln</span> -s /home/books /opt/shu1 //原来的软链指向</span><br><span class="line"><span class="built_in">ln</span> -snf /home/music /opt/shu1 //修改后的指向</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;当我们需要在不同的目录，用到相同的文件场景中：我们不需要在每一个需要的目录下都放一个相同的文件，我们只要在其它的目录下用&lt;strong&gt;ln命令链接（link）&lt;/strong&gt;就可以，不必重复的占用磁盘空间。&lt;br&gt;软连接是linux中一个常用命令，它的功能是为某一个文件</summary>
      
    
    
    
    <category term="服务器" scheme="https://blog.dollcode.cn/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
    
    <category term="Linux" scheme="https://blog.dollcode.cn/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>记一次FlinkSQL中Could not forward element to next operator异常</title>
    <link href="https://blog.dollcode.cn/flink-not-forward.html"/>
    <id>https://blog.dollcode.cn/flink-not-forward.html</id>
    <published>2022-11-11T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<p>在Flink SQL 开发过程中，遇到这样一个错误:Caused by: org.apache.flink.streaming.runtime.tasks.ExceptionInChainedOperatorException: Could not forward element to next operator</p><h2 id="错误日志"><a href="#错误日志" class="headerlink" title="错误日志"></a>错误日志</h2><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></pre></td><td class="code"><pre><span class="line">Caused by: org.apache.flink.streaming.runtime.tasks.ExceptionInChainedOperatorException: Could not forward element to next operator</span><br><span class="line">at org.apache.flink.streaming.runtime.tasks.ChainingOutput.pushToOperator(ChainingOutput.java:114) ~[flink-dist_2.11-1.13-vvr-4.0.13-1-SNAPSHOT.jar:1.13-vvr-4.0.13-1-SNAPSHOT]</span><br><span class="line">at org.apache.flink.streaming.runtime.tasks.ChainingOutput.collect(ChainingOutput.java:93) ~[flink-dist_2.11-1.13-vvr-4.0.13-1-SNAPSHOT.jar:1.13-vvr-4.0.13-1-SNAPSHOT]</span><br><span class="line">at org.apache.flink.streaming.runtime.tasks.ChainingOutput.collect(ChainingOutput.java:39) ~[flink-dist_2.11-1.13-vvr-4.0.13-1-SNAPSHOT.jar:1.13-vvr-4.0.13-1-SNAPSHOT]</span><br><span class="line">at org.apache.flink.streaming.api.operators.CountingOutput.collect(CountingOutput.java:50) ~[flink-dist_2.11-1.13-vvr-4.0.13-1-SNAPSHOT.jar:1.13-vvr-4.0.13-1-SNAPSHOT]</span><br><span class="line">at org.apache.flink.streaming.api.operators.CountingOutput.collect(CountingOutput.java:28) ~[flink-dist_2.11-1.13-vvr-4.0.13-1-SNAPSHOT.jar:1.13-vvr-4.0.13-1-SNAPSHOT]</span><br><span class="line">at StreamExecCalc$1653.processElement(Unknown Source) ~[?:?]</span><br></pre></td></tr></table></figure><h2 id="问题排查"><a href="#问题排查" class="headerlink" title="问题排查"></a>问题排查</h2><p>从异常描述来看是：无法将元素转发给下一个算子。</p><p>根据含义可以初步定位问题在数据源端，检查源表SQL字段类型、大概率是<strong>字段类型不对</strong>或者有<strong>NULL数据</strong>导致的。</p><ul><li>（比如：<strong>数据源主键为INT，FlinkSQL中定义成了VARCHAR</strong>，就会报这个错）</li><li>（比如：F<strong>linkSQL中定义了字段不能为NULL，但其实数据源端有NULL数据</strong>，也会报这个错）</li></ul><h2 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h2><ol><li>首先检查SQL中是否写错了数据源端的字段类型，保证两端的字段数据类型一致。</li><li>再对SQL中定义了NOT NULL的字段，在消费时需要判断NULL并赋个默认值。</li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;在Flink SQL 开发过程中，遇到这样一个错误:Caused by: org.apache.flink.streaming.runtime.tasks.ExceptionInChainedOperatorException: Could not forward elem</summary>
      
    
    
    
    <category term="数据库" scheme="https://blog.dollcode.cn/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
    <category term="Flink" scheme="https://blog.dollcode.cn/tags/Flink/"/>
    
  </entry>
  
  <entry>
    <title>cloudflared内网穿透实现Windows远程桌面</title>
    <link href="https://blog.dollcode.cn/cloudflared-tunnel-rdp.html"/>
    <id>https://blog.dollcode.cn/cloudflared-tunnel-rdp.html</id>
    <published>2022-07-30T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<blockquote><ul><li>个人经常会有远程Windows的需要，没有找到中意的远程软件</li><li>用过向日葵，三天两头服务器奔溃，账户莫名登录不上，直接劝退。</li><li>TeamViewer就厉害了，识别到国内IP就是特供版，不验证手机号直接不让用，也劝退了。</li><li>Todesk就直接告辞了，你以为在白嫖它的服务，殊不知电脑的网络被它一直在白嫖</li><li>偶然看到Cloudflare Tunnel穿透，配合Freenom的免费域名，通过windows远程桌面就可以直接远程了</li></ul></blockquote><h2 id="提前准备"><a href="#提前准备" class="headerlink" title="提前准备"></a>提前准备</h2><ul><li>Cloudflare账号，注册地址：<a href="https://www.cloudflare.com/">https://www.cloudflare.com</a></li><li>自定义域名并托管到Cloudflare（使用Freenom免费域名）</li><li>下载 Cloudflare可执行文件 下载地址：<a href="https://github.com/cloudflare/cloudflared/releases">https://github.com/cloudflare/cloudflared/releases</a></li></ul><h2 id="被控端电脑配置"><a href="#被控端电脑配置" class="headerlink" title="被控端电脑配置"></a>被控端电脑配置</h2><p>将 下载好的可执行文件<code>(cloudflared-windows-amd64.exe)</code> 复制到 自己定义的目录 并改短名称为<code>(cloudflared.exe)</code>，方便操作</p><p>在当前目录打开 <strong>cmd</strong> 窗口，输入如下命令进行登录验证，会自动打开游览器进行登录</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">cloudflared.exe login</span><br></pre></td></tr></table></figure><p>登录完成之后会在 <code>C:\Users\%USERNAME%\.cloudflared</code> 目录下生成登录凭证<br><img src="https://s2.loli.net/2022/07/29/LHAf2Dth4FNSspi.png"></p><p>创建隧道，<NAME>随意自定义名称</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">cloudflared.exe tunnel create &lt;NAME&gt;</span><br></pre></td></tr></table></figure><p>配置 DNS 记录（使用Freenom免费域名），<NAME>就是上一步创建的隧道名称</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">cloudflared.exe tunnel route dns &lt;NAME&gt; diy.domain.cf</span><br></pre></td></tr></table></figure><p>配置完成之后，可以在控制台看到记录<br><img src="https://s2.loli.net/2022/07/29/efSZ7wPW1Ab8ic4.png"></p><p>在 <strong>cloudflared.exe</strong> 同级目录创建一个 <code>config.yaml</code> 文件，内容如下  </p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 隧道的 UUID, 就是登录凭证的json文件名称</span></span><br><span class="line"><span class="attr">tunnel:</span> <span class="string">xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx</span></span><br><span class="line"><span class="comment"># 鉴权文件的全路径，注意替换为自己的</span></span><br><span class="line"><span class="attr">credentials-file:</span> <span class="string">C:\Users\%USERNAME%\.cloudflared\xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx.json</span></span><br><span class="line"></span><br><span class="line"><span class="attr">ingress:</span></span><br><span class="line">  <span class="comment"># 你的freenom二级域名</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">hostname:</span> <span class="string">diy.domain.cf</span></span><br><span class="line">    <span class="attr">service:</span> <span class="string">rdp://localhost:3389</span></span><br><span class="line">  <span class="comment"># 默认错误404</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">service:</span> <span class="string">http_status:404</span></span><br></pre></td></tr></table></figure><h2 id="验证连接情况"><a href="#验证连接情况" class="headerlink" title="验证连接情况"></a>验证连接情况</h2><h3 id="被控端"><a href="#被控端" class="headerlink" title="被控端"></a>被控端</h3><p>被控端输入如下命令，注意替换配置文件路径</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">cloudflared.exe --config=D:\Config\config.yaml tunnel run</span><br></pre></td></tr></table></figure><h3 id="控制端"><a href="#控制端" class="headerlink" title="控制端"></a>控制端</h3><p>同样下载可执行文件，并在目录打开 <strong>cmd</strong>。输入如下命令，即可启动 <code>Start Websocket listener</code></p><ul><li>hostname 填写自定义的域名</li><li>url 填写映射的本地端口，如localhost:3000</li></ul><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">cloudflared.exe access rdp --hostname diy.domain.cf --url localhost:3000</span><br></pre></td></tr></table></figure><p>再打开 windows远程桌面 -&gt; 输入 <strong>localhost:3000</strong> 能连接的话就说明配置没问题了<br><img src="https://s2.loli.net/2022/07/29/HoM6qyXmxfOv1EK.png"></p><h2 id="配置开机自启"><a href="#配置开机自启" class="headerlink" title="配置开机自启"></a>配置开机自启</h2><p>被控端如果还需要手动执行命令，那不是脱裤子放屁。</p><p>肯定是需要注册成Windows服务，自动启动滴！</p><p>首先 <strong>以管理员身份打开</strong> <code>cmd</code>， 进入cloudflared.exe所在目录，执行如下命令，注册成服务</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">cloudflared.exe service install</span><br></pre></td></tr></table></figure><p>打开注册表(regedit.exe)，在 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services 找到 Cloudflared<br>将 ImagePath 修改为 <code>D:\Config\cloudflared.exe --config=D:\Config\config.yaml tunnel run</code> 注意替换自己路径<br><img src="https://s2.loli.net/2022/07/29/qWEk3jwrlDasH1T.png"></p><p>再打开Windows服务(services.msc)，找到 <code>cloudflared agent</code> 右键 重新启动。自启就配置完成啦！！！<br><img src="https://s2.loli.net/2022/07/30/tDxsMVAkgaljTK7.png"></p><p>建议配合笔者之前写的 <a href="https://blog.dollcode.cn/win-autoemail.html">Windows开机自动发送邮件</a> 食用更佳。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;个人经常会有远程Windows的需要，没有找到中意的远程软件&lt;/li&gt;
&lt;li&gt;用过向日葵，三天两头服务器奔溃，账户莫名登录不上，直接劝退。&lt;/li&gt;
&lt;li&gt;TeamViewer就厉害了，识别到国内IP就是特供版，不验证手机号直接不让</summary>
      
    
    
    
    <category term="软件教程" scheme="https://blog.dollcode.cn/categories/%E8%BD%AF%E4%BB%B6%E6%95%99%E7%A8%8B/"/>
    
    
    <category term="Software" scheme="https://blog.dollcode.cn/tags/Software/"/>
    
  </entry>
  
  <entry>
    <title>nginx配置返回json或html</title>
    <link href="https://blog.dollcode.cn/nginx-return-type.html"/>
    <id>https://blog.dollcode.cn/nginx-return-type.html</id>
    <published>2022-07-28T00:00:00.000Z</published>
    <updated>2025-06-27T06:34:56.452Z</updated>
    
    <content type="html"><![CDATA[<p>最近刚好需要清理一些旧接口，不让外界访问。通过Nginx直接拦截接口，返回接口不可用信息。记录一下操作</p><h2 id="配置参数说明"><a href="#配置参数说明" class="headerlink" title="配置参数说明"></a>配置参数说明</h2><h3 id="default-type"><a href="#default-type" class="headerlink" title="default_type"></a>default_type</h3><table><thead><tr><th>配置</th><th>说明</th></tr></thead><tbody><tr><td>application&#x2F;json</td><td>返回json格式</td></tr><tr><td>text&#x2F;html</td><td>返回text&#x2F;html格式</td></tr></tbody></table><h2 id="配置直接返回数据"><a href="#配置直接返回数据" class="headerlink" title="配置直接返回数据"></a>配置直接返回数据</h2><p>需要配置 <strong>default_type</strong>，不然游览器无法识别数据类型，会触发游览器下载</p><p><strong>格式</strong>：return HTTP状态码 数据内容</p><h3 id="配置返回JSON"><a href="#配置返回JSON" class="headerlink" title="配置返回JSON"></a>配置返回JSON</h3><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></pre></td><td class="code"><pre><span class="line">location = /blog/choose &#123;</span><br><span class="line">    default_type application/json;</span><br><span class="line">    return 200 &#x27;&#123;&quot;code&quot;: -1, &quot;msg&quot;: &quot;接口已升级，请重新配置&quot;&#125;&#x27;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/img/article/k5WaFEBdHALjmn6.png"></p><h3 id="配置返回HTML"><a href="#配置返回HTML" class="headerlink" title="配置返回HTML"></a>配置返回HTML</h3><p>如果出现中文乱码，应该是Server没有配置字符集。增加 <code>charset utf-8;</code></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></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">  listen  80</span><br><span class="line">  server_name  域名;</span><br><span class="line">  charset utf-8;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">location = /blog/choose &#123;</span><br><span class="line">    default_type text/html;</span><br><span class="line">    return 200 &#x27;&lt;h3&gt;接口已升级，请重新配置&lt;/h3&gt;&#x27;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/img/article/1fzyakMOoXHdn6A.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;最近刚好需要清理一些旧接口，不让外界访问。通过Nginx直接拦截接口，返回接口不可用信息。记录一下操作&lt;/p&gt;
&lt;h2 id=&quot;配置参数说明&quot;&gt;&lt;a href=&quot;#配置参数说明&quot; class=&quot;headerlink&quot; title=&quot;配置参数说明&quot;&gt;&lt;/a&gt;配置参数说明&lt;/h</summary>
      
    
    
    
    <category term="Web技术" scheme="https://blog.dollcode.cn/categories/Web%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="Linux" scheme="https://blog.dollcode.cn/tags/Linux/"/>
    
    <category term="Nginx" scheme="https://blog.dollcode.cn/tags/Nginx/"/>
    
  </entry>
  
</feed>
