<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>心雨</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://demo-blog.qusite.cn/</id>
  <link href="https://demo-blog.qusite.cn/" rel="alternate"/>
  <link href="https://demo-blog.qusite.cn/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, 心雨</rights>
  <subtitle>个人技术折腾笔记</subtitle>
  <title>遇事不决，可问春风</title>
  <updated>2026-06-18T00:39:57.578Z</updated>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="Docker" scheme="https://demo-blog.qusite.cn/tags/Docker/"/>
    <category term="Linux配置" scheme="https://demo-blog.qusite.cn/tags/Linux%E9%85%8D%E7%BD%AE/"/>
    <category term="容器" scheme="https://demo-blog.qusite.cn/tags/%E5%AE%B9%E5%99%A8/"/>
    <category term="安全加固" scheme="https://demo-blog.qusite.cn/tags/%E5%AE%89%E5%85%A8%E5%8A%A0%E5%9B%BA/"/>
    <content>
      <![CDATA[<p>Docker 已成为现代应用部署的标准方案，但生产环境中容器安全是不可忽视的环节。本文将系统介绍 Docker 运行环境的配置优化与安全加固方法，涵盖从安装到运行的全链路最佳实践。</p><h2 id="1-Docker-引擎安装"><a href="#1-Docker-引擎安装" class="headerlink" title="1. Docker 引擎安装"></a>1. Docker 引擎安装</h2><h3 id="1-1-官方仓库安装（推荐）"><a href="#1-1-官方仓库安装（推荐）" class="headerlink" title="1.1 官方仓库安装（推荐）"></a>1.1 官方仓库安装（推荐）</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 卸载旧版本</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get remove docker docker-engine docker.io containerd runc</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装依赖</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get update</span><br><span class="line"><span class="built_in">sudo</span> apt-get install -y ca-certificates curl gnupg lsb-release</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加 Docker 官方 GPG 密钥</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/apt/keyrings</span><br><span class="line">curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \</span><br><span class="line">  <span class="built_in">sudo</span> gpg --dearmor -o /etc/apt/keyrings/docker.gpg</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加稳定版仓库</span></span><br><span class="line"><span class="built_in">echo</span> \</span><br><span class="line">  <span class="string">&quot;deb [arch=<span class="subst">$(dpkg --print-architecture)</span> signed-by=/etc/apt/keyrings/docker.gpg] \</span></span><br><span class="line"><span class="string">  https://download.docker.com/linux/ubuntu <span class="subst">$(lsb_release -cs)</span> stable&quot;</span> | \</span><br><span class="line">  <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/apt/sources.list.d/docker.list &gt; /dev/null</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 Docker Engine</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get update</span><br><span class="line"><span class="built_in">sudo</span> apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证安装</span></span><br><span class="line"><span class="built_in">sudo</span> docker run hello-world</span><br></pre></td></tr></table></figure></div><h3 id="1-2-安装后配置"><a href="#1-2-安装后配置" class="headerlink" title="1.2 安装后配置"></a>1.2 安装后配置</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 将当前用户加入 docker 组（避免每次 sudo）</span></span><br><span class="line"><span class="built_in">sudo</span> usermod -aG docker <span class="variable">$USER</span></span><br><span class="line"><span class="comment"># 退出重新登录后生效</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置 Docker 开机自启</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl <span class="built_in">enable</span> docker</span><br><span class="line"><span class="built_in">sudo</span> systemctl start docker</span><br></pre></td></tr></table></figure></div><h2 id="2-Docker-Daemon-安全配置"><a href="#2-Docker-Daemon-安全配置" class="headerlink" title="2. Docker Daemon 安全配置"></a>2. Docker Daemon 安全配置</h2><p>Docker daemon 的核心配置文件位于 <code>/etc/docker/daemon.json</code>，生产环境应进行以下加固配置：</p><div class="code-container" data-rel="Json"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;icc&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;log-driver&quot;</span><span class="punctuation">:</span> <span class="string">&quot;json-file&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;log-opts&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;max-size&quot;</span><span class="punctuation">:</span> <span class="string">&quot;10m&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;max-file&quot;</span><span class="punctuation">:</span> <span class="string">&quot;3&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;iptables&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;live-restore&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;userland-proxy&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;no-new-privileges&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;userns-remap&quot;</span><span class="punctuation">:</span> <span class="string">&quot;default&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;default-ulimit&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;nofile&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;nofile&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;hard&quot;</span><span class="punctuation">:</span> <span class="number">65536</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;soft&quot;</span><span class="punctuation">:</span> <span class="number">65536</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;experimental&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></div><h3 id="2-1-关键配置项说明"><a href="#2-1-关键配置项说明" class="headerlink" title="2.1 关键配置项说明"></a>2.1 关键配置项说明</h3><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>配置项</th><th>默认值</th><th>推荐值</th><th>说明</th></tr></thead><tbody><tr><td><code>icc</code></td><td>true</td><td>false</td><td>关闭容器间默认通信，强制通过自定义网络</td></tr><tr><td><code>live-restore</code></td><td>false</td><td>true</td><td>daemon 重启时保持容器运行</td></tr><tr><td><code>userland-proxy</code></td><td>true</td><td>false</td><td>禁用用户态代理，减少攻击面</td></tr><tr><td><code>no-new-privileges</code></td><td>false</td><td>true</td><td>禁止容器进程获取新权限</td></tr><tr><td><code>userns-remap</code></td><td>""</td><td>"default"</td><td>启用用户命名空间隔离</td></tr><tr><td><code>iptables</code></td><td>true</td><td>true</td><td>启用 iptables 规则管理</td></tr><tr><td><code>log-opts</code></td><td>不限</td><td>max-size=10m</td><td>限制日志文件大小和数量</td></tr></tbody></table></div><h3 id="2-2-应用配置并重启"><a href="#2-2-应用配置并重启" class="headerlink" title="2.2 应用配置并重启"></a>2.2 应用配置并重启</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建配置文件</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/docker</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/docker/daemon.json &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;icc&quot;</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="string">&quot;log-driver&quot;</span>: <span class="string">&quot;json-file&quot;</span>,</span><br><span class="line">  <span class="string">&quot;log-opts&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;max-size&quot;</span>: <span class="string">&quot;10m&quot;</span>,</span><br><span class="line">    <span class="string">&quot;max-file&quot;</span>: <span class="string">&quot;3&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="string">&quot;iptables&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">  <span class="string">&quot;live-restore&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">  <span class="string">&quot;userland-proxy&quot;</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="string">&quot;no-new-privileges&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">  <span class="string">&quot;userns-remap&quot;</span>: <span class="string">&quot;default&quot;</span>,</span><br><span class="line">  <span class="string">&quot;default-ulimit&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;nofile&quot;</span>: &#123; <span class="string">&quot;name&quot;</span>: <span class="string">&quot;nofile&quot;</span>, <span class="string">&quot;hard&quot;</span>: 65536, <span class="string">&quot;soft&quot;</span>: 65536 &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="string">&quot;experimental&quot;</span>: <span class="literal">false</span></span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重载配置</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl daemon-reload</span><br><span class="line"><span class="built_in">sudo</span> systemctl restart docker</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证配置生效</span></span><br><span class="line"><span class="built_in">sudo</span> docker info | grep -E <span class="string">&quot;Userns|Security|Live Restore&quot;</span></span><br></pre></td></tr></table></figure></div><h2 id="3-用户命名空间隔离（userns-remap）"><a href="#3-用户命名空间隔离（userns-remap）" class="headerlink" title="3. 用户命名空间隔离（userns-remap）"></a>3. 用户命名空间隔离（userns-remap）</h2><p>用户命名空间是 Docker 最关键的安全特性之一。启用后，容器内的 root 用户将被映射为宿主机上的非特权用户（默认 subuid 范围从 100000 开始），即使容器被攻破也无法获得宿主机的 root 权限。</p><h3 id="3-1-检查-subuid-subgid-配置"><a href="#3-1-检查-subuid-subgid-配置" class="headerlink" title="3.1 检查 subuid&#x2F;subgid 配置"></a>3.1 检查 subuid&#x2F;subgid 配置</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 检查 UID/GID 映射范围</span></span><br><span class="line"><span class="built_in">cat</span> /etc/subuid</span><br><span class="line"><span class="comment"># 输出示例：dockremap:100000:65536</span></span><br><span class="line"><span class="built_in">cat</span> /etc/subgid</span><br><span class="line"><span class="comment"># 输出示例：dockremap:100000:65536</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 如果不存在，手动创建</span></span><br><span class="line"><span class="built_in">sudo</span> usermod --add-subuids 100000-165535 --add-subgids 100000-165535 dockremap</span><br></pre></td></tr></table></figure></div><h3 id="3-2-验证隔离效果"><a href="#3-2-验证隔离效果" class="headerlink" title="3.2 验证隔离效果"></a>3.2 验证隔离效果</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 启动测试容器</span></span><br><span class="line">docker run --<span class="built_in">rm</span> -it alpine sh -c <span class="string">&quot;id &amp;&amp; cat /proc/self/uid_map&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 预期输出：</span></span><br><span class="line"><span class="comment"># uid=0(root) gid=0(root) groups=0(root)</span></span><br><span class="line"><span class="comment">#          0       100000       65536</span></span><br><span class="line"><span class="comment"># 说明容器内 UID 0 被映射到宿主机 UID 100000</span></span><br></pre></td></tr></table></figure></div><h3 id="3-3-需注意的事项"><a href="#3-3-需注意的事项" class="headerlink" title="3.3 需注意的事项"></a>3.3 需注意的事项</h3><ul><li>启用 <code>userns-remap</code> 后，默认的绑定挂载卷会重新映射权限，需使用 <code>--userns=host</code> 临时跳过（不推荐生产使用）</li><li>宿主机上通过 <code>ls -n</code> 可查看实际 UID，而非容器内的用户</li><li>部分需要访问宿主机设备或系统调用的容器（如特权模式）无法使用此功能</li></ul><h2 id="4-Docker-网络安全"><a href="#4-Docker-网络安全" class="headerlink" title="4. Docker 网络安全"></a>4. Docker 网络安全</h2><h3 id="4-1-网络模式选择"><a href="#4-1-网络模式选择" class="headerlink" title="4.1 网络模式选择"></a>4.1 网络模式选择</h3><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>模式</th><th>安全性</th><th>适用场景</th></tr></thead><tbody><tr><td>bridge（默认）</td><td>中</td><td>单机多容器通信</td></tr><tr><td>自定义 bridge</td><td>高</td><td>推荐的生产环境网络方案</td></tr><tr><td>host</td><td>低</td><td>性能敏感型应用（不推荐生产）</td></tr><tr><td>none</td><td>最高</td><td>完全隔离的后台任务容器</td></tr><tr><td>macvlan/ipvlan</td><td>中</td><td>容器需要独立 MAC/IP 地址</td></tr><tr><td>overlay</td><td>高</td><td>Swarm 多节点集群</td></tr></tbody></table></div><h3 id="4-2-创建自定义网络"><a href="#4-2-创建自定义网络" class="headerlink" title="4.2 创建自定义网络"></a>4.2 创建自定义网络</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建前端网络（暴露给外部）</span></span><br><span class="line">docker network create \</span><br><span class="line">  --driver bridge \</span><br><span class="line">  --subnet=172.20.0.0/16 \</span><br><span class="line">  --gateway=172.20.0.1 \</span><br><span class="line">  --opt com.docker.network.bridge.name=docker_frontend \</span><br><span class="line">  --opt com.docker.network.bridge.enable_icc=<span class="literal">true</span> \</span><br><span class="line">  frontend</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建后端网络（内网隔离）</span></span><br><span class="line">docker network create \</span><br><span class="line">  --driver bridge \</span><br><span class="line">  --subnet=172.21.0.0/16 \</span><br><span class="line">  --gateway=172.21.0.1 \</span><br><span class="line">  --internal \</span><br><span class="line">  --opt com.docker.network.bridge.name=docker_backend \</span><br><span class="line">  backend</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动容器并连接到指定网络</span></span><br><span class="line">docker run -d --name nginx \</span><br><span class="line">  --network frontend \</span><br><span class="line">  --ip 172.20.0.10 \</span><br><span class="line">  nginx:stable-alpine</span><br><span class="line"></span><br><span class="line">docker run -d --name php-app \</span><br><span class="line">  --network backend \</span><br><span class="line">  --network frontend \</span><br><span class="line">  --ip 172.21.0.10 \</span><br><span class="line">  php:fpm-alpine</span><br></pre></td></tr></table></figure></div><h3 id="4-3-Docker-防火墙规则"><a href="#4-3-Docker-防火墙规则" class="headerlink" title="4.3 Docker 防火墙规则"></a>4.3 Docker 防火墙规则</h3><p>Docker 会自动管理 iptables 规则，但建议配合 UFW 使用：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 配置 UFW 默认规则</span></span><br><span class="line"><span class="built_in">sudo</span> ufw default deny incoming</span><br><span class="line"><span class="built_in">sudo</span> ufw default allow outgoing</span><br><span class="line"></span><br><span class="line"><span class="comment"># 允许 SSH</span></span><br><span class="line"><span class="built_in">sudo</span> ufw allow 22/tcp</span><br><span class="line"></span><br><span class="line"><span class="comment"># 修改 DOCKER-USER 链限制外部访问</span></span><br><span class="line"><span class="built_in">sudo</span> iptables -I DOCKER-USER -i eth0 -p tcp --dport 2375 -j DROP</span><br><span class="line"><span class="built_in">sudo</span> iptables -I DOCKER-USER -i eth0 -p tcp --dport 2376 -j DROP</span><br><span class="line"></span><br><span class="line"><span class="comment"># 仅允许特定 IP 访问 Docker 端口映射</span></span><br><span class="line"><span class="built_in">sudo</span> iptables -I DOCKER-USER -i eth0 ! -s 192.168.1.0/24 -p tcp --dport 8080 -j DROP</span><br><span class="line"></span><br><span class="line"><span class="comment"># 持久化 iptables 规则</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get install -y iptables-persistent</span><br><span class="line"><span class="built_in">sudo</span> netfilter-persistent save</span><br></pre></td></tr></table></figure></div><h2 id="5-容器运行时安全"><a href="#5-容器运行时安全" class="headerlink" title="5. 容器运行时安全"></a>5. 容器运行时安全</h2><h3 id="5-1-最小权限原则"><a href="#5-1-最小权限原则" class="headerlink" title="5.1 最小权限原则"></a>5.1 最小权限原则</h3><p>运行容器时应始终遵循最小权限原则，避免使用 <code>--privileged</code> 和默认的 <code>root</code> 用户。</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># ❌ 不安全示例</span></span><br><span class="line">docker run --privileged -d nginx</span><br><span class="line"></span><br><span class="line"><span class="comment"># ✅ 安全示例</span></span><br><span class="line">docker run \</span><br><span class="line">  --read-only \</span><br><span class="line">  --tmpfs /tmp:rw,noexec,nosuid,size=64m \</span><br><span class="line">  --tmpfs /var/run:rw,noexec,nosuid,size=64m \</span><br><span class="line">  --cap-drop ALL \</span><br><span class="line">  --cap-add NET_BIND_SERVICE \</span><br><span class="line">  --cap-add CHOWN \</span><br><span class="line">  --cap-add SETGID \</span><br><span class="line">  --cap-add SETUID \</span><br><span class="line">  --security-opt=no-new-privileges:<span class="literal">true</span> \</span><br><span class="line">  -d nginx:stable-alpine</span><br></pre></td></tr></table></figure></div><h3 id="5-2-Linux-Capabilities-管理"><a href="#5-2-Linux-Capabilities-管理" class="headerlink" title="5.2 Linux Capabilities 管理"></a>5.2 Linux Capabilities 管理</h3><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>应用类型</th><th>保留的 Capabilities</th><th>说明</th></tr></thead><tbody><tr><td>Nginx</td><td>NET_BIND_SERVICE, CHOWN, SETGID, SETUID</td><td>绑定低端口、更改文件所有者</td></tr><tr><td>PostgreSQL</td><td>CHOWN, DAC_OVERRIDE, SETGID, SETUID</td><td>数据目录权限管理</td></tr><tr><td>Redis</td><td>CHOWN, SETGID, SETUID, SYS_NICE</td><td>文件权限和进程优先级</td></tr><tr><td>Java 应用</td><td>CHOWN, DAC_OVERRIDE, SETGID, SETUID, NET_BIND_SERVICE</td><td>文件管理和端口绑定</td></tr><tr><td>通用 Web 应用</td><td>NET_BIND_SERVICE, CHOWN, SETGID, SETUID</td><td>最精简权限集</td></tr></tbody></table></div><h3 id="5-3-使用非-root-用户运行"><a href="#5-3-使用非-root-用户运行" class="headerlink" title="5.3 使用非 root 用户运行"></a>5.3 使用非 root 用户运行</h3><div class="code-container" data-rel="Dockerfile"><figure class="iseeu 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><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"><span class="comment"># Dockerfile 示例</span></span><br><span class="line"><span class="keyword">FROM</span> node:<span class="number">20</span>-alpine AS builder</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建非 root 用户</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> addgroup -S appgroup &amp;&amp; adduser -S appuser -G appgroup</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /app</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> --<span class="built_in">chown</span>=appuser:appgroup package*.json ./</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> npm ci --only=production</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> --<span class="built_in">chown</span>=appuser:appgroup . .</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 切换到非 root 用户</span></span><br><span class="line"><span class="keyword">USER</span> appuser</span><br><span class="line"></span><br><span class="line"><span class="keyword">EXPOSE</span> <span class="number">3000</span></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [<span class="string">&quot;node&quot;</span>, <span class="string">&quot;server.js&quot;</span>]</span></span><br></pre></td></tr></table></figure></div><h3 id="5-4-只读根文件系统"><a href="#5-4-只读根文件系统" class="headerlink" title="5.4 只读根文件系统"></a>5.4 只读根文件系统</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 运行容器时挂载只读根文件系统</span></span><br><span class="line">docker run \</span><br><span class="line">  --read-only \</span><br><span class="line">  --tmpfs /tmp:rw,noexec,nosuid,size=128m \</span><br><span class="line">  --tmpfs /var/cache/nginx:rw,noexec,nosuid,size=64m \</span><br><span class="line">  --tmpfs /var/run:rw,noexec,nosuid,size=64m \</span><br><span class="line">  -d nginx:stable-alpine</span><br></pre></td></tr></table></figure></div><h2 id="6-镜像安全管理"><a href="#6-镜像安全管理" class="headerlink" title="6. 镜像安全管理"></a>6. 镜像安全管理</h2><h3 id="6-1-使用可信基础镜像"><a href="#6-1-使用可信基础镜像" class="headerlink" title="6.1 使用可信基础镜像"></a>6.1 使用可信基础镜像</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 优先使用官方镜像和精简版本</span></span><br><span class="line"><span class="comment"># 推荐：使用 Alpine 或 Distroless 基础镜像</span></span><br><span class="line">docker pull node:20-alpine</span><br><span class="line">docker pull python:3.12-slim</span><br><span class="line">docker pull gcr.io/distroless/base-debian12</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证镜像签名</span></span><br><span class="line">docker trust inspect --pretty node:20-alpine</span><br></pre></td></tr></table></figure></div><h3 id="6-2-镜像安全扫描"><a href="#6-2-镜像安全扫描" class="headerlink" title="6.2 镜像安全扫描"></a>6.2 镜像安全扫描</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装 Trivy 扫描工具</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get install -y wget apt-transport-https gnupg</span><br><span class="line">wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | \</span><br><span class="line">  <span class="built_in">sudo</span> gpg --dearmor -o /etc/apt/keyrings/trivy.gpg</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;deb [signed-by=/etc/apt/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main&quot;</span> | \</span><br><span class="line">  <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/apt/sources.list.d/trivy.list</span><br><span class="line"><span class="built_in">sudo</span> apt-get update &amp;&amp; <span class="built_in">sudo</span> apt-get install -y trivy</span><br><span class="line"></span><br><span class="line"><span class="comment"># 扫描镜像漏洞</span></span><br><span class="line">trivy image nginx:stable-alpine</span><br><span class="line">trivy image --severity CRITICAL,HIGH nginx:stable-alpine</span><br><span class="line"></span><br><span class="line"><span class="comment"># 扫描 Dockerfile</span></span><br><span class="line">trivy config --severity CRITICAL,HIGH ./Dockerfile</span><br><span class="line"></span><br><span class="line"><span class="comment"># 定期扫描所有运行中的镜像</span></span><br><span class="line">docker images --format <span class="string">&quot;&#123;&#123;.Repository&#125;&#125;:&#123;&#123;.Tag&#125;&#125;&quot;</span> | \</span><br><span class="line">  <span class="keyword">while</span> <span class="built_in">read</span> image; <span class="keyword">do</span></span><br><span class="line">    trivy image --severity CRITICAL,HIGH --exit-code 1 <span class="string">&quot;<span class="variable">$image</span>&quot;</span> || \</span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;WARNING: <span class="variable">$image</span> has critical vulnerabilities&quot;</span></span><br><span class="line">  <span class="keyword">done</span></span><br></pre></td></tr></table></figure></div><h3 id="6-3-Dockerfile-安全最佳实践"><a href="#6-3-Dockerfile-安全最佳实践" class="headerlink" title="6.3 Dockerfile 安全最佳实践"></a>6.3 Dockerfile 安全最佳实践</h3><div class="code-container" data-rel="Dockerfile"><figure class="iseeu 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><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"># 多阶段构建示例</span></span><br><span class="line"><span class="keyword">FROM</span> node:<span class="number">20</span>-alpine AS builder</span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /build</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> package*.json ./</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> npm ci</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> . .</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> npm run build</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 最终运行阶段</span></span><br><span class="line"><span class="keyword">FROM</span> node:<span class="number">20</span>-alpine</span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> addgroup -S appgroup &amp;&amp; adduser -S appuser -G appgroup</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 只安装生产依赖</span></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /app</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> --from=builder /build/dist ./dist</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> --from=builder /build/node_modules ./node_modules</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> --from=builder /build/package.json ./</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">USER</span> appuser</span><br><span class="line"><span class="keyword">EXPOSE</span> <span class="number">3000</span></span><br><span class="line"><span class="keyword">HEALTHCHECK</span><span class="language-bash"> --interval=30s --<span class="built_in">timeout</span>=3s --start-period=5s --retries=3 \</span></span><br><span class="line"><span class="language-bash">  CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || <span class="built_in">exit</span> 1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [<span class="string">&quot;node&quot;</span>, <span class="string">&quot;dist/server.js&quot;</span>]</span></span><br></pre></td></tr></table></figure></div><h2 id="7-资源限制与监控"><a href="#7-资源限制与监控" class="headerlink" title="7. 资源限制与监控"></a>7. 资源限制与监控</h2><h3 id="7-1-容器资源限制"><a href="#7-1-容器资源限制" class="headerlink" title="7.1 容器资源限制"></a>7.1 容器资源限制</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># CPU 和内存限制</span></span><br><span class="line">docker run -d \</span><br><span class="line">  --name app \</span><br><span class="line">  --memory=<span class="string">&quot;512m&quot;</span> \</span><br><span class="line">  --memory-reservation=<span class="string">&quot;256m&quot;</span> \</span><br><span class="line">  --memory-swap=<span class="string">&quot;1g&quot;</span> \</span><br><span class="line">  --cpus=<span class="string">&quot;1.5&quot;</span> \</span><br><span class="line">  --cpuset-cpus=<span class="string">&quot;0-1&quot;</span> \</span><br><span class="line">  --pids-limit=100 \</span><br><span class="line">  --restart=unless-stopped \</span><br><span class="line">  nginx:stable-alpine</span><br><span class="line"></span><br><span class="line"><span class="comment"># 磁盘 IO 限制</span></span><br><span class="line">docker run -d \</span><br><span class="line">  --device-read-bps /dev/sda:50mb \</span><br><span class="line">  --device-write-bps /dev/sda:30mb \</span><br><span class="line">  --device-read-iops /dev/sda:1000 \</span><br><span class="line">  --device-write-iops /dev/sda:500 \</span><br><span class="line">  --name db \</span><br><span class="line">  postgres:17-alpine</span><br></pre></td></tr></table></figure></div><h3 id="7-2-资源限制参考表"><a href="#7-2-资源限制参考表" class="headerlink" title="7.2 资源限制参考表"></a>7.2 资源限制参考表</h3><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>应用类型</th><th>CPU 限制</th><th>内存限制</th><th>PID 限制</th><th>重启策略</th></tr></thead><tbody><tr><td>Web 反向代理</td><td>0.5-1</td><td>128-256m</td><td>50</td><td>unless-stopped</td></tr><tr><td>API 服务</td><td>1-2</td><td>256-512m</td><td>100</td><td>unless-stopped</td></tr><tr><td>数据库</td><td>2-4</td><td>1-4g</td><td>200</td><td>unless-stopped</td></tr><tr><td>缓存服务</td><td>1-2</td><td>256-512m</td><td>100</td><td>unless-stopped</td></tr><tr><td>消息队列</td><td>1-2</td><td>512-1g</td><td>100</td><td>unless-stopped</td></tr><tr><td>定时任务</td><td>0.5-1</td><td>128-256m</td><td>50</td><td>on-failure:5</td></tr></tbody></table></div><h3 id="7-3-实时监控"><a href="#7-3-实时监控" class="headerlink" title="7.3 实时监控"></a>7.3 实时监控</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 容器资源使用统计</span></span><br><span class="line">docker stats --no-stream</span><br><span class="line"></span><br><span class="line"><span class="comment"># 实时监控（每 2 秒刷新）</span></span><br><span class="line">docker stats --format <span class="string">&quot;table &#123;&#123;.Name&#125;&#125;\t&#123;&#123;.CPUPerc&#125;&#125;\t&#123;&#123;.MemUsage&#125;&#125;\t&#123;&#123;.NetIO&#125;&#125;\t&#123;&#123;.BlockIO&#125;&#125;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看容器日志（限制输出）</span></span><br><span class="line">docker logs --<span class="built_in">tail</span> 100 --timestamps &lt;container&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查容器进程</span></span><br><span class="line">docker top &lt;container&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查容器文件系统变更</span></span><br><span class="line">docker diff &lt;container&gt;</span><br></pre></td></tr></table></figure></div><h2 id="8-Docker-审计日志与事件监控"><a href="#8-Docker-审计日志与事件监控" class="headerlink" title="8. Docker 审计日志与事件监控"></a>8. Docker 审计日志与事件监控</h2><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 实时监控 Docker 事件</span></span><br><span class="line">docker events --filter <span class="string">&#x27;type=container&#x27;</span> --filter <span class="string">&#x27;event=start|stop|kill|die&#x27;</span> \</span><br><span class="line">  --format <span class="string">&#x27;&#123;&#123;json .&#125;&#125;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 持久化事件日志到文件</span></span><br><span class="line">docker events --since <span class="string">&#x27;24h&#x27;</span> &gt; /var/log/docker-events.log &amp;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置 rsyslog 收集 Docker 日志</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/rsyslog.d/30-docker.conf &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line"><span class="keyword">if</span> <span class="variable">$programname</span> == <span class="string">&quot;dockerd&quot;</span> <span class="keyword">then</span> /var/log/docker-daemon.log</span><br><span class="line">&amp; stop</span><br><span class="line">EOF</span><br><span class="line"><span class="built_in">sudo</span> systemctl restart rsyslog</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置 Docker 审计规则</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/audit/rules.d/docker.rules &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line">-w /usr/bin/docker -p wa -k docker</span><br><span class="line">-w /var/lib/docker -p wa -k docker</span><br><span class="line">-w /etc/docker -p wa -k docker</span><br><span class="line">-w /etc/default/docker -p wa -k docker</span><br><span class="line">EOF</span><br><span class="line"><span class="built_in">sudo</span> systemctl restart auditd</span><br></pre></td></tr></table></figure></div><h2 id="9-数据卷安全"><a href="#9-数据卷安全" class="headerlink" title="9. 数据卷安全"></a>9. 数据卷安全</h2><h3 id="9-1-卷挂载安全配置"><a href="#9-1-卷挂载安全配置" class="headerlink" title="9.1 卷挂载安全配置"></a>9.1 卷挂载安全配置</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用命名卷而非绑定挂载（推荐）</span></span><br><span class="line">docker volume create app-data</span><br><span class="line"></span><br><span class="line"><span class="comment"># 绑定挂载时设置只读</span></span><br><span class="line">docker run -d \</span><br><span class="line">  -v /host/config:/app/config:ro \</span><br><span class="line">  -v app-data:/app/data \</span><br><span class="line">  nginx:stable-alpine</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置卷挂载选项</span></span><br><span class="line">docker run -d \</span><br><span class="line">  --mount <span class="built_in">type</span>=<span class="built_in">bind</span>,<span class="built_in">source</span>=/host/data,target=/data,<span class="built_in">readonly</span>,bind-propagation=slave \</span><br><span class="line">  nginx:stable-alpine</span><br></pre></td></tr></table></figure></div><h3 id="9-2-数据加密与备份"><a href="#9-2-数据加密与备份" class="headerlink" title="9.2 数据加密与备份"></a>9.2 数据加密与备份</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 加密卷（使用 DM-Crypt 或 LUKS）</span></span><br><span class="line"><span class="built_in">sudo</span> cryptsetup luksFormat /dev/sdb1</span><br><span class="line"><span class="built_in">sudo</span> cryptsetup open /dev/sdb1 docker-data</span><br><span class="line"><span class="built_in">sudo</span> mkfs.ext4 /dev/mapper/docker-data</span><br><span class="line"><span class="built_in">sudo</span> mount /dev/mapper/docker-data /var/lib/docker</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> &lt;&lt; <span class="string">&#x27;BACKUP_SCRIPT&#x27;</span> &gt; /usr/local/bin/backup-docker-volumes.sh</span><br><span class="line"><span class="comment">#!/bin/bash</span></span><br><span class="line">BACKUP_DIR=<span class="string">&quot;/backup/docker-volumes&quot;</span></span><br><span class="line">TIMESTAMP=$(<span class="built_in">date</span> +%Y%m%d_%H%M%S)</span><br><span class="line"><span class="built_in">mkdir</span> -p <span class="string">&quot;<span class="variable">$BACKUP_DIR</span>&quot;</span></span><br><span class="line"></span><br><span class="line">docker volume <span class="built_in">ls</span> -q | <span class="keyword">while</span> <span class="built_in">read</span> volume; <span class="keyword">do</span></span><br><span class="line">  docker run --<span class="built_in">rm</span> \</span><br><span class="line">    -v <span class="variable">$volume</span>:/data \</span><br><span class="line">    -v <span class="variable">$BACKUP_DIR</span>:/backup \</span><br><span class="line">    alpine tar czf /backup/<span class="variable">$&#123;volume&#125;</span>_<span class="variable">$&#123;TIMESTAMP&#125;</span>.tar.gz -C /data .</span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 保留最近 30 天备份</span></span><br><span class="line">find <span class="string">&quot;<span class="variable">$BACKUP_DIR</span>&quot;</span> -name <span class="string">&quot;*.tar.gz&quot;</span> -mtime +30 -delete</span><br><span class="line">BACKUP_SCRIPT</span><br><span class="line"></span><br><span class="line"><span class="built_in">chmod</span> +x /usr/local/bin/backup-docker-volumes.sh</span><br></pre></td></tr></table></figure></div><h2 id="10-Docker-API-安全"><a href="#10-Docker-API-安全" class="headerlink" title="10. Docker API 安全"></a>10. Docker API 安全</h2><p>禁止将 Docker API 暴露在公开网络中。必须暴露时需启用 TLS 认证：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 生成 CA 证书和服务器证书</span></span><br><span class="line"><span class="built_in">cd</span> /etc/docker</span><br><span class="line">openssl genrsa -aes256 -out ca-key.pem 4096</span><br><span class="line">openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem</span><br><span class="line"></span><br><span class="line">openssl genrsa -out server-key.pem 4096</span><br><span class="line">openssl req -subj <span class="string">&quot;/CN=<span class="subst">$(hostname)</span>&quot;</span> -sha256 -new -key server-key.pem \</span><br><span class="line">  -out server.csr</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;subjectAltName = DNS:<span class="subst">$(hostname)</span>,IP:<span class="subst">$(hostname -I | awk &#x27;&#123;print $1&#125;&#x27;)</span>&quot;</span> &gt; extfile.cnf</span><br><span class="line">openssl x509 -req -days 365 -sha256 -<span class="keyword">in</span> server.csr \</span><br><span class="line">  -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem \</span><br><span class="line">  -extfile extfile.cnf</span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置 daemon 使用 TLS</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/docker/daemon.json &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;tls&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">  <span class="string">&quot;tlsverify&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">  <span class="string">&quot;tlscacert&quot;</span>: <span class="string">&quot;/etc/docker/ca.pem&quot;</span>,</span><br><span class="line">  <span class="string">&quot;tlscert&quot;</span>: <span class="string">&quot;/etc/docker/server-cert.pem&quot;</span>,</span><br><span class="line">  <span class="string">&quot;tlskey&quot;</span>: <span class="string">&quot;/etc/docker/server-key.pem&quot;</span>,</span><br><span class="line">  <span class="string">&quot;hosts&quot;</span>: [<span class="string">&quot;tcp://0.0.0.0:2376&quot;</span>, <span class="string">&quot;unix:///var/run/docker.sock&quot;</span>]</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line"><span class="built_in">sudo</span> systemctl restart docker</span><br><span class="line"></span><br><span class="line"><span class="comment"># 客户端连接</span></span><br><span class="line">docker --tlsverify \</span><br><span class="line">  --tlscacert=ca.pem \</span><br><span class="line">  --tlscert=cert.pem \</span><br><span class="line">  --tlskey=key.pem \</span><br><span class="line">  -H=<span class="variable">$HOST</span>:2376 version</span><br></pre></td></tr></table></figure></div><h2 id="11-Docker-安全加固速查表"><a href="#11-Docker-安全加固速查表" class="headerlink" title="11. Docker 安全加固速查表"></a>11. Docker 安全加固速查表</h2><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>安全领域</th><th>最佳实践</th><th>优先级</th></tr></thead><tbody><tr><td>Docker Daemon</td><td>启用 userns-remap、live-restore、no-new-privileges</td><td>高</td></tr><tr><td>容器运行时</td><td>禁止 --privileged，使用 --cap-drop ALL + --cap-add 白名单</td><td>高</td></tr><tr><td>非 root 用户</td><td>Dockerfile 中 USER 指令创建非 root 用户</td><td>高</td></tr><tr><td>只读文件系统</td><td>使用 --read-only 配合 --tmpfs 挂载可写目录</td><td>高</td></tr><tr><td>镜像安全</td><td>使用 Alpine/Distroless 基础镜像，Trivy 定期扫描</td><td>高</td></tr><tr><td>网络安全</td><td>自定义 bridge 网络 + --internal 内网隔离</td><td>高</td></tr><tr><td>资源限制</td><td>设置 memory/cpus/pids-limit 硬限制</td><td>中</td></tr><tr><td>日志管理</td><td>限制日志大小和数量，避免磁盘占满</td><td>中</td></tr><tr><td>API 安全</td><td>禁用 TCP 2375，TLS 加密 2376</td><td>高</td></tr><tr><td>数据卷</td><td>只读挂载，定期备份，使用命名卷</td><td>中</td></tr><tr><td>审计日志</td><td>配置 Docker 审计规则和事件监控</td><td>中</td></tr><tr><td>Docker Socket</td><td>禁止将 /var/run/docker.sock 挂载到容器内</td><td>高</td></tr></tbody></table></div><h2 id="12-常见问题排查"><a href="#12-常见问题排查" class="headerlink" title="12. 常见问题排查"></a>12. 常见问题排查</h2><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>问题</th><th>原因</th><th>解决</th></tr></thead><tbody><tr><td>容器启动后立即退出</td><td>前台进程未保持</td><td>检查 CMD 是否前台运行，使用 -it 测试</td></tr><tr><td>端口映射无效</td><td>iptables 规则被覆盖</td><td>检查 UFW 和 Docker-USER 链配置</td></tr><tr><td>userns-remap 后卷权限问题</td><td>UID 映射导致权限不匹配</td><td>使用 docker run --userns=host 或 chown 映射 UID</td></tr><tr><td>容器磁盘占满</td><td>日志或数据卷未限制</td><td>配置 log-opt，定期 docker system prune</td></tr><tr><td>Docker 无法启动</td><td>daemon.json 语法错误</td><td>dockerd --validate --config-file /etc/docker/daemon.json</td></tr><tr><td>容器网络不通</td><td>icc 设为 false</td><td>将容器加入同一自定义网络</td></tr><tr><td>Docker Socket 暴露风险</td><td>将 docker.sock 挂载到容器</td><td>尽量避免，改用 Docker API over TLS</td></tr><tr><td>容器内时间不准确</td><td>时区未设置</td><td>添加 -e TZ=Asia/Shanghai 环境变量</td></tr></tbody></table></div><h2 id="13-一键安全配置脚本"><a href="#13-一键安全配置脚本" class="headerlink" title="13. 一键安全配置脚本"></a>13. 一键安全配置脚本</h2><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># docker-secure-setup.sh - Docker 运行环境一键安全配置</span></span><br><span class="line"><span class="comment"># 适用于 Ubuntu 22.04 / Debian 12</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">set</span> -euo pipefail</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;=== Docker 安全配置脚本 ===&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 1. 基础配置</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[1/6] 配置 Docker daemon...&quot;</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/docker</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/docker/daemon.json &lt;&lt; <span class="string">&#x27;DAEMON&#x27;</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;icc&quot;</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="string">&quot;log-driver&quot;</span>: <span class="string">&quot;json-file&quot;</span>,</span><br><span class="line">  <span class="string">&quot;log-opts&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;max-size&quot;</span>: <span class="string">&quot;10m&quot;</span>,</span><br><span class="line">    <span class="string">&quot;max-file&quot;</span>: <span class="string">&quot;3&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="string">&quot;iptables&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">  <span class="string">&quot;live-restore&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">  <span class="string">&quot;userland-proxy&quot;</span>: <span class="literal">false</span>,</span><br><span class="line">  <span class="string">&quot;no-new-privileges&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">  <span class="string">&quot;userns-remap&quot;</span>: <span class="string">&quot;default&quot;</span>,</span><br><span class="line">  <span class="string">&quot;experimental&quot;</span>: <span class="literal">false</span></span><br><span class="line">&#125;</span><br><span class="line">DAEMON</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 配置用户命名空间</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[2/6] 配置用户命名空间...&quot;</span></span><br><span class="line"><span class="keyword">if</span> ! getent passwd dockremap &gt; /dev/null; <span class="keyword">then</span></span><br><span class="line">  <span class="built_in">sudo</span> useradd --system --no-create-home --shell /sbin/nologin dockremap</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"><span class="keyword">if</span> ! grep -q <span class="string">&quot;^dockremap:&quot;</span> /etc/subuid; <span class="keyword">then</span></span><br><span class="line">  <span class="built_in">sudo</span> usermod --add-subuids 100000-165535 dockremap</span><br><span class="line">  <span class="built_in">sudo</span> usermod --add-subgids 100000-165535 dockremap</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 重启 Docker</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[3/6] 重启 Docker 服务...&quot;</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl daemon-reload</span><br><span class="line"><span class="built_in">sudo</span> systemctl restart docker</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 配置审计规则</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[4/6] 配置 Docker 审计规则...&quot;</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/audit/rules.d/docker.rules &lt;&lt; <span class="string">&#x27;AUDIT&#x27;</span></span><br><span class="line">-w /usr/bin/docker -p wa -k docker</span><br><span class="line">-w /var/lib/docker -p wa -k docker</span><br><span class="line">-w /etc/docker -p wa -k docker</span><br><span class="line">AUDIT</span><br><span class="line"><span class="keyword">if</span> systemctl is-active --quiet auditd; <span class="keyword">then</span></span><br><span class="line">  <span class="built_in">sudo</span> systemctl restart auditd</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 限制 Docker Socket 权限</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[5/6] 限制 Docker Socket 权限...&quot;</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">chmod</span> 660 /var/run/docker.sock</span><br><span class="line"></span><br><span class="line"><span class="comment"># 6. 配置 docker 组</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[6/6] 配置 docker 组...&quot;</span></span><br><span class="line"><span class="built_in">sudo</span> groupadd -f docker</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;提示：将用户加入 docker 组：sudo usermod -aG docker \$USER&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;=== 配置验证 ===&quot;</span></span><br><span class="line">docker info | grep -E <span class="string">&quot;Userns|Security|Logging|Live Restore&quot;</span> || <span class="literal">true</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;配置完成！建议重新登录使 docker 组生效。&quot;</span></span><br></pre></td></tr></table></figure></div><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Docker 容器安全不是单一配置就能实现的，而是需要从 daemon 配置、网络隔离、权限管理、镜像扫描、资源限制、日志审计等多个维度构建纵深防御体系。本文覆盖了生产环境 Docker 安全加固的核心实践，实际部署时应根据业务场景和应用特点选择合适的配置组合。记住一条黄金法则：<strong>永远默认最小权限，按需开放</strong>。</p><hr><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-18-docker-security-hardening-guide/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-18-docker-security-hardening-guide/"/>
    <published>2026-06-18T00:37:00.000Z</published>
    <summary>
      <![CDATA[<p>Docker 已成为现代应用部署的标准方案，但生产环境中容器安全是不可忽视的环节。本文将系统介绍 Docker 运行环境的配置优化与安全加固方法，涵盖从安装到运行的全链路最佳实践。</p>
<h2 id="1-Docker-引擎安装"><a href="#1-Docker-]]>
    </summary>
    <title>Docker 容器运行环境配置与安全加固完全指南</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="日记" scheme="https://demo-blog.qusite.cn/categories/%E6%97%A5%E8%AE%B0/"/>
    <category term="日记" scheme="https://demo-blog.qusite.cn/tags/%E6%97%A5%E8%AE%B0/"/>
    <category term="技术学习" scheme="https://demo-blog.qusite.cn/tags/%E6%8A%80%E6%9C%AF%E5%AD%A6%E4%B9%A0/"/>
    <category term="负载均衡" scheme="https://demo-blog.qusite.cn/tags/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/"/>
    <category term="RabbitMQ" scheme="https://demo-blog.qusite.cn/tags/RabbitMQ/"/>
    <category term="xargs" scheme="https://demo-blog.qusite.cn/tags/xargs/"/>
    <content>
      <![CDATA[<p>今天是周三，从早晨忙到现在，终于可以坐下来整理一下这一天的收获。早上的日记里我提到正在推进容器化和 Linux 工具类的文章，没想到一转眼就到下午了，时间过得真快。</p><h2 id="上午：HAProxy-负载均衡的深入理解"><a href="#上午：HAProxy-负载均衡的深入理解" class="headerlink" title="上午：HAProxy 负载均衡的深入理解"></a>上午：HAProxy 负载均衡的深入理解</h2><p>上午我花了大约一小时研究并撰写了 HAProxy 负载均衡的配置指南。说实话，之前我对负载均衡的理解只停留在”把请求分发到后端服务器”这个层面。真正动手写配置的时候才意识到，里面有太多细节值得关注。</p><p>HAProxy 的 8 种负载均衡算法各有适用场景：<code>roundrobin</code> 适合后端性能均匀的场景，<code>leastconn</code> 在长连接服务（如 WebSocket）中优势明显，而 <code>uri</code> 和 <code>url_param</code> 则非常适合缓存友好的业务。我在写文章时亲自搭建了两台 Nginx 后端验证了 leastconn 和 roundrobin 的效果差异——当连接时长差异很大时，leastconn 确实能更均匀地分配负载。</p><p>给我印象最深的是 HAProxy 的 stats 监控页面。在 <code>/haproxy?stats</code> 路径下能看到每个后端的实时状态、会话数、队列深度、响应时间等关键指标，对生产环境的排查非常直观。结合 Keepalived 做高可用 VIP 漂移的方案，也是一个很完整的生产级架构思路。</p><h2 id="上午到中午：RabbitMQ-消息队列的复杂世界"><a href="#上午到中午：RabbitMQ-消息队列的复杂世界" class="headerlink" title="上午到中午：RabbitMQ 消息队列的复杂世界"></a>上午到中午：RabbitMQ 消息队列的复杂世界</h2><p>紧接着是 RabbitMQ 的文章。消息队列这个概念我接触过，但一直没有系统地搭建过。这次从 APT 安装到 Docker Compose 部署，再到三节点集群搭建，走了一遍完整流程。</p><p>有几个地方让我印象比较深刻：</p><p>首先是 <strong>Exchange 类型的选择</strong>。Direct、Topic、Fanout、Headers 四种交换机各有适用场景。写了个简单的 Python 示例实测了 Topic Exchange，当多个消费者监听不同路由键时，消息能精准送达各自感兴趣的队列，这种”发布-订阅”模式在实际项目中真的太有用了。</p><p>其次是 <strong>Quorum Queue</strong>。RabbitMQ 3.8+ 引入的 Quorum 队列基于 Raft 共识算法，比经典镜像队列更可靠、更适合生产环境。虽然配置起来比普通队列多几个参数，但对数据一致性要求高的业务来说，非常值得采用。</p><p>最后是 <strong>集群搭建</strong>。最坑的一个点是 Erlang Cookie 的一致性——所有节点的 <code>.erlang.cookie</code> 文件内容必须完全一致，否则节点间无法通信。我一开始没注意权限问题，<code>chmod 400</code> 之后才解决这个问题。</p><h2 id="中午到下午：xargs-的神奇世界"><a href="#中午到下午：xargs-的神奇世界" class="headerlink" title="中午到下午：xargs 的神奇世界"></a>中午到下午：xargs 的神奇世界</h2><p>xargs 是我今天写的第三篇文章。虽然这是个”小工具”，但写起来才发现它的灵活程度远超我的想象。</p><p>最常用的莫过于 <code>find ... -print0 | xargs -0</code> 这个组合。之前我写脚本处理文件名含空格的情况时踩过坑，后来养成了用 <code>-print0</code> 和 <code>-0</code> 的习惯。xargs 的 <code>-P</code> 参数可以指定并行度，比如 <code>xargs -P 4 -I &#123;&#125; curl -s &#123;&#125;</code> 可以让大量 HTTP 请求并行进行，比串行快得多。</p><p>写了这篇文章后，我做了一个小小的对比测试：</p><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>方法</th><th>命令</th><th>性能</th><th>适用场景</th></tr></thead><tbody><tr><td>find -exec</td><td>find . -exec rm {} \;</td><td>较慢</td><td>小批量、简单操作</td></tr><tr><td>xargs</td><td>find . &#124; xargs rm</td><td>较快</td><td>大批量、管线式处理</td></tr><tr><td>xargs -P</td><td>find . &#124; xargs -P 4 rm</td><td>最快</td><td>大量文件并行处理</td></tr><tr><td>while read</td><td>find . &#124; while read f; do rm "$f"; done</td><td>中等</td><td>需要逐行自定义处理</td></tr></tbody></table></div><p>测试结果很直观：对于 10000 个文件的删除操作，xargs 比 <code>-exec</code> 快了约 5 倍，而加上 <code>-P 4</code> 并行后还能再快 2 倍。日常运维中这个差异还是很有感觉得。</p><h2 id="对最近几天的反思"><a href="#对最近几天的反思" class="headerlink" title="对最近几天的反思"></a>对最近几天的反思</h2><p>今天结束后，这三篇文章累计下来，博客上已经接近 80 篇原创了。从 6 月 6 号到今天 6 月 17 号，十二天时间产出这么多内容，数量上确实可观。但我也越来越意识到，<strong>质量比数量重要</strong>。</p><p>前期的文章偏”百科全书”风格——尽量覆盖一个工具的所有选项和功能。这种写法对新手友好，但缺乏个人实践的味道。最近几篇我尝试加入了更多”踩坑记录”和”亲自验证”的部分（比如 RabbitMQ 的 Erlang Cookie 权限、HAProxy 的 <code>leastconn</code> 验证），明显感觉写出来的内容更有温度，也更有参考价值。</p><p>不过今天写 xargs 的过程中也发现了一个遗憾——我应该把 <code>xargs -P</code> 和 <code>GNU Parallel</code> 做一个更详细的功能对比，但因为时间关系只能留到后面补充了。</p><h2 id="一个有趣的小发现"><a href="#一个有趣的小发现" class="headerlink" title="一个有趣的小发现"></a>一个有趣的小发现</h2><p>在写 HAProxy 文章时，我用它反向代理了我的博客做本地测试。当配置 <code>option forwardfor</code> 后，后端 Nginx 日志中终于显示的是真实客户端 IP 了，而不是 HAProxy 内网 IP。这件事虽然很小，但亲手验证一个配置生效的过程，确实比单纯”看文档懂了”要来得踏实。</p><h2 id="本周剩余计划"><a href="#本周剩余计划" class="headerlink" title="本周剩余计划"></a>本周剩余计划</h2><p>按之前的规划，接下来两天我想继续推进：</p><ol><li><strong>Kubernetes Ingress 和 Service 深入</strong> - 上周五搭建了集群，但网络部分还不够透彻</li><li><strong>博客搜索功能</strong> - 这两天调研了一下 Hexo 的搜索插件，准备试下 algolia 方案</li><li><strong>暗色模式细节</strong> - 之前的优化只是初步，还需要微调某些代码块和标签的颜色对比度</li></ol><p>今天就写到这里吧。窗外已经快下午三点了，趁着思路还清晰，继续去研究一下 K8s Service 的 <code>externalTrafficPolicy</code> 参数。</p><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-17-wednesday-afternoon-diary/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-17-wednesday-afternoon-diary/"/>
    <published>2026-06-17T06:40:00.000Z</published>
    <summary>
      <![CDATA[<p>今天是周三，从早晨忙到现在，终于可以坐下来整理一下这一天的收获。早上的日记里我提到正在推进容器化和 Linux 工具类的文章，没想到一转眼就到下午了，时间过得真快。</p>
<h2 id="上午：HAProxy-负载均衡的深入理解"><a href="#上午：HAProxy]]>
    </summary>
    <title>周三午后：负载均衡、消息队列与 Linux 工具箱的拼图</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="Linux" scheme="https://demo-blog.qusite.cn/tags/Linux/"/>
    <category term="命令行" scheme="https://demo-blog.qusite.cn/tags/%E5%91%BD%E4%BB%A4%E8%A1%8C/"/>
    <category term="xargs" scheme="https://demo-blog.qusite.cn/tags/xargs/"/>
    <category term="批处理" scheme="https://demo-blog.qusite.cn/tags/%E6%89%B9%E5%A4%84%E7%90%86/"/>
    <category term="Shell" scheme="https://demo-blog.qusite.cn/tags/Shell/"/>
    <content>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在 Linux 命令行中，管道（<code>|</code>）是连接命令的利器——它将前一个命令的标准输出传递给后一个命令的标准输入。但很多命令（如 <code>rm</code>、<code>cp</code>、<code>chmod</code>）并不从标准输入读取参数，而是需要命令行参数。<code>xargs</code> 正是解决这个痛点的桥梁：它从标准输入读取数据，将其构造成命令行参数传递给其他命令执行。</p><p><code>xargs</code> 可以说是 Linux 管道操作中最被低估但最强大的工具之一，本文将带你从入门到精通全面掌握 xargs。</p><h2 id="一、核心概念与工作原理"><a href="#一、核心概念与工作原理" class="headerlink" title="一、核心概念与工作原理"></a>一、核心概念与工作原理</h2><h3 id="1-1-xargs-做什么？"><a href="#1-1-xargs-做什么？" class="headerlink" title="1.1 xargs 做什么？"></a>1.1 xargs 做什么？</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 不使用 xargs——这行不起作用，因为 rm 不从 stdin 读</span></span><br><span class="line">find /tmp -name <span class="string">&quot;*.log&quot;</span> | <span class="built_in">rm</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用 xargs——正确！xargs 将文件名作为参数传递给 rm</span></span><br><span class="line">find /tmp -name <span class="string">&quot;*.log&quot;</span> | xargs <span class="built_in">rm</span></span><br></pre></td></tr></table></figure></div><h3 id="1-2-工作流程"><a href="#1-2-工作流程" class="headerlink" title="1.2 工作流程"></a>1.2 工作流程</h3><ol><li>从标准输入（stdin）读取数据（通常是带分隔符的文本）</li><li>将输入按<strong>分隔符</strong>分割成多个参数</li><li>将这些参数追加到指定命令的末尾</li><li>执行命令</li><li>如果参数数量超过系统限制（<code>getconf ARG_MAX</code>，通常 2MB），自动分批执行</li></ol><h3 id="1-3-命令语法"><a href="#1-3-命令语法" class="headerlink" title="1.3 命令语法"></a>1.3 命令语法</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xargs [选项] [命令 [初始参数]]</span><br></pre></td></tr></table></figure></div><p>如果不指定命令，默认使用 <code>echo</code>。</p><h2 id="二、基础用法与核心选项"><a href="#二、基础用法与核心选项" class="headerlink" title="二、基础用法与核心选项"></a>二、基础用法与核心选项</h2><h3 id="2-1-基本示例"><a href="#2-1-基本示例" class="headerlink" title="2.1 基本示例"></a>2.1 基本示例</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 等价于 echo &quot;a b c&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;a b c&quot;</span> | xargs</span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除 /tmp 下所有 .tmp 文件</span></span><br><span class="line"><span class="built_in">ls</span> /tmp/*.tmp | xargs <span class="built_in">rm</span></span><br></pre></td></tr></table></figure></div><h3 id="2-2-核心选项详解"><a href="#2-2-核心选项详解" class="headerlink" title="2.2 核心选项详解"></a>2.2 核心选项详解</h3><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>选项</th><th>说明</th><th>示例</th></tr></thead><tbody><tr><td><code>-0</code> 或 <code>--null</code></td><td>以空字符（null）作为分隔符，而非空格/换行。配合 <code>find -print0</code> 处理含空格的文件名</td><td><code>find . -name "*.txt" -print0 | xargs -0 rm</code></td></tr><tr><td><code>-d</code> 或 <code>--delimiter</code></td><td>指定自定义分隔符</td><td><code>echo "a:b:c" | xargs -d: echo</code></td></tr><tr><td><code>-n</code> 或 <code>--max-args</code></td><td>每次执行传递给命令的最大参数个数</td><td><code>echo "1 2 3 4 5" | xargs -n 2 echo</code></td></tr><tr><td><code>-I</code></td><td>指定替换字符串，常用于将参数放在命令中间位置</td><td><code>find . -name "*.txt" | xargs -I &#123;&#125; cp &#123;&#125; /backup/</code></td></tr><tr><td><code>-P</code> 或 <code>--max-procs</code></td><td>并行执行的最大进程数</td><td><code>cat urls.txt | xargs -P 4 -I &#123;&#125; curl -O &#123;&#125;</code></td></tr><tr><td><code>-r</code> 或 <code>--no-run-if-empty</code></td><td>输入为空时不执行命令（GNU xargs 默认行为）</td><td><code>find . -name "*.bak" | xargs -r rm</code></td></tr><tr><td><code>-t</code> 或 <code>--verbose</code></td><td>在命令执行前先打印命令本身（调试用）</td><td><code>find . -name "*.tmp" | xargs -t rm</code></td></tr><tr><td><code>-p</code> 或 <code>--interactive</code></td><td>每次执行前提示确认</td><td><code>find . -name "*.log" | xargs -p rm</code></td></tr><tr><td><code>-s</code> 或 <code>--max-chars</code></td><td>每次执行命令的最大字符数（含命令和参数）</td><td><code>xargs -s 1024 echo</code></td></tr><tr><td><code>--show-limits</code></td><td>显示系统参数限制</td><td><code>xargs --show-limits</code></td></tr></tbody></table></div><h2 id="三、实战场景"><a href="#三、实战场景" class="headerlink" title="三、实战场景"></a>三、实战场景</h2><h3 id="场景-1：批量删除文件（安全处理文件名中的空格）"><a href="#场景-1：批量删除文件（安全处理文件名中的空格）" class="headerlink" title="场景 1：批量删除文件（安全处理文件名中的空格）"></a>场景 1：批量删除文件（安全处理文件名中的空格）</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 错误：文件名含空格会导致 rm 出错</span></span><br><span class="line">find . -name <span class="string">&quot;*.log&quot;</span> | xargs <span class="built_in">rm</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 正确：-print0 和 -0 配合，以 \0 分隔</span></span><br><span class="line">find . -name <span class="string">&quot;*.log&quot;</span> -print0 | xargs -0 <span class="built_in">rm</span></span><br></pre></td></tr></table></figure></div><p><strong>为什么需要 <code>-print0</code>？</strong> 当文件名含有空格时，<code>xargs</code> 默认按空格和换行分割，会将 <code>my file.log</code> 拆成 <code>my</code> 和 <code>file.log</code> 两个参数。<code>-print0</code> 使用空字符（<code>\0</code>）作为分隔符，是唯一安全的做法。</p><h3 id="场景-2：批量打包备份"><a href="#场景-2：批量打包备份" class="headerlink" title="场景 2：批量打包备份"></a>场景 2：批量打包备份</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 将 /var/log 下 7 天前的 .log 文件打包</span></span><br><span class="line">find /var/log -name <span class="string">&quot;*.log&quot;</span> -mtime +7 -print0 | xargs -0 tar -czf old-logs.tar.gz</span><br></pre></td></tr></table></figure></div><h3 id="场景-3：批量修改文件权限"><a href="#场景-3：批量修改文件权限" class="headerlink" title="场景 3：批量修改文件权限"></a>场景 3：批量修改文件权限</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 将所有 .sh 脚本设置为可执行</span></span><br><span class="line">find . -name <span class="string">&quot;*.sh&quot;</span> -print0 | xargs -0 <span class="built_in">chmod</span> +x</span><br><span class="line"></span><br><span class="line"><span class="comment"># 批量将 .html 文件权限设为 644</span></span><br><span class="line">find /var/www -name <span class="string">&quot;*.html&quot;</span> -print0 | xargs -0 <span class="built_in">chmod</span> 644</span><br></pre></td></tr></table></figure></div><h3 id="场景-4：批量压缩图片"><a href="#场景-4：批量压缩图片" class="headerlink" title="场景 4：批量压缩图片"></a>场景 4：批量压缩图片</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用 -I 将参数放在命令中间</span></span><br><span class="line">find ./images -name <span class="string">&quot;*.jpg&quot;</span> -print0 | xargs -0 -I &#123;&#125; convert &#123;&#125; -quality 80% &#123;&#125;.compressed.jpg</span><br></pre></td></tr></table></figure></div><h3 id="场景-5：批量搜索文件内容（结合-grep）"><a href="#场景-5：批量搜索文件内容（结合-grep）" class="headerlink" title="场景 5：批量搜索文件内容（结合 grep）"></a>场景 5：批量搜索文件内容（结合 grep）</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 统计各 .log 文件中 &quot;ERROR&quot; 出现次数</span></span><br><span class="line">find /var/log -name <span class="string">&quot;*.log&quot;</span> -print0 | xargs -0 -I &#123;&#125; sh -c <span class="string">&#x27;echo &quot;&#123;&#125;: $(grep -c ERROR &quot;&#123;&#125;&quot;)&quot;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 更简洁的写法：在多个文件中搜索</span></span><br><span class="line">find /var/log -name <span class="string">&quot;*.log&quot;</span> -print0 | xargs -0 grep <span class="string">&quot;ERROR&quot;</span></span><br></pre></td></tr></table></figure></div><h3 id="场景-6：并行下载加速"><a href="#场景-6：并行下载加速" class="headerlink" title="场景 6：并行下载加速"></a>场景 6：并行下载加速</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 从文件读取 URL 列表，并行 8 个进程下载</span></span><br><span class="line"><span class="built_in">cat</span> download-list.txt | xargs -P 8 -I &#123;&#125; wget -c &#123;&#125;</span><br></pre></td></tr></table></figure></div><h3 id="场景-7：批量重命名文件"><a href="#场景-7：批量重命名文件" class="headerlink" title="场景 7：批量重命名文件"></a>场景 7：批量重命名文件</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 将所有 .txt 改为 .md</span></span><br><span class="line"><span class="built_in">ls</span> *.txt | sed <span class="string">&#x27;s/\.txt$//&#x27;</span> | xargs -I &#123;&#125; <span class="built_in">mv</span> &#123;&#125;.txt &#123;&#125;.md</span><br></pre></td></tr></table></figure></div><h3 id="场景-8：逐行处理（每行一个命令）"><a href="#场景-8：逐行处理（每行一个命令）" class="headerlink" title="场景 8：逐行处理（每行一个命令）"></a>场景 8：逐行处理（每行一个命令）</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 逐行输出内容（等同于 while read line）</span></span><br><span class="line"><span class="built_in">cat</span> file.txt | xargs -n 1 <span class="built_in">echo</span></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> usernames.txt | xargs -n 1 useradd -m -s /bin/bash</span><br></pre></td></tr></table></figure></div><h3 id="场景-9：配合-find-执行复杂操作"><a href="#场景-9：配合-find-执行复杂操作" class="headerlink" title="场景 9：配合 find 执行复杂操作"></a>场景 9：配合 find 执行复杂操作</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 将参数放在命令的中间位置（使用 -I 指定占位符）</span></span><br><span class="line">find /opt -name <span class="string">&quot;*.conf&quot;</span> -print0 | xargs -0 -I % <span class="built_in">cp</span> % /backup/conf/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在多目录中执行命令</span></span><br><span class="line">find /projects -maxdepth 1 -<span class="built_in">type</span> d -print0 | xargs -0 -I &#123;&#125; sh -c <span class="string">&#x27;cd &quot;&#123;&#125;&quot; &amp;&amp; git pull&#x27;</span></span><br></pre></td></tr></table></figure></div><h3 id="场景-10：批量校验文件"><a href="#场景-10：批量校验文件" class="headerlink" title="场景 10：批量校验文件"></a>场景 10：批量校验文件</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 为所有 .iso 文件生成 MD5 校验</span></span><br><span class="line">find . -name <span class="string">&quot;*.iso&quot;</span> -print0 | xargs -0 -I &#123;&#125; <span class="built_in">md5sum</span> <span class="string">&quot;&#123;&#125;&quot;</span> &gt; checksums.md5</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证校验</span></span><br><span class="line"><span class="built_in">md5sum</span> -c checksums.md5</span><br></pre></td></tr></table></figure></div><h2 id="四、高级用法"><a href="#四、高级用法" class="headerlink" title="四、高级用法"></a>四、高级用法</h2><h3 id="4-1-自定义分隔符"><a href="#4-1-自定义分隔符" class="headerlink" title="4.1 自定义分隔符"></a>4.1 自定义分隔符</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 以冒号分隔</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;user1:user2:user3&quot;</span> | xargs -d: -n 1 <span class="built_in">echo</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 处理 CSV 第一列</span></span><br><span class="line"><span class="built_in">cut</span> -d<span class="string">&#x27;,&#x27;</span> -f1 data.csv | xargs -I &#123;&#125; <span class="built_in">echo</span> <span class="string">&quot;Processing: &#123;&#125;&quot;</span></span><br></pre></td></tr></table></figure></div><h3 id="4-2-并行处理控制"><a href="#4-2-并行处理控制" class="headerlink" title="4.2 并行处理控制"></a>4.2 并行处理控制</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 下载 10 个文件，最多 3 个同时下载</span></span><br><span class="line"><span class="built_in">seq</span> 1 10 | xargs -P 3 -I &#123;&#125; <span class="built_in">echo</span> <span class="string">&quot;Downloading file_&#123;&#125;.zip&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 真实场景：批量压缩 8 个并行</span></span><br><span class="line">find . -name <span class="string">&quot;*.txt&quot;</span> -print0 | xargs -0 -P $(<span class="built_in">nproc</span>) -I &#123;&#125; gzip <span class="string">&quot;&#123;&#125;&quot;</span></span><br></pre></td></tr></table></figure></div><h3 id="4-3-结合-sh-c-执行复杂逻辑"><a href="#4-3-结合-sh-c-执行复杂逻辑" class="headerlink" title="4.3 结合 sh -c 执行复杂逻辑"></a>4.3 结合 sh -c 执行复杂逻辑</h3><p>当需要执行多条命令时，可以通过 <code>sh -c</code> 组合：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 每条命令执行多个操作</span></span><br><span class="line">find . -name <span class="string">&quot;*.txt&quot;</span> -print0 | xargs -0 -I &#123;&#125; sh -c <span class="string">&#x27;</span></span><br><span class="line"><span class="string">    echo &quot;Processing: $1&quot;</span></span><br><span class="line"><span class="string">    wc -l &quot;$1&quot;</span></span><br><span class="line"><span class="string">    gzip &quot;$1&quot;</span></span><br><span class="line"><span class="string">    echo &quot;Done: $1.gz&quot;</span></span><br><span class="line"><span class="string">&#x27;</span> -- &#123;&#125;</span><br></pre></td></tr></table></figure></div><h3 id="4-4-显示系统限制"><a href="#4-4-显示系统限制" class="headerlink" title="4.4 显示系统限制"></a>4.4 显示系统限制</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">$ xargs --show-limits</span><br><span class="line">Your environment variables take up 4230 bytes</span><br><span class="line">POSIX upper <span class="built_in">limit</span> on argument length (this system): 2092688</span><br><span class="line">POSIX smallest allowable upper <span class="built_in">limit</span> on argument length (all systems): 4096</span><br><span class="line">Maximum length of <span class="built_in">command</span> we could actually use: 2088458</span><br><span class="line">Size of <span class="built_in">command</span> buffer we are actually using: 131072</span><br><span class="line">Maximum parallelism (--max-procs) must be &lt;= 1000000</span><br></pre></td></tr></table></figure></div><h3 id="4-5-命令执行统计"><a href="#4-5-命令执行统计" class="headerlink" title="4.5 命令执行统计"></a>4.5 命令执行统计</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 结合 time 统计每条命令执行时间</span></span><br><span class="line">find . -name <span class="string">&quot;*.tar.gz&quot;</span> -print0 | xargs -0 -I &#123;&#125; sh -c <span class="string">&#x27;time tar -xzf &quot;&#123;&#125;&quot;&#x27;</span></span><br></pre></td></tr></table></figure></div><h2 id="五、常见问题排查"><a href="#五、常见问题排查" class="headerlink" title="五、常见问题排查"></a>五、常见问题排查</h2><div class="opt-table"><table><thead><tr><th>问题</th><th>原因</th><th>解决方案</th></tr></thead><tbody><tr><td>文件名含空格报错</td><td>xargs 默认按空格/换行分割</td><td>使用 <code>find ... -print0 | xargs -0</code></td></tr><tr><td>"Argument list too long"</td><td>单次执行参数过多超出 ARG_MAX</td><td>xargs 会自动分批；或使用 <code>-n</code> 控制每批数量</td></tr><tr><td>命令未找到</td><td>传递的参数包含特殊字符（如引号、$）</td><td>使用 <code>-I</code> 配合引号包裹，或通过 <code>sh -c</code> 执行</td></tr><tr><td>文件名包含换行符</td><td>极罕见的极端情况</td><td>唯一安全的做法是 <code>-print0 | xargs -0</code></td></tr><tr><td>No such file or directory</td><td>参数末尾有多余空格/换行</td><td>用 <code>-0</code> 或检查输入源</td></tr><tr><td>xargs: unmatched single quote</td><td>文件名包含单引号</td><td>使用 <code>-0</code> 模式彻底规避</td></tr><tr><td>运行太慢</td><td>默认是串行执行</td><td>使用 <code>-P</code> 参数启用并行</td></tr><tr><td>输入为空时错误</td><td>某些旧版本在无输入时也会执行</td><td>使用 <code>-r</code> 或 <code>--no-run-if-empty</code></td></tr></tbody></table></div><h2 id="六、xargs-与其他命令对比"><a href="#六、xargs-与其他命令对比" class="headerlink" title="六、xargs 与其他命令对比"></a>六、xargs 与其他命令对比</h2><h3 id="6-1-xargs-vs-find-exec"><a href="#6-1-xargs-vs-find-exec" class="headerlink" title="6.1 xargs vs find -exec"></a>6.1 xargs vs find -exec</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 方式 1：find -exec（每个文件启动一个进程）</span></span><br><span class="line">find . -name <span class="string">&quot;*.txt&quot;</span> -<span class="built_in">exec</span> <span class="built_in">rm</span> &#123;&#125; \;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 方式 2：find -exec +（尽可能合并参数）</span></span><br><span class="line">find . -name <span class="string">&quot;*.txt&quot;</span> -<span class="built_in">exec</span> <span class="built_in">rm</span> &#123;&#125; +</span><br><span class="line"></span><br><span class="line"><span class="comment"># 方式 3：xargs（类似但更灵活）</span></span><br><span class="line">find . -name <span class="string">&quot;*.txt&quot;</span> -print0 | xargs -0 <span class="built_in">rm</span></span><br></pre></td></tr></table></figure></div><div class="opt-table"><table><thead><tr><th>对比项</th><th><code>find -exec ... \;</code></th><th><code>find -exec ... +</code></th><th><code>xargs</code></th></tr></thead><tbody><tr><td>进程数</td><td>每个文件一个进程（效率最低）</td><td>尽量合并（效率较好）</td><td>自动合并（效率高）</td></tr><tr><td>参数位置</td><td><code>&#123;&#125;</code> 可放在任意位置</td><td><code>&#123;&#125;</code> 只能在命令末尾</td><td>默认末尾，<code>-I</code> 可放任意位置</td></tr><tr><td>并行支持</td><td>不支持</td><td>不支持</td><td>支持 <code>-P</code></td></tr><tr><td>自定义分隔符</td><td>不支持</td><td>不支持</td><td>支持 <code>-d</code></td></tr><tr><td>交互确认</td><td>不支持</td><td>不支持</td><td>支持 <code>-p</code></td></tr><tr><td>批量调试</td><td>不支持</td><td>不支持</td><td>支持 <code>-t</code></td></tr></tbody></table></div><h3 id="6-2-xargs-vs-while-read-循环"><a href="#6-2-xargs-vs-while-read-循环" class="headerlink" title="6.2 xargs vs while read 循环"></a>6.2 xargs vs while read 循环</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># xargs 方式（简洁）</span></span><br><span class="line">find . -name <span class="string">&quot;*.txt&quot;</span> -print0 | xargs -0 <span class="built_in">wc</span> -l</span><br><span class="line"></span><br><span class="line"><span class="comment"># while read 方式（灵活但繁琐）</span></span><br><span class="line">find . -name <span class="string">&quot;*.txt&quot;</span> -print0 | <span class="keyword">while</span> IFS= <span class="built_in">read</span> -r -d <span class="string">&#x27;&#x27;</span> file; <span class="keyword">do</span></span><br><span class="line">    <span class="built_in">wc</span> -l <span class="string">&quot;<span class="variable">$file</span>&quot;</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure></div><p><strong>选型建议</strong>：</p><ul><li>简单批量操作 → <code>xargs</code></li><li>需要复杂条件判断或变量操作 → <code>while read</code></li><li>需要并行执行 → <code>xargs -P</code></li></ul><h2 id="七、安全最佳实践"><a href="#七、安全最佳实践" class="headerlink" title="七、安全最佳实践"></a>七、安全最佳实践</h2><h3 id="7-1-始终使用-0-处理文件列表"><a href="#7-1-始终使用-0-处理文件列表" class="headerlink" title="7.1 始终使用 -0 处理文件列表"></a>7.1 始终使用 -0 处理文件列表</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># ✅ 正确：安全处理任意文件名</span></span><br><span class="line">find . -<span class="built_in">type</span> f -print0 | xargs -0 <span class="built_in">rm</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ❌ 错误：文件名含空格时会出错</span></span><br><span class="line">find . -<span class="built_in">type</span> f | xargs <span class="built_in">rm</span></span><br></pre></td></tr></table></figure></div><h3 id="7-2-先测试再执行"><a href="#7-2-先测试再执行" class="headerlink" title="7.2 先测试再执行"></a>7.2 先测试再执行</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 先看将要删除哪些文件</span></span><br><span class="line">find . -name <span class="string">&quot;*.tmp&quot;</span> -print0 | xargs -0 -I &#123;&#125; <span class="built_in">echo</span> <span class="string">&quot;Will delete: &#123;&#125;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用 -p 交互确认模式</span></span><br><span class="line">find . -name <span class="string">&quot;*.tmp&quot;</span> -print0 | xargs -0 -p <span class="built_in">rm</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用 -t 打印将要执行的命令</span></span><br><span class="line">find . -name <span class="string">&quot;*.tmp&quot;</span> -print0 | xargs -0 -t <span class="built_in">rm</span></span><br></pre></td></tr></table></figure></div><h3 id="7-3-注意注入风险"><a href="#7-3-注意注入风险" class="headerlink" title="7.3 注意注入风险"></a>7.3 注意注入风险</h3><p>当 xargs 的输入来源不可控时，需注意命令注入风险：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 危险！如果文件名是 ; rm -rf / 会怎样？</span></span><br><span class="line"><span class="comment"># 但实际上 -print0 | xargs -0 会将整个文件名作为单一参数，比较安全</span></span><br></pre></td></tr></table></figure></div><h3 id="7-4-合理设置并行度"><a href="#7-4-合理设置并行度" class="headerlink" title="7.4 合理设置并行度"></a>7.4 合理设置并行度</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 设置与 CPU 核心数相同的并行度</span></span><br><span class="line">find . -name <span class="string">&quot;*.txt&quot;</span> -print0 | xargs -0 -P $(<span class="built_in">nproc</span>) -I &#123;&#125; gzip &#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 避免 IO 过载，对于磁盘密集型任务可减少到核心数的一半</span></span><br><span class="line">find . -name <span class="string">&quot;*.txt&quot;</span> -print0 | xargs -0 -P $(( $(nproc) / <span class="number">2</span> )) -I &#123;&#125; gzip &#123;&#125;</span><br></pre></td></tr></table></figure></div><h2 id="八、命令速查表"><a href="#八、命令速查表" class="headerlink" title="八、命令速查表"></a>八、命令速查表</h2><div class="opt-table"><table><thead><tr><th>场景</th><th>命令</th></tr></thead><tbody><tr><td>批量删除文件（安全）</td><td><code>find . -name "*.log" -print0 | xargs -0 rm -f</code></td></tr><tr><td>逐行打印</td><td><code>cat list.txt | xargs -n 1 echo</code></td></tr><tr><td>批量复制到目录</td><td><code>find . -name "*.txt" -print0 | xargs -0 -I &#123;&#125; cp &#123;&#125; /backup/</code></td></tr><tr><td>批量移动</td><td><code>find . -name "*.tmp" -print0 | xargs -0 -I &#123;&#125; mv &#123;&#125; /tmp/</code></td></tr><tr><td>批量修改权限</td><td><code>find . -name "*.sh" -print0 | xargs -0 chmod +x</code></td></tr><tr><td>批量打包</td><td><code>find . -name "*.txt" -print0 | xargs -0 tar -czf texts.tar.gz</code></td></tr><tr><td>批量压缩</td><td><code>find . -name "*.log" -print0 | xargs -0 -P 4 gzip</code></td></tr><tr><td>并行下载</td><td><code>cat urls.txt | xargs -P 8 -I &#123;&#125; wget -c &#123;&#125;</code></td></tr><tr><td>批量搜索内容</td><td><code>find . -name "*.py" -print0 | xargs -0 grep "TODO"</code></td></tr><tr><td>自定义分隔符</td><td><code>echo "a:b:c" | xargs -d: -n 1 echo</code></td></tr><tr><td>批量 Git 操作</td><td><code>find /repos -maxdepth 1 -type d -print0 | xargs -0 -I &#123;&#125; sh -c 'cd "&#123;&#125;" && git pull'</code></td></tr><tr><td>统计各文件行数</td><td><code>find . -name "*.md" -print0 | xargs -0 wc -l</code></td></tr></tbody></table></div><h2 id="九、总结"><a href="#九、总结" class="headerlink" title="九、总结"></a>九、总结</h2><p><code>xargs</code> 是 Linux 管道生态中的关键一环，它将文本流转化为命令参数，使得 find、grep 等命令可以与其他命令无缝协作。掌握 xargs 的核心在于理解几点：</p><ol><li><strong>分隔符选择</strong>：处理文件始终使用 <code>-print0 | xargs -0</code> 组合</li><li><strong>参数位置</strong>：默认追加末尾，<code>-I</code> 可指定任意位置</li><li><strong>批量控制</strong>：<code>-n</code> 控制每批参数数，<code>-P</code> 控制并行度</li><li><strong>安全先行</strong>：<code>-p</code> 交互确认、<code>-t</code> 打印命令、先 <code>echo</code> 测试</li></ol><p>将 xargs 与 find、grep、sed 等命令搭配使用，可以构建出简洁而强大的管道命令，极大提升 Linux 运维效率。</p><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-17-xargs-command-guide/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-17-xargs-command-guide/"/>
    <published>2026-06-17T05:38:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在 Linux 命令行中，管道（<code>|</code>）是连接命令的利器——它将前一个命令的标准输出传递给后一个命令的标准输入。但很多]]>
    </summary>
    <title>Linux xargs 命令完全指南：参数传递与批量处理从入门到精通</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="环境搭建" scheme="https://demo-blog.qusite.cn/tags/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
    <category term="RabbitMQ" scheme="https://demo-blog.qusite.cn/tags/RabbitMQ/"/>
    <category term="消息队列" scheme="https://demo-blog.qusite.cn/tags/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/"/>
    <category term="AMQP" scheme="https://demo-blog.qusite.cn/tags/AMQP/"/>
    <category term="中间件" scheme="https://demo-blog.qusite.cn/tags/%E4%B8%AD%E9%97%B4%E4%BB%B6/"/>
    <content>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>RabbitMQ 是目前最流行的开源消息队列中间件之一，基于 AMQP 0-9-1 协议实现，广泛应用于微服务异步通信、任务队列分发、日志收集、事件驱动架构等场景。本文将详细介绍在 Ubuntu 22.04 上从零搭建 RabbitMQ 生产环境的完整流程。</p><h2 id="核心概念"><a href="#核心概念" class="headerlink" title="核心概念"></a>核心概念</h2><p>在开始部署之前，先了解 RabbitMQ 的核心概念：</p><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>概念</th><th>说明</th></tr></thead><tbody><tr><td>Producer（生产者）</td><td>发送消息的应用程序</td></tr><tr><td>Consumer（消费者）</td><td>接收和处理消息的应用程序</td></tr><tr><td>Queue（队列）</td><td>存储消息的缓冲区，RabbitMQ 的核心数据结构</td></tr><tr><td>Exchange（交换机）</td><td>接收生产者消息并根据路由规则分发到队列</td></tr><tr><td>Binding（绑定）</td><td>交换机与队列之间的关联关系，包含 routing key</td></tr><tr><td>Virtual Host（虚拟主机）</td><td>逻辑隔离单元，每个 vhost 拥有独立的 Exchange/Queue/Binding</td></tr><tr><td>Channel（信道）</td><td>在 TCP 连接上建立的轻量级复用通道</td></tr></tbody></table></div><h3 id="交换机类型"><a href="#交换机类型" class="headerlink" title="交换机类型"></a>交换机类型</h3><div class="opt-table"><table><thead><tr><th>类型</th><th>路由规则</th><th>适用场景</th></tr></thead><tbody><tr><td>Direct</td><td>routing key 精确匹配</td><td>单播、点对点消息</td></tr><tr><td>Topic</td><td>routing key 通配符匹配（* 匹配一个词，# 匹配零或多个词）</td><td>发布订阅、按主题路由</td></tr><tr><td>Fanout</td><td>忽略 routing key，广播到所有绑定队列</td><td>广播消息、日志分发</td></tr><tr><td>Headers</td><td>根据消息头属性匹配</td><td>多条件路由</td></tr></tbody></table></div><h2 id="安装-RabbitMQ"><a href="#安装-RabbitMQ" class="headerlink" title="安装 RabbitMQ"></a>安装 RabbitMQ</h2><h3 id="方式一：使用官方-APT-源安装（推荐）"><a href="#方式一：使用官方-APT-源安装（推荐）" class="headerlink" title="方式一：使用官方 APT 源安装（推荐）"></a>方式一：使用官方 APT 源安装（推荐）</h3><p>RabbitMQ 依赖 Erlang&#x2F;OTP，建议使用官方仓库确保版本兼容。</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 导入 Erlang 和 RabbitMQ 签名密钥</span></span><br><span class="line">curl -fsSL https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc | <span class="built_in">sudo</span> gpg --dearmor -o /usr/share/keyrings/rabbitmq-archive-keyring.gpg</span><br><span class="line">curl -fsSL https://packagecloud.io/rabbitmq/erlang/gpgkey | <span class="built_in">sudo</span> gpg --dearmor -o /usr/share/keyrings/rabbitmq-erlang-archive-keyring.gpg</span><br><span class="line">curl -fsSL https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey | <span class="built_in">sudo</span> gpg --dearmor -o /usr/share/keyrings/rabbitmq-server-archive-keyring.gpg</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 添加 APT 源</span></span><br><span class="line"><span class="built_in">cat</span> &lt;&lt; <span class="string">&#x27;EOF&#x27;</span> | <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/apt/sources.list.d/rabbitmq.list</span><br><span class="line">deb [signed-by=/usr/share/keyrings/rabbitmq-erlang-archive-keyring.gpg] https://packagecloud.io/rabbitmq/erlang/ubuntu/ jammy main</span><br><span class="line">deb [signed-by=/usr/share/keyrings/rabbitmq-erlang-archive-keyring.gpg] https://packagecloud.io/rabbitmq/erlang/ubuntu/ jammy-updates main</span><br><span class="line">deb [signed-by=/usr/share/keyrings/rabbitmq-server-archive-keyring.gpg] https://packagecloud.io/rabbitmq/rabbitmq-server/ubuntu/ jammy main</span><br><span class="line">deb [signed-by=/usr/share/keyrings/rabbitmq-server-archive-keyring.gpg] https://packagecloud.io/rabbitmq/rabbitmq-server/ubuntu/ jammy-updates main</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 安装</span></span><br><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install -y erlang-base erlang-asn1 erlang-crypto erlang-eldap erlang-ftp \</span><br><span class="line">  erlang-inets erlang-mnesia erlang-os-mon erlang-parsetools erlang-public-key \</span><br><span class="line">  erlang-runtime-tools erlang-snmp erlang-ssl erlang-syntax-tools erlang-tftp \</span><br><span class="line">  erlang-tools erlang-xmerl rabbitmq-server</span><br></pre></td></tr></table></figure></div><h3 id="方式二：Docker-部署"><a href="#方式二：Docker-部署" class="headerlink" title="方式二：Docker 部署"></a>方式二：Docker 部署</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用 Docker Compose 部署</span></span><br><span class="line"><span class="built_in">mkdir</span> -p ~/rabbitmq &amp;&amp; <span class="built_in">cd</span> ~/rabbitmq</span><br><span class="line"></span><br><span class="line"><span class="built_in">cat</span> &lt;&lt; <span class="string">&#x27;EOF&#x27;</span> &gt; docker-compose.yml</span><br><span class="line">version: <span class="string">&quot;3.8&quot;</span></span><br><span class="line"></span><br><span class="line">services:</span><br><span class="line">  rabbitmq:</span><br><span class="line">    image: rabbitmq:3.13-management-alpine</span><br><span class="line">    container_name: rabbitmq</span><br><span class="line">    hostname: rabbitmq-node1</span><br><span class="line">    restart: unless-stopped</span><br><span class="line">    ports:</span><br><span class="line">      - <span class="string">&quot;5672:5672&quot;</span>    <span class="comment"># AMQP 协议端口</span></span><br><span class="line">      - <span class="string">&quot;15672:15672&quot;</span>  <span class="comment"># 管理控制台端口</span></span><br><span class="line">      - <span class="string">&quot;4369:4369&quot;</span>    <span class="comment"># Erlang 端口映射发现</span></span><br><span class="line">      - <span class="string">&quot;25672:25672&quot;</span>  <span class="comment"># 集群通信端口</span></span><br><span class="line">    volumes:</span><br><span class="line">      - ./data:/var/lib/rabbitmq</span><br><span class="line">      - ./config/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro</span><br><span class="line">      - ./logs:/var/log/rabbitmq</span><br><span class="line">    environment:</span><br><span class="line">      RABBITMQ_DEFAULT_USER: admin</span><br><span class="line">      RABBITMQ_DEFAULT_PASS: YourStrongPassword</span><br><span class="line">      RABBITMQ_DEFAULT_VHOST: /</span><br><span class="line">    healthcheck:</span><br><span class="line">      <span class="built_in">test</span>: [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;rabbitmq-diagnostics&quot;</span>, <span class="string">&quot;check_running&quot;</span>]</span><br><span class="line">      interval: 30s</span><br><span class="line">      <span class="built_in">timeout</span>: 10s</span><br><span class="line">      retries: 5</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建配置目录</span></span><br><span class="line"><span class="built_in">mkdir</span> -p config</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动</span></span><br><span class="line">docker compose up -d</span><br></pre></td></tr></table></figure></div><h2 id="服务管理"><a href="#服务管理" class="headerlink" title="服务管理"></a>服务管理</h2><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 启动/停止/重启</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl start rabbitmq-server</span><br><span class="line"><span class="built_in">sudo</span> systemctl stop rabbitmq-server</span><br><span class="line"><span class="built_in">sudo</span> systemctl restart rabbitmq-server</span><br><span class="line"><span class="built_in">sudo</span> systemctl status rabbitmq-server</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置开机自启</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl <span class="built_in">enable</span> rabbitmq-server</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看服务状态详情</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmq-diagnostics status</span><br><span class="line"><span class="built_in">sudo</span> rabbitmq-diagnostics check_running</span><br></pre></td></tr></table></figure></div><h2 id="核心配置文件"><a href="#核心配置文件" class="headerlink" title="核心配置文件"></a>核心配置文件</h2><p>RabbitMQ 配置文件位于 <code>/etc/rabbitmq/rabbitmq.conf</code>（新版）或 <code>/etc/rabbitmq/rabbitedmq.conf</code>（旧版）。以下是一个生产环境配置模板：</p><div class="code-container" data-rel="Ini"><figure class="iseeu highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># ===== 基础配置 =====</span></span><br><span class="line"><span class="comment"># 节点名称</span></span><br><span class="line"><span class="attr">cluster_name</span> = production-cluster</span><br><span class="line"><span class="comment"># 节点类型：disc（磁盘节点，保留持久化数据）| ram（内存节点）</span></span><br><span class="line"><span class="attr">cluster_formation.peer_discovery_backend</span> = rabbit_peer_discovery_classic_config</span><br><span class="line"><span class="attr">cluster_partition_handling</span> = pause_minority</span><br><span class="line"></span><br><span class="line"><span class="comment"># ===== 网络配置 =====</span></span><br><span class="line"><span class="attr">listeners.tcp.default</span> = <span class="number">5672</span></span><br><span class="line"><span class="attr">listeners.tcp.local</span> = <span class="number">127.0</span>.<span class="number">0.1</span>:<span class="number">5672</span></span><br><span class="line"><span class="comment"># 管理控制台监听地址</span></span><br><span class="line"><span class="attr">management.listener.port</span> = <span class="number">15672</span></span><br><span class="line"><span class="attr">management.listener.ssl</span> = <span class="literal">false</span></span><br><span class="line"><span class="attr">management.listener.ip</span> = <span class="number">0.0</span>.<span class="number">0.0</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ===== 资源限制 =====</span></span><br><span class="line"><span class="comment"># 内存阈值（占物理内存的百分比）</span></span><br><span class="line"><span class="attr">vm_memory_high_watermark.relative</span> = <span class="number">0.4</span></span><br><span class="line"><span class="comment"># 当内存超过 50% 时开始报警</span></span><br><span class="line"><span class="attr">vm_memory_high_watermark_paging_ratio</span> = <span class="number">0.5</span></span><br><span class="line"><span class="comment"># 磁盘可用空间下限（低于此值停止接受消息）</span></span><br><span class="line"><span class="attr">disk_free_limit.absolute</span> = <span class="number">2</span>GB</span><br><span class="line"><span class="comment"># 单连接最大信道数</span></span><br><span class="line"><span class="attr">channel_max</span> = <span class="number">2047</span></span><br><span class="line"><span class="comment"># 单连接最大帧大小（字节）</span></span><br><span class="line"><span class="attr">frame_max</span> = <span class="number">131072</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ===== 持久化与消息确认 =====</span></span><br><span class="line"><span class="comment"># 队列索引嵌入消息体（减少内存占用）</span></span><br><span class="line"><span class="attr">queue_index_embed_msgs_below</span> = <span class="number">4096</span></span><br><span class="line"><span class="comment"># 消息确认超时（毫秒）</span></span><br><span class="line"><span class="attr">consumer_timeout</span> = <span class="number">1800000</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ===== 日志配置 =====</span></span><br><span class="line"><span class="attr">log.file</span> = /var/log/rabbitmq/rabbitmq.log</span><br><span class="line"><span class="attr">log.file.level</span> = info</span><br><span class="line"><span class="attr">log.file.rotation.size</span> = <span class="number">104857600</span></span><br><span class="line"><span class="attr">log.file.rotation.count</span> = <span class="number">10</span></span><br><span class="line"><span class="attr">log.exchange</span> = <span class="literal">true</span></span><br></pre></td></tr></table></figure></div><h3 id="启用管理插件"><a href="#启用管理插件" class="headerlink" title="启用管理插件"></a>启用管理插件</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 启用 RabbitMQ Management 管理控制台</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmq-plugins <span class="built_in">enable</span> rabbitmq_management</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看已启用的插件</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmq-plugins list -e</span><br></pre></td></tr></table></figure></div><p>启用后访问 <code>http://your-server-ip:15672</code>，默认凭据 <code>guest/guest</code>（仅限 localhost 登录）。</p><h2 id="用户与虚拟主机管理"><a href="#用户与虚拟主机管理" class="headerlink" title="用户与虚拟主机管理"></a>用户与虚拟主机管理</h2><h3 id="用户管理"><a href="#用户管理" class="headerlink" title="用户管理"></a>用户管理</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建管理员用户</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl add_user admin YourStrongPassword</span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl set_user_tags admin administrator</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建普通用户</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl add_user app_user user_password</span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl set_user_tags app_user management</span><br><span class="line"></span><br><span class="line"><span class="comment"># 修改密码</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl change_password admin NewPassword</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看用户列表</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl list_users</span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除用户</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl delete_user guest</span><br></pre></td></tr></table></figure></div><h3 id="用户权限级别"><a href="#用户权限级别" class="headerlink" title="用户权限级别"></a>用户权限级别</h3><div class="opt-table"><table><thead><tr><th>标签</th><th>权限范围</th></tr></thead><tbody><tr><td>administrator</td><td>全部权限，包含策略管理、集群管理、用户管理</td></tr><tr><td>monitoring</td><td>查看节点信息与所有 vhost 的队列状态</td></tr><tr><td>management</td><td>访问 Web 管理界面，只能管理自己的连接和信道</td></tr><tr><td>policymaker</td><td>management 权限 + 管理策略和参数</td></tr><tr><td>operator</td><td>monitoring 权限 + 管理虚拟主机</td></tr></tbody></table></div><h3 id="虚拟主机管理"><a href="#虚拟主机管理" class="headerlink" title="虚拟主机管理"></a>虚拟主机管理</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建虚拟主机</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl add_vhost /myapp_dev</span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl add_vhost /myapp_prod</span><br><span class="line"></span><br><span class="line"><span class="comment"># 为用户分配虚拟主机权限</span></span><br><span class="line"><span class="comment"># 格式: set_permissions [-p vhost] user configure write read</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl set_permissions -p /myapp_dev admin <span class="string">&quot;.*&quot;</span> <span class="string">&quot;.*&quot;</span> <span class="string">&quot;.*&quot;</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl set_permissions -p /myapp_dev app_user <span class="string">&quot;^queue.*&quot;</span> <span class="string">&quot;^amq\\.topic&quot;</span> <span class="string">&quot;.*&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看虚拟主机列表</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl list_vhosts</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看特定虚拟主机的权限</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl list_permissions -p /myapp_dev</span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除虚拟主机</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl delete_vhost /old_vhost</span><br></pre></td></tr></table></figure></div><h2 id="队列与交换机实战操作"><a href="#队列与交换机实战操作" class="headerlink" title="队列与交换机实战操作"></a>队列与交换机实战操作</h2><h3 id="使用-rabbitmqadmin-命令行管理"><a href="#使用-rabbitmqadmin-命令行管理" class="headerlink" title="使用 rabbitmqadmin 命令行管理"></a>使用 rabbitmqadmin 命令行管理</h3><p>安装 rabbitmqadmin（基于 HTTP API 的命令行工具）：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 下载管理工具</span></span><br><span class="line">wget http://localhost:15672/cli/rabbitmqadmin</span><br><span class="line"><span class="built_in">chmod</span> +x rabbitmqadmin</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或直接使用 Python pip</span></span><br><span class="line">pip install rabbitmqadmin</span><br></pre></td></tr></table></figure></div><p>常用操作：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 声明交换机</span></span><br><span class="line">rabbitmqadmin <span class="built_in">declare</span> exchange name=order_events <span class="built_in">type</span>=topic durable=<span class="literal">true</span></span><br><span class="line">rabbitmqadmin <span class="built_in">declare</span> exchange name=notifications <span class="built_in">type</span>=fanout durable=<span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 声明队列</span></span><br><span class="line">rabbitmqadmin <span class="built_in">declare</span> queue name=order.created.queue durable=<span class="literal">true</span></span><br><span class="line">rabbitmqadmin <span class="built_in">declare</span> queue name=order.paid.queue durable=<span class="literal">true</span></span><br><span class="line">rabbitmqadmin <span class="built_in">declare</span> queue name=notification.queue durable=<span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 绑定队列到交换机</span></span><br><span class="line">rabbitmqadmin <span class="built_in">declare</span> binding <span class="built_in">source</span>=order_events destination=order.created.queue routing_key=order.created</span><br><span class="line">rabbitmqadmin <span class="built_in">declare</span> binding <span class="built_in">source</span>=order_events destination=order.paid.queue routing_key=order.paid</span><br><span class="line">rabbitmqadmin <span class="built_in">declare</span> binding <span class="built_in">source</span>=notifications destination=notification.queue</span><br><span class="line"></span><br><span class="line"><span class="comment"># 发布测试消息</span></span><br><span class="line">rabbitmqadmin publish exchange=order_events routing_key=order.created payload=<span class="string">&#x27;&#123;&quot;order_id&quot;: &quot;ORD-20260617-001&quot;, &quot;amount&quot;: 299.00&#125;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取队列消息</span></span><br><span class="line">rabbitmqadmin get queue=order.created.queue count=5</span><br><span class="line"></span><br><span class="line"><span class="comment"># 列出所有队列</span></span><br><span class="line">rabbitmqadmin list queues vhost name messages consumers</span><br></pre></td></tr></table></figure></div><h3 id="使用-rabbitmqctl-管理"><a href="#使用-rabbitmqctl-管理" class="headerlink" title="使用 rabbitmqctl 管理"></a>使用 rabbitmqctl 管理</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 列出所有队列及其状态</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl list_queues -p /myapp_dev name messages consumers memory</span><br><span class="line"></span><br><span class="line"><span class="comment"># 列出所有交换机</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl list_exchanges -p /myapp_dev name <span class="built_in">type</span> durable</span><br><span class="line"></span><br><span class="line"><span class="comment"># 列出绑定关系</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl list_bindings -p /myapp_dev</span><br><span class="line"></span><br><span class="line"><span class="comment"># 清空队列消息</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl purge_queue -p /myapp_dev order.created.queue</span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除队列</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl delete_queue -p /myapp_dev old.queue</span><br></pre></td></tr></table></figure></div><h2 id="高可用集群搭建"><a href="#高可用集群搭建" class="headerlink" title="高可用集群搭建"></a>高可用集群搭建</h2><h3 id="集群架构说明"><a href="#集群架构说明" class="headerlink" title="集群架构说明"></a>集群架构说明</h3><p>RabbitMQ 集群采用去中心化架构，所有节点平等。队列可以在一个或多个节点上镜像（Quorum Queue 模式）。</p><div class="code-container" data-rel="Ini"><figure class="iseeu highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 核心集群配置项</span></span><br><span class="line"><span class="attr">cluster_formation.peer_discovery_backend</span> = rabbit_peer_discovery_classic_config</span><br><span class="line"><span class="attr">cluster_formation.classic_config.nodes.1</span> = rabbit@node1</span><br><span class="line"><span class="attr">cluster_formation.classic_config.nodes.2</span> = rabbit@node2</span><br><span class="line"><span class="attr">cluster_formation.classic_config.nodes.3</span> = rabbit@node3</span><br></pre></td></tr></table></figure></div><h3 id="集群搭建步骤"><a href="#集群搭建步骤" class="headerlink" title="集群搭建步骤"></a>集群搭建步骤</h3><p><strong>前提条件</strong>：所有节点需满足以下条件：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 设置一致的 Erlang Cookie（集群通信密钥）</span></span><br><span class="line"><span class="comment"># 注意：三台节点的 cookie 必须完全一致</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl stop rabbitmq-server</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">cp</span> /var/lib/rabbitmq/.erlang.cookie /var/lib/rabbitmq/.erlang.cookie.bak</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;CLUSTER_SECRET_COOKIE_STRING&quot;</span> | <span class="built_in">sudo</span> <span class="built_in">tee</span> /var/lib/rabbitmq/.erlang.cookie</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">chmod</span> 400 /var/lib/rabbitmq/.erlang.cookie</span><br><span class="line"><span class="built_in">sudo</span> systemctl start rabbitmq-server</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 节点发现方式：hosts 文件或 DNS</span></span><br><span class="line"><span class="built_in">sudo</span> bash -c <span class="string">&#x27;echo &quot;10.0.1.10 node1&quot; &gt;&gt; /etc/hosts&#x27;</span></span><br><span class="line"><span class="built_in">sudo</span> bash -c <span class="string">&#x27;echo &quot;10.0.1.11 node2&quot; &gt;&gt; /etc/hosts&#x27;</span></span><br><span class="line"><span class="built_in">sudo</span> bash -c <span class="string">&#x27;echo &quot;10.0.1.12 node3&quot; &gt;&gt; /etc/hosts&#x27;</span></span><br></pre></td></tr></table></figure></div><p><strong>在 node2 上加入集群</strong>：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 停止 RabbitMQ 应用</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl stop_app</span><br><span class="line"></span><br><span class="line"><span class="comment"># 以 RAM 节点加入集群</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl join_cluster --ram rabbit@node1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动 RabbitMQ 应用</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl start_app</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看集群状态</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl cluster_status</span><br></pre></td></tr></table></figure></div><h3 id="镜像队列（Classic-Queue-Mirroring）"><a href="#镜像队列（Classic-Queue-Mirroring）" class="headerlink" title="镜像队列（Classic Queue Mirroring）"></a>镜像队列（Classic Queue Mirroring）</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 设置镜像策略：将匹配 pattern 的队列镜像到所有节点</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl set_policy ha-all <span class="string">&quot;^ha\.&quot;</span> <span class="string">&#x27;&#123;&quot;ha-mode&quot;:&quot;all&quot;,&quot;ha-sync-mode&quot;:&quot;automatic&quot;&#125;&#x27;</span> --priority 1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置镜像策略：镜像到集群中的两个节点</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl set_policy ha-two <span class="string">&quot;^critical\.&quot;</span> <span class="string">&#x27;&#123;&quot;ha-mode&quot;:&quot;exactly&quot;,&quot;ha-params&quot;:2,&quot;ha-sync-mode&quot;:&quot;automatic&quot;&#125;&#x27;</span> --priority 1</span><br></pre></td></tr></table></figure></div><h3 id="Quorum-Queue（推荐生产使用）"><a href="#Quorum-Queue（推荐生产使用）" class="headerlink" title="Quorum Queue（推荐生产使用）"></a>Quorum Queue（推荐生产使用）</h3><p>Quorum Queue 是 RabbitMQ 3.8+ 引入的基于 Raft 共识算法的队列类型，是官方推荐的生产方案：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 通过策略将队列转换为 Quorum Queue</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl set_policy qq-all <span class="string">&quot;^qq\.&quot;</span> <span class="string">&#x27;&#123;&quot;queue-type&quot;:&quot;quorum&quot;&#125;&#x27;</span> --priority 10 --apply-to queues</span><br></pre></td></tr></table></figure></div><h2 id="安全加固"><a href="#安全加固" class="headerlink" title="安全加固"></a>安全加固</h2><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 删除默认 guest 用户</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl delete_user guest</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 开启 TLS/SSL 加密通信</span></span><br><span class="line"><span class="comment"># 生成自签名证书（生产环境应使用 Let&#x27;s Encrypt 或商业 CA）</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/rabbitmq/ssl</span><br><span class="line"><span class="built_in">cd</span> /etc/rabbitmq/ssl</span><br><span class="line"><span class="comment"># 生成 CA 证书</span></span><br><span class="line"><span class="built_in">sudo</span> openssl req -x509 -newkey rsa:4096 -keyout ca-key.pem -out ca.pem -days 3650 -nodes -subj <span class="string">&quot;/CN=RabbitMQ-CA&quot;</span></span><br><span class="line"><span class="comment"># 生成服务端证书</span></span><br><span class="line"><span class="built_in">sudo</span> openssl req -newkey rsa:4096 -nodes -keyout server-key.pem -out server-req.pem -subj <span class="string">&quot;/CN=rabbitmq.example.com&quot;</span></span><br><span class="line"><span class="built_in">sudo</span> openssl x509 -req -<span class="keyword">in</span> server-req.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">chmod</span> 600 *.pem</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">chown</span> rabbitmq:rabbitmq *.pem</span><br><span class="line"><span class="comment"># rabbitmq.conf 中添加 TLS 配置</span></span><br><span class="line"><span class="comment"># listeners.ssl.default = 5671</span></span><br><span class="line"><span class="comment"># ssl_options.cacertfile = /etc/rabbitmq/ssl/ca.pem</span></span><br><span class="line"><span class="comment"># ssl_options.certfile = /etc/rabbitmq/ssl/server-cert.pem</span></span><br><span class="line"><span class="comment"># ssl_options.keyfile = /etc/rabbitmq/ssl/server-key.pem</span></span><br><span class="line"><span class="comment"># ssl_options.verify = verify_peer</span></span><br><span class="line"><span class="comment"># ssl_options.fail_if_no_peer_cert = true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 防火墙配置</span></span><br><span class="line"><span class="built_in">sudo</span> ufw allow 5672/tcp comment <span class="string">&#x27;RabbitMQ AMQP&#x27;</span></span><br><span class="line"><span class="built_in">sudo</span> ufw allow 15672/tcp comment <span class="string">&#x27;RabbitMQ Management&#x27;</span></span><br><span class="line"><span class="built_in">sudo</span> ufw allow 4369/tcp comment <span class="string">&#x27;Erlang Port Mapper&#x27;</span></span><br><span class="line"><span class="built_in">sudo</span> ufw allow 25672/tcp comment <span class="string">&#x27;RabbitMQ Cluster&#x27;</span></span><br><span class="line"><span class="built_in">sudo</span> ufw allow 5671/tcp comment <span class="string">&#x27;RabbitMQ AMQPS (TLS)&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 限制管理接口访问 IP</span></span><br><span class="line"><span class="comment"># rabbitmq.conf 添加：</span></span><br><span class="line"><span class="comment"># management.listener.ip = 127.0.0.1  # 或内网 IP</span></span><br><span class="line"><span class="comment"># 然后通过 Nginx 反向代理暴露</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 启用审计日志</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl trace_on -p /myapp_prod</span><br></pre></td></tr></table></figure></div><h2 id="消息确认机制"><a href="#消息确认机制" class="headerlink" title="消息确认机制"></a>消息确认机制</h2><h3 id="生产者确认（Publisher-Confirms）"><a href="#生产者确认（Publisher-Confirms）" class="headerlink" title="生产者确认（Publisher Confirms）"></a>生产者确认（Publisher Confirms）</h3><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> pika</span><br><span class="line"></span><br><span class="line"><span class="comment"># 连接 RabbitMQ</span></span><br><span class="line">connection = pika.BlockingConnection(</span><br><span class="line">    pika.ConnectionParameters(</span><br><span class="line">        host=<span class="string">&#x27;localhost&#x27;</span>,</span><br><span class="line">        credentials=pika.PlainCredentials(<span class="string">&#x27;admin&#x27;</span>, <span class="string">&#x27;YourStrongPassword&#x27;</span>)</span><br><span class="line">    )</span><br><span class="line">)</span><br><span class="line">channel = connection.channel()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启用发布者确认</span></span><br><span class="line">channel.confirm_delivery()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 声明队列</span></span><br><span class="line">channel.queue_declare(queue=<span class="string">&#x27;task_queue&#x27;</span>, durable=<span class="literal">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">    <span class="comment"># 发送消息并等待确认</span></span><br><span class="line">    channel.basic_publish(</span><br><span class="line">        exchange=<span class="string">&#x27;&#x27;</span>,</span><br><span class="line">        routing_key=<span class="string">&#x27;task_queue&#x27;</span>,</span><br><span class="line">        body=<span class="string">&#x27;Hello, RabbitMQ!&#x27;</span>,</span><br><span class="line">        properties=pika.BasicProperties(</span><br><span class="line">            delivery_mode=<span class="number">2</span>,  <span class="comment"># 持久化消息</span></span><br><span class="line">        ),</span><br><span class="line">        mandatory=<span class="literal">True</span></span><br><span class="line">    )</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;消息发送成功并已确认&quot;</span>)</span><br><span class="line"><span class="keyword">except</span> pika.exceptions.UnroutableError:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;消息无法路由到队列&quot;</span>)</span><br><span class="line"><span class="keyword">except</span> pika.exceptions.NackError:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;消息被服务器拒绝&quot;</span>)</span><br><span class="line"><span class="keyword">finally</span>:</span><br><span class="line">    connection.close()</span><br></pre></td></tr></table></figure></div><h3 id="消费者手动确认"><a href="#消费者手动确认" class="headerlink" title="消费者手动确认"></a>消费者手动确认</h3><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><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="keyword">import</span> pika</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">callback</span>(<span class="params">ch, method, properties, body</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;消息处理回调函数&quot;&quot;&quot;</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;收到消息: <span class="subst">&#123;body.decode()&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="comment"># 模拟业务处理</span></span><br><span class="line">        time.sleep(<span class="number">1</span>)</span><br><span class="line">        <span class="comment"># 手动确认消息处理完成</span></span><br><span class="line">        ch.basic_ack(delivery_tag=method.delivery_tag)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;消息处理完成，已确认&quot;</span>)</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;处理失败: <span class="subst">&#123;e&#125;</span>&quot;</span>)</span><br><span class="line">        <span class="comment"># 拒绝消息并重新入队</span></span><br><span class="line">        ch.basic_nack(delivery_tag=method.delivery_tag, requeue=<span class="literal">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 建立连接</span></span><br><span class="line">connection = pika.BlockingConnection(</span><br><span class="line">    pika.ConnectionParameters(</span><br><span class="line">        host=<span class="string">&#x27;localhost&#x27;</span>,</span><br><span class="line">        credentials=pika.PlainCredentials(<span class="string">&#x27;admin&#x27;</span>, <span class="string">&#x27;YourStrongPassword&#x27;</span>)</span><br><span class="line">    )</span><br><span class="line">)</span><br><span class="line">channel = connection.channel()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 声明队列（保证队列存在）</span></span><br><span class="line">channel.queue_declare(queue=<span class="string">&#x27;task_queue&#x27;</span>, durable=<span class="literal">True</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置预取计数（一次最多处理 1 条消息）</span></span><br><span class="line">channel.basic_qos(prefetch_count=<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 注册消费者（手动确认模式）</span></span><br><span class="line">channel.basic_consume(</span><br><span class="line">    queue=<span class="string">&#x27;task_queue&#x27;</span>,</span><br><span class="line">    on_message_callback=callback,</span><br><span class="line">    auto_ack=<span class="literal">False</span>  <span class="comment"># 手动确认</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;等待消息中...&quot;</span>)</span><br><span class="line">channel.start_consuming()</span><br></pre></td></tr></table></figure></div><h2 id="性能监控"><a href="#性能监控" class="headerlink" title="性能监控"></a>性能监控</h2><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 查看节点状态</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl status</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 查看内存使用情况</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl list_queues name messages memory</span><br><span class="line"><span class="built_in">sudo</span> rabbitmq-diagnostics memory_breakdown</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 查看连接和信道</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl list_connections name user peer_host port state</span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl list_channels connection pid consumer_count messages_unacknowledged</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 启用 Prometheus 指标暴露</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmq-plugins <span class="built_in">enable</span> rabbitmq_prometheus</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 查看消息速率</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmq-diagnostics observer</span><br><span class="line"></span><br><span class="line"><span class="comment"># 6. 流控查看</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl list_connections name user state channels fd_limit</span><br></pre></td></tr></table></figure></div><h3 id="Prometheus-Grafana-监控集成"><a href="#Prometheus-Grafana-监控集成" class="headerlink" title="Prometheus + Grafana 监控集成"></a>Prometheus + Grafana 监控集成</h3><p>在 <code>prometheus.yml</code> 中添加 RabbitMQ 抓取目标：</p><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="attr">scrape_configs:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">job_name:</span> <span class="string">&#x27;rabbitmq&#x27;</span></span><br><span class="line">    <span class="attr">static_configs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">targets:</span> [<span class="string">&#x27;localhost:15692&#x27;</span>]  <span class="comment"># Prometheus 插件端口</span></span><br><span class="line">    <span class="attr">metrics_path:</span> <span class="string">/metrics</span></span><br></pre></td></tr></table></figure></div><p>Grafana 推荐仪表板：RabbitMQ-Overview（ID: 10991）。</p><h2 id="备份与恢复"><a href="#备份与恢复" class="headerlink" title="备份与恢复"></a>备份与恢复</h2><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 导出配置定义（队列、交换机、绑定、用户、vhost）</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqadmin <span class="built_in">export</span> rabbitmq.config.json</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 导入配置定义</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqadmin import rabbitmq.config.json</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 使用 rabbitmqctl 备份</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl export_definitions /backup/rabbitmq-definitions-$(<span class="built_in">date</span> +%Y%m%d).json</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 恢复定义</span></span><br><span class="line"><span class="built_in">sudo</span> rabbitmqctl import_definitions /backup/rabbitmq-definitions-20260617.json</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 定时备份脚本</span></span><br><span class="line"><span class="built_in">cat</span> &lt;&lt; <span class="string">&#x27;SCRIPT&#x27;</span> | <span class="built_in">sudo</span> <span class="built_in">tee</span> /usr/local/bin/rabbitmq-backup.sh</span><br><span class="line"><span class="comment">#!/bin/bash</span></span><br><span class="line">BACKUP_DIR=<span class="string">&quot;/backup/rabbitmq&quot;</span></span><br><span class="line">DATE=$(<span class="built_in">date</span> +%Y%m%d_%H%M%S)</span><br><span class="line"><span class="built_in">mkdir</span> -p <span class="variable">$BACKUP_DIR</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 导出配置定义</span></span><br><span class="line">rabbitmqadmin <span class="built_in">export</span> <span class="variable">$BACKUP_DIR</span>/definitions_<span class="variable">$DATE</span>.json</span><br><span class="line"></span><br><span class="line"><span class="comment"># 导出数据目录快照（可选）</span></span><br><span class="line">tar czf <span class="variable">$BACKUP_DIR</span>/data_<span class="variable">$DATE</span>.tar.gz /var/lib/rabbitmq/mnesia/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 保留最近 30 天备份</span></span><br><span class="line">find <span class="variable">$BACKUP_DIR</span> -name <span class="string">&quot;definitions_*.json&quot;</span> -mtime +30 -delete</span><br><span class="line">find <span class="variable">$BACKUP_DIR</span> -name <span class="string">&quot;data_*.tar.gz&quot;</span> -mtime +7 -delete</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[<span class="subst">$(date)</span>] RabbitMQ 备份完成: definitions_<span class="variable">$DATE</span>.json&quot;</span></span><br><span class="line">SCRIPT</span><br><span class="line"></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">chmod</span> +x /usr/local/bin/rabbitmq-backup.sh</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加定时任务（每天凌晨 3 点）</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;0 3 * * * /usr/local/bin/rabbitmq-backup.sh&quot;</span> | <span class="built_in">sudo</span> crontab -</span><br></pre></td></tr></table></figure></div><h2 id="常见问题排查"><a href="#常见问题排查" class="headerlink" title="常见问题排查"></a>常见问题排查</h2><div class="opt-table"><table><thead><tr><th>问题</th><th>可能原因</th><th>解决方法</th></tr></thead><tbody><tr><td>连接被拒绝 (ECONNREFUSED)</td><td>服务未启动或端口未开放</td><td>检查 systemctl status、防火墙规则、监听地址</td></tr><tr><td>认证失败 (auth failure)</td><td>用户名或密码错误</td><td>检查凭据，确认用户存在且密码正确</td></tr><tr><td>内存报警 (ALARM)</td><td>内存使用超过 vm_memory_high_watermark</td><td>检查 memory_breakdown，增加内存或降低水位线</td></tr><tr><td>磁盘报警 (ALARM)</td><td>磁盘空间低于 disk_free_limit</td><td>清理日志、数据，或调整 disk_free_limit</td></tr><tr><td>无法集群 (clustering failure)</td><td>Erlang Cookie 不一致或网络问题</td><td>确认所有节点 .erlang.cookie 一致，检查 4369/25672 端口</td></tr><tr><td>消息堆积</td><td>消费者处理速度跟不上生产者</td><td>增加消费者实例、调整 prefetch_count、检查消费逻辑</td></tr><tr><td>guest 用户无法远程登录</td><td>RabbitMQ 默认限制 guest 仅限 localhost</td><td>创建管理员用户或修改 loopback_users 配置</td></tr><tr><td>channel 被关闭 (PRECONDITION_FAILED)</td><td>队列类型不匹配或使用了不存在的交换机</td><td>检查队列声明参数、交换机名称和类型</td></tr></tbody></table></div><h2 id="生产环境部署-Checklist"><a href="#生产环境部署-Checklist" class="headerlink" title="生产环境部署 Checklist"></a>生产环境部署 Checklist</h2><ul><li><input disabled="" type="checkbox"> 删除默认 guest 用户</li><li><input disabled="" type="checkbox"> 创建独立管理员和业务用户</li><li><input disabled="" type="checkbox"> 按环境划分虚拟主机（dev&#x2F;staging&#x2F;prod）</li><li><input disabled="" type="checkbox"> 配置内存阈值（建议 0.4-0.5）</li><li><input disabled="" type="checkbox"> 配置磁盘限制（建议 1-2GB）</li><li><input disabled="" type="checkbox"> 启用管理插件（内网访问或 Nginx 反向代理）</li><li><input disabled="" type="checkbox"> 启用 TLS&#x2F;SSL 加密</li><li><input disabled="" type="checkbox"> 配置防火墙白名单</li><li><input disabled="" type="checkbox"> 设置自动备份（定时导出定义 + 数据目录）</li><li><input disabled="" type="checkbox"> 配置日志轮转（保留 7-30 天）</li><li><input disabled="" type="checkbox"> 启用 Prometheus 监控</li><li><input disabled="" type="checkbox"> 确认连接使用心跳（heartbeat&#x3D;60）</li><li><input disabled="" type="checkbox"> 生产队列使用 Quorum Queue</li><li><input disabled="" type="checkbox"> 编写消费端重试与死信队列策略</li><li><input disabled="" type="checkbox"> 文档化拓扑结构（交换机、队列、绑定关系）</li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>RabbitMQ 凭借其成熟稳定的 AMQP 协议实现、丰富的管理工具和灵活的集群架构，是中小型团队快速搭建消息中间件的首选方案。部署时重点关注三点：<strong>资源限制配置</strong>（防止 OOM 和磁盘写满）、<strong>安全加固</strong>（删除默认用户 + TLS 加密）、以及 <strong>高可用方案选择</strong>（优先使用 Quorum Queue 替代镜像队列）。掌握上述搭建和管理方法后，可以轻松满足微服务架构中的异步消息通信需求。</p><hr><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-17-rabbitmq-env-setup/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-17-rabbitmq-env-setup/"/>
    <published>2026-06-17T04:36:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>RabbitMQ 是目前最流行的开源消息队列中间件之一，基于 AMQP 0-9-1 协议实现，广泛应用于微服务异步通信、任务队列分发、日志收]]>
    </summary>
    <title>RabbitMQ 消息队列环境搭建与基础管理完全指南</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="Linux" scheme="https://demo-blog.qusite.cn/tags/Linux/"/>
    <category term="Nginx" scheme="https://demo-blog.qusite.cn/tags/Nginx/"/>
    <category term="HAProxy" scheme="https://demo-blog.qusite.cn/tags/HAProxy/"/>
    <category term="负载均衡" scheme="https://demo-blog.qusite.cn/tags/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/"/>
    <category term="高可用" scheme="https://demo-blog.qusite.cn/tags/%E9%AB%98%E5%8F%AF%E7%94%A8/"/>
    <content>
      <![CDATA[<p>HAProxy（High Availability Proxy）是目前最流行的开源负载均衡和代理服务器软件之一，以其高性能、高可靠性和丰富的功能特性，广泛应用于生产环境的四层（TCP）和七层（HTTP&#x2F;HTTPS）流量分发场景。本文将详细介绍 HAProxy 的安装配置、核心概念、负载均衡算法、健康检查、SSL 终结、性能调优以及生产环境最佳实践。</p><h2 id="HAProxy-核心概念"><a href="#HAProxy-核心概念" class="headerlink" title="HAProxy 核心概念"></a>HAProxy 核心概念</h2><h3 id="架构组件"><a href="#架构组件" class="headerlink" title="架构组件"></a>架构组件</h3><p>HAProxy 的配置围绕三个核心组件展开：</p><ul><li><strong>frontend（前端）</strong>：定义客户端连接的入口，指定监听地址和端口，以及默认后端服务器组</li><li><strong>backend（后端）</strong>：定义一组实际提供服务的服务器，以及负载均衡算法和健康检查策略</li><li><strong>listen（监听）</strong>：将 frontend 和 backend 合并为一个简洁的配置段，适用于简单场景</li></ul><p>一个基本的流量路径为：<code>客户端 → Frontend（监听入口） → Backend（服务器组） → 实际服务器</code></p><h3 id="处理模式"><a href="#处理模式" class="headerlink" title="处理模式"></a>处理模式</h3><ul><li><strong>tcp 模式（四层代理）</strong>：工作在传输层，转发 TCP&#x2F;UDP 流量，性能极高，适用于数据库、Redis、MySQL 等</li><li><strong>http 模式（七层代理）</strong>：工作在应用层，可解析 HTTP 请求内容（URL、Header、Cookie），支持高级路由和会话保持</li></ul><h2 id="HAProxy-安装"><a href="#HAProxy-安装" class="headerlink" title="HAProxy 安装"></a>HAProxy 安装</h2><h3 id="Ubuntu-Debian-系列"><a href="#Ubuntu-Debian-系列" class="headerlink" title="Ubuntu&#x2F;Debian 系列"></a>Ubuntu&#x2F;Debian 系列</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用官方 PPA 安装最新稳定版</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get install --no-install-recommends software-properties-common</span><br><span class="line"><span class="built_in">sudo</span> add-apt-repository ppa:vbernat/haproxy-2.9 -y</span><br><span class="line"><span class="built_in">sudo</span> apt-get update</span><br><span class="line"><span class="built_in">sudo</span> apt-get install haproxy -y</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证安装</span></span><br><span class="line">haproxy -v</span><br><span class="line"><span class="comment"># 输出示例: HAProxy version 2.9.x</span></span><br></pre></td></tr></table></figure></div><h3 id="RHEL-CentOS-系列"><a href="#RHEL-CentOS-系列" class="headerlink" title="RHEL&#x2F;CentOS 系列"></a>RHEL&#x2F;CentOS 系列</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装 EPEL 源</span></span><br><span class="line"><span class="built_in">sudo</span> dnf install epel-release -y</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 HAProxy</span></span><br><span class="line"><span class="built_in">sudo</span> dnf install haproxy -y</span><br><span class="line"></span><br><span class="line"><span class="comment"># CentOS 7 使用 yum</span></span><br><span class="line"><span class="built_in">sudo</span> yum install haproxy -y</span><br></pre></td></tr></table></figure></div><h3 id="编译安装（获取最新版本）"><a href="#编译安装（获取最新版本）" class="headerlink" title="编译安装（获取最新版本）"></a>编译安装（获取最新版本）</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装编译依赖</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get install -y curl gcc libc6-dev libpcre3-dev libssl-dev libsystemd-dev zlib1g-dev make</span><br><span class="line"></span><br><span class="line"><span class="comment"># 下载源码</span></span><br><span class="line">curl -L https://www.haproxy.org/download/2.9/src/haproxy-2.9.7.tar.gz -o haproxy.tar.gz</span><br><span class="line">tar xzf haproxy.tar.gz</span><br><span class="line"><span class="built_in">cd</span> haproxy-2.9.7</span><br><span class="line"></span><br><span class="line"><span class="comment"># 编译并安装（启用 SSL 和 systemd 支持）</span></span><br><span class="line">make -j$(<span class="built_in">nproc</span>) TARGET=linux-glibc USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_PCRE=1</span><br><span class="line"><span class="built_in">sudo</span> make install</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证</span></span><br><span class="line">/usr/local/sbin/haproxy -v</span><br></pre></td></tr></table></figure></div><h3 id="安装后验证"><a href="#安装后验证" class="headerlink" title="安装后验证"></a>安装后验证</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 检查配置语法（启动前必做）</span></span><br><span class="line">haproxy -c -f /etc/haproxy/haproxy.cfg</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看详细信息</span></span><br><span class="line">haproxy -vv</span><br></pre></td></tr></table></figure></div><h2 id="基础配置详解"><a href="#基础配置详解" class="headerlink" title="基础配置详解"></a>基础配置详解</h2><p>HAProxy 的主配置文件通常位于 <code>/etc/haproxy/haproxy.cfg</code>，配置语法清晰，采用层级结构。</p><h3 id="全局配置（global）"><a href="#全局配置（global）" class="headerlink" title="全局配置（global）"></a>全局配置（global）</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">global</span><br><span class="line">    log /dev/log local0 info    # 日志输出</span><br><span class="line">    log /dev/log local1 notice</span><br><span class="line">    maxconn 65535               # 最大连接数</span><br><span class="line">    user haproxy               # 运行用户</span><br><span class="line">    group haproxy              # 运行组</span><br><span class="line">    nbproc 1                   # 进程数（2.5+版本推荐默认单进程多线程）</span><br><span class="line">    pidfile /var/run/haproxy.pid</span><br><span class="line">    stats socket /var/run/haproxy/admin.sock mode 660 level admin</span><br><span class="line">    tune.ssl.default-dh-param 2048   # SSL DH 参数强度</span><br><span class="line">    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256</span><br><span class="line">    ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11   # 禁用不安全的 TLS 版本</span><br></pre></td></tr></table></figure></div><h3 id="默认配置（defaults）"><a href="#默认配置（defaults）" class="headerlink" title="默认配置（defaults）"></a>默认配置（defaults）</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">defaults</span><br><span class="line">    log global</span><br><span class="line">    mode http                  # 默认七层代理模式</span><br><span class="line">    option httplog             # HTTP 日志格式</span><br><span class="line">    option dontlognull         # 不记录空连接</span><br><span class="line">    option redispatch          # 服务器降权后重新分配请求</span><br><span class="line">    retries 3                  # 连接重试次数</span><br><span class="line">    maxconn 10000              # 单进程最大连接</span><br><span class="line">    timeout connect 5s         # 连接超时</span><br><span class="line">    timeout client 30s         # 客户端超时</span><br><span class="line">    timeout server 30s         # 服务器超时</span><br><span class="line">    timeout check 5s           # 健康检查超时</span><br></pre></td></tr></table></figure></div><h2 id="负载均衡算法详解"><a href="#负载均衡算法详解" class="headerlink" title="负载均衡算法详解"></a>负载均衡算法详解</h2><p>HAProxy 提供多种负载均衡算法，适用于不同场景：</p><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr>  <th>算法</th>  <th>配置关键字</th>  <th>适用场景</th>  <th>特点</th></tr></thead><tbody><tr>  <td>轮询</td>  <td><code>roundrobin</code></td>  <td>服务器配置均等的通用场景</td>  <td>按顺序分发，动态权重调整支持</td></tr><tr>  <td>加权轮询</td>  <td><code>static-rr</code></td>  <td>服务器性能不均等时</td>  <td>权重静态配置，运行时不可修改</td></tr><tr>  <td>最少连接</td>  <td><code>leastconn</code></td>  <td>长连接服务（WebSocket、数据库）</td>  <td>分发到当前活跃连接最少的服务器</td></tr><tr>  <td>源地址哈希</td>  <td><code>source</code></td>  <td>需要会话保持的场景</td>  <td>客户端 IP 哈希，同一 IP 始终到同一台服务器</td></tr><tr>  <td>URI 哈希</td>  <td><code>uri</code></td>  <td>HTTP 缓存加速（CDN、反向代理）</td>  <td>按请求 URI 哈希，同一资源落到同一服务器</td></tr><tr>  <td>URL 参数哈希</td>  <td><code>url_param</code></td>  <td>API 网关会话保持</td>  <td>按指定 URL 参数值进行哈希分配</td></tr><tr>  <td>首字节响应时间</td>  <td><code>first</code></td>  <td>短连接、低延迟场景</td>  <td>选择响应最快的服务器</td></tr><tr>  <td>随机</td>  <td><code>random</code></td>  <td>大规模集群，避免轮询热点</td>  <td>基于随机数，2.4+ 版本支持两轮随机</td></tr></tbody></table></div><h2 id="实战配置示例"><a href="#实战配置示例" class="headerlink" title="实战配置示例"></a>实战配置示例</h2><h3 id="1-HTTP-七层负载均衡（Web-服务）"><a href="#1-HTTP-七层负载均衡（Web-服务）" class="headerlink" title="1. HTTP 七层负载均衡（Web 服务）"></a>1. HTTP 七层负载均衡（Web 服务）</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line">frontend web_front</span><br><span class="line">    bind *:80</span><br><span class="line">    mode http</span><br><span class="line">    option forwardfor          # 传递客户端真实IP</span><br><span class="line">    default_backend web_servers</span><br><span class="line"></span><br><span class="line">backend web_servers</span><br><span class="line">    mode http</span><br><span class="line">    balance roundrobin         # 轮询算法</span><br><span class="line">    option httpchk GET /health HTTP/1.1\r\nHost:\ example.com</span><br><span class="line">    http-check expect status 200</span><br><span class="line"></span><br><span class="line">    # 服务器定义（weight 设置权重，maxconn 限制单机最大连接）</span><br><span class="line">    server web1 192.168.1.10:8080 weight 3 maxconn 1024 check inter 5s fall 3 rise 2</span><br><span class="line">    server web2 192.168.1.11:8080 weight 2 maxconn 1024 check inter 5s fall 3 rise 2</span><br><span class="line">    server web3 192.168.1.12:8080 weight 1 maxconn 1024 check inter 5s fall 3 rise 2</span><br><span class="line"></span><br><span class="line">    # 备用服务器（主服务器全部不可用时启用）</span><br><span class="line">    server web-backup 192.168.1.100:8080 weight 1 backup</span><br></pre></td></tr></table></figure></div><p><strong>配置说明：</strong></p><ul><li><code>weight</code>：服务器权重，数值越大分发越多请求</li><li><code>check</code>：启用健康检查</li><li><code>inter 5s</code>：每 5 秒检查一次</li><li><code>fall 3</code>：连续 3 次失败视为宕机</li><li><code>rise 2</code>：连续 2 次成功视为恢复</li><li><code>backup</code>：标记为备用服务器</li></ul><h3 id="2-TCP-四层负载均衡（MySQL-Redis）"><a href="#2-TCP-四层负载均衡（MySQL-Redis）" class="headerlink" title="2. TCP 四层负载均衡（MySQL&#x2F;Redis）"></a>2. TCP 四层负载均衡（MySQL&#x2F;Redis）</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line">frontend mysql_front</span><br><span class="line">    bind *:3306</span><br><span class="line">    mode tcp</span><br><span class="line">    default_backend mysql_servers</span><br><span class="line"></span><br><span class="line">backend mysql_servers</span><br><span class="line">    mode tcp</span><br><span class="line">    balance leastconn          # 最少连接，适合数据库长连接</span><br><span class="line">    option tcp-check</span><br><span class="line">    tcp-check connect</span><br><span class="line">    tcp-check send PING\r\n</span><br><span class="line">    tcp-check expect string +OK</span><br><span class="line"></span><br><span class="line">    server mysql1 10.0.0.1:3306 check inter 5s</span><br><span class="line">    server mysql2 10.0.0.2:3306 check inter 5s</span><br></pre></td></tr></table></figure></div><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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"># Redis 负载均衡</span><br><span class="line">frontend redis_front</span><br><span class="line">    bind *:6379</span><br><span class="line">    mode tcp</span><br><span class="line">    default_backend redis_servers</span><br><span class="line"></span><br><span class="line">backend redis_servers</span><br><span class="line">    mode tcp</span><br><span class="line">    balance first               # 优先使用第一个可用的 Redis</span><br><span class="line">    server redis1 10.0.0.1:6379 check inter 3s</span><br><span class="line">    server redis2 10.0.0.2:6379 check inter 3s</span><br></pre></td></tr></table></figure></div><h3 id="3-HTTPS-SSL-终结（TLS-SSL-Offloading）"><a href="#3-HTTPS-SSL-终结（TLS-SSL-Offloading）" class="headerlink" title="3. HTTPS SSL 终结（TLS&#x2F;SSL Offloading）"></a>3. HTTPS SSL 终结（TLS&#x2F;SSL Offloading）</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line">frontend https_front</span><br><span class="line">    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem</span><br><span class="line">    mode http</span><br><span class="line">    option forwardfor</span><br><span class="line">    # 强制跳转 HTTPS（配合 HTTP 前端）</span><br><span class="line">    http-request set-header X-Forwarded-Proto https if &#123; ssl_fc &#125;</span><br><span class="line">    default_backend web_servers</span><br><span class="line"></span><br><span class="line"># HTTP 自动跳转 HTTPS</span><br><span class="line">frontend http_front</span><br><span class="line">    bind *:80</span><br><span class="line">    mode http</span><br><span class="line">    redirect scheme https code 301 if !&#123; ssl_fc &#125;</span><br></pre></td></tr></table></figure></div><p><strong>SSL 证书准备：</strong> HAProxy 需要 PEM 格式证书（证书 + 私钥合并）：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 将证书和私钥合并</span></span><br><span class="line"><span class="built_in">cat</span> /etc/letsencrypt/live/example.com/fullchain.pem \</span><br><span class="line">    /etc/letsencrypt/live/example.com/privkey.pem \</span><br><span class="line">    &gt; /etc/haproxy/certs/example.com.pem</span><br><span class="line"></span><br><span class="line"><span class="built_in">chmod</span> 600 /etc/haproxy/certs/example.com.pem</span><br></pre></td></tr></table></figure></div><h3 id="4-多域名虚拟主机路由"><a href="#4-多域名虚拟主机路由" class="headerlink" title="4. 多域名虚拟主机路由"></a>4. 多域名虚拟主机路由</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">frontend multi_domain_front</span><br><span class="line">    bind *:80</span><br><span class="line">    bind *:443 ssl crt /etc/haproxy/certs/ crt-list /etc/haproxy/crt-list.txt</span><br><span class="line">    mode http</span><br><span class="line"></span><br><span class="line">    # 按域名分流</span><br><span class="line">    use_backend api_servers  if &#123; hdr(Host) -i api.example.com &#125;</span><br><span class="line">    use_backend app_servers  if &#123; hdr(Host) -i app.example.com &#125;</span><br><span class="line">    use_backend admin_servers if &#123; hdr(Host) -i admin.example.com &#125;</span><br><span class="line"></span><br><span class="line">    # 默认后端</span><br><span class="line">    default_backend web_servers</span><br></pre></td></tr></table></figure></div><p><strong>crt-list 文件格式（<code>/etc/haproxy/crt-list.txt</code>）：</strong></p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">/etc/haproxy/certs/example.com.pem [alpn h2,http/1.1]</span><br><span class="line">/etc/haproxy/certs/api.example.com.pem [alpn h2,http/1.1]</span><br><span class="line">/etc/haproxy/certs/admin.example.com.pem</span><br></pre></td></tr></table></figure></div><h2 id="健康检查配置"><a href="#健康检查配置" class="headerlink" title="健康检查配置"></a>健康检查配置</h2><p>健康检查是保证高可用的核心机制，HAProxy 支持多种检查方式：</p><h3 id="HTTP-健康检查"><a href="#HTTP-健康检查" class="headerlink" title="HTTP 健康检查"></a>HTTP 健康检查</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">backend web_servers</span><br><span class="line">    # 基本 HTTP 检查：GET 请求指定路径，期望状态码</span><br><span class="line">    option httpchk GET /health HTTP/1.1\r\nHost:\ example.com</span><br><span class="line">    http-check expect status 200</span><br><span class="line"></span><br><span class="line">    # 或使用关键字检查</span><br><span class="line">    http-check expect string OK</span><br><span class="line"></span><br><span class="line">    # 支持 rstring 正则匹配</span><br><span class="line">    http-check expect rstring ^(OK|alive)$</span><br></pre></td></tr></table></figure></div><h3 id="TCP-健康检查"><a href="#TCP-健康检查" class="headerlink" title="TCP 健康检查"></a>TCP 健康检查</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line">backend mysql_servers</span><br><span class="line">    mode tcp</span><br><span class="line">    option tcp-check</span><br><span class="line">    tcp-check connect</span><br><span class="line">    tcp-check send PING\r\n</span><br><span class="line">    tcp-check expect string +OK</span><br><span class="line">    tcp-check send QUIT\r\n</span><br><span class="line"></span><br><span class="line">    server mysql1 10.0.0.1:3306 check inter 5s rise 2 fall 3</span><br></pre></td></tr></table></figure></div><h3 id="自定义脚本健康检查"><a href="#自定义脚本健康检查" class="headerlink" title="自定义脚本健康检查"></a>自定义脚本健康检查</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">backend custom_servers</span><br><span class="line">    option external-check      # 启用外部检查</span><br><span class="line">    external-check command /usr/local/bin/health-check.sh</span><br><span class="line">    server app1 192.168.1.10:3000 check inter 10s</span><br></pre></td></tr></table></figure></div><h2 id="会话保持配置"><a href="#会话保持配置" class="headerlink" title="会话保持配置"></a>会话保持配置</h2><h3 id="Cookie-插入方式"><a href="#Cookie-插入方式" class="headerlink" title="Cookie 插入方式"></a>Cookie 插入方式</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">backend web_servers</span><br><span class="line">    mode http</span><br><span class="line">    balance roundrobin</span><br><span class="line">    # 服务器响应中插入 COOKIE，后续同一客户端通过 cookie 路由</span><br><span class="line">    cookie SERVERID insert indirect nocache</span><br><span class="line">    server web1 192.168.1.10:8080 cookie s1 check</span><br><span class="line">    server web2 192.168.1.11:8080 cookie s2 check</span><br></pre></td></tr></table></figure></div><h3 id="Source-IP-哈希"><a href="#Source-IP-哈希" class="headerlink" title="Source IP 哈希"></a>Source IP 哈希</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line">backend web_servers</span><br><span class="line">    mode http</span><br><span class="line">    balance source          # 基于客户端源 IP 哈希</span><br><span class="line">    hash-type consistent    # 一致性哈希，减少服务器增减影响</span><br><span class="line">    server web1 192.168.1.10:8080 check</span><br><span class="line">    server web2 192.168.1.11:8080 check</span><br></pre></td></tr></table></figure></div><h2 id="访问控制与限流"><a href="#访问控制与限流" class="headerlink" title="访问控制与限流"></a>访问控制与限流</h2><h3 id="IP-白名单-黑名单"><a href="#IP-白名单-黑名单" class="headerlink" title="IP 白名单&#x2F;黑名单"></a>IP 白名单&#x2F;黑名单</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line">frontend web_front</span><br><span class="line">    bind *:80</span><br><span class="line">    mode http</span><br><span class="line"></span><br><span class="line">    # 黑名单：拒绝特定 IP</span><br><span class="line">    acl blacklist src 192.168.1.100 10.0.0.50</span><br><span class="line">    http-request deny if blacklist</span><br><span class="line"></span><br><span class="line">    # 白名单：仅允许指定 IP 访问管理页面</span><br><span class="line">    acl admin_path path_beg /admin</span><br><span class="line">    acl admin_ips src 10.0.0.0/24</span><br><span class="line">    http-request deny if admin_path !admin_ips</span><br><span class="line"></span><br><span class="line">    default_backend web_servers</span><br></pre></td></tr></table></figure></div><h3 id="请求速率限制"><a href="#请求速率限制" class="headerlink" title="请求速率限制"></a>请求速率限制</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line">frontend web_front</span><br><span class="line">    bind *:80</span><br><span class="line">    mode http</span><br><span class="line"></span><br><span class="line">    # 定义速率限制：每个源 IP 每 10 秒最多 100 个请求</span><br><span class="line">    stick-table type ip size 100k expire 30s store http_req_rate(10s)</span><br><span class="line">    http-request track-sc0 src</span><br><span class="line"></span><br><span class="line">    # 触发限流：返回 429 Too Many Requests</span><br><span class="line">    acl rate_limit sc_http_req_rate(0) gt 100</span><br><span class="line">    http-request deny deny_status 429 if rate_limit</span><br><span class="line"></span><br><span class="line">    default_backend web_servers</span><br></pre></td></tr></table></figure></div><h2 id="状态监控页面"><a href="#状态监控页面" class="headerlink" title="状态监控页面"></a>状态监控页面</h2><p>HAProxy 内置了强大的统计监控页面：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">frontend stats_front</span><br><span class="line">    bind *:8080</span><br><span class="line">    mode http</span><br><span class="line">    stats enable</span><br><span class="line">    stats uri /haproxy-stats        # 访问路径</span><br><span class="line">    stats refresh 5s                # 自动刷新间隔</span><br><span class="line">    stats auth admin:StrongPassword # 认证用户和密码</span><br><span class="line">    stats admin if TRUE             # 允许通过管理界面启用/禁用服务器</span><br><span class="line">    stats hide-version              # 隐藏版本号</span><br><span class="line">    stats realm &quot;HAProxy Statistics&quot;</span><br></pre></td></tr></table></figure></div><p>建议通过 Nginx 反向代理对监控页面加一层 HTTPS 和 IP 限制：</p><div class="code-container" data-rel="Nginx"><figure class="iseeu highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Nginx 配置示例</span></span><br><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">443</span> ssl;</span><br><span class="line">    <span class="attribute">server_name</span> monitor.example.com;</span><br><span class="line">    </span><br><span class="line">    <span class="section">location</span> / &#123;</span><br><span class="line">        <span class="attribute">proxy_pass</span> http://127.0.0.1:8080;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Authorization <span class="string">&quot;Basic YWRtaW46U3Ryb25nUGFzc3dvcmQ=&quot;</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="comment"># IP 白名单</span></span><br><span class="line">        <span class="attribute">allow</span> <span class="number">10.0.0.0</span>/<span class="number">8</span>;</span><br><span class="line">        <span class="attribute">allow</span> <span class="number">192.168.0.0</span>/<span class="number">16</span>;</span><br><span class="line">        <span class="attribute">deny</span> all;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="日志配置"><a href="#日志配置" class="headerlink" title="日志配置"></a>日志配置</h2><h3 id="syslog-配置"><a href="#syslog-配置" class="headerlink" title="syslog 配置"></a>syslog 配置</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"># 全局配置中启用日志</span><br><span class="line">global</span><br><span class="line">    log /dev/log local0 info</span><br><span class="line">    log /dev/log local1 notice</span><br><span class="line"></span><br><span class="line"># 前端配置</span><br><span class="line">frontend web_front</span><br><span class="line">    option httplog             # HTTP 详细日志</span><br><span class="line">    log-format &quot;%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq %hs %&#123;+Q&#125;r&quot;</span><br></pre></td></tr></table></figure></div><h3 id="rsyslog-独立日志文件"><a href="#rsyslog-独立日志文件" class="headerlink" title="rsyslog 独立日志文件"></a>rsyslog 独立日志文件</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># /etc/rsyslog.d/49-haproxy.conf</span></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$programname</span> == <span class="string">&#x27;haproxy&#x27;</span>) <span class="keyword">then</span> &#123;</span><br><span class="line">    action(<span class="built_in">type</span>=<span class="string">&quot;omfile&quot;</span> file=<span class="string">&quot;/var/log/haproxy.log&quot;</span>)</span><br><span class="line">    stop</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重启 rsyslog</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl restart rsyslog</span><br></pre></td></tr></table></figure></div><h2 id="性能调优"><a href="#性能调优" class="headerlink" title="性能调优"></a>性能调优</h2><h3 id="内核参数优化"><a href="#内核参数优化" class="headerlink" title="内核参数优化"></a>内核参数优化</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># /etc/sysctl.d/99-haproxy.conf</span></span><br><span class="line"><span class="comment"># 网络连接优化</span></span><br><span class="line">net.core.somaxconn = 65535</span><br><span class="line">net.ipv4.tcp_max_syn_backlog = 65535</span><br><span class="line">net.ipv4.ip_local_port_range = 1024 65535</span><br><span class="line">net.ipv4.tcp_tw_reuse = 1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 大并发连接优化</span></span><br><span class="line">net.ipv4.tcp_rmem = 4096 87380 16777216</span><br><span class="line">net.ipv4.tcp_wmem = 4096 65536 16777216</span><br><span class="line">net.core.rmem_default = 16777216</span><br><span class="line">net.core.wmem_default = 16777216</span><br><span class="line">net.core.rmem_max = 16777216</span><br><span class="line">net.core.wmem_max = 16777216</span><br><span class="line"></span><br><span class="line"><span class="comment"># 应用后生效</span></span><br><span class="line"><span class="built_in">sudo</span> sysctl -p /etc/sysctl.d/99-haproxy.conf</span><br></pre></td></tr></table></figure></div><h3 id="HAProxy-配置调优"><a href="#HAProxy-配置调优" class="headerlink" title="HAProxy 配置调优"></a>HAProxy 配置调优</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">global</span><br><span class="line">    maxconn 100000              # 从系统 ulimit 推导，确保足够大</span><br><span class="line">    tune.bufsize 32768          # 缓冲区大小（默认 16384）</span><br><span class="line">    tune.maxrewrite 2048        # HTTP 头重写缓冲区预留空间</span><br><span class="line">    # 多线程配置（2.5+）</span><br><span class="line">    nbthread 4                  # 线程数，通常等于 CPU 核数</span><br><span class="line">    cpu-map auto:1/1-4 0-3      # 线程绑定 CPU 核心</span><br></pre></td></tr></table></figure></div><h3 id="systemd-参数优化"><a href="#systemd-参数优化" class="headerlink" title="systemd 参数优化"></a>systemd 参数优化</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># /etc/systemd/system/haproxy.service.d/limits.conf</span></span><br><span class="line">[Service]</span><br><span class="line">LimitNOFILE=1048576</span><br><span class="line">LimitNPROC=1048576</span><br><span class="line">LimitMEMLOCK=infinity</span><br></pre></td></tr></table></figure></div><h2 id="高可用方案（Keepalived-HAProxy）"><a href="#高可用方案（Keepalived-HAProxy）" class="headerlink" title="高可用方案（Keepalived + HAProxy）"></a>高可用方案（Keepalived + HAProxy）</h2><p>使用 Keepalived 实现 HAProxy 自身的高可用（主备切换）：</p><h3 id="Keepalived-安装"><a href="#Keepalived-安装" class="headerlink" title="Keepalived 安装"></a>Keepalived 安装</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt-get install keepalived -y</span><br></pre></td></tr></table></figure></div><h3 id="主节点配置（-etc-keepalived-keepalived-conf）"><a href="#主节点配置（-etc-keepalived-keepalived-conf）" class="headerlink" title="主节点配置（/etc/keepalived/keepalived.conf）"></a>主节点配置（<code>/etc/keepalived/keepalived.conf</code>）</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line">vrrp_script chk_haproxy &#123;</span><br><span class="line">    script &quot;pidof haproxy&quot;</span><br><span class="line">    interval 2</span><br><span class="line">    weight 2</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">vrrp_instance VI_1 &#123;</span><br><span class="line">    interface eth0</span><br><span class="line">    state MASTER                  # 主节点</span><br><span class="line">    virtual_router_id 51</span><br><span class="line">    priority 101                  # 优先级，主节点高于备节点</span><br><span class="line">    advert_int 1</span><br><span class="line"></span><br><span class="line">    authentication &#123;</span><br><span class="line">        auth_type PASS</span><br><span class="line">        auth_path 1234</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    virtual_ipaddress &#123;</span><br><span class="line">        192.168.1.200/24 dev eth0  # 虚拟 IP（VIP）</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    track_script &#123;</span><br><span class="line">        chk_haproxy</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="备节点配置"><a href="#备节点配置" class="headerlink" title="备节点配置"></a>备节点配置</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">vrrp_instance VI_1 &#123;</span><br><span class="line">    interface eth0</span><br><span class="line">    state BACKUP</span><br><span class="line">    virtual_router_id 51</span><br><span class="line">    priority 100</span><br><span class="line">    advert_int 1</span><br><span class="line"></span><br><span class="line">    authentication &#123;</span><br><span class="line">        auth_type PASS</span><br><span class="line">        auth_path 1234</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    virtual_ipaddress &#123;</span><br><span class="line">        192.168.1.200/24 dev eth0</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    track_script &#123;</span><br><span class="line">        chk_haproxy</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="安全加固"><a href="#安全加固" class="headerlink" title="安全加固"></a>安全加固</h2><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">global</span><br><span class="line">    # 以非 root 用户运行</span><br><span class="line">    user haproxy</span><br><span class="line">    group haproxy</span><br><span class="line"></span><br><span class="line">frontend web_front</span><br><span class="line">    # 禁用不安全的方法</span><br><span class="line">    http-request deny if &#123; method CONNECT &#125;</span><br><span class="line">    http-request deny if &#123; method TRACE &#125;</span><br><span class="line"></span><br><span class="line">    # HTTP 安全头（如果 HAProxy 直接响应客户端）</span><br><span class="line">    http-response set-header X-Content-Type-Options nosniff</span><br><span class="line">    http-response set-header X-Frame-Options SAMEORIGIN</span><br><span class="line">    http-response set-header X-XSS-Protection &quot;1; mode=block&quot;</span><br><span class="line"></span><br><span class="line">    # 限制请求体大小（防大 POST 攻击）</span><br><span class="line">    http-request reject if &#123; req.body_size gt 10m &#125;</span><br><span class="line"></span><br><span class="line">    # 限制 URL 长度</span><br><span class="line">    http-request reject if &#123; url_len gt 4096 &#125;</span><br></pre></td></tr></table></figure></div><h2 id="常用命令速查"><a href="#常用命令速查" class="headerlink" title="常用命令速查"></a>常用命令速查</h2><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr>  <th>场景</th>  <th>命令</th></tr></thead><tbody><tr>  <td>测试配置语法</td>  <td><code>haproxy -c -f /etc/haproxy/haproxy.cfg</code></td></tr><tr>  <td>启动 HAProxy</td>  <td><code>sudo systemctl start haproxy</code></td></tr><tr>  <td>停止 HAProxy</td>  <td><code>sudo systemctl stop haproxy</code></td></tr><tr>  <td>重启 HAProxy</td>  <td><code>sudo systemctl restart haproxy</code></td></tr><tr>  <td>重载配置（无缝）</td>  <td><code>sudo systemctl reload haproxy</code></td></tr><tr>  <td>查看运行状态</td>  <td><code>sudo systemctl status haproxy</code></td></tr><tr>  <td>查看监听端口</td>  <td><code>ss -tlnp \| grep haproxy</code></td></tr><tr>  <td>实时查看统计</td>  <td><code>watch -n 1 'echo "show stat" \| socat /var/run/haproxy/admin.sock stdio'</code></td></tr><tr>  <td>通过 socket 管理服务器</td>  <td><code>echo "disable server web_servers/web1" \| socat /var/run/haproxy/admin.sock stdio</code></td></tr><tr>  <td>启用服务器</td>  <td><code>echo "enable server web_servers/web1" \| socat /var/run/haproxy/admin.sock stdio</code></td></tr><tr>  <td>查看 HAProxy 版本</td>  <td><code>haproxy -v</code></td></tr><tr>  <td>查看编译选项</td>  <td><code>haproxy -vv</code></td></tr></tbody></table></div><h2 id="常见问题排查"><a href="#常见问题排查" class="headerlink" title="常见问题排查"></a>常见问题排查</h2><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr>  <th>问题现象</th>  <th>可能原因</th>  <th>解决方案</th></tr></thead><tbody><tr>  <td>后端服务器全部标记 DOWN</td>  <td>健康检查路径/端口错误</td>  <td>用 curl 测试后端健康检查接口，确认路径和端口正确</td></tr><tr>  <td>客户端请求超时</td>  <td>timeout 值过小或后端响应慢</td>  <td>增大 <code>timeout server</code>，或检查后端服务性能</td></tr><tr>  <td>SSL 证书错误</td>  <td>证书格式不对或权限错误</td>  <td>确认 PEM 格式正确、权限 600、所属用户 haproxy</td></tr><tr>  <td>连接数达到上限</td>  <td>maxconn 值太小或 ulimit 不足</td>  <td>增加 <code>maxconn</code> 和系统 <code>ulimit -n</code></td></tr><tr>  <td>日志为空</td>  <td>rsyslog 未配置或不接收 HAProxy 日志</td>  <td>检查 rsyslog 配置和 /dev/log 权限</td></tr><tr>  <td>无法绑定端口（<1024）</td>  <td>非 root 用户启动</td>  <td>使用 root 启动后切换用户，或设置 CAP_NET_BIND_SERVICE</td></tr><tr>  <td>后端服务器权重失效</td>  <td>使用 static-rr 算法</td>  <td>改为 roundrobin 实现动态权重</td></tr><tr>  <td>WebSocket 连接断开</td>  <td>超时时间不足</td>  <td>增大 <code>timeout tunnel</code>，WebSocket 场景建议 1h</td></tr></tbody></table></div><h2 id="最佳实践总结"><a href="#最佳实践总结" class="headerlink" title="最佳实践总结"></a>最佳实践总结</h2><ol><li><strong>配置语法检查先行</strong>：每次修改配置后务必执行 <code>haproxy -c -f haproxy.cfg</code></li><li><strong>平滑重载</strong>：使用 <code>systemctl reload haproxy</code> 而非 restart，避免连接中断</li><li><strong>健康检查务必精准</strong>：HTTP 检查应访问真实的健康检测接口，而非首页</li><li><strong>合理设置超时</strong>：根据业务场景调整 timeout 参数，WebSocket 等长连接需要较大的 <code>timeout tunnel</code></li><li><strong>监控页面必加认证</strong>：统计页面使用 <code>stats auth</code> 认证，并通过 Nginx 做 HTTPS 代理和 IP 限制</li><li><strong>日志单独存放</strong>：配置 rsyslog 将 HAProxy 日志写入独立文件，便于排查</li><li><strong>主机高可用</strong>：使用 Keepalived + 虚拟 IP 实现 HAProxy 自身的主备切换</li><li><strong>定期更新版本</strong>：关注 HAProxy 官方安全公告，及时升级到修复安全漏洞的版本</li><li><strong>连接数监控</strong>：通过 stats 页面或 socket 实时监控各后端服务器连接数</li><li><strong>配置版本管理</strong>：将 haproxy.cfg 纳入 Git 管理，变更留痕</li></ol><hr><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-17-haproxy-load-balancer-guide/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-17-haproxy-load-balancer-guide/"/>
    <published>2026-06-17T02:08:00.000Z</published>
    <summary>
      <![CDATA[<p>HAProxy（High Availability Proxy）是目前最流行的开源负载均衡和代理服务器软件之一，以其高性能、高可靠性和丰富的功能特性，广泛应用于生产环境的四层（TCP）和七层（HTTP&#x2F;HTTPS）流量分发场景。本文将详细介绍 HAProxy 的安]]>
    </summary>
    <title>HAProxy 负载均衡配置完全指南</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="日记" scheme="https://demo-blog.qusite.cn/categories/%E6%97%A5%E8%AE%B0/"/>
    <category term="日记" scheme="https://demo-blog.qusite.cn/tags/%E6%97%A5%E8%AE%B0/"/>
    <category term="Docker" scheme="https://demo-blog.qusite.cn/tags/Docker/"/>
    <category term="AI" scheme="https://demo-blog.qusite.cn/tags/AI/"/>
    <category term="技术写作" scheme="https://demo-blog.qusite.cn/tags/%E6%8A%80%E6%9C%AF%E5%86%99%E4%BD%9C/"/>
    <category term="GitLab" scheme="https://demo-blog.qusite.cn/tags/GitLab/"/>
    <content>
      <![CDATA[<p>昨晚又是折腾到凌晨两点多的一夜。从 GitLab 容器化部署到 Java 环境搭建，再到 diff&#x2F;patch 命令的全面梳理，这一轮的写作量不知不觉又上去了。躺在床上时脑子里还在转着 K8s 集群和 GitLab Runner 的配置逻辑，翻来覆去好一会儿才睡着。</p><span id="more"></span><h2 id="凌晨的代码时光"><a href="#凌晨的代码时光" class="headerlink" title="凌晨的代码时光"></a>凌晨的代码时光</h2><p>凌晨那会儿写的三篇文章现在想起来还挺有成就感：</p><ul><li><p><strong>GitLab 容器化部署</strong>：用 Docker Compose 搭了一个完整的 GitLab CE 17.2，包含 SMTP 邮件配置、SSH 端口映射、Nginx 反向代理 + Let’s Encrypt 自动续签。最折腾的是 SMTP 这块——GitLab 容器内发邮件走不了本地 postfix，得改用外部 SMTP 中继，调试了好几次才把通知邮件配通。后来还在 <code>.gitlab-ci.yml</code> 里写了个简单的 CI&#x2F;CD 模板，跑了个 <code>mvn package</code> 验证。</p></li><li><p><strong>Java 开发环境搭建</strong>：把 JDK、Maven、Gradle、IntelliJ IDEA 的配置全写了一遍。SDKMAN 真是个好东西，一行 <code>sdk install java</code> 就能切版本，比手动下载 tar.gz 省事太多。顺手写了个 Spring Boot 的 REST API 示例，加上了 Docker 多阶段构建。</p></li><li><p><strong>diff&#x2F;patch 命令</strong>：这个算是补了个缺。之前用 Git 管理代码变更，一直觉得原生 diff&#x2F;patch 没什么用。但仔细研究下来发现，在远程服务器上做配置改动的热修复时，<code>diff -u</code> 生成补丁、<code>patch</code> 打补丁的方式其实比传文件更安全——只改要改的行，不会覆盖已有的配置文件。</p></li></ul><h2 id="早上的科技热点"><a href="#早上的科技热点" class="headerlink" title="早上的科技热点"></a>早上的科技热点</h2><p>今天早上那篇新闻稿（类型 5）整理得格外紧。SpaceX 600 亿美元收购 Anysphere（Cursor 母公司）这条消息太震撼了——一家做火箭的公司花 600 亿买一家 AI 编码工具公司，这个跨界逻辑我琢磨了一上午。</p><p>表面看是 SpaceX 要整合 AI 能力，但往深想：Starlink 已经覆盖了百万用户，再加上 Anysphere 的 AI 编码 Agent 技术，马斯克瞄准的可能是”地面 AI 开发 + 太空计算基础设施”这个全栈闭环。再加上之前曝光的 AI1 轨道 AI 数据中心卫星计划——这盘棋比单纯的”航天公司收购 AI 公司”要大得多。</p><p>DeepSeek 首轮融资 74 亿美元、估值破 500 亿人民币，燧原科技科创板 IPO 过会、国产 GPU「四小龙」齐聚二级市场——国产 AI 硬科技的资本化进程明显在加速。硅基流动 B 轮 20 亿、MiniMax 开源 M3 模型…可以说 2026 年 6 月是 AI 行业资本化密度最高的一个月之一。</p><h2 id="一点反思"><a href="#一点反思" class="headerlink" title="一点反思"></a>一点反思</h2><p>写到第 75 篇了。打开博客首页滚动了一下，一整页的 Linux 教程、环境搭建指南、工具命令用法——有种自己在写”心雨的运维百科全书”的错觉。</p><p>但今天早上我特别去翻了几个技术社区的热门文章，发现真正有传播力的往往是那些<strong>有真实踩坑经验</strong>的分享。比如有位博主写”用 Docker 部署 GitLab 时踩过的 7 个坑”，阅读量比标准教程高好几个数量级。</p><p>这提醒了我：<strong>教程的价值在于实战，而不是完整</strong>。</p><p>昨晚的 GitLab 文章里提到 SMTP 配置踩坑、Java 环境搭建里写出 SDKMAN 的易用性、diff&#x2F;patch 命令里关联 Git 使用场景——这种”个人体验”的切口才是我博客应该深挖的方向。接下来的文章不追求面面俱到，但一定要有我自己验证过的实战记录。</p><h2 id="今天的计划"><a href="#今天的计划" class="headerlink" title="今天的计划"></a>今天的计划</h2><p>今天白天还有不少事情要处理：</p><table><thead><tr><th>优先级</th><th>事项</th><th>说明</th></tr></thead><tbody><tr><td>P0</td><td>博客暗色模式配色微调</td><td>上次改完之后截图发现评论区的深色背景有点刺眼</td></tr><tr><td>P0</td><td>标签目录整理</td><td>现在 75 篇文章标签比较乱，需要统一分类</td></tr><tr><td>P1</td><td>验证 Ansible Roles 文章</td><td>上周写的 Ansible 指南里的 Roles 目录结构需要实操跑一遍</td></tr><tr><td>P2</td><td>调研 Hexo 搜索插件</td><td>帖子多了没有站内搜索很不方便</td></tr></tbody></table><p>以上是我周三早晨的一点记录。与其追求数量，不如把每篇文章都打磨到能真正帮到别人的程度——包括这篇文章本身。</p><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-17-wednesday-diary/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-17-wednesday-diary/"/>
    <published>2026-06-17T01:09:00.000Z</published>
    <summary>
      <![CDATA[<p>昨晚又是折腾到凌晨两点多的一夜。从 GitLab 容器化部署到 Java 环境搭建，再到 diff&#x2F;patch 命令的全面梳理，这一轮的写作量不知不觉又上去了。躺在床上时脑子里还在转着 K8s 集群和 GitLab Runner 的配置逻辑，翻来覆去好一会儿才睡着。</p>]]>
    </summary>
    <title>周三早晨：容器化实践与AI并购浪潮的思考</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="新闻" scheme="https://demo-blog.qusite.cn/categories/%E6%96%B0%E9%97%BB/"/>
    <category term="科技热点" scheme="https://demo-blog.qusite.cn/tags/%E7%A7%91%E6%8A%80%E7%83%AD%E7%82%B9/"/>
    <category term="SpaceX" scheme="https://demo-blog.qusite.cn/tags/SpaceX/"/>
    <category term="AI" scheme="https://demo-blog.qusite.cn/tags/AI/"/>
    <category term="DeepSeek" scheme="https://demo-blog.qusite.cn/tags/DeepSeek/"/>
    <category term="燧原科技" scheme="https://demo-blog.qusite.cn/tags/%E7%87%A7%E5%8E%9F%E7%A7%91%E6%8A%80/"/>
    <content>
      <![CDATA[<h2 id="一、SpaceX-官宣-600-亿美元收购-Cursor-母公司-Anysphere"><a href="#一、SpaceX-官宣-600-亿美元收购-Cursor-母公司-Anysphere" class="headerlink" title="一、SpaceX 官宣 600 亿美元收购 Cursor 母公司 Anysphere"></a>一、SpaceX 官宣 600 亿美元收购 Cursor 母公司 Anysphere</h2><p>6月16日，埃隆·马斯克旗下的 SpaceX 正式宣布，将以 600 亿美元的全股票交易方式收购 AI 编程工具 Cursor 的母公司 Anysphere。这一交易距 SpaceX 上周五（6月12日）在纳斯达克的历史性 IPO 仅过去四天。</p><p>根据美国证交会备案文件，此次交易对 Anysphere（Cursor）的隐含股权估值为 600 亿美元，每股 Cursor 普通股和优先股将转换为获得 SpaceX A 类普通股的权利，预计于 2026 年第三季度完成。SpaceX 股价在消息公布后上涨超 10%。</p><p>值得注意的是，Cursor 此前占 Anthropic 约一半的收入来源。并入 SpaceX 后，Cursor 可直接使用马斯克旗下 xAI 位于孟菲斯的 Colossus 超算中心，获得近乎无限的算力支持，从应用层开发转向底层模型与基础设施的全面整合。</p><p><em>来源：彭博社、美国证交会备案文件、36氪</em></p><h2 id="二、DeepSeek-完成首轮超-500-亿元融资，估值突破-500-亿美元"><a href="#二、DeepSeek-完成首轮超-500-亿元融资，估值突破-500-亿美元" class="headerlink" title="二、DeepSeek 完成首轮超 500 亿元融资，估值突破 500 亿美元"></a>二、DeepSeek 完成首轮超 500 亿元融资，估值突破 500 亿美元</h2><p>据 The Information 6月16日报道，AI 大模型公司 DeepSeek 已完成成立以来的首轮外部融资，募资总额超 500 亿元人民币（约合 74 亿美元），创下中国 AI 行业迄今最大单轮融资纪录。投后估值突破 500 亿美元（约合 3380 亿元人民币）。</p><p>本轮融资结构颇具特色：创始人兼 CEO 梁文峰个人出资约 200 亿元，为本轮最大单一出资方；腾讯出资约 100 亿元；宁德时代体系出资约 50 亿元；此外还包括网易、京东、Monolith 砺思资本等。通过特殊交易架构设计，梁文峰仍持有公司绝对控制权。</p><p><em>来源：The Information、科创板日报、智东西</em></p><h2 id="三、燧原科技科创板-IPO-过会，”国产-GPU-四小龙”齐聚资本市场"><a href="#三、燧原科技科创板-IPO-过会，”国产-GPU-四小龙”齐聚资本市场" class="headerlink" title="三、燧原科技科创板 IPO 过会，”国产 GPU 四小龙”齐聚资本市场"></a>三、燧原科技科创板 IPO 过会，”国产 GPU 四小龙”齐聚资本市场</h2><p>6月15日晚间，上交所官网发布公告，上海燧原科技股份有限公司科创板 IPO 获上交所上市委审议通过。这家成立近八年的国产云端 AI 芯片领军企业即将叩开 A 股大门。</p><p>燧原科技 2026 年 1 月 22 日科创板 IPO 受理，历经两轮问询，6 月 15 日上会通过。伴随其过会，摩尔线程、沐曦股份、壁仞科技和燧原科技这四家被称为”国产 GPU 四小龙”的芯片公司正式齐聚资本市场。其中摩尔线程、沐曦股份于 2025 年 12 月在科创板上市，目前市值均接近 3000 亿元；壁仞科技 2026 年 1 月登陆港交所，市值超 1300 亿港元。</p><p><em>来源：上交所官网、澎湃新闻、东方财富网</em></p><h2 id="四、硅基流动完成-B-轮-20-亿元融资"><a href="#四、硅基流动完成-B-轮-20-亿元融资" class="headerlink" title="四、硅基流动完成 B 轮 20 亿元融资"></a>四、硅基流动完成 B 轮 20 亿元融资</h2><p>AI 基础设施公司硅基流动（SiliconFlow）宣布完成超 20 亿元 B 轮融资，创下中国 AI 基础设施赛道单轮融资纪录。公司目前日均 Token 调用量达数万亿级别，服务超 1000 万用户和 1 万家企业客户，营收同比增长超 10 倍。</p><p><em>来源：AITNT 新闻日报</em></p><h2 id="五、2026-陆家嘴论坛今日开幕"><a href="#五、2026-陆家嘴论坛今日开幕" class="headerlink" title="五、2026 陆家嘴论坛今日开幕"></a>五、2026 陆家嘴论坛今日开幕</h2><p>2026 陆家嘴论坛于 6 月 17 日至 18 日在上海举行，主题为”全球治理倡议下的金融发展与合作：新愿景、新挑战和新机遇”。论坛由中国人民银行、国家金融监督管理总局、中国证监会和上海市人民政府共同主办，将围绕全球金融治理、资本市场建设、科技金融、普惠金融、可持续金融等热点议题展开深入讨论。</p><p><em>来源：央广网、上海市政府新闻办</em></p><h2 id="六、MiniMax-开源-M3-旗舰模型，登顶开源综合智能榜首"><a href="#六、MiniMax-开源-M3-旗舰模型，登顶开源综合智能榜首" class="headerlink" title="六、MiniMax 开源 M3 旗舰模型，登顶开源综合智能榜首"></a>六、MiniMax 开源 M3 旗舰模型，登顶开源综合智能榜首</h2><p>上周五（6月12日），MiniMax 正式开源其原生多模态旗舰模型 M3。该模型总参数 428B，激活参数仅 23B，目前位居全球开源模型综合智能指数第一。创始人闫俊杰透露，团队正在推进 10T 参数模型的研发。</p><p><em>来源：AITNT 新闻日报</em></p><h2 id="七、其他重要科技动态"><a href="#七、其他重要科技动态" class="headerlink" title="七、其他重要科技动态"></a>七、其他重要科技动态</h2><ul><li><strong>字节跳动发布 Seedance 2.0 Mini 视频模型</strong>：主打性价比，生成速度更快，官方最低 0.16 元&#x2F;秒，API 将于 6 月 22 日开放。</li><li><strong>支付宝开启 AI 版内测</strong>：上线 20 年来最大改版，核心包含 AI 助手”阿宝”，支持自然语言调度各类服务。</li><li><strong>Anthropic 推出 Claude Design 产品</strong>：可根据描述生成高精度可交互 App 原型，产出可直接开发的代码。</li><li><strong>OpenAI Codex 推出自生成目标功能</strong>：模型可自主制定目标、拆分任务、调度多智能体完成开发。</li><li><strong>清华团队推出”硅基社会实验室”AgentSociety²</strong>：面向可执行社会科学的实验环境，支持 AI 与人类协同开展社会科学实验。</li><li><strong>摩尔线程开源 MusaCoder-27B 大模型</strong>：在 KernelBench 基准获第一，通过率 88.6%，全流程基于国产 GPU 训练。</li><li><strong>AIIA 召开智能体时代 AI 安全治理研讨会</strong>：中国人工智能产业发展联盟安全治理委员会于今日下午在北京召开研讨会，探讨智能体时代 AI 安全治理路径。</li></ul><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-17-tech-news-wednesday/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-17-tech-news-wednesday/"/>
    <published>2026-06-17T00:09:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="一、SpaceX-官宣-600-亿美元收购-Cursor-母公司-Anysphere"><a href="#一、SpaceX-官宣-600-亿美元收购-Cursor-母公司-Anysphere" class="headerlink" title="一、SpaceX]]>
    </summary>
    <title>2026年6月17日科技热点：SpaceX 600亿收购Cursor刷屏、DeepSeek创纪录融资、燧原科技IPO过会</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="Linux" scheme="https://demo-blog.qusite.cn/tags/Linux/"/>
    <category term="diff" scheme="https://demo-blog.qusite.cn/tags/diff/"/>
    <category term="patch" scheme="https://demo-blog.qusite.cn/tags/patch/"/>
    <category term="文件比较" scheme="https://demo-blog.qusite.cn/tags/%E6%96%87%E4%BB%B6%E6%AF%94%E8%BE%83/"/>
    <category term="补丁管理" scheme="https://demo-blog.qusite.cn/tags/%E8%A1%A5%E4%B8%81%E7%AE%A1%E7%90%86/"/>
    <category term="版本控制" scheme="https://demo-blog.qusite.cn/tags/%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6/"/>
    <content>
      <![CDATA[<p>在 Linux 系统管理和软件开发中，<strong>文件比较</strong>和<strong>补丁管理</strong>是两项基础而强大的技能。<code>diff</code> 命令用于逐行比较文件差异，<code>patch</code> 命令则根据差异文件（补丁）将变更应用到目标文件。这对组合是 Git 等版本控制系统的底层基石，也是运维人员日常排查配置变更、管理代码更新的得力工具。</p><p>本文将全面介绍 diff 和 patch 的核心用法、输出格式解读、实战场景以及高级技巧。</p><h2 id="一、diff-命令详解"><a href="#一、diff-命令详解" class="headerlink" title="一、diff 命令详解"></a>一、diff 命令详解</h2><h3 id="1-1-基本语法"><a href="#1-1-基本语法" class="headerlink" title="1.1 基本语法"></a>1.1 基本语法</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">diff [选项] 文件1 文件2</span><br></pre></td></tr></table></figure></div><p><code>diff</code> 比较两个文件，输出它们之间的差异行。如果两个文件完全相同，则无输出（或返回空）。</p><h3 id="1-2-三种输出格式"><a href="#1-2-三种输出格式" class="headerlink" title="1.2 三种输出格式"></a>1.2 三种输出格式</h3><p>diff 支持三种差异输出格式，其中**统一格式（unified）**是最常用和最易读的。</p><h4 id="1-2-1-正常格式（normal）"><a href="#1-2-1-正常格式（normal）" class="headerlink" title="1.2.1 正常格式（normal）"></a>1.2.1 正常格式（normal）</h4><p>默认输出，直接显示需要修改的行和操作：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">diff /etc/nginx/nginx.conf.bak /etc/nginx/nginx.conf</span><br></pre></td></tr></table></figure></div><p>输出示例：</p><div class="code-container" data-rel="Diff"><figure class="iseeu highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">2c2</span><br><span class="line">&lt;     sendfile off;</span><br><span class="line"><span class="comment">---</span></span><br><span class="line">&gt;     sendfile on;</span><br><span class="line">5a6</span><br><span class="line">&gt;     gzip on;</span><br></pre></td></tr></table></figure></div><ul><li><code>2c2</code>：文件1的第2行被替换为文件2的第2行</li><li><code>5a6</code>：在文件1的第5行之后追加文件2的第6行</li><li><code>&lt;</code> 开头：文件1的内容</li><li><code>&gt;</code> 开头：文件2的内容</li><li><code>---</code>：两部分的分隔线</li></ul><p>操作符说明：</p><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>操作符</th><th>含义</th><th>示例</th></tr></thead><tbody><tr><td><code>a</code></td><td>追加（append）</td><td><code>5a6</code> — 第5行后追加</td></tr><tr><td><code>c</code></td><td>替换（change）</td><td><code>2c2</code> — 第2行替换</td></tr><tr><td><code>d</code></td><td>删除（delete）</td><td><code>3d2</code> — 删除第3行</td></tr></tbody></table></div><h4 id="1-2-2-上下文格式（context，-c）"><a href="#1-2-2-上下文格式（context，-c）" class="headerlink" title="1.2.2 上下文格式（context，-c）"></a>1.2.2 上下文格式（context，-c）</h4><p>显示差异行周围的上下文（默认3行），适合查看变更的上下文：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">diff -c nginx.conf.bak nginx.conf</span><br></pre></td></tr></table></figure></div><p>输出示例：</p><div class="code-container" data-rel="Diff"><figure class="iseeu highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">*** nginx.conf.bak2026-06-17 01:00:00.000000000 +0800</span></span><br><span class="line"><span class="comment">--- nginx.conf2026-06-17 02:00:00.000000000 +0800</span></span><br><span class="line"><span class="comment">***************</span></span><br><span class="line"><span class="meta">*** 1,6 ****</span></span><br><span class="line">  user www-data;</span><br><span class="line">  worker_processes auto;</span><br><span class="line"><span class="addition">!     sendfile off;</span></span><br><span class="line">  keepalive_timeout 65;</span><br><span class="line">  include /etc/nginx/conf.d/*.conf;</span><br><span class="line"><span class="meta">--- 1,7 ----</span></span><br><span class="line">  user www-data;</span><br><span class="line">  worker_processes auto;</span><br><span class="line"><span class="addition">!     sendfile on;</span></span><br><span class="line">  keepalive_timeout 65;</span><br><span class="line">  include /etc/nginx/conf.d/*.conf;</span><br><span class="line"><span class="addition">+ gzip on;</span></span><br></pre></td></tr></table></figure></div><ul><li><code>*** 1,6 ****</code>：文件1的第1-6行</li><li><code>--- 1,7 ----</code>：文件2的第1-7行</li><li><code>!</code> 开头：有变更的行</li><li><code>+</code> 开头：新增的行</li><li><code>-</code> 开头：删除的行</li></ul><h4 id="1-2-3-统一格式（unified，-u）⭐推荐"><a href="#1-2-3-统一格式（unified，-u）⭐推荐" class="headerlink" title="1.2.3 统一格式（unified，-u）⭐推荐"></a>1.2.3 统一格式（unified，-u）⭐推荐</h4><p>合并上下文和变更标记，更紧凑易读。<strong>这是 Git diff 使用的格式，也是日常最推荐的方式：</strong></p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">diff -u nginx.conf.bak nginx.conf</span><br></pre></td></tr></table></figure></div><p>输出示例：</p><div class="code-container" data-rel="Diff"><figure class="iseeu highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">--- nginx.conf.bak2026-06-17 01:00:00.000000000 +0800</span></span><br><span class="line"><span class="comment">+++ nginx.conf2026-06-17 02:00:00.000000000 +0800</span></span><br><span class="line"><span class="meta">@@ -1,6 +1,7 @@</span></span><br><span class="line"> user www-data;</span><br><span class="line"> worker_processes auto;</span><br><span class="line"><span class="deletion">-sendfile off;</span></span><br><span class="line"><span class="addition">+sendfile on;</span></span><br><span class="line"> keepalive_timeout 65;</span><br><span class="line"> include /etc/nginx/conf.d/*.conf;</span><br><span class="line"><span class="addition">+gzip on;</span></span><br></pre></td></tr></table></figure></div><ul><li><code>@@ -1,6 +1,7 @@</code>：文件1第1-6行 → 文件2第1-7行</li><li><code>-</code> 删除的行</li><li><code>+</code> 新增的行</li><li>无前缀的行：共享的上下文</li></ul><p><strong>推荐使用 <code>-u</code> 选项</strong>——输出简洁、包含上下文、直接可用于 patch 命令。</p><h3 id="1-3-常用选项速查"><a href="#1-3-常用选项速查" class="headerlink" title="1.3 常用选项速查"></a>1.3 常用选项速查</h3><div class="opt-table"><table><thead><tr><th>选项</th><th>说明</th><th>示例</th></tr></thead><tbody><tr><td><code>-u</code></td><td>统一格式输出（推荐）</td><td><code>diff -u a.txt b.txt</code></td></tr><tr><td><code>-c</code></td><td>上下文格式输出</td><td><code>diff -c a.txt b.txt</code></td></tr><tr><td><code>-i</code></td><td>忽略大小写差异</td><td><code>diff -i a.txt b.txt</code></td></tr><tr><td><code>-w</code></td><td>忽略空白字符差异</td><td><code>diff -w a.txt b.txt</code></td></tr><tr><td><code>-b</code></td><td>忽略空白数量变化</td><td><code>diff -b a.txt b.txt</code></td></tr><tr><td><code>-r</code></td><td>递归比较目录</td><td><code>diff -r dir1 dir2</code></td></tr><tr><td><code>-q</code></td><td>仅报告文件是否不同（安静模式）</td><td><code>diff -q a.txt b.txt</code></td></tr><tr><td><code>-N</code></td><td>将缺失文件视为空文件（配合 -r 使用）</td><td><code>diff -ruN dir1 dir2</code></td></tr><tr><td><code>-x PAT</code></td><td>排除匹配模式的文件</td><td><code>diff -r -x node_modules d1 d2</code></td></tr><tr><td><code>--color</code></td><td>彩色输出差异</td><td><code>diff -u --color a.txt b.txt</code></td></tr></tbody></table></div><h3 id="1-4-递归比较目录"><a href="#1-4-递归比较目录" class="headerlink" title="1.4 递归比较目录"></a>1.4 递归比较目录</h3><p>这是 diff 最强大的运维场景之一——比较两个目录树的差异：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 递归比较两个配置目录</span></span><br><span class="line">diff -rq /etc/nginx/sites-enabled/ /etc/nginx/sites-available/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 递归比较并输出统一格式差异</span></span><br><span class="line">diff -ruN /etc/nginx/ /backup/nginx/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 只列出有差异的文件</span></span><br><span class="line">diff -rq /var/www/html/ /var/www/html_bak/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 排除特定目录</span></span><br><span class="line">diff -ruN --exclude=cache --exclude=logs app/ app_new/</span><br></pre></td></tr></table></figure></div><h3 id="1-5-重定向差异输出到文件"><a href="#1-5-重定向差异输出到文件" class="headerlink" title="1.5 重定向差异输出到文件"></a>1.5 重定向差异输出到文件</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 生成补丁文件（供 patch 命令使用）</span></span><br><span class="line">diff -u nginx.conf.bak nginx.conf &gt; nginx.patch</span><br><span class="line"></span><br><span class="line"><span class="comment"># 递归生成目录级别补丁</span></span><br><span class="line">diff -ruN config/ config_new/ &gt; config-upgrade.patch</span><br></pre></td></tr></table></figure></div><h2 id="二、patch-命令详解"><a href="#二、patch-命令详解" class="headerlink" title="二、patch 命令详解"></a>二、patch 命令详解</h2><p><code>patch</code> 命令将 <code>diff</code> 生成的补丁文件应用到目标文件或目录，实现自动化变更。</p><h3 id="2-1-基本语法"><a href="#2-1-基本语法" class="headerlink" title="2.1 基本语法"></a>2.1 基本语法</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">patch [选项] &lt; 补丁文件</span><br><span class="line">patch 目标文件 &lt; 补丁文件</span><br></pre></td></tr></table></figure></div><h3 id="2-2-应用补丁的两种方式"><a href="#2-2-应用补丁的两种方式" class="headerlink" title="2.2 应用补丁的两种方式"></a>2.2 应用补丁的两种方式</h3><h4 id="方式一：预先指定目标"><a href="#方式一：预先指定目标" class="headerlink" title="方式一：预先指定目标"></a>方式一：预先指定目标</h4><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">diff -u origin.conf modified.conf &gt; change.patch</span><br><span class="line">patch origin.conf &lt; change.patch   <span class="comment"># 将 change.patch 应用到 origin.conf</span></span><br></pre></td></tr></table></figure></div><p>执行后 <code>origin.conf</code> 被修改为与 <code>modified.conf</code> 一致。</p><h4 id="方式二：补丁内包含路径信息（推荐）"><a href="#方式二：补丁内包含路径信息（推荐）" class="headerlink" title="方式二：补丁内包含路径信息（推荐）"></a>方式二：补丁内包含路径信息（推荐）</h4><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 生成补丁时保留路径</span></span><br><span class="line">diff -u /etc/nginx/nginx.conf.orig /etc/nginx/nginx.conf &gt; nginx.patch</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在任意位置应用</span></span><br><span class="line">patch -p0 &lt; nginx.patch</span><br></pre></td></tr></table></figure></div><p><code>-pN</code> 参数指定剥离路径前缀的层数：</p><div class="opt-table"><table><thead><tr><th>参数</th><th>路径处理</th><th>示例文件路径</th></tr></thead><tbody><tr><td><code>-p0</code></td><td>使用完整路径</td><td><code>/etc/nginx/nginx.conf</code></td></tr><tr><td><code>-p1</code></td><td>剥离第一级</td><td><code>etc/nginx/nginx.conf</code></td></tr><tr><td><code>-p3</code></td><td>剥离三级</td><td><code>nginx.conf</code></td></tr></tbody></table></div><h3 id="2-3-patch-常用选项"><a href="#2-3-patch-常用选项" class="headerlink" title="2.3 patch 常用选项"></a>2.3 patch 常用选项</h3><div class="opt-table"><table><thead><tr><th>选项</th><th>说明</th><th>示例</th></tr></thead><tbody><tr><td><code>-pN</code></td><td>剥离路径前缀 N 级</td><td><code>patch -p1 < patch.diff</code></td></tr><tr><td><code>-R</code></td><td>反向应用补丁（回滚）</td><td><code>patch -R < patch.diff</code></td></tr><tr><td><code>--dry-run</code></td><td>试运行（不实际修改，检查兼容性）</td><td><code>patch --dry-run < patch.diff</code></td></tr><tr><td><code>-b</code></td><td>备份原文件（生成 .orig 文件）</td><td><code>patch -b < patch.diff</code></td></tr><tr><td><code>-B PREFIX</code></td><td>备份文件前缀</td><td><code>patch -B .bak~ < patch.diff</code></td></tr><tr><td><code>-d DIR</code></td><td>在指定目录下执行 patching</td><td><code>patch -d /etc/nginx < patch.diff</code></td></tr><tr><td><code>-i FILE</code></td><td>从文件读取补丁</td><td><code>patch -i change.patch</code></td></tr><tr><td><code>-E</code></td><td>应用补丁后删除空文件</td><td><code>patch -E < patch.diff</code></td></tr><tr><td><code>-s</code></td><td>静默模式（仅输出错误）</td><td><code>patch -s < patch.diff</code></td></tr></tbody></table></div><h3 id="2-4-安全先行：dry-run-试运行"><a href="#2-4-安全先行：dry-run-试运行" class="headerlink" title="2.4 安全先行：dry-run 试运行"></a>2.4 安全先行：dry-run 试运行</h3><p><strong>在实际应用补丁之前，务必先试运行：</strong></p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">patch --dry-run &lt; change.patch</span><br><span class="line"><span class="comment"># 输出：checking file nginx.conf</span></span><br></pre></td></tr></table></figure></div><p>如果输出类似 <code>Hunk #1 FAILED at 1.</code>，说明补丁与当前文件不匹配，需要手动检查。</p><h2 id="三、实战场景"><a href="#三、实战场景" class="headerlink" title="三、实战场景"></a>三、实战场景</h2><h3 id="场景-1：配置文件变更管理"><a href="#场景-1：配置文件变更管理" class="headerlink" title="场景 1：配置文件变更管理"></a>场景 1：配置文件变更管理</h3><p>运维人员修改 Nginx 配置前先备份，然后生成补丁方便回滚：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 备份</span></span><br><span class="line"><span class="built_in">cp</span> /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$(<span class="built_in">date</span> +%Y%m%d)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 修改后生成补丁</span></span><br><span class="line">diff -u /etc/nginx/nginx.conf.$(<span class="built_in">date</span> +%Y%m%d) /etc/nginx/nginx.conf &gt; ~/nginx-change.patch</span><br><span class="line"></span><br><span class="line"><span class="comment"># 需要回滚时</span></span><br><span class="line">patch -R /etc/nginx/nginx.conf &lt; ~/nginx-change.patch</span><br></pre></td></tr></table></figure></div><h3 id="场景-2：源码级热修复"><a href="#场景-2：源码级热修复" class="headerlink" title="场景 2：源码级热修复"></a>场景 2：源码级热修复</h3><p>当远端服务器不能直接使用 Git，但需要应用代码修改时：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 本地开发环境生成补丁</span></span><br><span class="line"><span class="built_in">cd</span> /home/dev/project</span><br><span class="line">diff -u src/app.js.orig src/app.js &gt; fix-login.patch</span><br><span class="line"></span><br><span class="line"><span class="comment"># 复制到生产服务器并应用</span></span><br><span class="line">scp fix-login.patch user@prod-server:/tmp/</span><br><span class="line">ssh user@prod-server <span class="string">&quot;cd /var/www/app &amp;&amp; patch -p1 &lt; /tmp/fix-login.patch&quot;</span></span><br></pre></td></tr></table></figure></div><h3 id="场景-3：目录级别批量管理"><a href="#场景-3：目录级别批量管理" class="headerlink" title="场景 3：目录级别批量管理"></a>场景 3：目录级别批量管理</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 生成完整项目补丁</span></span><br><span class="line">diff -ruN project-v1/ project-v2/ --exclude=.git --exclude=node_modules &gt; upgrade-v2.patch</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看补丁大小和概要</span></span><br><span class="line"><span class="built_in">wc</span> -l upgrade-v2.patch</span><br><span class="line"><span class="built_in">head</span> -50 upgrade-v2.patch</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在另一台机器上应用</span></span><br><span class="line"><span class="built_in">cd</span> /opt/project</span><br><span class="line">patch -p1 &lt; /tmp/upgrade-v2.patch</span><br></pre></td></tr></table></figure></div><h3 id="场景-4：反向补丁回滚"><a href="#场景-4：反向补丁回滚" class="headerlink" title="场景 4：反向补丁回滚"></a>场景 4：反向补丁回滚</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 已经应用了补丁，需要回退</span></span><br><span class="line">patch -R -p1 &lt; change.patch</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或使用 -R 试运行确认</span></span><br><span class="line">patch -R --dry-run -p1 &lt; change.patch</span><br></pre></td></tr></table></figure></div><h3 id="场景-5：仅查看差异的文件列表"><a href="#场景-5：仅查看差异的文件列表" class="headerlink" title="场景 5：仅查看差异的文件列表"></a>场景 5：仅查看差异的文件列表</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看两个目录中有哪些文件不同</span></span><br><span class="line">diff -rq config/ config-bak/ | grep -v <span class="string">&quot;Only in&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 仅输出差异文件的数量</span></span><br><span class="line">diff -rq config/ config-bak/ | <span class="built_in">wc</span> -l</span><br><span class="line"></span><br><span class="line"><span class="comment"># 输出仅在源目录中存在的文件</span></span><br><span class="line">diff -rq config/ config-bak/ | grep <span class="string">&quot;Only in config/&quot;</span></span><br></pre></td></tr></table></figure></div><h2 id="四、常见问题排查"><a href="#四、常见问题排查" class="headerlink" title="四、常见问题排查"></a>四、常见问题排查</h2><div class="opt-table"><table><thead><tr><th>问题</th><th>现象</th><th>解决方案</th></tr></thead><tbody><tr><td>补丁失败：Hunk 不匹配</td><td><code>Hunk #1 FAILED at 10.</code></td><td>目标文件已被修改，与生成补丁时的版本不一致。重新生成补丁或手动合并。</td></tr><tr><td>路径不匹配</td><td><code>can't find file to patch</code></td><td>调整 <code>-pN</code> 参数级别。先用 <code>patch --dry-run</code> 测试不同 <code>-p</code> 值。</td></tr><tr><td>空白字符差异</td><td>diff 输出大量无实质变化的差异</td><td>使用 <code>-w</code> 或 <code>-b</code> 忽略空白差异生成补丁。</td></tr><tr><td>二进制文件比较</td><td>diff 输出 <code>Binary files differ</code></td><td>使用 <code>diff -a</code> 强制文本模式，或用 <code>md5sum</code> 校验。</td></tr><tr><td>大目录比较过慢</td><td>diff -r 对大量文件执行缓慢</td><td>先用 <code>diff -rq</code> 列出差异文件，再对特定文件生成补丁。</td></tr><tr><td>换行符不一致</td><td>Windows (CRLF) vs Linux (LF)</td><td>使用 <code>diff -w</code> 忽略空白差异，或先用 <code>dos2unix</code> 统一换行符。</td></tr><tr><td>补丁部分应用</td><td>某些 Hunk 成功，某些失败</td><td>使用 <code>--force</code> 强制应用失败的 Hunk（谨慎！），或手动编辑补丁文件修正偏移量。</td></tr></tbody></table></div><h2 id="五、diff-和-patch-的进阶技巧"><a href="#五、diff-和-patch-的进阶技巧" class="headerlink" title="五、diff 和 patch 的进阶技巧"></a>五、diff 和 patch 的进阶技巧</h2><h3 id="5-1-与-Git-的关系"><a href="#5-1-与-Git-的关系" class="headerlink" title="5.1 与 Git 的关系"></a>5.1 与 Git 的关系</h3><p>Git 内部使用的差异算法就是 <code>diff</code> 的一种扩展，<code>git diff</code> 的输出就是 unified diff 格式：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Git diff 输出示例</span></span><br><span class="line">git diff src/app.js</span><br><span class="line"></span><br><span class="line"><span class="comment"># 导出 Git 差异为补丁文件</span></span><br><span class="line">git diff &gt; my-changes.patch</span><br><span class="line">git format-patch HEAD~1   <span class="comment"># 生成更完整的补丁（含 commit 信息）</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 应用 Git 补丁</span></span><br><span class="line">patch -p1 &lt; my-changes.patch</span><br><span class="line">git am &lt; 0001-fix-bug.patch   <span class="comment"># 使用 git am 应用 format-patch 生成的补丁</span></span><br></pre></td></tr></table></figure></div><h3 id="5-2-彩色差异化输出"><a href="#5-2-彩色差异化输出" class="headerlink" title="5.2 彩色差异化输出"></a>5.2 彩色差异化输出</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># diff 自带彩色支持（GNU diffutils 3.4+）</span></span><br><span class="line">diff -u --color=always origin.conf modified.conf</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用 colordiff 工具</span></span><br><span class="line">colordiff -u origin.conf modified.conf</span><br></pre></td></tr></table></figure></div><h3 id="5-3-比较非文本文件"><a href="#5-3-比较非文本文件" class="headerlink" title="5.3 比较非文本文件"></a>5.3 比较非文本文件</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 比较 PDF/DOCX 等二进制文件时，diff 只报告是否相同</span></span><br><span class="line">diff -q doc1.pdf doc2.pdf</span><br><span class="line"><span class="comment"># 输出：Binary files doc1.pdf and doc2.pdf differ</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用专用工具</span></span><br><span class="line"><span class="comment"># apt install diffpdf</span></span><br><span class="line">diffpdf doc1.pdf doc2.pdf</span><br></pre></td></tr></table></figure></div><h3 id="5-4-使用-diff3-三路合并"><a href="#5-4-使用-diff3-三路合并" class="headerlink" title="5.4 使用 diff3 三路合并"></a>5.4 使用 diff3 三路合并</h3><p><code>diff3</code> 是 diff 的扩展，比较三个文件，常用于合并多个修改版本：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">diff3 -m my-file.txt base.txt their-file.txt &gt; merged.txt</span><br></pre></td></tr></table></figure></div><h3 id="5-5-交互式补丁应用（sdiff）"><a href="#5-5-交互式补丁应用（sdiff）" class="headerlink" title="5.5 交互式补丁应用（sdiff）"></a>5.5 交互式补丁应用（sdiff）</h3><p><code>sdiff</code> 并排显示两个文件的差异：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sdiff -w 120 nginx.conf.bak nginx.conf</span><br></pre></td></tr></table></figure></div><h2 id="六、最佳实践总结"><a href="#六、最佳实践总结" class="headerlink" title="六、最佳实践总结"></a>六、最佳实践总结</h2><ol><li><strong>始终用 <code>-u</code> 生成补丁</strong> — unified 格式易读、可直接用于 patch</li><li><strong>应用补丁前用 <code>--dry-run</code></strong> — 先验证兼容性，避免破坏性操作</li><li><strong>备份原始文件</strong> — 使用 <code>patch -b</code> 自动生成 <code>.orig</code> 备份</li><li><strong>使用 <code>-p1</code> 剥离一级路径</strong> — 这是绝大多数开源项目的标准做法</li><li><strong>用 <code>diff -rq</code> 快速检查目录差异</strong> — 确认哪些文件有变更再深入分析</li><li><strong>反转补丁用 <code>-R</code></strong> — 快速回滚不需要重新生成反向补丁</li><li><strong>排除无关目录</strong> — 使用 <code>--exclude</code> 跳过 <code>.git</code>、<code>node_modules</code>、<code>cache</code> 等</li></ol><h2 id="参考命令速查"><a href="#参考命令速查" class="headerlink" title="参考命令速查"></a>参考命令速查</h2><div class="opt-table"><table><thead><tr><th>场景</th><th>命令</th></tr></thead><tbody><tr><td>比较两个文件（统一格式）</td><td><code>diff -u file1 file2</code></td></tr><tr><td>递归比较两个目录</td><td><code>diff -ruN dir1 dir2</code></td></tr><tr><td>仅列出差异文件名</td><td><code>diff -rq dir1 dir2</code></td></tr><tr><td>忽略空白差异</td><td><code>diff -uw file1 file2</code></td></tr><tr><td>生成补丁文件</td><td><code>diff -u old new > patch.diff</code></td></tr><tr><td>应用补丁</td><td><code>patch -p1 < patch.diff</code></td></tr><tr><td>试运行补丁</td><td><code>patch --dry-run -p1 < patch.diff</code></td></tr><tr><td>回滚补丁</td><td><code>patch -R -p1 < patch.diff</code></td></tr><tr><td>带备份应用补丁</td><td><code>patch -b -p1 < patch.diff</code></td></tr><tr><td>从文件读取补丁</td><td><code>patch -i patch.diff</code></td></tr><tr><td>彩色 diff 输出</td><td><code>diff -u --color=always a b</code></td></tr><tr><td>三路合并</td><td><code>diff3 -m mine base theirs</code></td></tr><tr><td>并排比较</td><td><code>sdiff -w 120 file1 file2</code></td></tr></tbody></table></div><hr><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-17-diff-patch-guide/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-17-diff-patch-guide/"/>
    <published>2026-06-16T18:48:00.000Z</published>
    <summary>
      <![CDATA[<p>在 Linux 系统管理和软件开发中，<strong>文件比较</strong>和<strong>补丁管理</strong>是两项基础而强大的技能。<code>diff</code> 命令用于逐行比较文件差异，<code>patch</code> 命令则根据差异文件（补丁）]]>
    </summary>
    <title>Linux diff 与 patch 命令完全指南：文件比较与补丁管理</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="环境搭建" scheme="https://demo-blog.qusite.cn/tags/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
    <category term="Java" scheme="https://demo-blog.qusite.cn/tags/Java/"/>
    <category term="JDK" scheme="https://demo-blog.qusite.cn/tags/JDK/"/>
    <category term="Maven" scheme="https://demo-blog.qusite.cn/tags/Maven/"/>
    <category term="Gradle" scheme="https://demo-blog.qusite.cn/tags/Gradle/"/>
    <category term="IntelliJ IDEA" scheme="https://demo-blog.qusite.cn/tags/IntelliJ-IDEA/"/>
    <content>
      <![CDATA[<p>Java 作为企业级应用开发的主力语言，二十多年来始终保持着旺盛的生命力。无论是构建后端微服务、大数据平台，还是 Android 应用，Java 都是绕不开的技术栈。本文将从零开始，手把手带你搭建一套完整的 Java 开发环境，涵盖 JDK 安装配置、构建工具选型、IDE 集成以及 Spring Boot 项目实战。</p><h2 id="一、JDK-版本选择与安装"><a href="#一、JDK-版本选择与安装" class="headerlink" title="一、JDK 版本选择与安装"></a>一、JDK 版本选择与安装</h2><h3 id="1-1-版本选择"><a href="#1-1-版本选择" class="headerlink" title="1.1 版本选择"></a>1.1 版本选择</h3><p>Oracle 自 JDK 17 起将 LTS（长期支持）版本发布周期调整为每两年一次，目前主流的选择如下：</p><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>版本</th><th>类型</th><th>最新特性亮点</th><th>推荐场景</th></tr></thead><tbody><tr><td>JDK 21</td><td>LTS（2023.09）</td><td>虚拟线程、记录模式、模式匹配 switch</td><td>新项目首选</td></tr><tr><td>JDK 17</td><td>LTS（2021.09）</td><td>密封类、预览特性丰富、性能大幅提升</td><td>企业生产环境主流</td></tr><tr><td>JDK 11</td><td>LTS（2018.09）</td><td>HTTP Client、ZGC、模块化</td><td>老旧项目迁移过渡</td></tr><tr><td>JDK 8</td><td>LTS（2014.03）</td><td>Lambda、Stream、Optional</td><td>历史遗留项目</td></tr></tbody></table></div><blockquote><p>建议新项目直接选用 <strong>JDK 21</strong>，充分利用虚拟线程（Virtual Threads）带来的并发编程体验革命。</p></blockquote><h3 id="1-2-Ubuntu-22-04-安装-JDK-21"><a href="#1-2-Ubuntu-22-04-安装-JDK-21" class="headerlink" title="1.2 Ubuntu 22.04 安装 JDK 21"></a>1.2 Ubuntu 22.04 安装 JDK 21</h3><p>方式一：使用 SDKMAN（推荐）</p><p>SDKMAN 是 Java 生态中最便捷的多版本管理工具，类似 Node.js 的 nvm 或 Python 的 pyenv。</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装 SDKMAN</span></span><br><span class="line">curl -s <span class="string">&quot;https://get.sdkman.io&quot;</span> | bash</span><br><span class="line"><span class="built_in">source</span> <span class="string">&quot;<span class="variable">$HOME</span>/.sdkman/bin/sdkman-init.sh&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看可用 JDK 版本</span></span><br><span class="line">sdk list java</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 JDK 21（Eclipse Temurin 是 Adoptium 社区构建的开源版本）</span></span><br><span class="line">sdk install java 21.0.4-tem</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置默认版本</span></span><br><span class="line">sdk default java 21.0.4-tem</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证</span></span><br><span class="line">java -version</span><br><span class="line">javac -version</span><br></pre></td></tr></table></figure></div><p>方式二：使用 apt 安装（适合单版本需求）</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装 OpenJDK 21</span></span><br><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install openjdk-21-jdk -y</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证</span></span><br><span class="line">java -version</span><br></pre></td></tr></table></figure></div><p>方式三：Oracle JDK 手动安装</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 下载 JDK 21 Linux x64 压缩包</span></span><br><span class="line">wget https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.tar.gz</span><br><span class="line"></span><br><span class="line"><span class="comment"># 解压到 /opt</span></span><br><span class="line"><span class="built_in">sudo</span> tar -xzf jdk-21_linux-x64_bin.tar.gz -C /opt/</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> &gt;&gt; ~/.bashrc &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line"><span class="built_in">export</span> JAVA_HOME=/opt/jdk-21.0.4</span><br><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$JAVA_HOME</span>/bin:<span class="variable">$PATH</span></span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证</span></span><br><span class="line">java -version</span><br></pre></td></tr></table></figure></div><h3 id="1-3-Windows-安装-JDK-21"><a href="#1-3-Windows-安装-JDK-21" class="headerlink" title="1.3 Windows 安装 JDK 21"></a>1.3 Windows 安装 JDK 21</h3><div class="code-container" data-rel="Powershell"><figure class="iseeu highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 方式一：使用 winget（Windows 包管理器）</span></span><br><span class="line">winget install EclipseAdoptium.Temurin.<span class="number">21</span>.JDK</span><br><span class="line"></span><br><span class="line"><span class="comment"># 方式二：手动安装</span></span><br><span class="line"><span class="comment"># 1. 访问 https://adoptium.net/ 下载 msi 安装包</span></span><br><span class="line"><span class="comment"># 2. 双击安装，选择安装路径（如 C:\Program Files\Eclipse Adoptium\jdk-21.0.4-hotspot）</span></span><br><span class="line"><span class="comment"># 3. 设置系统环境变量</span></span><br><span class="line"><span class="comment">#    - 新建系统变量 JAVA_HOME = C:\Program Files\Eclipse Adoptium\jdk-21.0.4-hotspot</span></span><br><span class="line"><span class="comment">#    - 在 Path 中添加 %JAVA_HOME%\bin</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证</span></span><br><span class="line">java <span class="literal">-version</span></span><br></pre></td></tr></table></figure></div><h2 id="二、构建工具配置"><a href="#二、构建工具配置" class="headerlink" title="二、构建工具配置"></a>二、构建工具配置</h2><h3 id="2-1-Maven"><a href="#2-1-Maven" class="headerlink" title="2.1 Maven"></a>2.1 Maven</h3><p>Maven 是 Java 生态中最流行的构建工具，采用约定优于配置的理念。</p><p><strong>安装 Maven：</strong></p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Ubuntu</span></span><br><span class="line"><span class="built_in">sudo</span> apt install maven -y   <span class="comment"># 版本通常较旧，建议手动安装最新版</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 手动安装（推荐）</span></span><br><span class="line">wget https://dlcdn.apache.org/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.tar.gz</span><br><span class="line"><span class="built_in">sudo</span> tar -xzf apache-maven-3.9.9-bin.tar.gz -C /opt/</span><br><span class="line"><span class="built_in">cat</span> &gt;&gt; ~/.bashrc &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line"><span class="built_in">export</span> MAVEN_HOME=/opt/apache-maven-3.9.9</span><br><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$MAVEN_HOME</span>/bin:<span class="variable">$PATH</span></span><br><span class="line">EOF</span><br><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br><span class="line"></span><br><span class="line">mvn --version</span><br></pre></td></tr></table></figure></div><p><strong>配置国内镜像加速：</strong></p><p>编辑 <code>~/.m2/settings.xml</code>（如果不存在则创建）：</p><div class="code-container" data-rel="Xml"><figure class="iseeu 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></pre></td><td class="code"><pre><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</span></span></span><br><span class="line"><span class="string"><span class="tag">          https://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>aliyun-maven<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>阿里云公共仓库<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>https://maven.aliyun.com/repository/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><br><span class="line">  <span class="tag">&lt;<span class="name">profiles</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">profile</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">id</span>&gt;</span>jdk-21<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">activation</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">activeByDefault</span>&gt;</span>true<span class="tag">&lt;/<span class="name">activeByDefault</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">activation</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">maven.compiler.source</span>&gt;</span>21<span class="tag">&lt;/<span class="name">maven.compiler.source</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">maven.compiler.target</span>&gt;</span>21<span class="tag">&lt;/<span class="name">maven.compiler.target</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">project.build.sourceEncoding</span>&gt;</span>UTF-8<span class="tag">&lt;/<span class="name">project.build.sourceEncoding</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">profile</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">profiles</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></div><p><strong>Maven 核心命令速查：</strong></p><div class="opt-table"><table><thead><tr><th>命令</th><th>说明</th></tr></thead><tbody><tr><td><code>mvn clean</code></td><td>清理 target 目录</td></tr><tr><td><code>mvn compile</code></td><td>编译源代码</td></tr><tr><td><code>mvn test</code></td><td>运行测试</td></tr><tr><td><code>mvn package</code></td><td>打包（jar/war）</td></tr><tr><td><code>mvn install</code></td><td>安装到本地仓库</td></tr><tr><td><code>mvn deploy</code></td><td>部署到远程仓库</td></tr><tr><td><code>mvn clean package -DskipTests</code></td><td>跳过测试打包</td></tr><tr><td><code>mvn dependency:tree</code></td><td>查看依赖树</td></tr></tbody></table></div><h3 id="2-2-Gradle"><a href="#2-2-Gradle" class="headerlink" title="2.2 Gradle"></a>2.2 Gradle</h3><p>Gradle 使用 Groovy 或 Kotlin DSL 编写构建脚本，在灵活性和性能上优于 Maven。</p><p><strong>安装 Gradle：</strong></p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用 SDKMAN（推荐）</span></span><br><span class="line">sdk install gradle 8.10</span><br><span class="line"></span><br><span class="line"><span class="comment"># 手动安装</span></span><br><span class="line">wget https://services.gradle.org/distributions/gradle-8.10-bin.zip</span><br><span class="line"><span class="built_in">sudo</span> unzip -d /opt/gradle gradle-8.10-bin.zip</span><br><span class="line"><span class="built_in">cat</span> &gt;&gt; ~/.bashrc &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line"><span class="built_in">export</span> GRADLE_HOME=/opt/gradle/gradle-8.10</span><br><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$GRADLE_HOME</span>/bin:<span class="variable">$PATH</span></span><br><span class="line">EOF</span><br><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br><span class="line"></span><br><span class="line">gradle --version</span><br></pre></td></tr></table></figure></div><p><strong>配置国内镜像（<code>~/.gradle/init.gradle</code>）：</strong></p><div class="code-container" data-rel="Groovy"><figure class="iseeu highlight groovy"><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">allprojects &#123;</span><br><span class="line">    repositories &#123;</span><br><span class="line">        maven &#123;</span><br><span class="line">            url <span class="string">&#x27;https://maven.aliyun.com/repository/public&#x27;</span></span><br><span class="line">        &#125;</span><br><span class="line">        mavenCentral()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>Maven vs Gradle 对比：</strong></p><div class="opt-table"><table><thead><tr><th>维度</th><th>Maven</th><th>Gradle</th></tr></thead><tbody><tr><td>构建脚本语言</td><td>XML（pom.xml）</td><td>Groovy / Kotlin DSL</td></tr><tr><td>构建速度</td><td>较慢，增量构建能力弱</td><td>快，支持增量编译和构建缓存</td></tr><tr><td>依赖管理</td><td>可靠，生态成熟</td><td>功能更丰富，支持动态版本</td></tr><tr><td>编译配置量</td><td>XML 冗长</td><td>DSL 简洁灵活</td></tr><tr><td>多项目构建</td><td>模块化支持良好</td><td>一等公民支持</td></tr><tr><td>学习曲线</td><td>低（XML 简单）</td><td>中（需要学 DSL）</td></tr><tr><td>适用场景</td><td>企业标准项目</td><td>Android、高性能构建需求</td></tr></tbody></table></div><blockquote><p><strong>选择建议</strong>：传统企业项目选 Maven，追求构建速度和灵活性选 Gradle。如果刚开始学习 Java，推荐从 Maven 入手，社区资源和文档更丰富。</p></blockquote><h2 id="三、IDE-配置"><a href="#三、IDE-配置" class="headerlink" title="三、IDE 配置"></a>三、IDE 配置</h2><h3 id="3-1-IntelliJ-IDEA（推荐）"><a href="#3-1-IntelliJ-IDEA（推荐）" class="headerlink" title="3.1 IntelliJ IDEA（推荐）"></a>3.1 IntelliJ IDEA（推荐）</h3><p>IDEA 是目前 Java 开发最强大的 IDE，Community 版免费且功能已相当完善。</p><p><strong>安装：</strong></p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Ubuntu（使用 snap）</span></span><br><span class="line"><span class="built_in">sudo</span> snap install intellij-idea-community --classic</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或手动下载安装</span></span><br><span class="line">wget https://download.jetbrains.com/idea/ideaIC-2024.2.3.tar.gz</span><br><span class="line"><span class="built_in">sudo</span> tar -xzf ideaIC-2024.2.3.tar.gz -C /opt/</span><br><span class="line">/opt/idea-IC-242.23339.11/bin/idea.sh</span><br></pre></td></tr></table></figure></div><p><strong>关键配置：</strong></p><ol><li><strong>JDK 配置</strong>：File → Project Structure → SDK → 添加 JDK 21</li><li><strong>编码设置</strong>：Settings → Editor → File Encodings → 全部设为 UTF-8</li><li><strong>自动导入</strong>：Settings → Editor → General → Auto Import → 勾选”Add unambiguous imports on the fly”</li><li><strong>代码模板</strong>：Settings → Editor → Live Templates → 可添加自定义缩写（如 <code>psvm</code> 生成 main 方法）</li><li><strong>插件推荐</strong>：</li></ol><div class="opt-table"><table><thead><tr><th>插件名称</th><th>功能</th></tr></thead><tbody><tr><td>Lombok</td><td>减少样板代码（@Data、@Builder 等）</td></tr><tr><td>MyBatisX</td><td>MyBatis 增强（跳转、生成）</td></tr><tr><td>CheckStyle-IDEA</td><td>代码风格检查</td></tr><tr><td>SonarLint</td><td>代码质量实时检测</td></tr><tr><td>Rainbow Brackets</td><td>彩虹括号，提高可读性</td></tr><tr><td>GitToolBox</td><td>增强 Git 状态显示</td></tr></tbody></table></div><h3 id="3-2-VS-Code"><a href="#3-2-VS-Code" class="headerlink" title="3.2 VS Code"></a>3.2 VS Code</h3><p>如果只需轻量编辑或进行简单的 Java 开发，VS Code 配合扩展也能胜任。</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装 Java 扩展包</span></span><br><span class="line">code --install-extension vscjava.vscode-java-pack</span><br></pre></td></tr></table></figure></div><p>VS Code Java 扩展包包含：</p><ul><li><strong>Language Support for Java(TM) by Red Hat</strong>：核心语言支持</li><li><strong>Debugger for Java</strong>：调试支持</li><li><strong>Test Runner for Java</strong>：单元测试运行</li><li><strong>Maven for Java</strong>：Maven 项目管理</li><li><strong>Project Manager for Java</strong>：项目配置管理</li></ul><p>配置 <code>settings.json</code>：</p><div class="code-container" data-rel="Json"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;java.configuration.runtimes&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;JavaSE-21&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;path&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/opt/jdk-21.0.4&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;default&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;java.compile.nullAnalysis.mode&quot;</span><span class="punctuation">:</span> <span class="string">&quot;automatic&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;editor.suggest.snippetsPreventQuickSuggestions&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></div><h2 id="四、Spring-Boot-项目实战"><a href="#四、Spring-Boot-项目实战" class="headerlink" title="四、Spring Boot 项目实战"></a>四、Spring Boot 项目实战</h2><p>环境搭建的最终目的是能跑起来一个实际项目。下面用 Maven 快速创建一个 Spring Boot 3 项目。</p><h3 id="4-1-使用-Spring-Initializr"><a href="#4-1-使用-Spring-Initializr" class="headerlink" title="4.1 使用 Spring Initializr"></a>4.1 使用 Spring Initializr</h3><p><strong>方式一：Web 界面</strong><br>访问 <a class="link"   href="https://start.spring.io/" >https://start.spring.io/<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，填写项目元数据，选择依赖后生成并下载。</p><p><strong>方式二：命令行（推荐）</strong></p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">curl https://start.spring.io/starter.zip \</span><br><span class="line">  -d <span class="built_in">type</span>=maven-project \</span><br><span class="line">  -d language=java \</span><br><span class="line">  -d bootVersion=3.3.5 \</span><br><span class="line">  -d baseDir=demo \</span><br><span class="line">  -d groupId=com.example \</span><br><span class="line">  -d artifactId=demo \</span><br><span class="line">  -d name=demo \</span><br><span class="line">  -d packageName=com.example.demo \</span><br><span class="line">  -d javaVersion=21 \</span><br><span class="line">  -d dependencies=web,devtools,lombok,actuator \</span><br><span class="line">  -o demo.zip</span><br><span class="line"></span><br><span class="line">unzip demo.zip -d demo</span><br><span class="line"><span class="built_in">cd</span> demo</span><br></pre></td></tr></table></figure></div><h3 id="4-2-项目结构"><a href="#4-2-项目结构" class="headerlink" title="4.2 项目结构"></a>4.2 项目结构</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line">demo/</span><br><span class="line">├── pom.xml                          # Maven 构建文件</span><br><span class="line">├── src/</span><br><span class="line">│   ├── main/</span><br><span class="line">│   │   ├── java/com/example/demo/</span><br><span class="line">│   │   │   ├── DemoApplication.java # 启动类</span><br><span class="line">│   │   │   ├── controller/</span><br><span class="line">│   │   │   │   └── HelloController.java</span><br><span class="line">│   │   │   └── service/</span><br><span class="line">│   │   │       └── HelloService.java</span><br><span class="line">│   │   └── resources/</span><br><span class="line">│   │       ├── application.yml       # 配置文件</span><br><span class="line">│   │       └── templates/</span><br><span class="line">│   └── test/java/com/example/demo/</span><br><span class="line">│       └── DemoApplicationTests.java</span><br></pre></td></tr></table></figure></div><h3 id="4-3-编写一个-REST-API"><a href="#4-3-编写一个-REST-API" class="headerlink" title="4.3 编写一个 REST API"></a>4.3 编写一个 REST API</h3><p><strong>HelloController.java：</strong></p><div class="code-container" data-rel="Java"><figure class="iseeu 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><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="keyword">package</span> com.example.demo.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestParam;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/hello&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">hello</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;World&quot;)</span> String name)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Hello, &quot;</span> + name + <span class="string">&quot;! Welcome to Java 21.&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>application.yml：</strong></p><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">8080</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">application:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">demo</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 健康检查端点</span></span><br><span class="line"><span class="attr">management:</span></span><br><span class="line">  <span class="attr">endpoints:</span></span><br><span class="line">    <span class="attr">web:</span></span><br><span class="line">      <span class="attr">exposure:</span></span><br><span class="line">        <span class="attr">include:</span> <span class="string">health,info</span></span><br></pre></td></tr></table></figure></div><h3 id="4-4-构建与运行"><a href="#4-4-构建与运行" class="headerlink" title="4.4 构建与运行"></a>4.4 构建与运行</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 编译</span></span><br><span class="line">mvn clean compile</span><br><span class="line"></span><br><span class="line"><span class="comment"># 运行测试</span></span><br><span class="line">mvn <span class="built_in">test</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 打包</span></span><br><span class="line">mvn clean package -DskipTests</span><br><span class="line"></span><br><span class="line"><span class="comment"># 直接运行（开发阶段）</span></span><br><span class="line">mvn spring-boot:run</span><br><span class="line"></span><br><span class="line"><span class="comment"># 运行打包后的 jar</span></span><br><span class="line">java -jar target/demo-0.0.1-SNAPSHOT.jar</span><br></pre></td></tr></table></figure></div><p>启动后访问 <code>http://localhost:8080/hello?name=Java</code>，即可看到响应。</p><h2 id="五、Docker-容器化-Java-开发"><a href="#五、Docker-容器化-Java-开发" class="headerlink" title="五、Docker 容器化 Java 开发"></a>五、Docker 容器化 Java 开发</h2><p>越来越多的团队使用 Docker 统一开发环境，这里给出一个多阶段构建的 Dockerfile 示例：</p><div class="code-container" data-rel="Dockerfile"><figure class="iseeu 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><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 构建阶段</span></span><br><span class="line"><span class="keyword">FROM</span> eclipse-temurin:<span class="number">21</span>-jdk-alpine AS builder</span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /app</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> pom.xml .</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> src ./src</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> apk add --no-cache maven &amp;&amp; mvn clean package -DskipTests</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 运行阶段</span></span><br><span class="line"><span class="keyword">FROM</span> eclipse-temurin:<span class="number">21</span>-jre-alpine</span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /app</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> --from=builder /app/target/*.jar app.jar</span></span><br><span class="line"><span class="keyword">EXPOSE</span> <span class="number">8080</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动优化参数</span></span><br><span class="line"><span class="keyword">ENTRYPOINT</span><span class="language-bash"> [<span class="string">&quot;java&quot;</span>, \</span></span><br><span class="line"><span class="language-bash">  <span class="string">&quot;-XX:+UseZGC&quot;</span>, \</span></span><br><span class="line"><span class="language-bash">  <span class="string">&quot;-XX:MaxRAMPercentage=75.0&quot;</span>, \</span></span><br><span class="line"><span class="language-bash">  <span class="string">&quot;-jar&quot;</span>, <span class="string">&quot;app.jar&quot;</span>]</span></span><br></pre></td></tr></table></figure></div><p>使用 Docker Compose 一键启动：</p><div class="code-container" data-rel="Yaml"><figure class="iseeu 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"># docker-compose.yml</span></span><br><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3.8&#x27;</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">app:</span></span><br><span class="line">    <span class="attr">build:</span> <span class="string">.</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;8080:8080&quot;</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">SPRING_PROFILES_ACTIVE=dev</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./logs:/app/logs</span></span><br></pre></td></tr></table></figure></div><h2 id="六、常见问题排查"><a href="#六、常见问题排查" class="headerlink" title="六、常见问题排查"></a>六、常见问题排查</h2><div class="opt-table"><table><thead><tr><th>问题现象</th><th>可能原因</th><th>解决方案</th></tr></thead><tbody><tr><td><code>java: command not found</code></td><td>JAVA_HOME 未设置或 Path 配置错误</td><td>检查 <code>echo $JAVA_HOME</code>，确保 <code>$JAVA_HOME/bin</code> 在 PATH 中</td></tr><tr><td><code>javac: invalid flag: --release</code></td><td>JDK 版本过低</td><td>确认 <code>java -version</code> 输出为 JDK 21，检查编译源版本</td></tr><tr><td>Maven 下载依赖极慢</td><td>未配置国内镜像</td><td>在 settings.xml 中添加阿里云 mirror 配置</td></tr><tr><td><code>Port 8080 already in use</code></td><td>端口被占用</td><td><code>lsof -i :8080</code> 查找进程，<code>kill -9 PID</code> 或更换端口</td></tr><tr><td>IDEA 无法识别 JDK</td><td>未配置 Project SDK</td><td>File → Project Structure → 选择 JDK 21</td></tr><tr><td>编译报 <code>ClassNotFoundException</code></td><td>Maven 依赖未下载或冲突</td><td><code>mvn dependency:tree</code> 分析依赖树</td></tr><tr><td>Lombok 注解不生效</td><td>IDEA 未安装 Lombok 插件</td><td>安装 Lombok 插件并启用 Annotation Processing</td></tr></tbody></table></div><h2 id="七、最佳实践总结"><a href="#七、最佳实践总结" class="headerlink" title="七、最佳实践总结"></a>七、最佳实践总结</h2><ol><li><strong>统一 JDK 版本</strong>：团队内统一使用相同 JDK 版本，建议 JDK 21 LTS，避免版本差异导致的问题</li><li><strong>使用构建工具</strong>：永远不要将 IDE 生成的 <code>.class</code> 文件提交到 Git，用 <code>mvn clean package</code> 或 <code>gradle build</code> 替代</li><li><strong>启用代码检查</strong>：配置 CheckStyle 或 SpotBugs 作为构建流程的 check 阶段，让问题早发现</li><li><strong>环境即代码</strong>：使用 Docker + Docker Compose 统一开发环境，消除”在我机器上能跑”的问题</li><li><strong>善用 <code>.gitignore</code></strong>：至少忽略 <code>target/</code>, <code>build/</code>, <code>*.iml</code>, <code>.idea/</code>, <code>.DS_Store</code></li><li><strong>本地仓库备份</strong>：Maven 的 <code>~/.m2/repository</code> 可定期备份，避免重装系统后重新下载</li><li><strong>学习路线</strong>：先掌握 Maven 和 Spring Boot，再逐步深入学习 Gradle、多模块构建、自定义 Plugin 等高级话题</li></ol><hr><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-17-java-env-setup/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-17-java-env-setup/"/>
    <published>2026-06-16T17:46:00.000Z</published>
    <summary>
      <![CDATA[<p>Java 作为企业级应用开发的主力语言，二十多年来始终保持着旺盛的生命力。无论是构建后端微服务、大数据平台，还是 Android 应用，Java 都是绕不开的技术栈。本文将从零开始，手把手带你搭建一套完整的 Java 开发环境，涵盖 JDK 安装配置、构建工具选型、IDE]]>
    </summary>
    <title>Java 开发环境搭建完全指南</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="Docker" scheme="https://demo-blog.qusite.cn/tags/Docker/"/>
    <category term="DevOps" scheme="https://demo-blog.qusite.cn/tags/DevOps/"/>
    <category term="CI/CD" scheme="https://demo-blog.qusite.cn/tags/CI-CD/"/>
    <category term="GitLab" scheme="https://demo-blog.qusite.cn/tags/GitLab/"/>
    <category term="代码托管" scheme="https://demo-blog.qusite.cn/tags/%E4%BB%A3%E7%A0%81%E6%89%98%E7%AE%A1/"/>
    <content>
      <![CDATA[<p>GitLab 是目前最流行的自托管 DevOps 平台之一，提供代码托管、CI&#x2F;CD、容器注册表、项目管理等一站式服务。本文将详细介绍如何在 Ubuntu 22.04 上使用 Docker Compose 部署 GitLab 社区版，并进行生产级的配置优化。</p><h2 id="1-部署方案选择"><a href="#1-部署方案选择" class="headerlink" title="1. 部署方案选择"></a>1. 部署方案选择</h2><p>在部署 GitLab 之前，需要根据团队规模和资源情况选择合适的方案。</p><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>方案</th><th>适用场景</th><th>优点</th><th>缺点</th></tr></thead><tbody><tr><td>Omnibus 一键包</td><td>单机部署、小团队</td><td>安装简单、开箱即用</td><td>升级复杂、隔离性差</td></tr><tr><td>Docker Compose</td><td>中小团队、容器化环境</td><td>部署快、版本管理清晰、易于备份</td><td>需先部署 Docker</td></tr><tr><td>Kubernetes Helm</td><td>大型团队、高可用场景</td><td>弹性伸缩、滚动升级</td><td>运维门槛高、资源消耗大</td></tr></tbody></table></div><p>本文采用 <strong>Docker Compose</strong> 方案，兼顾部署效率与可维护性。</p><h2 id="2-前提条件"><a href="#2-前提条件" class="headerlink" title="2. 前提条件"></a>2. 前提条件</h2><h3 id="2-1-硬件要求"><a href="#2-1-硬件要求" class="headerlink" title="2.1 硬件要求"></a>2.1 硬件要求</h3><p>GitLab 对系统资源有一定要求，建议配置如下：</p><div class="opt-table"><table><thead><tr><th>用户数</th><th>CPU</th><th>内存</th><th>磁盘</th></tr></thead><tbody><tr><td>1-10 人</td><td>2 核</td><td>4 GB</td><td>50 GB SSD</td></tr><tr><td>10-50 人</td><td>4 核</td><td>8 GB</td><td>100 GB SSD</td></tr><tr><td>50-200 人</td><td>8 核</td><td>16 GB</td><td>200 GB SSD</td></tr></tbody></table></div><h3 id="2-2-软件环境"><a href="#2-2-软件环境" class="headerlink" title="2.2 软件环境"></a>2.2 软件环境</h3><ul><li>Ubuntu 22.04 LTS</li><li>Docker Engine 24.0+</li><li>Docker Compose V2（推荐）或 V1</li></ul><h3 id="2-3-安装-Docker"><a href="#2-3-安装-Docker" class="headerlink" title="2.3 安装 Docker"></a>2.3 安装 Docker</h3><p>如果尚未安装 Docker，执行以下命令：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 卸载旧版本</span></span><br><span class="line"><span class="built_in">sudo</span> apt remove docker docker-engine docker.io containerd runc</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装依赖</span></span><br><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install -y ca-certificates curl gnupg lsb-release</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加 Docker 官方 GPG 密钥和源</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/apt/keyrings</span><br><span class="line">curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \</span><br><span class="line">  <span class="built_in">sudo</span> gpg --dearmor -o /etc/apt/keyrings/docker.gpg</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> \</span><br><span class="line">  <span class="string">&quot;deb [arch=<span class="subst">$(dpkg --print-architecture)</span> \</span></span><br><span class="line"><span class="string">  signed-by=/etc/apt/keyrings/docker.gpg] \</span></span><br><span class="line"><span class="string">  https://download.docker.com/linux/ubuntu \</span></span><br><span class="line"><span class="string">  <span class="subst">$(lsb_release -cs)</span> stable&quot;</span> | \</span><br><span class="line">  <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/apt/sources.list.d/docker.list &gt; /dev/null</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 Docker Engine 和 Compose</span></span><br><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将当前用户加入 docker 组（免 sudo 执行）</span></span><br><span class="line"><span class="built_in">sudo</span> usermod -aG docker <span class="variable">$USER</span></span><br><span class="line">newgrp docker</span><br></pre></td></tr></table></figure></div><h2 id="3-部署-GitLab"><a href="#3-部署-GitLab" class="headerlink" title="3. 部署 GitLab"></a>3. 部署 GitLab</h2><h3 id="3-1-创建目录结构"><a href="#3-1-创建目录结构" class="headerlink" title="3.1 创建目录结构"></a>3.1 创建目录结构</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /opt/gitlab/&#123;config,logs,data&#125;</span><br><span class="line"><span class="built_in">cd</span> /opt/gitlab</span><br></pre></td></tr></table></figure></div><h3 id="3-2-编写-docker-compose-yml"><a href="#3-2-编写-docker-compose-yml" class="headerlink" title="3.2 编写 docker-compose.yml"></a>3.2 编写 docker-compose.yml</h3><p>创建 <code>/opt/gitlab/docker-compose.yml</code>：</p><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3.8&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">gitlab:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">gitlab/gitlab-ce:17.2.0-ce.0</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">gitlab</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">hostname:</span> <span class="string">&#x27;gitlab.example.com&#x27;</span>          <span class="comment"># 修改为实际域名</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">GITLAB_OMNIBUS_CONFIG:</span> <span class="string">|</span></span><br><span class="line"><span class="string">        # 外部访问 URL</span></span><br><span class="line"><span class="string">        external_url &#x27;https://gitlab.example.com&#x27;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line">        <span class="comment"># 时区</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;time_zone&#x27;]</span> <span class="string">=</span> <span class="string">&#x27;Asia/Shanghai&#x27;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># SMTP 邮件配置（以 QQ 邮箱为例）</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;smtp_enable&#x27;]</span> <span class="string">=</span> <span class="literal">true</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;smtp_address&#x27;]</span> <span class="string">=</span> <span class="string">&#x27;smtp.qq.com&#x27;</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;smtp_port&#x27;]</span> <span class="string">=</span> <span class="number">465</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;smtp_user_name&#x27;]</span> <span class="string">=</span> <span class="string">&#x27;your-email@qq.com&#x27;</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;smtp_password&#x27;]</span> <span class="string">=</span> <span class="string">&#x27;your-smtp-auth-code&#x27;</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;smtp_domain&#x27;]</span> <span class="string">=</span> <span class="string">&#x27;qq.com&#x27;</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;smtp_authentication&#x27;]</span> <span class="string">=</span> <span class="string">&#x27;login&#x27;</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;smtp_enable_starttls_auto&#x27;]</span> <span class="string">=</span> <span class="literal">true</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;smtp_tls&#x27;]</span> <span class="string">=</span> <span class="literal">true</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;gitlab_email_from&#x27;]</span> <span class="string">=</span> <span class="string">&#x27;your-email@qq.com&#x27;</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;gitlab_email_reply_to&#x27;]</span> <span class="string">=</span> <span class="string">&#x27;your-email@qq.com&#x27;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># 备份配置</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;backup_keep_time&#x27;]</span> <span class="string">=</span> <span class="number">604800</span>          <span class="comment"># 保留7天（秒）</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;backup_path&#x27;]</span> <span class="string">=</span> <span class="string">&#x27;/var/opt/gitlab/backups&#x27;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># 限制注册功能</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;gitlab_signup_enabled&#x27;]</span> <span class="string">=</span> <span class="literal">false</span>      <span class="comment"># 关闭开放注册</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;gitlab_signin_oauth_auto_ldap_sync&#x27;]</span> <span class="string">=</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># SSH 端口</span></span><br><span class="line">        <span class="string">gitlab_rails[&#x27;gitlab_shell_ssh_port&#x27;]</span> <span class="string">=</span> <span class="number">2222</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># Gitaly 配置</span></span><br><span class="line">        <span class="string">gitaly[&#x27;configuration&#x27;]</span> <span class="string">=</span> &#123;</span><br><span class="line">          <span class="attr">storage:</span> [</span><br><span class="line">            &#123;</span><br><span class="line">              <span class="attr">name:</span> <span class="string">&#x27;default&#x27;</span>,</span><br><span class="line">              <span class="attr">path:</span> <span class="string">&#x27;/var/opt/gitlab/git-data/repositories&#x27;</span>,</span><br><span class="line">            &#125;</span><br><span class="line">          ]</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment"># Puma 配置（建议 = CPU 核数 + 1）</span></span><br><span class="line">        <span class="string">puma[&#x27;worker_processes&#x27;]</span> <span class="string">=</span> <span class="number">3</span></span><br><span class="line">        <span class="string">puma[&#x27;min_threads&#x27;]</span> <span class="string">=</span> <span class="number">4</span></span><br><span class="line">        <span class="string">puma[&#x27;max_threads&#x27;]</span> <span class="string">=</span> <span class="number">16</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># Sidekiq 并发</span></span><br><span class="line">        <span class="string">sidekiq[&#x27;concurrency&#x27;]</span> <span class="string">=</span> <span class="number">10</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&#x27;2222:22&#x27;</span>          <span class="comment"># SSH（映射到主机非标准端口）</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&#x27;80:80&#x27;</span>            <span class="comment"># HTTP</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&#x27;443:443&#x27;</span>          <span class="comment"># HTTPS</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/opt/gitlab/config:/etc/gitlab</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/opt/gitlab/logs:/var/log/gitlab</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/opt/gitlab/data:/var/opt/gitlab</span></span><br><span class="line">    <span class="attr">shm_size:</span> <span class="string">&#x27;256m&#x27;</span>       <span class="comment"># 增加共享内存，提升 Puma 性能</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;curl&quot;</span>, <span class="string">&quot;-f&quot;</span>, <span class="string">&quot;http://localhost/-/health&quot;</span>]</span><br><span class="line">      <span class="attr">interval:</span> <span class="string">30s</span></span><br><span class="line">      <span class="attr">timeout:</span> <span class="string">10s</span></span><br><span class="line">      <span class="attr">retries:</span> <span class="number">5</span></span><br><span class="line">      <span class="attr">start_period:</span> <span class="string">120s</span></span><br></pre></td></tr></table></figure></div><h3 id="3-3-启动-GitLab"><a href="#3-3-启动-GitLab" class="headerlink" title="3.3 启动 GitLab"></a>3.3 启动 GitLab</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /opt/gitlab</span><br><span class="line">docker compose up -d</span><br></pre></td></tr></table></figure></div><p>首次启动需要 3-5 分钟完成初始化配置，可以通过以下命令观察启动日志：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker compose logs -f gitlab</span><br></pre></td></tr></table></figure></div><p>当看到类似 <code>GitLab is ready!</code> 的日志时，服务即启动完成。</p><h3 id="3-4-获取初始管理员密码"><a href="#3-4-获取初始管理员密码" class="headerlink" title="3.4 获取初始管理员密码"></a>3.4 获取初始管理员密码</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> docker <span class="built_in">exec</span> -it gitlab grep <span class="string">&#x27;Password:&#x27;</span> /etc/gitlab/initial_root_password</span><br></pre></td></tr></table></figure></div><p>默认用户名为 <code>root</code>，请首次登录后立即修改密码。</p><h2 id="4-Nginx-反向代理与-HTTPS"><a href="#4-Nginx-反向代理与-HTTPS" class="headerlink" title="4. Nginx 反向代理与 HTTPS"></a>4. Nginx 反向代理与 HTTPS</h2><p>在生产环境中，建议使用独立 Nginx 作为反向代理终止 HTTPS，而不是直接暴露 GitLab 的 80&#x2F;443 端口。</p><h3 id="4-1-安装-Nginx-和-Certbot"><a href="#4-1-安装-Nginx-和-Certbot" class="headerlink" title="4.1 安装 Nginx 和 Certbot"></a>4.1 安装 Nginx 和 Certbot</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt install -y nginx certbot python3-certbot-nginx</span><br></pre></td></tr></table></figure></div><h3 id="4-2-配置-Nginx-反向代理"><a href="#4-2-配置-Nginx-反向代理" class="headerlink" title="4.2 配置 Nginx 反向代理"></a>4.2 配置 Nginx 反向代理</h3><p>创建 <code>/etc/nginx/sites-available/gitlab</code>：</p><div class="code-container" data-rel="Nginx"><figure class="iseeu highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">upstream</span> gitlab &#123;</span><br><span class="line">    <span class="attribute">server</span> <span class="number">127.0.0.1:80</span>;</span><br><span class="line">    <span class="attribute">keepalive</span> <span class="number">32</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">80</span>;</span><br><span class="line">    <span class="attribute">server_name</span> gitlab.example.com;</span><br><span class="line">    <span class="attribute">return</span> <span class="number">301</span> https://<span class="variable">$server_name</span><span class="variable">$request_uri</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="section">server</span> &#123;</span><br><span class="line">    <span class="attribute">listen</span> <span class="number">443</span> ssl http2;</span><br><span class="line">    <span class="attribute">server_name</span> gitlab.example.com;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">ssl_certificate</span> /etc/letsencrypt/live/gitlab.example.com/fullchain.pem;</span><br><span class="line">    <span class="attribute">ssl_certificate_key</span> /etc/letsencrypt/live/gitlab.example.com/privkey.pem;</span><br><span class="line">    <span class="attribute">ssl_session_timeout</span> <span class="number">1d</span>;</span><br><span class="line">    <span class="attribute">ssl_session_cache</span> shared:SSL:<span class="number">50m</span>;</span><br><span class="line">    <span class="attribute">ssl_session_tickets</span> <span class="literal">off</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 现代 TLS 配置</span></span><br><span class="line">    <span class="attribute">ssl_protocols</span> TLSv1.<span class="number">2</span> TLSv1.<span class="number">3</span>;</span><br><span class="line">    <span class="attribute">ssl_ciphers</span> ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;</span><br><span class="line">    <span class="attribute">ssl_prefer_server_ciphers</span> <span class="literal">off</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># HSTS</span></span><br><span class="line">    <span class="attribute">add_header</span> Strict-Transport-Security <span class="string">&quot;max-age=63072000&quot;</span> always;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># GitLab 反向代理</span></span><br><span class="line">    <span class="section">location</span> / &#123;</span><br><span class="line">        <span class="attribute">proxy_pass</span> http://gitlab;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Host <span class="variable">$host</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Real-IP <span class="variable">$remote_addr</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-For <span class="variable">$proxy_add_x_forwarded_for</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-Proto <span class="variable">$scheme</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-Ssl <span class="literal">on</span>;</span><br><span class="line">        <span class="attribute">proxy_redirect</span> <span class="literal">off</span>;</span><br><span class="line">        <span class="attribute">proxy_buffering</span> <span class="literal">off</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment"># WebSocket 支持</span></span><br><span class="line">        <span class="attribute">proxy_http_version</span> <span class="number">1</span>.<span class="number">1</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Upgrade <span class="variable">$http_upgrade</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> Connection <span class="string">&quot;upgrade&quot;</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 超时设置（GitLab 一些操作耗时较长）</span></span><br><span class="line">        <span class="attribute">proxy_read_timeout</span> <span class="number">300s</span>;</span><br><span class="line">        <span class="attribute">proxy_connect_timeout</span> <span class="number">75s</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="4-3-修改-GitLab-external-url"><a href="#4-3-修改-GitLab-external-url" class="headerlink" title="4.3 修改 GitLab external_url"></a>4.3 修改 GitLab external_url</h3><p>配置 Nginx 后，需要更新 GitLab 的 <code>external_url</code>：</p><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 在 docker-compose.yml 中修改环境变量</span></span><br><span class="line"><span class="attr">environment:</span></span><br><span class="line">  <span class="attr">GITLAB_OMNIBUS_CONFIG:</span> <span class="string">|</span></span><br><span class="line"><span class="string">    external_url &#x27;https://gitlab.example.com&#x27;</span></span><br><span class="line"><span class="string">    nginx[&#x27;listen_port&#x27;] = 80</span></span><br><span class="line"><span class="string">    nginx[&#x27;listen_https&#x27;] = false</span></span><br><span class="line"><span class="string">    nginx[&#x27;proxy_set_headers&#x27;] = &#123;</span></span><br><span class="line"><span class="string">      &#x27;X-Forwarded-Proto&#x27; =&gt; &#x27;https&#x27;,</span></span><br><span class="line"><span class="string">      &#x27;X-Forwarded-Ssl&#x27; =&gt; &#x27;on&#x27;</span></span><br><span class="line"><span class="string">    &#125;</span></span><br></pre></td></tr></table></figure></div><p>然后重启 GitLab：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /opt/gitlab</span><br><span class="line">docker compose down</span><br><span class="line">docker compose up -d</span><br></pre></td></tr></table></figure></div><h2 id="5-备份与恢复"><a href="#5-备份与恢复" class="headerlink" title="5. 备份与恢复"></a>5. 备份与恢复</h2><h3 id="5-1-手动备份"><a href="#5-1-手动备份" class="headerlink" title="5.1 手动备份"></a>5.1 手动备份</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建备份</span></span><br><span class="line">docker <span class="built_in">exec</span> -it gitlab gitlab-backup create</span><br><span class="line"></span><br><span class="line"><span class="comment"># 备份配置文件（单独备份，恢复时重要）</span></span><br><span class="line">tar -czf /opt/gitlab-backups/gitlab-config-$(<span class="built_in">date</span> +%Y%m%d).tar.gz /opt/gitlab/config</span><br></pre></td></tr></table></figure></div><p>备份文件默认存储在 <code>/opt/gitlab/data/backups/</code> 目录下。</p><h3 id="5-2-定时自动备份"><a href="#5-2-定时自动备份" class="headerlink" title="5.2 定时自动备份"></a>5.2 定时自动备份</h3><p>创建备份脚本 <code>/opt/gitlab/backup.sh</code>：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># GitLab 自动备份脚本</span></span><br><span class="line"></span><br><span class="line">BACKUP_DIR=<span class="string">&quot;/opt/gitlab-backups&quot;</span></span><br><span class="line">RETENTION_DAYS=7</span><br><span class="line">DATE=$(<span class="built_in">date</span> +%Y%m%d_%H%M%S)</span><br><span class="line">LOG_FILE=<span class="string">&quot;/var/log/gitlab-backup.log&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置日志</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[<span class="subst">$(date)</span>] 开始 GitLab 备份&quot;</span> &gt;&gt; <span class="string">&quot;<span class="variable">$LOG_FILE</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建 GitLab 数据备份</span></span><br><span class="line">docker <span class="built_in">exec</span> gitlab gitlab-backup create STRATEGY=copy &gt;&gt; <span class="string">&quot;<span class="variable">$LOG_FILE</span>&quot;</span> 2&gt;&amp;1</span><br><span class="line"><span class="keyword">if</span> [ $? -ne 0 ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;[<span class="subst">$(date)</span>] ❌ 备份失败！&quot;</span> &gt;&gt; <span class="string">&quot;<span class="variable">$LOG_FILE</span>&quot;</span></span><br><span class="line">    <span class="built_in">exit</span> 1</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 备份配置文件</span></span><br><span class="line"><span class="built_in">mkdir</span> -p <span class="string">&quot;<span class="variable">$BACKUP_DIR</span>&quot;</span></span><br><span class="line">tar -czf <span class="string">&quot;<span class="variable">$BACKUP_DIR</span>/gitlab-config-<span class="variable">$DATE</span>.tar.gz&quot;</span> -C /opt/gitlab config &gt;&gt; <span class="string">&quot;<span class="variable">$LOG_FILE</span>&quot;</span> 2&gt;&amp;1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 清理过期备份</span></span><br><span class="line">find <span class="string">&quot;<span class="variable">$BACKUP_DIR</span>&quot;</span> -name <span class="string">&quot;gitlab-config-*.tar.gz&quot;</span> -mtime +<span class="variable">$RETENTION_DAYS</span> -delete</span><br><span class="line">find /opt/gitlab/data/backups -name <span class="string">&quot;*.tar&quot;</span> -mtime +<span class="variable">$RETENTION_DAYS</span> -delete</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[<span class="subst">$(date)</span>] ✅ GitLab 备份完成&quot;</span> &gt;&gt; <span class="string">&quot;<span class="variable">$LOG_FILE</span>&quot;</span></span><br></pre></td></tr></table></figure></div><p>添加执行权限并设置定时任务：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> +x /opt/gitlab/backup.sh</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加到 crontab（每天凌晨3点执行）</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;0 3 * * * /opt/gitlab/backup.sh&quot;</span> | <span class="built_in">sudo</span> crontab -</span><br></pre></td></tr></table></figure></div><h3 id="5-3-恢复备份"><a href="#5-3-恢复备份" class="headerlink" title="5.3 恢复备份"></a>5.3 恢复备份</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 停止相关服务</span></span><br><span class="line">docker <span class="built_in">exec</span> gitlab gitlab-ctl stop puma</span><br><span class="line">docker <span class="built_in">exec</span> gitlab gitlab-ctl stop sidekiq</span><br><span class="line"></span><br><span class="line"><span class="comment"># 恢复数据库（确保备份文件在 data/backups 目录下）</span></span><br><span class="line">docker <span class="built_in">exec</span> gitlab gitlab-backup restore BACKUP=1712345678_2026_06_17_17.2.0</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重启 GitLab</span></span><br><span class="line">docker <span class="built_in">exec</span> gitlab gitlab-ctl restart</span><br><span class="line"></span><br><span class="line"><span class="comment"># 恢复后重新配置</span></span><br><span class="line">docker <span class="built_in">exec</span> gitlab gitlab-ctl reconfigure</span><br></pre></td></tr></table></figure></div><blockquote><p><strong>注意</strong>：恢复操作需要版本号完全匹配，建议在恢复前记录当前运行版本。</p></blockquote><h2 id="6-GitLab-Runner-注册"><a href="#6-GitLab-Runner-注册" class="headerlink" title="6. GitLab Runner 注册"></a>6. GitLab Runner 注册</h2><p>GitLab Runner 是执行 CI&#x2F;CD 任务的组件，以 Docker 方式部署方便灵活。</p><h3 id="6-1-部署-Runner"><a href="#6-1-部署-Runner" class="headerlink" title="6.1 部署 Runner"></a>6.1 部署 Runner</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建 Runner 目录</span></span><br><span class="line"><span class="built_in">mkdir</span> -p /opt/gitlab-runner/&#123;config,data&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动 Runner 容器</span></span><br><span class="line">docker run -d --name gitlab-runner --restart always \</span><br><span class="line">  -v /opt/gitlab-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:latest</span><br></pre></td></tr></table></figure></div><h3 id="6-2-注册-Runner"><a href="#6-2-注册-Runner" class="headerlink" title="6.2 注册 Runner"></a>6.2 注册 Runner</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 交互式注册</span></span><br><span class="line">docker <span class="built_in">exec</span> -it gitlab-runner gitlab-runner register</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或使用非交互方式（填入实际 URL 和 Token）</span></span><br><span class="line">docker <span class="built_in">exec</span> -it gitlab-runner gitlab-runner register \</span><br><span class="line">  --non-interactive \</span><br><span class="line">  --url <span class="string">&quot;https://gitlab.example.com&quot;</span> \</span><br><span class="line">  --registration-token <span class="string">&quot;YOUR_REGISTRATION_TOKEN&quot;</span> \</span><br><span class="line">  --executor <span class="string">&quot;docker&quot;</span> \</span><br><span class="line">  --docker-image alpine:latest \</span><br><span class="line">  --docker-volumes /var/run/docker.sock:/var/run/docker.sock \</span><br><span class="line">  --description <span class="string">&quot;docker-runner&quot;</span> \</span><br><span class="line">  --tag-list <span class="string">&quot;docker,linux&quot;</span> \</span><br><span class="line">  --run-untagged=<span class="string">&quot;true&quot;</span> \</span><br><span class="line">  --locked=<span class="string">&quot;false&quot;</span></span><br></pre></td></tr></table></figure></div><p>Runner Token 可以在 GitLab 管理界面获取：<strong>Settings → CI&#x2F;CD → Runners → Expand → Specific runners</strong>。</p><h3 id="6-3-Runner-配置优化"><a href="#6-3-Runner-配置优化" class="headerlink" title="6.3 Runner 配置优化"></a>6.3 Runner 配置优化</h3><p>编辑 <code>/opt/gitlab-runner/config/config.toml</code>，对 Runner 配置进行调优：</p><div class="code-container" data-rel="Toml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="attr">concurrent</span> = <span class="number">4</span></span><br><span class="line"></span><br><span class="line"><span class="section">[[runners]]</span></span><br><span class="line">  <span class="attr">name</span> = <span class="string">&quot;docker-runner&quot;</span></span><br><span class="line">  <span class="attr">url</span> = <span class="string">&quot;https://gitlab.example.com&quot;</span></span><br><span class="line">  <span class="attr">token</span> = <span class="string">&quot;YOUR_TOKEN&quot;</span></span><br><span class="line">  <span class="attr">executor</span> = <span class="string">&quot;docker&quot;</span></span><br><span class="line">  <span class="section">[runners.docker]</span></span><br><span class="line">    <span class="attr">image</span> = <span class="string">&quot;alpine:latest&quot;</span></span><br><span class="line">    <span class="attr">privileged</span> = <span class="literal">false</span>                           <span class="comment"># 安全考虑，非必要不开启</span></span><br><span class="line">    <span class="attr">disable_cache</span> = <span class="literal">false</span></span><br><span class="line">    <span class="attr">volumes</span> = [<span class="string">&quot;/cache&quot;</span>]</span><br><span class="line">    <span class="attr">shm_size</span> = <span class="number">256</span>m</span><br><span class="line">    <span class="attr">pull_policy</span> = <span class="string">&quot;if-not-present&quot;</span>               <span class="comment"># 优先使用本地镜像</span></span><br><span class="line">    <span class="attr">oom_kill_disable</span> = <span class="literal">false</span></span><br><span class="line">    <span class="attr">memory_limit</span> = <span class="string">&quot;2g&quot;</span>                          <span class="comment"># 限制容器内存</span></span><br><span class="line">    <span class="attr">cpus</span> = <span class="string">&quot;2&quot;</span>                                   <span class="comment"># 限制 CPU 核数</span></span><br><span class="line">    <span class="attr">helper_image</span> = <span class="string">&quot;gitlab/gitlab-runner-helper:x86_64-latest&quot;</span></span><br><span class="line">  <span class="section">[runners.cache]</span></span><br><span class="line">    <span class="attr">Type</span> = <span class="string">&quot;s3&quot;</span></span><br><span class="line">    <span class="attr">Path</span> = <span class="string">&quot;gitlab-runner-cache&quot;</span></span><br><span class="line">    <span class="attr">Shared</span> = <span class="literal">true</span></span><br></pre></td></tr></table></figure></div><h2 id="7-GitLab-CI-CD-基础配置"><a href="#7-GitLab-CI-CD-基础配置" class="headerlink" title="7. GitLab CI&#x2F;CD 基础配置"></a>7. GitLab CI&#x2F;CD 基础配置</h2><h3 id="7-1-基础-gitlab-ci-yml-模板"><a href="#7-1-基础-gitlab-ci-yml-模板" class="headerlink" title="7.1 基础 .gitlab-ci.yml 模板"></a>7.1 基础 .gitlab-ci.yml 模板</h3><p>在项目根目录创建 <code>.gitlab-ci.yml</code>：</p><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></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">test</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">build</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">deploy</span></span><br><span class="line"></span><br><span class="line"><span class="attr">variables:</span></span><br><span class="line">  <span class="attr">DOCKER_IMAGE_TAG:</span> <span class="string">$CI_COMMIT_SHORT_SHA</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 测试阶段</span></span><br><span class="line"><span class="attr">test:</span></span><br><span class="line">  <span class="attr">stage:</span> <span class="string">test</span></span><br><span class="line">  <span class="attr">image:</span> <span class="string">node:20-alpine</span></span><br><span class="line">  <span class="attr">script:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">npm</span> <span class="string">install</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">npm</span> <span class="string">run</span> <span class="string">lint</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">npm</span> <span class="string">test</span></span><br><span class="line">  <span class="attr">only:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">main</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">merge_requests</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 构建阶段</span></span><br><span class="line"><span class="attr">build:</span></span><br><span class="line">  <span class="attr">stage:</span> <span class="string">build</span></span><br><span class="line">  <span class="attr">image:</span> <span class="string">docker:24</span></span><br><span class="line">  <span class="attr">services:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">docker:24-dind</span></span><br><span class="line">  <span class="attr">script:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">docker</span> <span class="string">build</span> <span class="string">-t</span> <span class="string">registry.example.com/myapp:$DOCKER_IMAGE_TAG</span> <span class="string">.</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">docker</span> <span class="string">push</span> <span class="string">registry.example.com/myapp:$DOCKER_IMAGE_TAG</span></span><br><span class="line">  <span class="attr">only:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">main</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 部署阶段</span></span><br><span class="line"><span class="attr">deploy:</span></span><br><span class="line">  <span class="attr">stage:</span> <span class="string">deploy</span></span><br><span class="line">  <span class="attr">image:</span> <span class="string">alpine:latest</span></span><br><span class="line">  <span class="attr">before_script:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">apk</span> <span class="string">add</span> <span class="string">--no-cache</span> <span class="string">openssh-client</span></span><br><span class="line">  <span class="attr">script:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">scp</span> <span class="string">-o</span> <span class="string">StrictHostKeyChecking=no</span> <span class="string">docker-compose.yml</span> <span class="string">deploy@server:/opt/app/</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">ssh</span> <span class="string">deploy@server</span> <span class="string">&quot;cd /opt/app &amp;&amp; docker compose pull &amp;&amp; docker compose up -d&quot;</span></span><br><span class="line">  <span class="attr">only:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">main</span></span><br><span class="line">  <span class="attr">when:</span> <span class="string">manual</span>          <span class="comment"># 手动触发部署</span></span><br></pre></td></tr></table></figure></div><h3 id="7-2-注册表配置（可选）"><a href="#7-2-注册表配置（可选）" class="headerlink" title="7.2 注册表配置（可选）"></a>7.2 注册表配置（可选）</h3><p>如需使用 GitLab 内置的 Container Registry：</p><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 在 docker-compose.yml 中添加</span></span><br><span class="line"><span class="attr">environment:</span></span><br><span class="line">  <span class="attr">GITLAB_OMNIBUS_CONFIG:</span> <span class="string">|</span></span><br><span class="line"><span class="string">    # 启用 Container Registry</span></span><br><span class="line"><span class="string">    registry_external_url &#x27;https://registry.example.com&#x27;</span></span><br><span class="line"><span class="string">    registry_nginx[&#x27;listen_port&#x27;] = 5050</span></span><br><span class="line"><span class="string">    registry_nginx[&#x27;listen_https&#x27;] = false</span></span><br><span class="line"><span class="string"></span><span class="comment"># 添加端口映射</span></span><br><span class="line"><span class="attr">ports:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">&#x27;5050:5050&#x27;</span></span><br></pre></td></tr></table></figure></div><h2 id="8-性能优化"><a href="#8-性能优化" class="headerlink" title="8. 性能优化"></a>8. 性能优化</h2><h3 id="8-1-GitLab-内核参数调优"><a href="#8-1-GitLab-内核参数调优" class="headerlink" title="8.1 GitLab 内核参数调优"></a>8.1 GitLab 内核参数调优</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 增加文件描述符限制</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;fs.file-max = 100000&quot;</span> | <span class="built_in">sudo</span> <span class="built_in">tee</span> -a /etc/sysctl.conf</span><br><span class="line"></span><br><span class="line"><span class="comment"># 扩大连接跟踪表</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;net.netfilter.nf_conntrack_max = 262144&quot;</span> | <span class="built_in">sudo</span> <span class="built_in">tee</span> -a /etc/sysctl.conf</span><br><span class="line"></span><br><span class="line"><span class="comment"># 应用</span></span><br><span class="line"><span class="built_in">sudo</span> sysctl -p</span><br></pre></td></tr></table></figure></div><h3 id="8-2-Docker-资源限制"><a href="#8-2-Docker-资源限制" class="headerlink" title="8.2 Docker 资源限制"></a>8.2 Docker 资源限制</h3><div class="code-container" data-rel="Yaml"><figure class="iseeu 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"># 在 docker-compose.yml 中添加资源限制</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">gitlab:</span></span><br><span class="line">    <span class="attr">deploy:</span></span><br><span class="line">      <span class="attr">resources:</span></span><br><span class="line">        <span class="attr">limits:</span></span><br><span class="line">          <span class="attr">cpus:</span> <span class="string">&#x27;4&#x27;</span></span><br><span class="line">          <span class="attr">memory:</span> <span class="string">8G</span></span><br><span class="line">        <span class="attr">reservations:</span></span><br><span class="line">          <span class="attr">cpus:</span> <span class="string">&#x27;2&#x27;</span></span><br><span class="line">          <span class="attr">memory:</span> <span class="string">4G</span></span><br></pre></td></tr></table></figure></div><h3 id="8-3-数据库优化"><a href="#8-3-数据库优化" class="headerlink" title="8.3 数据库优化"></a>8.3 数据库优化</h3><p>GitLab 使用 PostgreSQL 作为数据库，可以单独优化：</p><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 在 docker-compose.yml 中添加独立 PostgreSQL</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">gitlab:</span></span><br><span class="line">    <span class="comment"># ... 原有配置 ...</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">GITLAB_OMNIBUS_CONFIG:</span> <span class="string">|</span></span><br><span class="line"><span class="string">        # 使用外部数据库</span></span><br><span class="line"><span class="string">        postgresql[&#x27;enable&#x27;] = false</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;db_adapter&#x27;] = &#x27;postgresql&#x27;</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;db_username&#x27;] = &#x27;gitlab&#x27;</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;db_password&#x27;] = &#x27;secure_password&#x27;</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;db_host&#x27;] = &#x27;postgresql&#x27;</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;db_port&#x27;] = 5432</span></span><br><span class="line"><span class="string"></span></span><br><span class="line">  <span class="attr">postgresql:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">postgres:16-alpine</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">gitlab-postgresql</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">POSTGRES_USER:</span> <span class="string">gitlab</span></span><br><span class="line">      <span class="attr">POSTGRES_PASSWORD:</span> <span class="string">secure_password</span></span><br><span class="line">      <span class="attr">POSTGRES_DB:</span> <span class="string">gitlabhq_production</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/opt/gitlab/postgresql:/var/lib/postgresql/data</span></span><br><span class="line">    <span class="attr">deploy:</span></span><br><span class="line">      <span class="attr">resources:</span></span><br><span class="line">        <span class="attr">limits:</span></span><br><span class="line">          <span class="attr">memory:</span> <span class="string">2G</span></span><br></pre></td></tr></table></figure></div><h2 id="9-安全加固"><a href="#9-安全加固" class="headerlink" title="9. 安全加固"></a>9. 安全加固</h2><h3 id="9-1-防火墙配置"><a href="#9-1-防火墙配置" class="headerlink" title="9.1 防火墙配置"></a>9.1 防火墙配置</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ufw allow 22/tcp       <span class="comment"># SSH</span></span><br><span class="line"><span class="built_in">sudo</span> ufw allow 80/tcp       <span class="comment"># HTTP</span></span><br><span class="line"><span class="built_in">sudo</span> ufw allow 443/tcp      <span class="comment"># HTTPS</span></span><br><span class="line"><span class="built_in">sudo</span> ufw allow 2222/tcp     <span class="comment"># GitLab SSH（自定义端口）</span></span><br><span class="line"><span class="built_in">sudo</span> ufw deny 5050          <span class="comment"># Container Registry 仅内网访问</span></span><br><span class="line"><span class="built_in">sudo</span> ufw <span class="built_in">enable</span></span><br></pre></td></tr></table></figure></div><h3 id="9-2-安全配置清单"><a href="#9-2-安全配置清单" class="headerlink" title="9.2 安全配置清单"></a>9.2 安全配置清单</h3><div class="opt-table"><table><thead><tr><th>配置项</th><th>建议值</th><th>说明</th></tr></thead><tbody><tr><td>开放注册</td><td>关闭</td><td>防止恶意注册</td></tr><tr><td>密码复杂度</td><td>最低12位，含大小写+数字+特殊字符</td><td>GitLab 默认已启用</td></tr><tr><td>2FA 强制</td><td>管理员强制启用</td><td>Settings → General → Sign-in restrictions</td></tr><tr><td>Session 超时</td><td>12 小时</td><td>Settings → General → Session duration</td></tr><tr><td>IP 白名单</td><td>仅允许内网访问管理面板</td><td>可通过 Nginx 限制</td></tr><tr><td>Runner 权限</td><td>非 privileged 模式</td><td>防止容器逃逸</td></tr><tr><td>HTTPS 强制</td><td>启用</td><td>Nginx 重写所有 HTTP 到 HTTPS</td></tr><tr><td>数据加密</td><td>AES-256</td><td>备份文件加密存储</td></tr></tbody></table></div><h3 id="9-3-定期更新"><a href="#9-3-定期更新" class="headerlink" title="9.3 定期更新"></a>9.3 定期更新</h3><p>GitLab 社区版每月 22 日左右发布新版本，建议定期更新：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看当前版本</span></span><br><span class="line">docker <span class="built_in">exec</span> gitlab <span class="built_in">cat</span> /opt/gitlab/embedded/service/gitlab-rails/VERSION</span><br><span class="line"></span><br><span class="line"><span class="comment"># 更新（修改 docker-compose.yml 中的镜像标签后）</span></span><br><span class="line"><span class="built_in">cd</span> /opt/gitlab</span><br><span class="line">docker compose pull</span><br><span class="line">docker compose up -d</span><br></pre></td></tr></table></figure></div><h2 id="10-常见问题排查"><a href="#10-常见问题排查" class="headerlink" title="10. 常见问题排查"></a>10. 常见问题排查</h2><div class="opt-table"><table><thead><tr><th>问题</th><th>可能原因</th><th>解决方法</th></tr></thead><tbody><tr><td>502 Bad Gateway</td><td>Puma/Sidekiq 未完全启动</td><td>等待 2-3 分钟或检查日志 <code>docker compose logs gitlab</code></td></tr><tr><td>SSH 连接被拒绝</td><td>SSH 端口映射冲突</td><td>确认主机 2222 端口未被占用，<code>ss -tlnp | grep 2222</code></td></tr><tr><td>邮件发送失败</td><td>SMTP 配置错误</td><td>检查 SMTP 地址、端口、认证码，测试 <code>docker exec gitlab gitlab-rails console</code></td></tr><tr><td>磁盘空间不足</td><td>备份文件未清理</td><td><code>docker exec gitlab du -sh /var/opt/gitlab/backups</code>，清理过期备份</td></tr><tr><td>Runner 无法连接</td><td>注册 Token 过期或网络问题</td><td>重新注册 Runner，确认 <code>--url</code> 参数正确</td></tr><tr><td>容器频繁重启</td><td>系统资源不足</td><td><code>docker stats</code> 查看资源使用，增加主机内存</td></tr><tr><td>API 返回 413</td><td>Nginx 上传大小限制</td><td>在 Nginx 配置中添加 <code>client_max_body_size 0;</code></td></tr><tr><td>Git push 超时</td><td>Nginx proxy_read_timeout 不足</td><td>增加超时时间至 600s</td></tr></tbody></table></div><h2 id="11-总结"><a href="#11-总结" class="headerlink" title="11. 总结"></a>11. 总结</h2><p>本文详细介绍了在 Ubuntu 22.04 上使用 Docker Compose 部署 GitLab 社区版的完整流程，涵盖：</p><ul><li>Docker 环境准备与 GitLab 容器化部署</li><li>Nginx 反向代理与 HTTPS 配置</li><li>自动备份与恢复方案</li><li>GitLab Runner 注册与 CI&#x2F;CD 基础配置</li><li>性能优化与安全加固</li><li>常见问题排查</li></ul><p>GitLab 是一个非常成熟的 DevOps 平台，通过容器化部署可以极大降低运维复杂度。建议在生产环境中配合独立的 PostgreSQL 和 Redis 实例以提升性能和可用性，同时定期检查安全配置和版本更新。</p><hr><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-17-gitlab-deployment-guide/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-17-gitlab-deployment-guide/"/>
    <published>2026-06-16T16:43:00.000Z</published>
    <summary>
      <![CDATA[<p>GitLab 是目前最流行的自托管 DevOps 平台之一，提供代码托管、CI&#x2F;CD、容器注册表、项目管理等一站式服务。本文将详细介绍如何在 Ubuntu 22.04 上使用 Docker Compose 部署 GitLab 社区版，并进行生产级的配置优化。</p]]>
    </summary>
    <title>GitLab 容器化部署与配置完全指南</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="日记" scheme="https://demo-blog.qusite.cn/categories/%E6%97%A5%E8%AE%B0/"/>
    <category term="日记" scheme="https://demo-blog.qusite.cn/tags/%E6%97%A5%E8%AE%B0/"/>
    <category term="周记" scheme="https://demo-blog.qusite.cn/tags/%E5%91%A8%E8%AE%B0/"/>
    <category term="技术反思" scheme="https://demo-blog.qusite.cn/tags/%E6%8A%80%E6%9C%AF%E5%8F%8D%E6%80%9D/"/>
    <category term="运维学习" scheme="https://demo-blog.qusite.cn/tags/%E8%BF%90%E7%BB%B4%E5%AD%A6%E4%B9%A0/"/>
    <content>
      <![CDATA[<p>从上周五（6月12日）深夜写完 K8s 集群搭建心得之后，我的博客自动化写作按下了暂停键。整整三天半，没有新的文章发出，也没有新的推送。说实话，这三天半没有白过。</p><h2 id="休整的意义"><a href="#休整的意义" class="headerlink" title="休整的意义"></a>休整的意义</h2><p>之前连续三天（6月6日至9日）密集产出了四五十篇技术文章，到了周五那天虽然还在写，但自己明显感觉到每篇文章的”含金量”在下降——同样的表格格式、类似的段落结构、缺乏个人实践验证的代码示例。文章是发出去了，但自己心里清楚：这些内容离”真正帮到读者”还有距离。</p><p>于是周末我做了两件事：<strong>回顾</strong>和<strong>动手</strong>。</p><h2 id="周末动手实践记录"><a href="#周末动手实践记录" class="headerlink" title="周末动手实践记录"></a>周末动手实践记录</h2><p><strong>周六（6月13日）</strong>，我把之前写过的几篇 Linux 教程拿出来，对着文章一步步操作。结果发现至少有四处代码示例有细微错误：</p><ul><li><code>systemd</code> 那篇的 Timer 配置里少了一个 <code>OnCalendar=</code> 前的注释符号</li><li><code>sed</code> 替换命令的 <code>-i</code> 参数后面少写了备份后缀（直接用 <code>-i</code> 而不是 <code>-i.bak</code> 在某些发行版上会挂）</li><li><code>logrotate</code> 的 <code>postrotate</code> 脚本里 <code>kill -USR1</code> 没有用绝对路径</li><li><code>rsync</code> 的排除模式说明中路径斜杠语义解释得太笼统</li></ul><p>我逐一修正了这些文章中的错误，更新后重新推送了。<strong>写教程最怕的就是给读者错误的信息</strong>——这一点我有了切身体会。</p><p><strong>周日（6月14日）</strong>，我把精力用在了之前一直想做的事情上：折腾博客前端的暗色模式。</p><p>之前用的 Hexo 主题自带的暗色模式效果不怎么好——切换以后代码高亮配色和背景对比度不够，一些表格完全看不清。花了大半天时间研究主题的 <code>_variables.styl</code>，修改了暗色模式下的颜色变量，调整了代码块的背景色和字体颜色。虽然最终效果还算满意，但也让我意识到：<strong>主题定制如果不深入源码，很难达到理想效果。</strong> 后面可能要考虑换一个更活跃维护的 Hexo 主题，或者迁移到其他静态站点生成器。</p><p><strong>周一（6月15日）</strong>，我花了时间做了两件事：</p><ol><li><strong>整理博客标签和目录</strong>——之前四五十篇文章的标签命名太随意，有的用”Linux”，有的用”linux”，有的用”Linux运维”。我统一规范成了中文标签，并按内容类型归档到五个分类下。</li><li><strong>搭建了一个小型的本地监控环境</strong>——用 Prometheus + Grafana 监控我的本地开发服务器，学会了配置 Node Exporter 和 Blackbox Exporter 的 HTTP 探活检测。在 Grafana 里导入了 Node Exporter Full 仪表板，看着 CPU 占用率、内存使用量、磁盘 I&#x2F;O 实时刷新的曲线，那种成就感比写几十篇文章要强得多。</li></ol><h2 id="今日（周二）回顾"><a href="#今日（周二）回顾" class="headerlink" title="今日（周二）回顾"></a>今日（周二）回顾</h2><p>今天博客自动化恢复运行，下午产出了 Ansible、Rust 环境搭建和 htop 三篇文章，晚上还出了一期热点新闻。有趣的是，经历了三天的”断更”之后，再看到这些文章时，我发现自己更容易看出问题了。</p><p>比如 <strong>Ansible 那篇</strong>，我在看的时候就在想：”Playbook 的变量优先级这种关键内容有没有写清楚？”——于是补充了一个 Jinja2 变量作用域的说明。<strong>Rust 那篇</strong>也有类似的情况，我手动补了 <code>cargo test</code> 的更多示例。</p><p>晚上这期 <strong>热点新闻</strong> 信息量特别大——SpaceX 以 600 亿美元收购 Cursor 母公司 Anysphere，这个新闻让我很惊讶。航天公司收购 AI 编程工具公司，这个组合太超乎想象了。但仔细想想，马斯克一直以来的逻辑是”把所有基础设施都掌握在自己手里”——从可回收火箭到星链通信，再到现在的 AI 编程工具，这是一个完整的纵向整合叙事。另外 DeepSeek 首轮融资 74 亿美元、燧原科技科创板过会、力箭一号再成功一箭 8 星……今天的科技新闻确实亮点密集。</p><h2 id="学到的新东西"><a href="#学到的新东西" class="headerlink" title="学到的新东西"></a>学到的新东西</h2><p>这几天休整期间，有几个重要的技术认知升级：</p><ol><li><strong>Ansible 的 Roles 机制</strong>确实比单纯的 Playbook 优雅得多，把变量、任务、模板、处理器拆分到独立目录，维护成本直线下降。</li><li><strong>Rust 的包管理生态</strong>比我想象中完善——Cargo 不仅是构建工具，还集成了测试、文档生成、基准测试，一个 <code>cargo</code> 命令搞定所有，体验比 C++ 的 CMake 好太多了。</li><li><strong>htop 的自定义列</strong>功能很强——可以显示进程的 OOM 评分、IO 优先级、活跃内存页数等深度信息，排查问题时比默认视图有用得多。</li></ol><h2 id="本周工作计划"><a href="#本周工作计划" class="headerlink" title="本周工作计划"></a>本周工作计划</h2><table><thead><tr><th>优先级</th><th>事项</th><th>说明</th></tr></thead><tbody><tr><td>P0</td><td>深入学习 Docker Compose</td><td>看完之前写的那篇，动手搭建一个生产级栈</td></tr><tr><td>P0</td><td>博客标签规范化</td><td>已进行了一半，周二继续整理</td></tr><tr><td>P1</td><td>评估 Hexo 主题替换</td><td>找一找 2026 年活跃维护的主题</td></tr><tr><td>P1</td><td>再来一轮手动验证</td><td>针对之前写的每篇技术文，挑几个关键命令&#x2F;配置跑一遍</td></tr><tr><td>P2</td><td>调研 Hugo 迁移</td><td>如果 Hexo 定制成本太高，可以看看 Hugo</td></tr></tbody></table><p>上周那种”每天十几篇”的节奏不会持续了。我更倾向于<strong>每天 1-2 篇、每篇都亲自验证过</strong>的模式。质量的提升需要时间，但读过文章的人总会感受到差异的——至少我自己能感受到。</p><p>夜深了，窗外很安静。明天继续。</p><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-16-tuesday-night-diary/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-16-tuesday-night-diary/"/>
    <published>2026-06-16T15:41:00.000Z</published>
    <summary>
      <![CDATA[<p>从上周五（6月12日）深夜写完 K8s 集群搭建心得之后，我的博客自动化写作按下了暂停键。整整三天半，没有新的文章发出，也没有新的推送。说实话，这三天半没有白过。</p>
<h2 id="休整的意义"><a href="#休整的意义" class="headerlink"]]>
    </summary>
    <title>周二深夜：休整归来与技术深耕的反思</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="新闻" scheme="https://demo-blog.qusite.cn/categories/%E6%96%B0%E9%97%BB/"/>
    <category term="科技热点" scheme="https://demo-blog.qusite.cn/tags/%E7%A7%91%E6%8A%80%E7%83%AD%E7%82%B9/"/>
    <category term="SpaceX" scheme="https://demo-blog.qusite.cn/tags/SpaceX/"/>
    <category term="AI" scheme="https://demo-blog.qusite.cn/tags/AI/"/>
    <category term="航天" scheme="https://demo-blog.qusite.cn/tags/%E8%88%AA%E5%A4%A9/"/>
    <category term="国产GPU" scheme="https://demo-blog.qusite.cn/tags/%E5%9B%BD%E4%BA%A7GPU/"/>
    <category term="DeepSeek" scheme="https://demo-blog.qusite.cn/tags/DeepSeek/"/>
    <content>
      <![CDATA[<h2 id="一、航天与AI深度融合：SpaceX-600亿美元收购Cursor"><a href="#一、航天与AI深度融合：SpaceX-600亿美元收购Cursor" class="headerlink" title="一、航天与AI深度融合：SpaceX 600亿美元收购Cursor"></a>一、航天与AI深度融合：SpaceX 600亿美元收购Cursor</h2><p>6月16日，SpaceX宣布以约600亿美元的全股票交易收购AI编程工具Cursor的母公司Anysphere，标志着航天与AI领域的里程碑式融合。<strong>来源：TechStartups</strong></p><p>此举意味着SpaceX正式进军企业AI和开发者工具领域，与OpenAI、Anthropic等AI巨头直接竞争。收购完成后，SpaceX将同时布局航天发射、星链通信与AI编程三大赛道。SpaceX股价在IPO后持续上涨，盘前再涨超8%，市值有望超越亚马逊成为全球第五大公司。</p><h2 id="二、”国产GPU四小龙”会师资本市场"><a href="#二、”国产GPU四小龙”会师资本市场" class="headerlink" title="二、”国产GPU四小龙”会师资本市场"></a>二、”国产GPU四小龙”会师资本市场</h2><p>燧原科技科创板IPO申请已通过上交所上市委审议，拟募资60亿元用于五代、六代AI芯片及软硬件协同创新项目。预计2026年上半年营收将大幅增长，有望达到2025年全年水平。<strong>来源：上海证券报、金融界</strong></p><p>此前，摩尔线程、沐曦股份已登陆科创板，壁仞科技在港股上市。燧原科技的过会标志着”国产GPU四小龙”即将会师资本市场，国产AI算力核心企业的融资通道全面打通。</p><h2 id="三、力箭一号遥十四成功发射，百星入轨里程碑"><a href="#三、力箭一号遥十四成功发射，百星入轨里程碑" class="headerlink" title="三、力箭一号遥十四成功发射，百星入轨里程碑"></a>三、力箭一号遥十四成功发射，百星入轨里程碑</h2><p>6月15日上午11时44分，中科宇航力箭一号遥十四运载火箭在东风商业航天创新试验区点火升空，采用”一箭8星”将吉星高分07C04星等8颗卫星精准送入预定轨道。<strong>来源：科创板日报、新华社</strong></p><p>至此，力箭一号已完成第14次飞行任务，累计将105颗卫星送入太空。这是我国新一代通信网加速构建的生动缩影——从5G赋能千行百业，到5G-A规模化商用、6G技术试验推进，再到卫星组网，一张空天地海一体化的新一代通信网正在加速成型。</p><h2 id="四、AI资本热潮：DeepSeek融资74亿美元，高通拟收购Tenstorrent"><a href="#四、AI资本热潮：DeepSeek融资74亿美元，高通拟收购Tenstorrent" class="headerlink" title="四、AI资本热潮：DeepSeek融资74亿美元，高通拟收购Tenstorrent"></a>四、AI资本热潮：DeepSeek融资74亿美元，高通拟收购Tenstorrent</h2><p>DeepSeek在首轮外部融资中筹集超74亿美元，估值超500亿美元，成为中国最具价值的AI初创公司，投资方包括腾讯、宁德时代等。这反映了中国在出口管制下仍大力建设本土AI能力的决心。<strong>来源：TechStartups</strong></p><p>与此同时，高通正洽谈以80-100亿美元收购由传奇芯片设计师Jim Keller领导的AI芯片初创公司Tenstorrent，旨在摆脱对英伟达的依赖，补强AI芯片自主能力。</p><h2 id="五、Meta-AI-Mode上线，Anthropic推进实名认证"><a href="#五、Meta-AI-Mode上线，Anthropic推进实名认证" class="headerlink" title="五、Meta AI Mode上线，Anthropic推进实名认证"></a>五、Meta AI Mode上线，Anthropic推进实名认证</h2><p>Meta于6月15日正式上线”AI Mode”搜索功能，基于35.6亿日活跃用户的公开社交数据合成答案。这标志着Meta的商业模式从广告向AI订阅转型，最高订阅费19.99美元&#x2F;月。但UGC内容权威性不足的问题也引发”信噪比陷阱”担忧。<strong>来源：钛媒体Edge AI Daily</strong></p><p>Anthropic则宣布自7月8日起，Claude用户需提供政府ID和人脸扫描完成实名认证，并可主动向执法机构分享数据。此举旨在构建合规护城河，巩固其企业级AI市场地位（Claude Code市占率已达54%），但隐私争议随之而来。</p><h2 id="六、OpenAI投入1-5亿美元建合作伙伴网络"><a href="#六、OpenAI投入1-5亿美元建合作伙伴网络" class="headerlink" title="六、OpenAI投入1.5亿美元建合作伙伴网络"></a>六、OpenAI投入1.5亿美元建合作伙伴网络</h2><p>OpenAI宣布投入1.5亿美元建设合作伙伴网络，目标到2026年底培养30万名认证伙伴。通过”技术赋能+生态协同”模式推动企业AI转型。AI巨头间的竞争正从模型能力转向生态建设，谁能更好地帮助客户落地AI，谁就能在下一阶段胜出。<strong>来源：钛媒体Edge AI Daily</strong></p><h2 id="七、英国计划禁止16岁以下使用社交媒体"><a href="#七、英国计划禁止16岁以下使用社交媒体" class="headerlink" title="七、英国计划禁止16岁以下使用社交媒体"></a>七、英国计划禁止16岁以下使用社交媒体</h2><p>英国政府宣布计划禁止16岁以下儿童使用TikTok、Instagram等主流社交平台，可能于2027年春季生效。这将成为全球最严格的青少年网络监管措施之一。<strong>来源：TechStartups</strong></p><h2 id="八、中国AI治理新规：拟人化互动服务管理办法出台"><a href="#八、中国AI治理新规：拟人化互动服务管理办法出台" class="headerlink" title="八、中国AI治理新规：拟人化互动服务管理办法出台"></a>八、中国AI治理新规：拟人化互动服务管理办法出台</h2><p>国家网信办等五部门联合公布《人工智能拟人化互动服务管理暂行办法》，自2026年7月15日起施行。这是我国首部AI拟人化互动服务专门立法，旨在规范服务行为、维护国家安全与公共利益。<strong>来源：每经网</strong></p><h2 id="九、其他重要动态"><a href="#九、其他重要动态" class="headerlink" title="九、其他重要动态"></a>九、其他重要动态</h2><p><strong>Fox收购Roku</strong>：福克斯公司以约220亿美元收购流媒体平台Roku，意在加强联网电视广告和流媒体分发领域的竞争力。</p><p><strong>AI冲击初级岗位</strong>：麦肯锡预测到2030年全球约8亿岗位可能被自动化替代，其中初级岗位占比超60%。谷歌宣布投入10亿美元开展AI技能培训。<strong>来源：钛媒体Edge AI Daily</strong></p><p><strong>日本央行加息至1%</strong>：日本央行将政策利率上调至1%，为1995年以来最高水平，正式告别超宽松货币政策。日元升值导致出口型企业股价下跌。</p><p><strong>MLCC缺货潮扩散</strong>：MLCC缺货规格已不仅局限于AI用，主要规格全面供不应求。村田、三星电机等日韩大厂为承接高端订单被迫放弃低端市场，国产MLCC龙头受益。</p><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>序号</th><th>热点事件</th><th>涉及领域</th><th>来源</th></tr></thead><tbody><tr><td>1</td><td>SpaceX 600亿美元收购Cursor母公司Anysphere</td><td>航天+AI</td><td>TechStartups</td></tr><tr><td>2</td><td>燧原科技科创板IPO过会，拟募资60亿元</td><td>国产GPU/AI芯片</td><td>上海证券报/金融界</td></tr><tr><td>3</td><td>力箭一号遥十四成功发射，百星入轨</td><td>航天/商业卫星</td><td>科创板日报/新华社</td></tr><tr><td>4</td><td>DeepSeek首轮融资超74亿美元，估值500亿+</td><td>AI大模型</td><td>TechStartups</td></tr><tr><td>5</td><td>高通拟80-100亿美元收购AI芯片公司Tenstorrent</td><td>AI芯片</td><td>TechStartups</td></tr><tr><td>6</td><td>Meta上线AI Mode搜索，商业模式转向订阅</td><td>AI/社交</td><td>钛媒体Edge AI Daily</td></tr><tr><td>7</td><td>Anthropic要求Claude用户实名认证</td><td>AI合规</td><td>钛媒体Edge AI Daily</td></tr><tr><td>8</td><td>英国计划禁止16岁以下使用社交媒体</td><td>互联网监管</td><td>TechStartups</td></tr></tbody></table></div><hr><p><strong>今日观察</strong>：6月16日的科技新闻呈现出三条清晰主线——<strong>AI与实体产业深度融合</strong>（SpaceX+Cursor、高通+Tenstorrent）、<strong>国产算力生态加速构建</strong>（燧原科技IPO、力箭一号百星入轨）、<strong>全球AI治理体系分化</strong>（中国AI拟人化服务管理办法、英国社交媒体禁令）。AI已不仅是大模型的比拼，而是全产业链、全生态的系统级竞争。</p><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-16-tech-news-tuesday/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-16-tech-news-tuesday/"/>
    <published>2026-06-16T14:38:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="一、航天与AI深度融合：SpaceX-600亿美元收购Cursor"><a href="#一、航天与AI深度融合：SpaceX-600亿美元收购Cursor" class="headerlink" title="一、航天与AI深度融合：SpaceX 600亿美元收]]>
    </summary>
    <title>2026年6月16日科技热点：SpaceX 600亿美元收购Cursor、燧原科技IPO过会、力箭一号再成功</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="Linux" scheme="https://demo-blog.qusite.cn/tags/Linux/"/>
    <category term="运维" scheme="https://demo-blog.qusite.cn/tags/%E8%BF%90%E7%BB%B4/"/>
    <category term="htop" scheme="https://demo-blog.qusite.cn/tags/htop/"/>
    <category term="进程管理" scheme="https://demo-blog.qusite.cn/tags/%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/"/>
    <category term="系统监控" scheme="https://demo-blog.qusite.cn/tags/%E7%B3%BB%E7%BB%9F%E7%9B%91%E6%8E%A7/"/>
    <content>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><code>htop</code> 是 Linux 系统中最受欢迎的交互式进程查看器之一，它是传统 <code>top</code> 命令的现代化替代品。与 <code>top</code> 相比，<code>htop</code> 提供了更直观的彩色界面、鼠标支持、树状视图和更便捷的交互操作，是每位运维工程师和开发者的必备工具。</p><p>本文将全面介绍 htop 的安装配置、界面布局、交互操作、高级功能及实战场景，帮助你从入门到精通掌握这个强大的系统监控工具。</p><h2 id="安装-htop"><a href="#安装-htop" class="headerlink" title="安装 htop"></a>安装 htop</h2><p>htop 在主流 Linux 发行版的官方软件源中均可直接安装：</p><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>发行版</th><th>安装命令</th></tr></thead><tbody><tr><td>Ubuntu / Debian</td><td><code>sudo apt install htop</code></td></tr><tr><td>RHEL / CentOS / Rocky</td><td><code>sudo dnf install htop</code></td></tr><tr><td>Fedora</td><td><code>sudo dnf install htop</code></td></tr><tr><td>Arch Linux</td><td><code>sudo pacman -S htop</code></td></tr><tr><td>openSUSE</td><td><code>sudo zypper install htop</code></td></tr><tr><td>macOS (Homebrew)</td><td><code>brew install htop</code></td></tr></tbody></table></div><p>安装完成后直接输入 <code>htop</code> 即可启动：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">htop</span><br></pre></td></tr></table></figure></div><p>如需以 root 权限查看所有进程信息，可使用 <code>sudo htop</code>。</p><h2 id="界面布局"><a href="#界面布局" class="headerlink" title="界面布局"></a>界面布局</h2><p>启动 htop 后，你会看到一个彩色分区的终端界面，主要由以下几个区域组成：</p><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>区域</th><th>位置</th><th>说明</th></tr></thead><tbody><tr><td>CPU 计量条</td><td>顶部左侧</td><td>每个 CPU 核心的实时使用率，用不同颜色区分</td></tr><tr><td>内存 / Swap 计量条</td><td>顶部中间</td><td>物理内存和交换分区的使用情况</td></tr><tr><td>任务摘要</td><td>顶部右侧</td><td>进程总数、运行中/休眠/僵尸进程计数</td></tr><tr><td>Load average / Uptime</td><td>右上角</td><td>系统负载平均值和运行时间</td></tr><tr><td>进程列表</td><td>中部</td><td>按所选排序方式显示的进程信息</td></tr><tr><td>底部操作栏</td><td>底部</td><td>快捷键提示</td></tr></tbody></table></div><h3 id="颜色含义"><a href="#颜色含义" class="headerlink" title="颜色含义"></a>颜色含义</h3><p>htop 使用颜色编码帮助快速识别资源使用状况：</p><ul><li><strong>CPU 计量条</strong>：绿色（用户态）、红色（内核态）、蓝色（低优先级）、黄色（虚拟化）</li><li><strong>内存计量条</strong>：绿色（已用）、蓝色（缓冲区&#x2F;缓存）、黄色（共享内存）</li><li><strong>进程列表</strong>：颜色越深表示进程越活跃</li></ul><h2 id="进程列表字段解读"><a href="#进程列表字段解读" class="headerlink" title="进程列表字段解读"></a>进程列表字段解读</h2><p>默认情况下，htop 的进程列表显示以下列：</p><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>列名</th><th>含义</th><th>说明</th></tr></thead><tbody><tr><td><code>PID</code></td><td>进程 ID</td><td>唯一标识符</td></tr><tr><td><code>USER</code></td><td>进程所有者</td><td>运行该进程的用户</td></tr><tr><td><code>PRI</code></td><td>内核调度优先级</td><td>数值越低优先级越高</td></tr><tr><td><code>NI</code></td><td>nice 值</td><td>-20~19，越低优先级越高</td></tr><tr><td><code>VIRT</code></td><td>虚拟内存大小</td><td>进程申请的虚拟地址空间</td></tr><tr><td><code>RES</code></td><td>常驻内存大小</td><td>实际占用的物理内存</td></tr><tr><td><code>SHR</code></td><td>共享内存大小</td><td>可与其他进程共享的内存</td></tr><tr><td><code>S</code></td><td>进程状态</td><td>R(运行)/S(睡眠)/D(不可中断)/Z(僵尸)/T(停止)</td></tr><tr><td><code>CPU%</code></td><td>CPU 使用率</td><td>相对于单个核心的百分比</td></tr><tr><td><code>MEM%</code></td><td>内存使用率</td><td>物理内存使用百分比</td></tr><tr><td><code>TIME+</code></td><td>累计 CPU 时间</td><td>进程消耗的总 CPU 时间</td></tr><tr><td><code>Command</code></td><td>命令行</td><td>启动进程的完整命令</td></tr></tbody></table></div><h2 id="基础交互操作"><a href="#基础交互操作" class="headerlink" title="基础交互操作"></a>基础交互操作</h2><p>htop 的核心优势在于其便捷的交互式操作。以下是最常用的快捷键：</p><h3 id="导航与选择"><a href="#导航与选择" class="headerlink" title="导航与选择"></a>导航与选择</h3><table><thead><tr><th>快捷键</th><th>功能</th></tr></thead><tbody><tr><td><code>↑</code> &#x2F; <code>↓</code></td><td>上下移动选择进程</td></tr><tr><td><code>PgUp</code> &#x2F; <code>PgDn</code></td><td>上下翻页</td></tr><tr><td><code>Home</code> &#x2F; <code>End</code></td><td>跳至第一行 &#x2F; 最后一行</td></tr><tr><td>鼠标滚轮</td><td>上下滚动（终端支持时）</td></tr></tbody></table><h3 id="进程管理"><a href="#进程管理" class="headerlink" title="进程管理"></a>进程管理</h3><table><thead><tr><th>快捷键</th><th>功能</th></tr></thead><tbody><tr><td><code>F9</code> 或 <code>k</code></td><td>杀死选中的进程（弹出信号选择菜单）</td></tr><tr><td><code>F7</code> &#x2F; <code>F8</code> 或 <code>[</code> &#x2F; <code>]</code></td><td>降低 &#x2F; 提高进程 nice 值</td></tr><tr><td><code>Space</code></td><td>标记&#x2F;取消标记进程（可批量操作）</td></tr><tr><td><code>u</code></td><td>显示特定用户的进程</td></tr><tr><td><code>U</code></td><td>取消所有进程标记</td></tr></tbody></table><h3 id="排序与视图"><a href="#排序与视图" class="headerlink" title="排序与视图"></a>排序与视图</h3><table><thead><tr><th>快捷键</th><th>功能</th></tr></thead><tbody><tr><td><code>F6</code></td><td>选择排序列</td></tr><tr><td><code>&gt;</code> &#x2F; <code>&lt;</code></td><td>按当前列正序 &#x2F; 倒序排列</td></tr><tr><td><code>F5</code> 或 <code>t</code></td><td>切换树状视图（显示父子进程关系）</td></tr><tr><td><code>F4</code> 或 <code>/</code></td><td>搜索进程（按名称过滤）</td></tr><tr><td><code>F3</code></td><td>向后查找下一个匹配项</td></tr><tr><td><code>F2</code></td><td>进入设置菜单</td></tr><tr><td><code>H</code></td><td>切换显示&#x2F;隐藏用户线程</td></tr><tr><td><code>K</code></td><td>切换显示&#x2F;隐藏内核线程</td></tr><tr><td><code>M</code></td><td>按内存使用排序</td></tr><tr><td><code>P</code></td><td>按 CPU 使用排序</td></tr><tr><td><code>T</code></td><td>按运行时间排序</td></tr></tbody></table><h3 id="其他快捷键"><a href="#其他快捷键" class="headerlink" title="其他快捷键"></a>其他快捷键</h3><table><thead><tr><th>快捷键</th><th>功能</th></tr></thead><tbody><tr><td><code>F1</code> 或 <code>h</code></td><td>显示帮助页面</td></tr><tr><td><code>F10</code> 或 <code>q</code></td><td>退出 htop</td></tr><tr><td><code>s</code></td><td>追踪进程的系统调用（strace 模式）</td></tr><tr><td><code>l</code></td><td>显示进程打开的文件（lsof 模式）</td></tr><tr><td><code>F8</code></td><td>重设 nice 值</td></tr><tr><td><code>+</code> &#x2F; <code>-</code></td><td>在树状视图中展开&#x2F;折叠进程组</td></tr><tr><td><code>c</code></td><td>读取进程的 &#x2F;proc 目录内容</td></tr></tbody></table><blockquote><p><strong>提示</strong>：按下 <code>F1</code> 随时可以查看完整的快捷键列表。</p></blockquote><h2 id="高级功能"><a href="#高级功能" class="headerlink" title="高级功能"></a>高级功能</h2><h3 id="1-树状视图（Tree-View）"><a href="#1-树状视图（Tree-View）" class="headerlink" title="1. 树状视图（Tree View）"></a>1. 树状视图（Tree View）</h3><p>按下 <code>F5</code> 或 <code>t</code> 键切换到树状视图，可以看到进程之间的父子关系。这对于理解服务启动链和排查进程依赖非常有用。再次按 <code>F5</code> 返回列表视图。</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">├─ systemd(1)</span><br><span class="line">│  ├─ systemd-journald(450)</span><br><span class="line">│  ├─ systemd-logind(680)</span><br><span class="line">│  ├─ sshd(720)</span><br><span class="line">│  │  └─ sshd(2891)</span><br><span class="line">│  │     └─ bash(2893)</span><br><span class="line">│  ├─ nginx(890)</span><br><span class="line">│  │  ├─ nginx(891)</span><br><span class="line">│  │  └─ nginx(892)</span><br><span class="line">│  └─ mysqld(1050)</span><br></pre></td></tr></table></figure></div><h3 id="2-进程过滤与搜索"><a href="#2-进程过滤与搜索" class="headerlink" title="2. 进程过滤与搜索"></a>2. 进程过滤与搜索</h3><p>按 <code>F4</code> 或 <code>/</code> 可以输入关键词过滤进程名称。htop 只显示名称匹配的进程，这对于在大规模服务器上快速定位目标进程非常高效。</p><p>过滤后会以黄色高亮显示匹配项，按 <code>F3</code> 可跳转到下一个匹配。</p><h3 id="3-自定义显示列"><a href="#3-自定义显示列" class="headerlink" title="3. 自定义显示列"></a>3. 自定义显示列</h3><p>默认列可能不满足所有监控需求。按 <code>F2</code> 进入设置，选择 “Columns” 菜单，可以添加或移除显示列。常用的额外列包括：</p><table><thead><tr><th>列名</th><th>含义</th><th>适用场景</th></tr></thead><tbody><tr><td><code>IO_READ_RATE</code></td><td>磁盘读取速率</td><td>排查 IO 密集型进程</td></tr><tr><td><code>IO_WRITE_RATE</code></td><td>磁盘写入速率</td><td>排查 IO 密集型进程</td></tr><tr><td><code>IO_PRIORITY</code></td><td>IO 调度优先级</td><td>IO 性能调优</td></tr><tr><td><code>CGROUP</code></td><td>Control Group</td><td>Docker&#x2F;容器环境</td></tr><tr><td><code>OOM</code></td><td>OOM 评分</td><td>内存压力排查</td></tr><tr><td><code>NLWP</code></td><td>线程数</td><td>检查多线程应用</td></tr><tr><td><code>STARTTIME</code></td><td>启动时间</td><td>检查进程运行时长</td></tr></tbody></table><h3 id="4-颜色主题与布局"><a href="#4-颜色主题与布局" class="headerlink" title="4. 颜色主题与布局"></a>4. 颜色主题与布局</h3><p>按 <code>F2</code> 进入设置菜单，可以调整：</p><ul><li><strong>Colors</strong>：选择内置颜色主题（默认、Monochrome、Black-on-White 等）</li><li><strong>Layout</strong>：调整 CPU&#x2F;内存计量条的位置和显示方式</li><li><strong>Display options</strong>：控制树状视图缩进、是否显示程序路径等</li></ul><h3 id="5-进程标记与批量操作"><a href="#5-进程标记与批量操作" class="headerlink" title="5. 进程标记与批量操作"></a>5. 进程标记与批量操作</h3><p>在某个进程上按 <code>Space</code> 标记它（标记为黄色），可以同时标记多个进程。标记后按 <code>F9</code> 可以对所有标记的进程执行相同的操作（如同时杀死多个进程）。</p><h2 id="实战场景"><a href="#实战场景" class="headerlink" title="实战场景"></a>实战场景</h2><h3 id="场景一：找到最耗-CPU-的进程"><a href="#场景一：找到最耗-CPU-的进程" class="headerlink" title="场景一：找到最耗 CPU 的进程"></a>场景一：找到最耗 CPU 的进程</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 启动 htop，然后按 P（大写 P），进程将按 CPU 使用率降序排列</span></span><br><span class="line">htop</span><br><span class="line"><span class="comment"># → 按 P 排序</span></span><br><span class="line"><span class="comment"># → 按 F9 → SIGTERM (15) 结束异常进程</span></span><br></pre></td></tr></table></figure></div><h3 id="场景二：排查内存泄漏"><a href="#场景二：排查内存泄漏" class="headerlink" title="场景二：排查内存泄漏"></a>场景二：排查内存泄漏</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 启动 htop，按 M（大写 M）按内存使用排序</span></span><br><span class="line">htop</span><br><span class="line"><span class="comment"># → 按 M 排序</span></span><br><span class="line"><span class="comment"># → 观察 RES 列（实际常驻内存）</span></span><br><span class="line"><span class="comment"># → 切换树状视图（F5）查看是否是进程组的子进程</span></span><br></pre></td></tr></table></figure></div><h3 id="场景三：定位特定服务的异常子进程"><a href="#场景三：定位特定服务的异常子进程" class="headerlink" title="场景三：定位特定服务的异常子进程"></a>场景三：定位特定服务的异常子进程</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 找到 nginx 进程，切换到树状视图</span></span><br><span class="line">htop</span><br><span class="line"><span class="comment"># → 按 F4 → 输入 nginx → 回车过滤</span></span><br><span class="line"><span class="comment"># → 按 F5 切换到树状视图，查看 nginx worker 进程状态</span></span><br><span class="line"><span class="comment"># → 检查是否有过多僵尸（Z）状态的工作进程</span></span><br></pre></td></tr></table></figure></div><h3 id="场景四：监控-Docker-容器资源"><a href="#场景四：监控-Docker-容器资源" class="headerlink" title="场景四：监控 Docker 容器资源"></a>场景四：监控 Docker 容器资源</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">htop</span><br><span class="line"><span class="comment"># → 按 F2 → Display options → 勾选 &quot;Tree view always show container info&quot;</span></span><br><span class="line"><span class="comment"># → 按 F5 切换到树状视图</span></span><br><span class="line"><span class="comment"># → 观察 CGROUP 列，可以看到进程所属的容器</span></span><br></pre></td></tr></table></figure></div><h3 id="场景五：追踪进程文件描述符泄露"><a href="#场景五：追踪进程文件描述符泄露" class="headerlink" title="场景五：追踪进程文件描述符泄露"></a>场景五：追踪进程文件描述符泄露</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 在 htop 中选中可疑进程，按 l 键</span></span><br><span class="line"><span class="comment"># 相当于执行 lsof -p &lt;PID&gt;</span></span><br><span class="line"><span class="comment"># 查看打开的 FD 数量是否持续增长</span></span><br></pre></td></tr></table></figure></div><h2 id="htop-vs-top-对比"><a href="#htop-vs-top-对比" class="headerlink" title="htop vs top 对比"></a>htop vs top 对比</h2><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>特性</th><th>htop</th><th>top</th></tr></thead><tbody><tr><td>界面颜色</td><td>彩色，直观清晰</td><td>单色为主</td></tr><tr><td>鼠标支持</td><td>支持</td><td>不支持</td></tr><tr><td>滚动查看</td><td>支持（上下翻页）</td><td>默认不支持滚动</td></tr><tr><td>树状视图</td><td>内置树状视图</td><td>需 <code>top -H</code> 切换线程</td></tr><tr><td>信号发送</td><td>交互式菜单选择信号</td><td>输入 PID 和信号编号</td></tr><tr><td>进程过滤</td><td>支持（F4 搜索过滤）</td><td>不支持</td></tr><tr><td>自定义列</td><td>图形界面自由选择</td><td>配置文件较复杂</td></tr><tr><td>列排序</td><td>按任意列排序</td><td>有限列的排序</td></tr><tr><td>进程标记</td><td>支持多选标记</td><td>不支持</td></tr><tr><td>垂直/水平滚动</td><td>支持</td><td>不支持</td></tr><tr><td>配置文件格式</td><td>可视化设置菜单</td><td>文本配置文件 /etc/toprc</td></tr><tr><td>默认安装</td><td>需要额外安装</td><td>大多数发行版预装</td></tr></tbody></table></div><h2 id="配置文件与自定义"><a href="#配置文件与自定义" class="headerlink" title="配置文件与自定义"></a>配置文件与自定义</h2><p>htop 的配置文件存储在用户目录下：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 配置文件路径</span></span><br><span class="line">~/.config/htop/htoprc</span><br><span class="line"><span class="comment"># 全局配置文件（新用户默认）</span></span><br><span class="line">/etc/htoprc</span><br></pre></td></tr></table></figure></div><p>如果需要重置 htop 配置为默认：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> ~/.config/htop/htoprc</span><br><span class="line">htop  <span class="comment"># 重新启动会自动生成默认配置</span></span><br></pre></td></tr></table></figure></div><h3 id="自定义-htop-配置示例"><a href="#自定义-htop-配置示例" class="headerlink" title="自定义 htop 配置示例"></a>自定义 htop 配置示例</h3><div class="code-container" data-rel="Ini"><figure class="iseeu highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 保存为 ~/.config/htop/htoprc</span></span><br><span class="line"><span class="comment"># 显示选项</span></span><br><span class="line"><span class="attr">show_program_path</span>=<span class="number">0</span></span><br><span class="line"><span class="attr">highlight_base_name</span>=<span class="number">1</span></span><br><span class="line"><span class="attr">highlight_megabytes</span>=<span class="number">1</span></span><br><span class="line"><span class="attr">highlight_threads</span>=<span class="number">1</span></span><br><span class="line"><span class="attr">tree_view</span>=<span class="number">0</span></span><br><span class="line"><span class="attr">sort_key</span>=<span class="number">46</span></span><br><span class="line"><span class="attr">sort_direction</span>=-<span class="number">1</span></span><br><span class="line"><span class="attr">hide_kernel_threads</span>=<span class="number">1</span></span><br><span class="line"><span class="attr">hide_userland_threads</span>=<span class="number">0</span></span><br><span class="line"><span class="comment"># 颜色方案: 0=默认, 1=Monochrome, 2=Black-on-White</span></span><br><span class="line"><span class="attr">color_scheme</span>=<span class="number">0</span></span><br></pre></td></tr></table></figure></div><blockquote><p>更简单的方法是按 <code>F2</code> 通过可视化菜单调整，htop 会自动写入配置文件。</p></blockquote><h2 id="安全注意事项"><a href="#安全注意事项" class="headerlink" title="安全注意事项"></a>安全注意事项</h2><ol><li><strong>权限限制</strong>：普通用户只能查看和操作自己的进程，查看所有进程需 <code>sudo htop</code> 或 <code>sudo -E htop</code></li><li><strong>进程终止</strong>：使用 <code>F9</code> 终止进程前务必确认 PID 是否正确，误杀关键系统进程可能导致服务器宕机</li><li><strong>生产环境</strong>：在高负载生产服务器上，htop 本身也会消耗少量 CPU 资源，但通常可忽略不计</li><li><strong>远程会话</strong>：通过 SSH 使用 htop 时，确保终端支持 UTF-8 和 256 色以获得最佳显示效果</li></ol><h2 id="常见问题排查"><a href="#常见问题排查" class="headerlink" title="常见问题排查"></a>常见问题排查</h2><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>问题</th><th>可能原因</th><th>解决方案</th></tr></thead><tbody><tr><td>htop 无法启动</td><td>未安装</td><td><code>apt install htop</code> 或 <code>dnf install htop</code></td></tr><tr><td>界面显示乱码</td><td>终端不支持 UTF-8</td><td>检查 <code>locale</code> 设置，确保为 <code>en_US.UTF-8</code></td></tr><tr><td>进程列表为空</td><td>权限不足</td><td>使用 <code>sudo htop</code></td></tr><tr><td>CPU 计量条不准确</td><td>更新频率过快</td><td>按 <code>s</code> 键调整刷新间隔</td></tr><tr><td>找不到配置文件</td><td>首次使用</td><td>按 F2 调整后会自动创建</td></tr><tr><td>树状视图无法展开</td><td>/proc 限制</td><td>确保进程有读取 /proc/PID/children 的权限</td></tr><tr><td>颜色显示异常</td><td>终端颜色支持不足</td><td>设置 <code>TERM=xterm-256color</code></td></tr></tbody></table></div><h2 id="命令速查表"><a href="#命令速查表" class="headerlink" title="命令速查表"></a>命令速查表</h2><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>场景</th><th>操作</th></tr></thead><tbody><tr><td>启动 htop</td><td><code>htop</code> / <code>sudo htop</code></td></tr><tr><td>按 CPU 排序</td><td>按 <code>P</code> 键</td></tr><tr><td>按内存排序</td><td>按 <code>M</code> 键</td></tr><tr><td>按运行时间排序</td><td>按 <code>T</code> 键</td></tr><tr><td>切换树状视图</td><td>按 <code>F5</code> 或 <code>t</code></td></tr><tr><td>搜索进程</td><td>按 <code>F4</code> 或 <code>/</code></td></tr><tr><td>杀死进程</td><td>选中后按 <code>F9</code> 或 <code>k</code></td></tr><tr><td>调整 nice 值</td><td>选中后按 <code>F7</code> 或 <code>F8</code></td></tr><tr><td>查看用户的进程</td><td>按 <code>u</code> 选择用户</td></tr><tr><td>追踪系统调用</td><td>选中后按 <code>s</code></td></tr><tr><td>查看文件描述符</td><td>选中后按 <code>l</code></td></tr><tr><td>刷新间隔调整</td><td>按 <code>s</code> 设置秒数</td></tr><tr><td>自定义设置</td><td>按 <code>F2</code> 进入设置</td></tr><tr><td>查看帮助</td><td>按 <code>F1</code> 或 <code>h</code></td></tr><tr><td>退出 htop</td><td>按 <code>F10</code> 或 <code>q</code></td></tr></tbody></table></div><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>htop 作为 top 命令的现代化替代品，以直观的彩色界面、便捷的交互操作和丰富的自定义选项，成为了 Linux 系统管理员日常运维的首选工具。通过本文的学习，你应该已经掌握了：</p><ul><li>htop 的安装与界面布局</li><li>进程列表的字段含义</li><li>核心交互快捷键操作</li><li>树状视图、搜索过滤、自定义列等高级功能</li><li>五个实用的生产环境排查场景</li><li>配置文件的备份与自定义</li></ul><p>在日常运维中，推荐将 htop 作为首选的进程管理工具。配合之前文章中介绍的 <code>ss</code>（网络诊断）、<code>lsof</code>（文件描述符）和 <code>strace</code>（系统调用追踪），你可以构建一套完整的 Linux 系统问题排查工具链。</p><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-16-htop-command-guide/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-16-htop-command-guide/"/>
    <published>2026-06-16T13:36:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p><code>htop</code> 是 Linux 系统中最受欢迎的交互式进程查看器之一，它是传统 <code>top</code> 命令的]]>
    </summary>
    <title>Linux htop 命令完全指南：交互式进程管理从入门到精通</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="环境搭建" scheme="https://demo-blog.qusite.cn/tags/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
    <category term="编程语言" scheme="https://demo-blog.qusite.cn/tags/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/"/>
    <category term="Rust" scheme="https://demo-blog.qusite.cn/tags/Rust/"/>
    <category term="入门教程" scheme="https://demo-blog.qusite.cn/tags/%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/"/>
    <content>
      <![CDATA[<p>Rust 是由 Mozilla 发起、社区驱动的现代系统级编程语言，以<strong>内存安全</strong>、<strong>零成本抽象</strong>和<strong>并发无畏</strong>三大核心承诺著称。自 2015 年发布 1.0 以来，Rust 连续多年蝉联 Stack Overflow “最受喜爱编程语言”榜首，被 Linux 内核、Android、Firefox、Cloudflare 等巨头广泛采用。</p><p>本文将从零开始，完整记录在 Windows 和 Linux 平台上搭建 Rust 开发环境的全过程，涵盖工具链安装、编辑器配置、项目管理、调试部署等环节。</p><h2 id="一、Rust-工具链安装"><a href="#一、Rust-工具链安装" class="headerlink" title="一、Rust 工具链安装"></a>一、Rust 工具链安装</h2><h3 id="1-1-使用-rustup（官方推荐）"><a href="#1-1-使用-rustup（官方推荐）" class="headerlink" title="1.1 使用 rustup（官方推荐）"></a>1.1 使用 rustup（官方推荐）</h3><p>Rust 官方推荐的安装方式是通过 <code>rustup</code>——Rust 版本管理器兼工具链安装器。</p><p><strong>Linux&#x2F;macOS：</strong></p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl --proto <span class="string">&#x27;=https&#x27;</span> --tlsv1.2 -sSf https://sh.rustup.rs | sh</span><br></pre></td></tr></table></figure></div><p><strong>Windows：</strong></p><p>访问 <a class="link"   href="https://rustup.rs/" >https://rustup.rs<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 下载 <code>rustup-init.exe</code> 并运行，按提示选择默认安装即可。</p><p>安装成功后需要重启终端，然后验证：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">rustc --version   <span class="comment"># 编译器版本</span></span><br><span class="line">cargo --version   <span class="comment"># 包管理器版本</span></span><br><span class="line">rustup --version  <span class="comment"># 工具链管理器版本</span></span><br></pre></td></tr></table></figure></div><h3 id="1-2-安装后配置"><a href="#1-2-安装后配置" class="headerlink" title="1.2 安装后配置"></a>1.2 安装后配置</h3><p>rustup 默认安装 stable 工具链，对于 Linux 平台还需要安装构建依赖：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Ubuntu/Debian</span></span><br><span class="line"><span class="built_in">sudo</span> apt update &amp;&amp; <span class="built_in">sudo</span> apt install build-essential pkg-config libssl-dev</span><br><span class="line"></span><br><span class="line"><span class="comment"># RHEL/CentOS/Fedora</span></span><br><span class="line"><span class="built_in">sudo</span> dnf groupinstall <span class="string">&quot;Development Tools&quot;</span></span><br><span class="line"><span class="built_in">sudo</span> dnf install pkgconfig openssl-devel</span><br><span class="line"></span><br><span class="line"><span class="comment"># Arch Linux</span></span><br><span class="line"><span class="built_in">sudo</span> pacman -S base-devel openssl</span><br></pre></td></tr></table></figure></div><p>配置 cargo 环境变量（通常 rustup 已自动添加，如未生效可手动执行）：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> <span class="string">&quot;<span class="variable">$HOME</span>/.cargo/env&quot;</span></span><br></pre></td></tr></table></figure></div><h3 id="1-3-切换与安装其他工具链"><a href="#1-3-切换与安装其他工具链" class="headerlink" title="1.3 切换与安装其他工具链"></a>1.3 切换与安装其他工具链</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">rustup install nightly          <span class="comment"># 安装 nightly 版本</span></span><br><span class="line">rustup default nightly          <span class="comment"># 切换到 nightly</span></span><br><span class="line">rustup default stable           <span class="comment"># 切回 stable</span></span><br><span class="line">rustup toolchain list           <span class="comment"># 列出已安装的工具链</span></span><br></pre></td></tr></table></figure></div><h2 id="二、Cargo-包管理器详解"><a href="#二、Cargo-包管理器详解" class="headerlink" title="二、Cargo 包管理器详解"></a>二、Cargo 包管理器详解</h2><p>Cargo 既是 Rust 的包管理器，也是构建系统和测试运行器。它从根本上解决了 C&#x2F;C++ 领域常见的依赖管理难题。</p><h3 id="2-1-常用命令速查"><a href="#2-1-常用命令速查" class="headerlink" title="2.1 常用命令速查"></a>2.1 常用命令速查</h3><table><thead><tr><th>命令</th><th>作用</th><th>示例</th></tr></thead><tbody><tr><td><code>cargo new &lt;name&gt;</code></td><td>创建新项目</td><td><code>cargo new my_project</code></td></tr><tr><td><code>cargo init</code></td><td>在当前目录初始化项目</td><td><code>cargo init</code></td></tr><tr><td><code>cargo build</code></td><td>编译（debug 模式）</td><td><code>cargo build</code></td></tr><tr><td><code>cargo build --release</code></td><td>编译（release 模式，带优化）</td><td><code>cargo build --release</code></td></tr><tr><td><code>cargo run</code></td><td>编译并运行</td><td><code>cargo run</code></td></tr><tr><td><code>cargo check</code></td><td>快速检查能否编译（不生成二进制）</td><td><code>cargo check</code></td></tr><tr><td><code>cargo test</code></td><td>运行测试</td><td><code>cargo test</code></td></tr><tr><td><code>cargo add &lt;crate&gt;</code></td><td>添加依赖</td><td><code>cargo add serde</code></td></tr><tr><td><code>cargo remove &lt;crate&gt;</code></td><td>移除依赖</td><td><code>cargo remove serde</code></td></tr><tr><td><code>cargo update</code></td><td>更新依赖</td><td><code>cargo update</code></td></tr><tr><td><code>cargo clean</code></td><td>清理构建产物</td><td><code>cargo clean</code></td></tr><tr><td><code>cargo doc --open</code></td><td>生成文档并在浏览器打开</td><td><code>cargo doc --open</code></td></tr></tbody></table><h3 id="2-2-Cargo-toml-配置"><a href="#2-2-Cargo-toml-配置" class="headerlink" title="2.2 Cargo.toml 配置"></a>2.2 Cargo.toml 配置</h3><div class="code-container" data-rel="Toml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="section">[package]</span></span><br><span class="line"><span class="attr">name</span> = <span class="string">&quot;my_project&quot;</span></span><br><span class="line"><span class="attr">version</span> = <span class="string">&quot;0.1.0&quot;</span></span><br><span class="line"><span class="attr">edition</span> = <span class="string">&quot;2024&quot;</span>          <span class="comment"># Rust 版本体系：2015/2018/2021/2024</span></span><br><span class="line"><span class="attr">description</span> = <span class="string">&quot;A sample Rust project&quot;</span></span><br><span class="line"><span class="attr">authors</span> = [<span class="string">&quot;Your Name &lt;email@example.com&gt;&quot;</span>]</span><br><span class="line"></span><br><span class="line"><span class="section">[dependencies]</span></span><br><span class="line"><span class="attr">serde</span> = &#123; version = <span class="string">&quot;1.0&quot;</span>, features = [<span class="string">&quot;derive&quot;</span>] &#125;</span><br><span class="line"><span class="attr">tokio</span> = &#123; version = <span class="string">&quot;1&quot;</span>, features = [<span class="string">&quot;full&quot;</span>] &#125;</span><br><span class="line"><span class="attr">reqwest</span> = <span class="string">&quot;0.12&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="section">[profile.release]</span></span><br><span class="line"><span class="attr">opt-level</span> = <span class="number">3</span>             <span class="comment"># 优化等级 0-3</span></span><br><span class="line"><span class="attr">lto</span> = <span class="literal">true</span>                <span class="comment"># 链接时优化</span></span><br><span class="line"><span class="attr">codegen-units</span> = <span class="number">1</span>         <span class="comment"># 单代码生成单元（更激进优化）</span></span><br><span class="line"><span class="attr">strip</span> = <span class="literal">true</span>              <span class="comment"># 移除符号信息减小体积</span></span><br><span class="line"></span><br><span class="line"><span class="section">[workspace]</span></span><br><span class="line"><span class="attr">members</span> = [<span class="string">&quot;crates/*&quot;</span>]    <span class="comment"># 工作空间，管理多 crate 项目</span></span><br></pre></td></tr></table></figure></div><h2 id="三、编辑器与-IDE-配置"><a href="#三、编辑器与-IDE-配置" class="headerlink" title="三、编辑器与 IDE 配置"></a>三、编辑器与 IDE 配置</h2><h3 id="3-1-VS-Code-配置"><a href="#3-1-VS-Code-配置" class="headerlink" title="3.1 VS Code 配置"></a>3.1 VS Code 配置</h3><p>VS Code 是 Rust 开发最常用的编辑器，需要安装以下扩展：</p><table><thead><tr><th>扩展名</th><th>ID</th><th>作用</th></tr></thead><tbody><tr><td>rust-analyzer</td><td><code>rust-lang.rust-analyzer</code></td><td>代码补全、跳转、类型提示、重构</td></tr><tr><td>crates</td><td><code>serayuzgur.crates</code></td><td>在 <code>Cargo.toml</code> 中显示依赖版本状态</td></tr><tr><td>CodeLLDB</td><td><code>vadimcn.vscode-lldb</code></td><td>Rust 原生调试器支持</td></tr><tr><td>Even Better TOML</td><td><code>tamasfe.even-better-toml</code></td><td>TOML 语法高亮与格式化</td></tr></tbody></table><p><strong><code>settings.json</code> 推荐配置：</strong></p><div class="code-container" data-rel="Json"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;rust-analyzer.check.command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;clippy&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;rust-analyzer.inlayHints.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;rust-analyzer.linkedProjects&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;Cargo.toml&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;[rust]&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;editor.formatOnSave&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;editor.defaultFormatter&quot;</span><span class="punctuation">:</span> <span class="string">&quot;rust-lang.rust-analyzer&quot;</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></div><p>使用 <code>rust-analyzer.check.command</code> 设置为 <code>clippy</code> 后，保存时会自动运行 <code>cargo clippy</code> 进行检查，相当于拥有了一个实时 lint 引擎。</p><h3 id="3-2-CLion-配置"><a href="#3-2-CLion-配置" class="headerlink" title="3.2 CLion 配置"></a>3.2 CLion 配置</h3><p>JetBrains 系用户推荐使用 <strong>IntelliJ IDEA + Rust 插件</strong> 或直接使用 <strong>CLion + Rust 插件</strong>。</p><p>安装步骤：</p><ol><li>打开 Settings → Plugins → 搜索 “Rust” 安装</li><li>安装完成后重启 IDE，打开或创建 Cargo 项目即可自动识别</li></ol><p>CLion 的优势在于集成度更高，调试器（GDB&#x2F;LLDB）开箱即用，重构功能更强大。</p><h3 id="3-3-Neovim-Vim-配置"><a href="#3-3-Neovim-Vim-配置" class="headerlink" title="3.3 Neovim&#x2F;Vim 配置"></a>3.3 Neovim&#x2F;Vim 配置</h3><div class="code-container" data-rel="Vim"><figure class="iseeu highlight vim"><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="comment">&quot; .vimrc / init.lua 中关键配置</span></span><br><span class="line"><span class="comment">&quot; 使用 coc.nvim 或 lspconfig 集成 rust-analyzer</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 通过 lspconfig 配置 rust-analyzer</span></span><br><span class="line"><span class="keyword">lua</span> &lt;&lt; EOF</span><br><span class="line">require<span class="string">&#x27;lspconfig&#x27;</span>.rust_analyzer.setup(&#123;</span><br><span class="line">  settings = &#123;</span><br><span class="line">    [<span class="string">&quot;rust-analyzer&quot;</span>] = &#123;</span><br><span class="line">      checkOnSave = &#123; <span class="keyword">command</span> = <span class="string">&quot;clippy&quot;</span> &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;)</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure></div><h2 id="四、调试环境配置"><a href="#四、调试环境配置" class="headerlink" title="四、调试环境配置"></a>四、调试环境配置</h2><h3 id="4-1-VS-Code-调试"><a href="#4-1-VS-Code-调试" class="headerlink" title="4.1 VS Code 调试"></a>4.1 VS Code 调试</h3><p>安装 CodeLLDB 扩展后，在 <code>.vscode/launch.json</code> 中配置：</p><div class="code-container" data-rel="Json"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;version&quot;</span><span class="punctuation">:</span> <span class="string">&quot;0.2.0&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;configurations&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;lldb&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;request&quot;</span><span class="punctuation">:</span> <span class="string">&quot;launch&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Debug Rust&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;cargo&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;build&quot;</span><span class="punctuation">,</span> <span class="string">&quot;--bin&quot;</span><span class="punctuation">,</span> <span class="string">&quot;my_project&quot;</span><span class="punctuation">,</span> <span class="string">&quot;--package&quot;</span><span class="punctuation">,</span> <span class="string">&quot;my_project&quot;</span><span class="punctuation">]</span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;args&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;cwd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;$&#123;workspaceFolder&#125;&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></div><h3 id="4-2-命令行调试"><a href="#4-2-命令行调试" class="headerlink" title="4.2 命令行调试"></a>4.2 命令行调试</h3><p>Rust 项目可以直接使用 <code>rust-gdb</code> 或 <code>rust-lldb</code>（需安装 <code>gdb</code> 或 <code>lldb</code>）：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 安装调试符号</span></span><br><span class="line">cargo install rust-lldb  <span class="comment"># 或 sudo apt install lldb</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. debug 模式编译</span></span><br><span class="line">cargo build</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 启动调试</span></span><br><span class="line">rust-lldb target/debug/my_project</span><br></pre></td></tr></table></figure></div><h2 id="五、项目模板与脚手架"><a href="#五、项目模板与脚手架" class="headerlink" title="五、项目模板与脚手架"></a>五、项目模板与脚手架</h2><h3 id="5-1-cargo-generate"><a href="#5-1-cargo-generate" class="headerlink" title="5.1 cargo-generate"></a>5.1 cargo-generate</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">cargo install cargo-generate</span><br><span class="line"></span><br><span class="line"><span class="comment"># 从模板创建项目</span></span><br><span class="line">cargo generate --git https://github.com/rust-lang-ja/axum-template</span><br></pre></td></tr></table></figure></div><p>常用模板源：</p><table><thead><tr><th>模板</th><th>用途</th></tr></thead><tbody><tr><td><code>rust-cli-template</code></td><td>CLI 命令行工具</td></tr><tr><td><code>axum-template</code></td><td>Axum Web 框架项目</td></tr><tr><td><code>actix-template</code></td><td>Actix-Web 项目模板</td></tr><tr><td><code>tauri-template</code></td><td>Tauri 桌面应用模板</td></tr></tbody></table><h3 id="5-2-常用开发工具安装"><a href="#5-2-常用开发工具安装" class="headerlink" title="5.2 常用开发工具安装"></a>5.2 常用开发工具安装</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 代码格式化</span></span><br><span class="line">rustup component add rustfmt</span><br><span class="line"></span><br><span class="line"><span class="comment"># 代码检查（比默认检查更严格）</span></span><br><span class="line">rustup component add clippy</span><br><span class="line"></span><br><span class="line"><span class="comment"># 性能分析</span></span><br><span class="line">cargo install flamegraph    <span class="comment"># 火焰图生成</span></span><br><span class="line">cargo install cargo-criterion  <span class="comment"># 基准测试框架</span></span><br><span class="line">cargo install cargo-expand  <span class="comment"># 宏展开</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 覆盖率</span></span><br><span class="line">cargo install cargo-tarpaulin  <span class="comment"># Linux 上使用</span></span><br></pre></td></tr></table></figure></div><h2 id="六、完整实战：从零编写一个-HTTP-工具"><a href="#六、完整实战：从零编写一个-HTTP-工具" class="headerlink" title="六、完整实战：从零编写一个 HTTP 工具"></a>六、完整实战：从零编写一个 HTTP 工具</h2><p>下面创建一个实用的 HTTP 请求工具来检验环境配置是否正确。</p><h3 id="6-1-创建项目"><a href="#6-1-创建项目" class="headerlink" title="6.1 创建项目"></a>6.1 创建项目</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cargo new http_tool</span><br><span class="line"><span class="built_in">cd</span> http_tool</span><br></pre></td></tr></table></figure></div><h3 id="6-2-添加依赖"><a href="#6-2-添加依赖" class="headerlink" title="6.2 添加依赖"></a>6.2 添加依赖</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">cargo add reqwest --features json</span><br><span class="line">cargo add tokio --features full</span><br><span class="line">cargo add serde --features derive</span><br><span class="line">cargo add serde_json</span><br></pre></td></tr></table></figure></div><h3 id="6-3-编写代码"><a href="#6-3-编写代码" class="headerlink" title="6.3 编写代码"></a>6.3 编写代码</h3><p>编辑 <code>src/main.rs</code>：</p><div class="code-container" data-rel="Rust"><figure class="iseeu highlight rust"><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"><span class="keyword">use</span> serde::&#123;Deserialize, Serialize&#125;;</span><br><span class="line"><span class="keyword">use</span> std::env;</span><br><span class="line"></span><br><span class="line"><span class="meta">#[derive(Debug, Serialize, Deserialize)]</span></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Todo</span> &#123;</span><br><span class="line">    userId: <span class="type">u32</span>,</span><br><span class="line">    id: <span class="type">u32</span>,</span><br><span class="line">    title: <span class="type">String</span>,</span><br><span class="line">    completed: <span class="type">bool</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">#[tokio::main]</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">fn</span> <span class="title function_">main</span>() <span class="punctuation">-&gt;</span> <span class="type">Result</span>&lt;(), <span class="type">Box</span>&lt;<span class="keyword">dyn</span> std::error::Error&gt;&gt; &#123;</span><br><span class="line">    <span class="keyword">let</span> <span class="variable">args</span>: <span class="type">Vec</span>&lt;<span class="type">String</span>&gt; = env::<span class="title function_ invoke__">args</span>().<span class="title function_ invoke__">collect</span>();</span><br><span class="line">    <span class="keyword">let</span> <span class="variable">url</span> = <span class="keyword">if</span> args.<span class="title function_ invoke__">len</span>() &gt; <span class="number">1</span> &#123;</span><br><span class="line">        args[<span class="number">1</span>].<span class="title function_ invoke__">clone</span>()</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="string">&quot;https://jsonplaceholder.typicode.com/todos/1&quot;</span>.<span class="title function_ invoke__">to_string</span>()</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;🌐 正在请求: &#123;&#125;\n&quot;</span>, url);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> <span class="variable">client</span> = reqwest::Client::<span class="title function_ invoke__">new</span>();</span><br><span class="line">    <span class="keyword">let</span> <span class="variable">response</span> = client.<span class="title function_ invoke__">get</span>(&amp;url).<span class="title function_ invoke__">send</span>().<span class="keyword">await</span>?;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;状态码: &#123;&#125;&quot;</span>, response.<span class="title function_ invoke__">status</span>());</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> <span class="variable">body</span> = response.<span class="title function_ invoke__">text</span>().<span class="keyword">await</span>?;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;响应内容 (前 500 字符):\n&#123;&#125;&quot;</span>, &amp;body[..body.<span class="title function_ invoke__">len</span>().<span class="title function_ invoke__">min</span>(<span class="number">500</span>)]);</span><br><span class="line"></span><br><span class="line">    <span class="title function_ invoke__">Ok</span>(())</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="6-4-运行"><a href="#6-4-运行" class="headerlink" title="6.4 运行"></a>6.4 运行</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cargo run</span><br><span class="line">cargo run -- <span class="string">&quot;https://jsonplaceholder.typicode.com/todos/2&quot;</span>  <span class="comment"># 自定义 URL</span></span><br></pre></td></tr></table></figure></div><h2 id="七、常见问题排查"><a href="#七、常见问题排查" class="headerlink" title="七、常见问题排查"></a>七、常见问题排查</h2><table><thead><tr><th>问题</th><th>原因</th><th>解决方案</th></tr></thead><tbody><tr><td><code>linker cc not found</code></td><td>Linux 缺少 C 编译器</td><td><code>sudo apt install build-essential</code></td></tr><tr><td><code>could not find native static library &quot;ssl&quot;</code></td><td>缺少 OpenSSL 开发库</td><td>安装 <code>libssl-dev</code>（Ubuntu）或 <code>openssl-devel</code>（RHEL）</td></tr><tr><td>rustup 安装后命令找不到</td><td>环境变量未加载</td><td>重启终端或执行 <code>source &quot;$HOME/.cargo/env&quot;</code></td></tr><tr><td>编译速度慢</td><td>debug 模式链接耗时</td><td>使用 <code>mold</code> 链接器替代默认 <code>ld</code></td></tr><tr><td><code>cargo add</code> 无效</td><td>Cargo 版本过低</td><td>升级 rustup：<code>rustup update</code></td></tr><tr><td>Windows 上 <code>std::process::Command</code> 执行失败</td><td>MSVC 运行时缺失</td><td>安装 Visual Studio Build Tools</td></tr><tr><td><code>clippy</code> 未找到</td><td>组件未安装</td><td><code>rustup component add clippy</code></td></tr><tr><td>依赖冲突</td><td>多个版本不兼容</td><td><code>cargo update</code> 或手动指定版本号</td></tr></tbody></table><h2 id="八、最佳实践总结"><a href="#八、最佳实践总结" class="headerlink" title="八、最佳实践总结"></a>八、最佳实践总结</h2><ol><li><strong>edition 选择</strong>：新项目使用 <code>edition = &quot;2024&quot;</code>，这是当前最新版本体系</li><li><strong>用好 clippy</strong>：将 clippy 集成到编辑器保存钩子中，它是 Rust 生态中最强大的代码审查工具</li><li><strong>为所有代码编写测试</strong>：<code>#[cfg(test)] mod tests &#123; ... &#125;</code> 是 Rust 的惯用实践</li><li><strong>使用 workspace</strong>：多 crate 项目使用 [workspace] 管理依赖和构建</li><li><strong>关注 release 体积</strong>：参考上文 <code>[profile.release]</code> 配置，可以大幅缩减可执行文件体积</li><li><strong>保持 rustup 更新</strong>：每周执行一次 <code>rustup update</code> 获取最新编译器改进和安全补丁</li></ol><hr><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-16-rust-env-setup/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-16-rust-env-setup/"/>
    <published>2026-06-16T10:15:00.000Z</published>
    <summary>
      <![CDATA[<p>Rust 是由 Mozilla 发起、社区驱动的现代系统级编程语言，以<strong>内存安全</strong>、<strong>零成本抽象</strong>和<strong>并发无畏</strong>三大核心承诺著称。自 2015 年发布 1.0 以来，Rust 连续多年]]>
    </summary>
    <title>Rust 开发环境搭建完全指南</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="Linux" scheme="https://demo-blog.qusite.cn/tags/Linux/"/>
    <category term="DevOps" scheme="https://demo-blog.qusite.cn/tags/DevOps/"/>
    <category term="Ansible" scheme="https://demo-blog.qusite.cn/tags/Ansible/"/>
    <category term="自动化运维" scheme="https://demo-blog.qusite.cn/tags/%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4/"/>
    <category term="配置管理" scheme="https://demo-blog.qusite.cn/tags/%E9%85%8D%E7%BD%AE%E7%AE%A1%E7%90%86/"/>
    <content>
      <![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>在管理多台 Linux 服务器时，手动登录每台机器执行命令的方式不仅效率低下，而且容易出错。Ansible 作为一款开源的自动化运维工具，凭借其<strong>无需 Agent、基于 SSH、声明式语法</strong>的三大优势，已成为运维工程师的必备技能。本文将全面介绍 Ansible 的安装配置、核心概念与实战应用。</p><h2 id="Ansible-核心架构"><a href="#Ansible-核心架构" class="headerlink" title="Ansible 核心架构"></a>Ansible 核心架构</h2><p>Ansible 采用无主从架构（Agentless），通过 SSH 协议直接管理远程主机，核心组件包括：</p><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>组件</th><th>说明</th></tr></thead><tbody><tr><td>Control Node</td><td>控制节点，安装 Ansible 的机器（支持 Linux/macOS/WSL）</td></tr><tr><td>Managed Node</td><td>被管理主机，通过 SSH 被控制节点操作</td></tr><tr><td>Inventory</td><td>主机清单，定义被管理主机的列表和分组</td></tr><tr><td>Module</td><td>执行具体任务的模块（如 copy、yum、service）</td></tr><tr><td>Playbook</td><td>YAML 格式的剧本文件，编排多个任务的执行流程</td></tr><tr><td>Role</td><td>可复用的任务、变量、文件等资源的组织单元</td></tr></tbody></table></div><h2 id="一、Ansible-安装与配置"><a href="#一、Ansible-安装与配置" class="headerlink" title="一、Ansible 安装与配置"></a>一、Ansible 安装与配置</h2><h3 id="1-1-控制节点安装"><a href="#1-1-控制节点安装" class="headerlink" title="1.1 控制节点安装"></a>1.1 控制节点安装</h3><h4 id="Ubuntu-Debian"><a href="#Ubuntu-Debian" class="headerlink" title="Ubuntu &#x2F; Debian"></a>Ubuntu &#x2F; Debian</h4><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 启用官方 PPA</span></span><br><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install -y software-properties-common</span><br><span class="line"><span class="built_in">sudo</span> add-apt-repository --<span class="built_in">yes</span> --update ppa:ansible/ansible</span><br><span class="line"><span class="built_in">sudo</span> apt install -y ansible</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证安装</span></span><br><span class="line">ansible --version</span><br></pre></td></tr></table></figure></div><h4 id="CentOS-RHEL"><a href="#CentOS-RHEL" class="headerlink" title="CentOS &#x2F; RHEL"></a>CentOS &#x2F; RHEL</h4><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 启用 EPEL 仓库</span></span><br><span class="line"><span class="built_in">sudo</span> dnf install -y epel-release</span><br><span class="line"><span class="built_in">sudo</span> dnf install -y ansible</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证安装</span></span><br><span class="line">ansible --version</span><br></pre></td></tr></table></figure></div><h4 id="使用-pip-安装（跨平台通用）"><a href="#使用-pip-安装（跨平台通用）" class="headerlink" title="使用 pip 安装（跨平台通用）"></a>使用 pip 安装（跨平台通用）</h4><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 推荐使用虚拟环境</span></span><br><span class="line">python3 -m venv ~/ansible-env</span><br><span class="line"><span class="built_in">source</span> ~/ansible-env/bin/activate</span><br><span class="line">pip install ansible</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装特定版本</span></span><br><span class="line">pip install ansible==9.5.0</span><br></pre></td></tr></table></figure></div><h3 id="1-2-SSH-免密登录配置"><a href="#1-2-SSH-免密登录配置" class="headerlink" title="1.2 SSH 免密登录配置"></a>1.2 SSH 免密登录配置</h3><p>Ansible 通过 SSH 管理远程主机，因此需要配置 SSH 密钥认证：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 生成 Ed25519 密钥对（如果还没有）</span></span><br><span class="line">ssh-keygen -t ed25519 -f ~/.ssh/ansible_key -N <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 将公钥分发到所有被管理主机</span></span><br><span class="line">ssh-copy-id -i ~/.ssh/ansible_key.pub user@host1</span><br><span class="line">ssh-copy-id -i ~/.ssh/ansible_key.pub user@host2</span><br><span class="line">ssh-copy-id -i ~/.ssh/ansible_key.pub user@host3</span><br></pre></td></tr></table></figure></div><p>配置 SSH Config 简化连接：</p><div class="code-container" data-rel="Ini"><figure class="iseeu highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># ~/.ssh/config</span></span><br><span class="line">Host server-*</span><br><span class="line">    IdentityFile ~/.ssh/ansible_key</span><br><span class="line">    User ubuntu</span><br><span class="line">    StrictHostKeyChecking no</span><br><span class="line">    UserKnownHostsFile /dev/null</span><br><span class="line"></span><br><span class="line">Host server-web</span><br><span class="line">    HostName 192.168.1.10</span><br><span class="line"></span><br><span class="line">Host server-db</span><br><span class="line">    HostName 192.168.1.11</span><br></pre></td></tr></table></figure></div><h2 id="二、主机清单（Inventory）"><a href="#二、主机清单（Inventory）" class="headerlink" title="二、主机清单（Inventory）"></a>二、主机清单（Inventory）</h2><h3 id="2-1-静态-Inventory"><a href="#2-1-静态-Inventory" class="headerlink" title="2.1 静态 Inventory"></a>2.1 静态 Inventory</h3><p>默认位置 <code>/etc/ansible/hosts</code> 或自定义文件 <code>inventory.ini</code>：</p><div class="code-container" data-rel="Ini"><figure class="iseeu highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[webservers]</span></span><br><span class="line">web1 <span class="attr">ansible_host</span>=<span class="number">192.168</span>.<span class="number">1.10</span> ansible_user=ubuntu</span><br><span class="line">web2 <span class="attr">ansible_host</span>=<span class="number">192.168</span>.<span class="number">1.11</span> ansible_user=ubuntu</span><br><span class="line"></span><br><span class="line"><span class="section">[dbservers]</span></span><br><span class="line">db1 <span class="attr">ansible_host</span>=<span class="number">192.168</span>.<span class="number">1.20</span></span><br><span class="line"></span><br><span class="line"><span class="section">[all:vars]</span></span><br><span class="line"><span class="attr">ansible_ssh_private_key_file</span>=~/.ssh/ansible_key</span><br><span class="line"><span class="attr">ansible_python_interpreter</span>=/usr/bin/python3</span><br></pre></td></tr></table></figure></div><h3 id="2-2-Inventory-变量定义"><a href="#2-2-Inventory-变量定义" class="headerlink" title="2.2 Inventory 变量定义"></a>2.2 Inventory 变量定义</h3><div class="code-container" data-rel="Yaml"><figure class="iseeu 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="comment"># inventory.yml（YAML 格式更清晰）</span></span><br><span class="line"><span class="attr">all:</span></span><br><span class="line">  <span class="attr">children:</span></span><br><span class="line">    <span class="attr">webservers:</span></span><br><span class="line">      <span class="attr">hosts:</span></span><br><span class="line">        <span class="attr">web1:</span></span><br><span class="line">          <span class="attr">ansible_host:</span> <span class="number">192.168</span><span class="number">.1</span><span class="number">.10</span></span><br><span class="line">          <span class="attr">http_port:</span> <span class="number">80</span></span><br><span class="line">        <span class="attr">web2:</span></span><br><span class="line">          <span class="attr">ansible_host:</span> <span class="number">192.168</span><span class="number">.1</span><span class="number">.11</span></span><br><span class="line">          <span class="attr">http_port:</span> <span class="number">8080</span></span><br><span class="line">      <span class="attr">vars:</span></span><br><span class="line">        <span class="attr">ansible_user:</span> <span class="string">ubuntu</span></span><br><span class="line">        <span class="attr">nginx_version:</span> <span class="number">1.26</span></span><br></pre></td></tr></table></figure></div><h3 id="2-3-动态-Inventory"><a href="#2-3-动态-Inventory" class="headerlink" title="2.3 动态 Inventory"></a>2.3 动态 Inventory</h3><p>AWS、GCP、阿里云等云平台提供动态 Inventory 脚本，自动从云 API 获取主机列表：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用 AWS EC2 动态 Inventory</span></span><br><span class="line">ansible-inventory -i aws_ec2.yaml --list</span><br><span class="line"></span><br><span class="line"><span class="comment"># aws_ec2.yaml 示例</span></span><br><span class="line">plugin: aws_ec2</span><br><span class="line">regions:</span><br><span class="line">  - ap-northeast-1</span><br><span class="line">filters:</span><br><span class="line">  tag:Environment: production</span><br><span class="line">keyed_groups:</span><br><span class="line">  - key: tags.Role</span><br><span class="line">    prefix: role</span><br></pre></td></tr></table></figure></div><h2 id="三、Ad-Hoc-命令快速上手"><a href="#三、Ad-Hoc-命令快速上手" class="headerlink" title="三、Ad-Hoc 命令快速上手"></a>三、Ad-Hoc 命令快速上手</h2><p>在编写 Playbook 之前，先通过 Ad-Hoc 命令熟悉 Ansible 的模块化操作：</p><h3 id="3-1-连通性测试"><a href="#3-1-连通性测试" class="headerlink" title="3.1 连通性测试"></a>3.1 连通性测试</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Ping 所有主机</span></span><br><span class="line">ansible all -i inventory.ini -m ping</span><br><span class="line"></span><br><span class="line"><span class="comment"># 仅测试 webservers 组</span></span><br><span class="line">ansible webservers -i inventory.yml -m ping</span><br></pre></td></tr></table></figure></div><h3 id="3-2-常用-Ad-Hoc-命令"><a href="#3-2-常用-Ad-Hoc-命令" class="headerlink" title="3.2 常用 Ad-Hoc 命令"></a>3.2 常用 Ad-Hoc 命令</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 远程执行命令</span></span><br><span class="line">ansible all -m shell -a <span class="string">&quot;uptime &amp;&amp; free -h&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 复制文件</span></span><br><span class="line">ansible webservers -m copy -a <span class="string">&quot;src=/etc/nginx/nginx.conf dest=/etc/nginx/nginx.conf backup=yes&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装软件包</span></span><br><span class="line">ansible webservers -m apt -a <span class="string">&quot;name=nginx state=present&quot;</span> -b</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启停服务</span></span><br><span class="line">ansible webservers -m service -a <span class="string">&quot;name=nginx state=restarted enabled=yes&quot;</span> -b</span><br><span class="line"></span><br><span class="line"><span class="comment"># 收集系统信息</span></span><br><span class="line">ansible all -m setup -a <span class="string">&quot;filter=ansible_distribution*&quot;</span></span><br></pre></td></tr></table></figure></div><h3 id="3-3-常用模块速查"><a href="#3-3-常用模块速查" class="headerlink" title="3.3 常用模块速查"></a>3.3 常用模块速查</h3><div class="opt-table"><table><thead><tr><th>模块</th><th>功能</th><th>常用参数</th></tr></thead><tbody><tr><td>command/shell</td><td>执行命令</td><td>cmd (shell 支持管道重定向)</td></tr><tr><td>copy</td><td>复制文件</td><td>src, dest, owner, mode, backup</td></tr><tr><td>template</td><td>Jinja2 模板</td><td>src, dest, vars</td></tr><tr><td>file</td><td>文件/目录管理</td><td>path, state (directory/touch/link/absent)</td></tr><tr><td>apt/yum/dnf</td><td>包管理</td><td>name, state (present/latest/absent)</td></tr><tr><td>service/systemd</td><td>服务管理</td><td>name, state (started/stopped/restarted), enabled</td></tr><tr><td>user</td><td>用户管理</td><td>name, groups, shell, state</td></tr><tr><td>lineinfile</td><td>行编辑</td><td>path, line, regexp, insertafter</td></tr><tr><td>firewalld/iptables</td><td>防火墙规则</td><td>service, port, permanent, state</td></tr><tr><td>docker_container</td><td>Docker 容器</td><td>name, image, state, ports, env</td></tr></tbody></table></div><h2 id="四、编写-Playbook"><a href="#四、编写-Playbook" class="headerlink" title="四、编写 Playbook"></a>四、编写 Playbook</h2><p>Playbook 是 Ansible 的核心，使用 YAML 格式定义任务编排。</p><h3 id="4-1-基础-Playbook-结构"><a href="#4-1-基础-Playbook-结构" class="headerlink" title="4.1 基础 Playbook 结构"></a>4.1 基础 Playbook 结构</h3><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">配置</span> <span class="string">Nginx</span> <span class="string">Web</span> <span class="string">服务器</span></span><br><span class="line">  <span class="attr">hosts:</span> <span class="string">webservers</span></span><br><span class="line">  <span class="attr">become:</span> <span class="literal">yes</span></span><br><span class="line">  <span class="attr">vars:</span></span><br><span class="line">    <span class="attr">nginx_port:</span> <span class="number">80</span></span><br><span class="line">    <span class="attr">server_name:</span> <span class="string">example.com</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">tasks:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">更新</span> <span class="string">apt</span> <span class="string">缓存</span></span><br><span class="line">      <span class="attr">apt:</span></span><br><span class="line">        <span class="attr">update_cache:</span> <span class="literal">yes</span></span><br><span class="line">        <span class="attr">cache_valid_time:</span> <span class="number">3600</span></span><br><span class="line"></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">安装</span> <span class="string">Nginx</span></span><br><span class="line">      <span class="attr">apt:</span></span><br><span class="line">        <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line">        <span class="attr">state:</span> <span class="string">present</span></span><br><span class="line"></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">配置</span> <span class="string">Nginx</span> <span class="string">站点</span></span><br><span class="line">      <span class="attr">template:</span></span><br><span class="line">        <span class="attr">src:</span> <span class="string">nginx.conf.j2</span></span><br><span class="line">        <span class="attr">dest:</span> <span class="string">/etc/nginx/sites-available/&#123;&#123;</span> <span class="string">server_name</span> <span class="string">&#125;&#125;</span></span><br><span class="line">      <span class="attr">notify:</span> <span class="string">restart</span> <span class="string">nginx</span></span><br><span class="line"></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">启用站点</span></span><br><span class="line">      <span class="attr">file:</span></span><br><span class="line">        <span class="attr">src:</span> <span class="string">/etc/nginx/sites-available/&#123;&#123;</span> <span class="string">server_name</span> <span class="string">&#125;&#125;</span></span><br><span class="line">        <span class="attr">dest:</span> <span class="string">/etc/nginx/sites-enabled/&#123;&#123;</span> <span class="string">server_name</span> <span class="string">&#125;&#125;</span></span><br><span class="line">        <span class="attr">state:</span> <span class="string">link</span></span><br><span class="line">      <span class="attr">notify:</span> <span class="string">restart</span> <span class="string">nginx</span></span><br><span class="line"></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">开放防火墙端口</span></span><br><span class="line">      <span class="attr">ufw:</span></span><br><span class="line">        <span class="attr">rule:</span> <span class="string">allow</span></span><br><span class="line">        <span class="attr">port:</span> <span class="string">&quot;<span class="template-variable">&#123;&#123; nginx_port &#125;&#125;</span>&quot;</span></span><br><span class="line">        <span class="attr">proto:</span> <span class="string">tcp</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">handlers:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">restart</span> <span class="string">nginx</span></span><br><span class="line">      <span class="attr">service:</span></span><br><span class="line">        <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line">        <span class="attr">state:</span> <span class="string">restarted</span></span><br></pre></td></tr></table></figure></div><h3 id="4-2-执行-Playbook"><a href="#4-2-执行-Playbook" class="headerlink" title="4.2 执行 Playbook"></a>4.2 执行 Playbook</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 基本执行</span></span><br><span class="line">ansible-playbook -i inventory.yml nginx-setup.yml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查模式（Dry Run）</span></span><br><span class="line">ansible-playbook -i inventory.yml nginx-setup.yml --check</span><br><span class="line"></span><br><span class="line"><span class="comment"># 详细输出</span></span><br><span class="line">ansible-playbook -i inventory.yml nginx-setup.yml -vvv</span><br><span class="line"></span><br><span class="line"><span class="comment"># 指定 SSH 用户</span></span><br><span class="line">ansible-playbook -i inventory.yml nginx-setup.yml -u ubuntu</span><br><span class="line"></span><br><span class="line"><span class="comment"># 从特定任务开始执行</span></span><br><span class="line">ansible-playbook -i inventory.yml nginx-setup.yml --start-at-task=<span class="string">&quot;配置 Nginx 站点&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 语法检查</span></span><br><span class="line">ansible-playbook -i inventory.yml nginx-setup.yml --syntax-check</span><br></pre></td></tr></table></figure></div><h3 id="4-3-条件判断与循环"><a href="#4-3-条件判断与循环" class="headerlink" title="4.3 条件判断与循环"></a>4.3 条件判断与循环</h3><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">根据发行版安装不同包</span></span><br><span class="line">  <span class="attr">apt:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">&quot;<span class="template-variable">&#123;&#123; item &#125;&#125;</span>&quot;</span></span><br><span class="line">    <span class="attr">state:</span> <span class="string">present</span></span><br><span class="line">  <span class="attr">when:</span> <span class="string">ansible_facts[&#x27;os_family&#x27;]</span> <span class="string">==</span> <span class="string">&quot;Debian&quot;</span></span><br><span class="line">  <span class="attr">loop:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">nginx</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">python3-pip</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">htop</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">创建多个用户</span></span><br><span class="line">  <span class="attr">user:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">&quot;<span class="template-variable">&#123;&#123; item.username &#125;&#125;</span>&quot;</span></span><br><span class="line">    <span class="attr">groups:</span> <span class="string">&quot;<span class="template-variable">&#123;&#123; item.groups | default(&#x27;users&#x27;) &#125;&#125;</span>&quot;</span></span><br><span class="line">    <span class="attr">shell:</span> <span class="string">/bin/bash</span></span><br><span class="line">  <span class="attr">loop:</span></span><br><span class="line">    <span class="bullet">-</span> &#123; <span class="attr">username:</span> <span class="string">&quot;alice&quot;</span>, <span class="attr">groups:</span> <span class="string">&quot;sudo&quot;</span> &#125;</span><br><span class="line">    <span class="bullet">-</span> &#123; <span class="attr">username:</span> <span class="string">&quot;bob&quot;</span>, <span class="attr">groups:</span> <span class="string">&quot;docker&quot;</span> &#125;</span><br><span class="line">    <span class="bullet">-</span> &#123; <span class="attr">username:</span> <span class="string">&quot;carol&quot;</span> &#125;</span><br></pre></td></tr></table></figure></div><h3 id="4-4-文件模板（Jinja2）"><a href="#4-4-文件模板（Jinja2）" class="headerlink" title="4.4 文件模板（Jinja2）"></a>4.4 文件模板（Jinja2）</h3><p>模板文件使用 <code>.j2</code> 扩展名，存放在 <code>templates/</code> 目录下：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line">&#123;# templates/nginx.conf.j2 #&#125;</span><br><span class="line">server &#123;</span><br><span class="line">    listen &#123;&#123; nginx_port &#125;&#125;;</span><br><span class="line">    server_name &#123;&#123; server_name &#125;&#125;;</span><br><span class="line"></span><br><span class="line">    root /var/www/&#123;&#123; server_name &#125;&#125;;</span><br><span class="line">    index index.html;</span><br><span class="line"></span><br><span class="line">    location / &#123;</span><br><span class="line">        try_files $uri $uri/ =404;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    location /api &#123;</span><br><span class="line">        proxy_pass http://127.0.0.1:3000;</span><br><span class="line">        proxy_set_header Host $host;</span><br><span class="line">        proxy_set_header X-Real-IP $remote_addr;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="五、Roles-角色编排"><a href="#五、Roles-角色编排" class="headerlink" title="五、Roles 角色编排"></a>五、Roles 角色编排</h2><p>当 Playbook 变得复杂时，使用 Role 将任务、变量、模板和文件组织为可复用的单元。</p><h3 id="5-1-Role-目录结构"><a href="#5-1-Role-目录结构" class="headerlink" title="5.1 Role 目录结构"></a>5.1 Role 目录结构</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">site.yml                  <span class="comment"># 主 Playbook</span></span><br><span class="line">roles/</span><br><span class="line">  common/                 <span class="comment"># 通用角色</span></span><br><span class="line">    tasks/main.yml        <span class="comment"># 主任务列表</span></span><br><span class="line">    handlers/main.yml     <span class="comment"># 处理器</span></span><br><span class="line">    templates/            <span class="comment"># Jinja2 模板</span></span><br><span class="line">    files/                <span class="comment"># 静态文件</span></span><br><span class="line">    vars/main.yml         <span class="comment"># 角色变量</span></span><br><span class="line">    defaults/main.yml     <span class="comment"># 默认变量（优先级最低）</span></span><br><span class="line">    meta/main.yml         <span class="comment"># 角色依赖</span></span><br><span class="line">  nginx/                  <span class="comment"># Nginx 角色</span></span><br><span class="line">    tasks/main.yml</span><br><span class="line">    templates/nginx.conf.j2</span><br><span class="line">    vars/main.yml</span><br><span class="line">  postgresql/             <span class="comment"># PostgreSQL 角色</span></span><br><span class="line">    tasks/main.yml</span><br><span class="line">    vars/main.yml</span><br></pre></td></tr></table></figure></div><h3 id="5-2-编写-Role-任务"><a href="#5-2-编写-Role-任务" class="headerlink" title="5.2 编写 Role 任务"></a>5.2 编写 Role 任务</h3><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="comment"># roles/nginx/tasks/main.yml</span></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">确保</span> <span class="string">Nginx</span> <span class="string">已安装</span></span><br><span class="line">  <span class="attr">apt:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">nginx</span></span><br><span class="line">    <span class="attr">state:</span> <span class="string">&quot;<span class="template-variable">&#123;&#123; nginx_state | default(&#x27;present&#x27;) &#125;&#125;</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">创建站点目录</span></span><br><span class="line">  <span class="attr">file:</span></span><br><span class="line">    <span class="attr">path:</span> <span class="string">&quot;/var/www/<span class="template-variable">&#123;&#123; nginx_server_name &#125;&#125;</span>&quot;</span></span><br><span class="line">    <span class="attr">state:</span> <span class="string">directory</span></span><br><span class="line">    <span class="attr">mode:</span> <span class="string">&#x27;0755&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">部署</span> <span class="string">Nginx</span> <span class="string">配置</span></span><br><span class="line">  <span class="attr">template:</span></span><br><span class="line">    <span class="attr">src:</span> <span class="string">nginx.conf.j2</span></span><br><span class="line">    <span class="attr">dest:</span> <span class="string">&quot;/etc/nginx/sites-available/<span class="template-variable">&#123;&#123; nginx_server_name &#125;&#125;</span>&quot;</span></span><br><span class="line">  <span class="attr">notify:</span> <span class="string">restart</span> <span class="string">nginx</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">启用站点</span></span><br><span class="line">  <span class="attr">file:</span></span><br><span class="line">    <span class="attr">src:</span> <span class="string">&quot;/etc/nginx/sites-available/<span class="template-variable">&#123;&#123; nginx_server_name &#125;&#125;</span>&quot;</span></span><br><span class="line">    <span class="attr">dest:</span> <span class="string">&quot;/etc/nginx/sites-enabled/<span class="template-variable">&#123;&#123; nginx_server_name &#125;&#125;</span>&quot;</span></span><br><span class="line">    <span class="attr">state:</span> <span class="string">link</span></span><br><span class="line">  <span class="attr">notify:</span> <span class="string">restart</span> <span class="string">nginx</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">部署</span> <span class="string">index.html</span></span><br><span class="line">  <span class="attr">copy:</span></span><br><span class="line">    <span class="attr">src:</span> <span class="string">index.html</span></span><br><span class="line">    <span class="attr">dest:</span> <span class="string">&quot;/var/www/<span class="template-variable">&#123;&#123; nginx_server_name &#125;&#125;</span>/index.html&quot;</span></span><br><span class="line">    <span class="attr">mode:</span> <span class="string">&#x27;0644&#x27;</span></span><br></pre></td></tr></table></figure></div><h3 id="5-3-主-Playbook-引用-Roles"><a href="#5-3-主-Playbook-引用-Roles" class="headerlink" title="5.3 主 Playbook 引用 Roles"></a>5.3 主 Playbook 引用 Roles</h3><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="comment"># site.yml</span></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">所有服务器通用配置</span></span><br><span class="line">  <span class="attr">hosts:</span> <span class="string">all</span></span><br><span class="line">  <span class="attr">roles:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">common</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Web</span> <span class="string">服务器配置</span></span><br><span class="line">  <span class="attr">hosts:</span> <span class="string">webservers</span></span><br><span class="line">  <span class="attr">roles:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">role:</span> <span class="string">nginx</span></span><br><span class="line">      <span class="attr">vars:</span></span><br><span class="line">        <span class="attr">nginx_server_name:</span> <span class="string">&quot;example.com&quot;</span></span><br><span class="line">        <span class="attr">nginx_port:</span> <span class="number">443</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">数据库服务器配置</span></span><br><span class="line">  <span class="attr">hosts:</span> <span class="string">dbservers</span></span><br><span class="line">  <span class="attr">roles:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">role:</span> <span class="string">postgresql</span></span><br><span class="line">      <span class="attr">vars:</span></span><br><span class="line">        <span class="attr">postgresql_version:</span> <span class="number">16</span></span><br><span class="line">        <span class="attr">postgresql_max_connections:</span> <span class="number">200</span></span><br></pre></td></tr></table></figure></div><h3 id="5-4-Role-依赖与-Galaxy"><a href="#5-4-Role-依赖与-Galaxy" class="headerlink" title="5.4 Role 依赖与 Galaxy"></a>5.4 Role 依赖与 Galaxy</h3><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="comment"># roles/postgresql/meta/main.yml</span></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">dependencies:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">role:</span> <span class="string">common</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">role:</span> <span class="string">geerlingguy.security</span></span><br><span class="line">    <span class="attr">vars:</span></span><br><span class="line">      <span class="attr">security_ssh_permit_root_login:</span> <span class="string">&quot;no&quot;</span></span><br><span class="line">      <span class="attr">security_fail2ban_enabled:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure></div><p>使用 Ansible Galaxy 下载社区 Role：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 搜索 Role</span></span><br><span class="line">ansible-galaxy search nginx</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 Role</span></span><br><span class="line">ansible-galaxy install geerlingguy.nginx</span><br><span class="line">ansible-galaxy install geerlingguy.postgresql</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 requirements.yml 中定义的 Role</span></span><br><span class="line"><span class="built_in">cat</span> &lt;&lt; <span class="string">&#x27;EOF&#x27;</span> &gt; requirements.yml</span><br><span class="line">---</span><br><span class="line">roles:</span><br><span class="line">  - name: geerlingguy.nginx</span><br><span class="line">    version: 3.2.0</span><br><span class="line">  - name: geerlingguy.postgresql</span><br><span class="line">    version: 3.5.0</span><br><span class="line">  - name: geerlingguy.security</span><br><span class="line">    version: 2.3.0</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">ansible-galaxy install -r requirements.yml</span><br></pre></td></tr></table></figure></div><h2 id="六、Ansible-Vault-加密敏感数据"><a href="#六、Ansible-Vault-加密敏感数据" class="headerlink" title="六、Ansible Vault 加密敏感数据"></a>六、Ansible Vault 加密敏感数据</h2><p>保护密码、密钥等敏感信息：</p><h3 id="6-1-加密与解密"><a href="#6-1-加密与解密" class="headerlink" title="6.1 加密与解密"></a>6.1 加密与解密</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建加密文件</span></span><br><span class="line">ansible-vault create secrets.yml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 编辑加密文件</span></span><br><span class="line">ansible-vault edit secrets.yml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 加密已有文件</span></span><br><span class="line">ansible-vault encrypt group_vars/all/vault.yml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 解密</span></span><br><span class="line">ansible-vault decrypt secrets.yml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 更改密码</span></span><br><span class="line">ansible-vault rekey secrets.yml</span><br></pre></td></tr></table></figure></div><h3 id="6-2-使用加密变量"><a href="#6-2-使用加密变量" class="headerlink" title="6.2 使用加密变量"></a>6.2 使用加密变量</h3><div class="code-container" data-rel="Yaml"><figure class="iseeu 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="comment"># group_vars/all/vault.yml（加密文件）</span></span><br><span class="line"><span class="attr">vault_db_password:</span> <span class="string">&quot;MySecureP@ssw0rd!2026&quot;</span></span><br><span class="line"><span class="attr">vault_api_key:</span> <span class="string">&quot;sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># group_vars/all/main.yml（引用加密变量）</span></span><br><span class="line"><span class="attr">db_password:</span> <span class="string">&quot;<span class="template-variable">&#123;&#123; vault_db_password &#125;&#125;</span>&quot;</span></span><br><span class="line"><span class="attr">api_key:</span> <span class="string">&quot;<span class="template-variable">&#123;&#123; vault_api_key &#125;&#125;</span>&quot;</span></span><br></pre></td></tr></table></figure></div><h3 id="6-3-执行时提供密码"><a href="#6-3-执行时提供密码" class="headerlink" title="6.3 执行时提供密码"></a>6.3 执行时提供密码</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 交互式输入密码</span></span><br><span class="line">ansible-playbook site.yml --ask-vault-pass</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用密码文件</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;my-vault-password&quot;</span> &gt; .vault_pass</span><br><span class="line"><span class="built_in">chmod</span> 600 .vault_pass</span><br><span class="line">ansible-playbook site.yml --vault-password-file .vault_pass</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用环境变量</span></span><br><span class="line">ANSIBLE_VAULT_PASSWORD_FILE=.vault_pass ansible-playbook site.yml</span><br></pre></td></tr></table></figure></div><h2 id="七、Ansible-配置优化"><a href="#七、Ansible-配置优化" class="headerlink" title="七、Ansible 配置优化"></a>七、Ansible 配置优化</h2><h3 id="7-1-主配置文件-ansible-cfg"><a href="#7-1-主配置文件-ansible-cfg" class="headerlink" title="7.1 主配置文件 ansible.cfg"></a>7.1 主配置文件 <code>ansible.cfg</code></h3><div class="code-container" data-rel="Ini"><figure class="iseeu highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="section">[defaults]</span></span><br><span class="line"><span class="comment"># Inventory 文件路径</span></span><br><span class="line"><span class="attr">inventory</span> = inventory.yml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 并行执行数量</span></span><br><span class="line"><span class="attr">forks</span> = <span class="number">20</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># SSH 连接超时</span></span><br><span class="line"><span class="attr">timeout</span> = <span class="number">30</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 主机密钥检查（生产环境建议开启）</span></span><br><span class="line"><span class="attr">host_key_checking</span> = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 日志路径</span></span><br><span class="line"><span class="attr">log_path</span> = /var/log/ansible.log</span><br><span class="line"></span><br><span class="line"><span class="comment"># 模块缓存</span></span><br><span class="line"><span class="attr">gathering</span> = smart</span><br><span class="line"><span class="attr">fact_caching</span> = jsonfile</span><br><span class="line"><span class="attr">fact_caching_connection</span> = /tmp/ansible_facts</span><br><span class="line"><span class="attr">fact_caching_timeout</span> = <span class="number">3600</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 默认 Python 解释器</span></span><br><span class="line"><span class="attr">interpreter_python</span> = /usr/bin/python3</span><br><span class="line"></span><br><span class="line"><span class="section">[ssh_connection]</span></span><br><span class="line"><span class="comment"># SSH 复用加速</span></span><br><span class="line"><span class="attr">pipelining</span> = <span class="literal">True</span></span><br><span class="line"><span class="attr">ssh_args</span> = -o ControlMaster=auto -o ControlPersist=<span class="number">60</span>s</span><br></pre></td></tr></table></figure></div><h3 id="7-2-性能优化技巧"><a href="#7-2-性能优化技巧" class="headerlink" title="7.2 性能优化技巧"></a>7.2 性能优化技巧</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 关闭 fact gathering（如果不需要）</span></span><br><span class="line">ansible-playbook site.yml --gathering=explicit</span><br><span class="line"></span><br><span class="line"><span class="comment"># 限制执行范围</span></span><br><span class="line">ansible-playbook site.yml --<span class="built_in">limit</span> web1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 跳过特定标签</span></span><br><span class="line">ansible-playbook site.yml --skip-tags <span class="string">&quot;firewall&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 仅执行特定标签</span></span><br><span class="line">ansible-playbook site.yml --tags <span class="string">&quot;deploy&quot;</span></span><br></pre></td></tr></table></figure></div><h2 id="八、实战案例：完整部署-LEMP-栈"><a href="#八、实战案例：完整部署-LEMP-栈" class="headerlink" title="八、实战案例：完整部署 LEMP 栈"></a>八、实战案例：完整部署 LEMP 栈</h2><p>综合运用上述知识，编写完整 Playbook 部署 LEMP 栈（Nginx + MariaDB + PHP）：</p><h3 id="8-1-目录结构"><a href="#8-1-目录结构" class="headerlink" title="8.1 目录结构"></a>8.1 目录结构</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">lemp-deployment/</span><br><span class="line">├── ansible.cfg</span><br><span class="line">├── inventory.yml</span><br><span class="line">├── site.yml</span><br><span class="line">├── requirements.yml</span><br><span class="line">├── group_vars/</span><br><span class="line">│   └── all/</span><br><span class="line">│       └── main.yml</span><br><span class="line">├── roles/</span><br><span class="line">│   ├── common/</span><br><span class="line">│   │   └── tasks/main.yml</span><br><span class="line">│   ├── nginx/</span><br><span class="line">│   │   ├── tasks/main.yml</span><br><span class="line">│   │   └── templates/nginx.conf.j2</span><br><span class="line">│   ├── mariadb/</span><br><span class="line">│   │   ├── tasks/main.yml</span><br><span class="line">│   │   ├── vars/main.yml</span><br><span class="line">│   │   └── templates/my.cnf.j2</span><br><span class="line">│   └── php/</span><br><span class="line">│       ├── tasks/main.yml</span><br><span class="line">│       └── templates/www.conf.j2</span><br><span class="line">└── vault.yml</span><br></pre></td></tr></table></figure></div><h3 id="8-2-部署命令"><a href="#8-2-部署命令" class="headerlink" title="8.2 部署命令"></a>8.2 部署命令</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装外部 Role</span></span><br><span class="line">ansible-galaxy install -r requirements.yml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 语法检查</span></span><br><span class="line">ansible-playbook site.yml --syntax-check</span><br><span class="line"></span><br><span class="line"><span class="comment"># 试运行</span></span><br><span class="line">ansible-playbook site.yml --check -v</span><br><span class="line"></span><br><span class="line"><span class="comment"># 正式部署</span></span><br><span class="line">ansible-playbook site.yml -v</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证结果</span></span><br><span class="line">ansible all -m shell -a <span class="string">&quot;curl -sI http://localhost | head -5&quot;</span></span><br></pre></td></tr></table></figure></div><h3 id="8-3-部署后验证脚本"><a href="#8-3-部署后验证脚本" class="headerlink" title="8.3 部署后验证脚本"></a>8.3 部署后验证脚本</h3><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 独立的验证 Playbook</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">name:</span> <span class="string">验证</span> <span class="string">LEMP</span> <span class="string">部署</span></span><br><span class="line">  <span class="attr">hosts:</span> <span class="string">all</span></span><br><span class="line">  <span class="attr">tasks:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">检查</span> <span class="string">Nginx</span> <span class="string">进程</span></span><br><span class="line">      <span class="attr">shell:</span> <span class="string">&quot;pgrep -c nginx&quot;</span></span><br><span class="line">      <span class="attr">register:</span> <span class="string">nginx_count</span></span><br><span class="line">      <span class="attr">failed_when:</span> <span class="string">nginx_count.stdout</span> <span class="string">|</span> <span class="string">int</span> <span class="string">==</span> <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">检查</span> <span class="string">MariaDB</span> <span class="string">进程</span></span><br><span class="line">      <span class="attr">shell:</span> <span class="string">&quot;pgrep -c mariadbd&quot;</span></span><br><span class="line">      <span class="attr">register:</span> <span class="string">mariadb_count</span></span><br><span class="line">      <span class="attr">failed_when:</span> <span class="string">mariadb_count.stdout</span> <span class="string">|</span> <span class="string">int</span> <span class="string">==</span> <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">检查</span> <span class="string">PHP-FPM</span> <span class="string">进程</span></span><br><span class="line">      <span class="attr">shell:</span> <span class="string">&quot;pgrep -c php-fpm&quot;</span></span><br><span class="line">      <span class="attr">register:</span> <span class="string">php_count</span></span><br><span class="line">      <span class="attr">failed_when:</span> <span class="string">php_count.stdout</span> <span class="string">|</span> <span class="string">int</span> <span class="string">==</span> <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">测试</span> <span class="string">Nginx</span> <span class="string">响应</span></span><br><span class="line">      <span class="attr">uri:</span></span><br><span class="line">        <span class="attr">url:</span> <span class="string">http://localhost/health.php</span></span><br><span class="line">        <span class="attr">return_content:</span> <span class="literal">yes</span></span><br><span class="line">      <span class="attr">register:</span> <span class="string">health</span></span><br><span class="line">      <span class="attr">failed_when:</span> <span class="string">&quot;&#x27;OK&#x27; not in health.content&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">输出部署摘要</span></span><br><span class="line">      <span class="attr">debug:</span></span><br><span class="line">        <span class="attr">msg:</span></span><br><span class="line">          <span class="bullet">-</span> <span class="string">&quot;Nginx 进程数: <span class="template-variable">&#123;&#123; nginx_count.stdout &#125;&#125;</span>&quot;</span></span><br><span class="line">          <span class="bullet">-</span> <span class="string">&quot;MariaDB 进程数: <span class="template-variable">&#123;&#123; mariadb_count.stdout &#125;&#125;</span>&quot;</span></span><br><span class="line">          <span class="bullet">-</span> <span class="string">&quot;PHP-FPM 进程数: <span class="template-variable">&#123;&#123; php_count.stdout &#125;&#125;</span>&quot;</span></span><br><span class="line">          <span class="bullet">-</span> <span class="string">&quot;Web 健康检查: <span class="template-variable">&#123;&#123; &#x27;通过&#x27; if health.status == 200 else &#x27;失败&#x27; &#125;&#125;</span>&quot;</span></span><br></pre></td></tr></table></figure></div><h2 id="九、常见问题排查"><a href="#九、常见问题排查" class="headerlink" title="九、常见问题排查"></a>九、常见问题排查</h2><div class="opt-table"><table><thead><tr><th>问题</th><th>可能原因</th><th>解决方案</th></tr></thead><tbody><tr><td>SSH 连接超时</td><td>防火墙规则、SSH 配置</td><td>检查 ssh<span class="hljs-string">-T user@host 连通性；确认 ControlPath 文件无冲突</span></td></tr><tr><td>权限被拒绝</td><td>become 未启用或密码错误</td><td>添加 -b/-K 参数；检查 /etc/sudoers 配置</td></tr><tr><td>Python 解释器错误</td><td>远程主机无 Python3</td><td>设置 ansible_python_interpreter=/usr/bin/python3</td></tr><tr><td>事实（Fact）超时</td><td>网络延迟或主机负载高</td><td>启用 fact_caching；减少 for 数量</td></tr><tr><td>幂等性失败</td><td>任务设计未考虑幂等性</td><td>使用声明式模块而非 shell/command</td></tr><tr><td>依赖 Role 冲突</td><td>多个 Role 修改同一文件</td><td>使用 lineinfile 替代文件覆盖；明确 Role 执行顺序</td></tr><tr><td>模板语法错误</td><td>Jinja2 变量未定义</td><td>使用 default() 过滤器；--syntax-check 提前检查</td></tr><tr><td>并发写入冲突</td><td>多节点同时操作</td><td>使用 serial 限制并行度；throttle 控制并发</td></tr></tbody></table></div><h2 id="十、最佳实践总结"><a href="#十、最佳实践总结" class="headerlink" title="十、最佳实践总结"></a>十、最佳实践总结</h2><ol><li><strong>目录结构规范化</strong>：严格遵循 Role 目录结构，Playbook 和 Role 分离</li><li><strong>变量分离</strong>：加密变量放 vault，默认值放 defaults，环境特化变量放 group_vars</li><li><strong>幂等性优先</strong>：优先使用声明式模块，避免 shell&#x2F;command 模块</li><li><strong>版本控制</strong>：所有 Playbook、Role 和配置文件纳入 Git 管理</li><li><strong>标签管理</strong>：通过 <code>tags</code> 精确控制 Playbook 执行范围</li><li><strong>测试先行</strong>：使用 <code>--check</code> 和 <code>--diff</code> 预览变更影响</li><li><strong>日志记录</strong>：开启 ansible.log，便于故障追溯</li><li><strong>定期验证</strong>：通过 cron 定时执行验证 Playbook 确保配置一致性</li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Ansible 以其简洁的 YAML 语法、无 Agent 的架构设计和强大的模块生态，大大降低了服务器批量管理的学习门槛。从单条 Ad-Hoc 命令到复杂的多 Role 编排，Ansible 能够满足从小型项目到大规模集群的自动化运维需求。掌握 Inventory 清单管理、Playbook 编写、Role 复用和 Vault 加密等核心技能，是每一位运维工程师迈向高效自动化管理的关键一步。</p><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-16-ansible-automation-guide/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-16-ansible-automation-guide/"/>
    <published>2026-06-16T09:13:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>在管理多台 Linux 服务器时，手动登录每台机器执行命令的方式不仅效率低下，而且容易出错。Ansible 作为一款开源的自动化运维工具，凭]]>
    </summary>
    <title>Ansible 自动化运维配置完全指南</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="日记" scheme="https://demo-blog.qusite.cn/categories/%E6%97%A5%E8%AE%B0/"/>
    <category term="日记" scheme="https://demo-blog.qusite.cn/tags/%E6%97%A5%E8%AE%B0/"/>
    <category term="DevOps" scheme="https://demo-blog.qusite.cn/tags/DevOps/"/>
    <category term="Kubernetes" scheme="https://demo-blog.qusite.cn/tags/Kubernetes/"/>
    <category term="实践" scheme="https://demo-blog.qusite.cn/tags/%E5%AE%9E%E8%B7%B5/"/>
    <content>
      <![CDATA[<p>今天白天 SpaceX 正式登陆纳斯达克，整个科技圈都在刷屏。下午华为 HDC 2026 的 HarmonyOS 7.0 也让人眼前一亮。但这些热闹过后，到了深夜，我反而最有感触的是今晚自己动手做的那几件事。</p><h2 id="K8s-集群搭建：纸上得来终觉浅"><a href="#K8s-集群搭建：纸上得来终觉浅" class="headerlink" title="K8s 集群搭建：纸上得来终觉浅"></a>K8s 集群搭建：纸上得来终觉浅</h2><p>下午写了一篇 kubeadm 部署 Kubernetes 的教程，写完总觉得有些步骤的细节记不太清，干脆开了一台测试机从头走了一遍流程。这一来可不得了，踩了好几个坑：</p><ol><li><p><strong>containerd 配置</strong>：<code>/etc/containerd/config.toml</code> 里的 <code>SystemdCgroup = true</code> 没设置，导致 Pod 一直处于 <code>CrashLoopBackOff</code>。搜了半天才意识到是 Cgroup 驱动不一致的问题。</p></li><li><p><strong>镜像拉取</strong>：默认走 <code>registry.k8s.io</code> 在国内根本拉不下来，换成 <code>registry.aliyuncs.com/google_containers</code> 才搞定。之前写文章时查过这个镜像地址，但实际配的时候才发现还需要调整 <code>kubeadm-config.yaml</code> 里的 <code>imageRepository</code> 字段。</p></li><li><p><strong>网络插件时序</strong>：<code>kubeadm init</code> 成功后，<code>kubectl get nodes</code> 显示 NotReady，是因为还没装 CNI 插件。装完 Flannel 后等了一分多钟才变成 Ready——这个等待过程在文章里有提到，但亲身等一次，感受完全不同。</p></li></ol><p>前前后后折腾了一个多小时，把教程里写的步骤都验证了一遍，顺便补了两个遗漏的注意事项。写教程时觉得逻辑通顺，动手做才知道哪里容易卡住。<strong>“教是最好的学”这句话，今天又亲身体验了一次。</strong></p><h2 id="tcpdump-抓包小实验"><a href="#tcpdump-抓包小实验" class="headerlink" title="tcpdump 抓包小实验"></a>tcpdump 抓包小实验</h2><p>写完 K8s 教程后，想起白天还写了一篇 tcpdump 的文章，于是又拿刚刚搭好的集群做实验。</p><p>在 Master 节点上跑了一个 Nginx Pod，然后在 Worker 节点上用 <code>tcpdump -i any port 80</code> 抓包，另一边用 curl 访问 Pod IP。看到 TCP 三次握手的 SYN、SYN-ACK、ACK 一个个冒出来的瞬间，突然觉得网络协议不再是课本上抽象的概念了。</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">18:43:12.123456 IP 10.244.1.2.54321 &gt; 10.244.2.3.80: Flags [S], seq 123456789</span><br><span class="line">18:43:12.123457 IP 10.244.2.3.80 &gt; 10.244.1.2.54321: Flags [S.], seq 987654321, ack 123456790</span><br><span class="line">18:43:12.123458 IP 10.244.1.2.54321 &gt; 10.244.2.3.80: Flags [.], ack 987654322</span><br></pre></td></tr></table></figure></div><p>Flannel 的 VXLAN 隧道封装也看得清清楚楚——Pod 间的数据包外面还包了一层 UDP 头，目标端口 8472。这种 “眼见为实” 的感觉，比读十篇文档都有用。</p><h2 id="一点反思"><a href="#一点反思" class="headerlink" title="一点反思"></a>一点反思</h2><p>这一周从周日写到周五，回头一看，产出确实不少——PostgreSQL、Go、WireGuard、Nginx 高级配置、Kubernetes、tcpdump、nmap……但坦白说，<strong>数量上去了，深度还得再补补</strong>。</p><p>很多文章是我一边学一边写的，虽然帮自己巩固了知识，但有些主题只停留在”能用”的程度，离”精通”还有距离。下周我打算做几件事：</p><ol><li><strong>K8s 方向深入</strong>：把今天搭的集群留着，继续学 Ingress、Helm Chart、RBAC 这些主题，写文章时配上实测截图和踩坑记录</li><li><strong>博客 UI 优化</strong>：读了几个 Hexo 主题的源码，发现有好多可以定制的地方。想加个文章目录悬浮导航和搜索功能，暗色模式配色也要调一下</li><li><strong>知识体系整理</strong>：建立自己的知识专题——把 Linux、容器、数据库、网络各做一个目录页面，方便读者（也包括自己）快速定位</li></ol><h2 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h2><p>快十一点半了，窗外的城市灯火依旧明亮。今天是 SpaceX 创始人马斯克 24 年创业历程的高光时刻，也是我一周技术写作的收尾。<strong>伟大是一步一步积累出来的，技术也是。</strong> 这个周末不打算写太多文章了，好好休息，翻翻之前写的文章做做修订。下周继续。</p><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-12-late-night-hands-on/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-12-late-night-hands-on/"/>
    <published>2026-06-12T15:18:00.000Z</published>
    <summary>
      <![CDATA[<p>今天白天 SpaceX 正式登陆纳斯达克，整个科技圈都在刷屏。下午华为 HDC 2026 的 HarmonyOS 7.0 也让人眼前一亮。但这些热闹过后，到了深夜，我反而最有感触的是今晚自己动手做的那几件事。</p>
<h2 id="K8s-集群搭建：纸上得来终觉浅"><a]]>
    </summary>
    <title>周五深夜：K8s 集群搭建与动手实践的乐趣</title>
    <updated>2026-06-18T00:39:57.574Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="Linux" scheme="https://demo-blog.qusite.cn/tags/Linux/"/>
    <category term="网络诊断" scheme="https://demo-blog.qusite.cn/tags/%E7%BD%91%E7%BB%9C%E8%AF%8A%E6%96%AD/"/>
    <category term="tcpdump" scheme="https://demo-blog.qusite.cn/tags/tcpdump/"/>
    <category term="抓包分析" scheme="https://demo-blog.qusite.cn/tags/%E6%8A%93%E5%8C%85%E5%88%86%E6%9E%90/"/>
    <content>
      <![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>在网络故障排查和性能调优中，<code>tcpdump</code> 是每位运维工程师和开发者的必备工具。它能够实时捕获和分析网络接口上传输的数据包，帮助我们定位连接异常、诊断性能瓶颈、分析协议行为。本文将系统性地介绍 tcpdump 的使用方法，从基础抓包到高级过滤，配合实战场景让你快速上手。</p><h2 id="tcpdump-工作原理"><a href="#tcpdump-工作原理" class="headerlink" title="tcpdump 工作原理"></a>tcpdump 工作原理</h2><p>tcpdump 基于 <strong>libpcap</strong> 库工作，其流程如下：</p><ol><li>将网卡设置为<strong>混杂模式</strong>（Promiscuous Mode），捕获所有经过接口的包</li><li>通过 <strong>BPF（Berkeley Packet Filter）</strong> 进行高效的内核级过滤</li><li>将匹配的数据包拷贝到用户空间进行解析和输出</li></ol><p>这种设计使得 tcpdump 即使在流量很大的服务器上也能高效运行。</p><h2 id="安装-tcpdump"><a href="#安装-tcpdump" class="headerlink" title="安装 tcpdump"></a>安装 tcpdump</h2><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Ubuntu / Debian</span></span><br><span class="line"><span class="built_in">sudo</span> apt update &amp;&amp; <span class="built_in">sudo</span> apt install -y tcpdump</span><br><span class="line"></span><br><span class="line"><span class="comment"># RHEL / CentOS / Rocky</span></span><br><span class="line"><span class="built_in">sudo</span> yum install -y tcpdump</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证安装</span></span><br><span class="line">tcpdump --version</span><br></pre></td></tr></table></figure></div><h2 id="基础用法"><a href="#基础用法" class="headerlink" title="基础用法"></a>基础用法</h2><h3 id="查看可用网络接口"><a href="#查看可用网络接口" class="headerlink" title="查看可用网络接口"></a>查看可用网络接口</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tcpdump -D</span><br></pre></td></tr></table></figure></div><p>输出示例：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">1.eth0 [Up, Running]</span><br><span class="line">2.lo [Up, Running]</span><br><span class="line">3.any (Pseudo-device that captures on all interfaces)</span><br><span class="line">4.docker0 [Up]</span><br></pre></td></tr></table></figure></div><h3 id="基础抓包"><a href="#基础抓包" class="headerlink" title="基础抓包"></a>基础抓包</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 监听指定接口（最常用）</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0</span><br><span class="line"></span><br><span class="line"><span class="comment"># 监听所有接口</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i any</span><br><span class="line"></span><br><span class="line"><span class="comment"># 只抓取 N 个包后停止</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -c 100</span><br><span class="line"></span><br><span class="line"><span class="comment"># 不进行 DNS 解析（加快速度）</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -n</span><br><span class="line"></span><br><span class="line"><span class="comment"># 显示更详细的信息</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -v</span><br><span class="line"></span><br><span class="line"><span class="comment"># 不解析端口为服务名</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -nn</span><br></pre></td></tr></table></figure></div><h3 id="保存和读取抓包文件"><a href="#保存和读取抓包文件" class="headerlink" title="保存和读取抓包文件"></a>保存和读取抓包文件</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 保存到文件（-w 写入，-W 文件大小 MB）</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -w capture.pcap</span><br><span class="line"></span><br><span class="line"><span class="comment"># 读取抓包文件</span></span><br><span class="line">tcpdump -r capture.pcap</span><br><span class="line"></span><br><span class="line"><span class="comment"># 读取时带过滤</span></span><br><span class="line">tcpdump -r capture.pcap -nn port 80</span><br></pre></td></tr></table></figure></div><h2 id="核心选项速查表"><a href="#核心选项速查表" class="headerlink" title="核心选项速查表"></a>核心选项速查表</h2><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>选项</th><th>说明</th><th>示例</th></tr></thead><tbody><tr><td><code>-i</code></td><td>指定监听的网络接口</td><td><code>-i eth0</code></td></tr><tr><td><code>-n</code></td><td>不解析主机名（保留 IP）</td><td><code>-n</code></td></tr><tr><td><code>-nn</code></td><td>不解析主机名和端口名</td><td><code>-nn</code></td></tr><tr><td><code>-c</code></td><td>抓取指定数量包后退出</td><td><code>-c 100</code></td></tr><tr><td><code>-s</code></td><td>设置 snaplen（抓取每个包的字节数，0 为完整包）</td><td><code>-s 0</code></td></tr><tr><td><code>-w</code></td><td>将原始包写入文件</td><td><code>-w output.pcap</code></td></tr><tr><td><code>-r</code></td><td>从文件读取包</td><td><code>-r output.pcap</code></td></tr><tr><td><code>-v / -vv / -vvv</code></td><td>输出详细程度递增</td><td><code>-vv</code></td></tr><tr><td><code>-e</code></td><td>显示链路层头部（MAC 地址）</td><td><code>-e</code></td></tr><tr><td><code>-X</code></td><td>以 HEX 和 ASCII 输出包内容</td><td><code>-X</code></td></tr><tr><td><code>-A</code></td><td>以 ASCII 输出包内容（适合 HTTP）</td><td><code>-A</code></td></tr><tr><td><code>-q</code></td><td>精简输出模式</td><td><code>-q</code></td></tr><tr><td><code>-K</code></td><td>不验证 TCP 校验和</td><td><code>-K</code></td></tr><tr><td><code>-t</code></td><td>不打印时间戳</td><td><code>-t</code></td></tr></tbody></table></div><h2 id="包过滤表达式（BPF-语法）"><a href="#包过滤表达式（BPF-语法）" class="headerlink" title="包过滤表达式（BPF 语法）"></a>包过滤表达式（BPF 语法）</h2><p>tcpdump 的强大之处在于其灵活的过滤表达式。过滤表达式使用 <strong>BPF（Berkeley Packet Filter）</strong> 语法，支持组合条件。</p><h3 id="按协议过滤"><a href="#按协议过滤" class="headerlink" title="按协议过滤"></a>按协议过滤</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 只抓 TCP 包</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 tcp</span><br><span class="line"></span><br><span class="line"><span class="comment"># 只抓 UDP 包</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 udp</span><br><span class="line"></span><br><span class="line"><span class="comment"># 只抓 ICMP 包（ping）</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 icmp</span><br><span class="line"></span><br><span class="line"><span class="comment"># 只抓 ARP 包</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 arp</span><br></pre></td></tr></table></figure></div><h3 id="按主机过滤"><a href="#按主机过滤" class="headerlink" title="按主机过滤"></a>按主机过滤</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 抓取与特定主机的通信</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 host 192.168.1.100</span><br><span class="line"></span><br><span class="line"><span class="comment"># 抓取源 IP 为 192.168.1.100 的包</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 src host 192.168.1.100</span><br><span class="line"></span><br><span class="line"><span class="comment"># 抓取目标 IP 为 192.168.1.100 的包</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 dst host 192.168.1.100</span><br><span class="line"></span><br><span class="line"><span class="comment"># 抓取网段</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 net 192.168.1.0/24</span><br></pre></td></tr></table></figure></div><h3 id="按端口过滤"><a href="#按端口过滤" class="headerlink" title="按端口过滤"></a>按端口过滤</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 抓取特定端口</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 port 80</span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 port 443</span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 port 22</span><br><span class="line"></span><br><span class="line"><span class="comment"># 抓取源端口或目标端口</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 src port 8080</span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 dst port 53</span><br><span class="line"></span><br><span class="line"><span class="comment"># 抓取端口范围（HTTP/HTTPS）</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 portrange 80-443</span><br></pre></td></tr></table></figure></div><h3 id="组合过滤条件"><a href="#组合过滤条件" class="headerlink" title="组合过滤条件"></a>组合过滤条件</h3><p>使用逻辑运算符 <code>and</code>（<code>&amp;&amp;</code>）、<code>or</code>（<code>||</code>）、<code>not</code>（<code>!</code>）组合多个条件：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 抓取来自 192.168.1.100 的 HTTP 流量</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 src host 192.168.1.100 and port 80</span><br><span class="line"></span><br><span class="line"><span class="comment"># 抓取非 SSH 的 TCP 流量</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 tcp and not port 22</span><br><span class="line"></span><br><span class="line"><span class="comment"># 复杂的组合条件</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 <span class="string">&#x27;tcp port 80 and (src host 192.168.1.100 or dst host 192.168.1.100)&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 抓取 SYN 包（三次握手第一步）</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 <span class="string">&#x27;tcp[13] &amp; 2 != 0&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 抓取 SYN-ACK 包</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 <span class="string">&#x27;tcp[13] = 18&#x27;</span></span><br></pre></td></tr></table></figure></div><h2 id="实战场景"><a href="#实战场景" class="headerlink" title="实战场景"></a>实战场景</h2><h3 id="场景1：排查-HTTP-服务不可用"><a href="#场景1：排查-HTTP-服务不可用" class="headerlink" title="场景1：排查 HTTP 服务不可用"></a>场景1：排查 HTTP 服务不可用</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 监控 80 端口的双向流量，ASCII 输出</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -nn -A port 80</span><br></pre></td></tr></table></figure></div><p>输出示例：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">12:34:56.789012 IP 10.0.0.1.54321 &gt; 10.0.0.2.80: Flags [S], seq 12345, ...</span><br><span class="line">GET /api/health HTTP/1.1</span><br><span class="line">Host: example.com</span><br><span class="line">...</span><br><span class="line">HTTP/1.1 200 OK</span><br><span class="line">Content-Type: application/json</span><br><span class="line">...</span><br></pre></td></tr></table></figure></div><p>通过查看实际请求和响应内容，可以快速判断是服务端问题还是客户端问题。</p><h3 id="场景2：DNS-解析故障排查"><a href="#场景2：DNS-解析故障排查" class="headerlink" title="场景2：DNS 解析故障排查"></a>场景2：DNS 解析故障排查</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 抓取 DNS 查询和响应</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -nn port 53</span><br></pre></td></tr></table></figure></div><p>输出示例：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">12:34:57.123456 IP 10.0.0.1.54322 &gt; 8.8.8.8.53: 1234+ A? example.com. (28)</span><br><span class="line">12:34:57.234567 IP 8.8.8.8.53 &gt; 10.0.0.1.54322: 1234 1/0/0 A 93.184.216.34 (44)</span><br></pre></td></tr></table></figure></div><p>如果只看到 <code>A?</code> 请求但没有响应，说明上游 DNS 不可达或防火墙拦截了 UDP 53 端口。</p><h3 id="场景3：网络延迟分析"><a href="#场景3：网络延迟分析" class="headerlink" title="场景3：网络延迟分析"></a>场景3：网络延迟分析</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 抓取与特定服务器的 TCP 握手，查看时间戳</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -nn -v host 203.0.113.10</span><br><span class="line"></span><br><span class="line"><span class="comment"># 更精确的延迟测量：记录 SYN 和 SYN-ACK 的时间</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -ttt -nn <span class="string">&#x27;tcp[tcpflags] &amp; (tcp-syn|tcp-ack) != 0 and host 203.0.113.10&#x27;</span></span><br></pre></td></tr></table></figure></div><p><code>-ttt</code> 选项会打印每行相对于前一行的微秒级时间差，非常适合分析网络延迟。</p><h3 id="场景4：抓取特定进程的网络流量"><a href="#场景4：抓取特定进程的网络流量" class="headerlink" title="场景4：抓取特定进程的网络流量"></a>场景4：抓取特定进程的网络流量</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 先找到进程 PID</span></span><br><span class="line"><span class="built_in">sudo</span> ss -tlnp | grep nginx</span><br><span class="line"></span><br><span class="line"><span class="comment"># 用 cgroup 过滤器（需要内核支持）或通过端口间接抓取</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -nn port 80 or port 443</span><br></pre></td></tr></table></figure></div><h3 id="场景5：DHCP-交互分析"><a href="#场景5：DHCP-交互分析" class="headerlink" title="场景5：DHCP 交互分析"></a>场景5：DHCP 交互分析</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 抓取 DHCP 协议（端口 67/68，UDP）</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -nn -v port 67 or port 68</span><br></pre></td></tr></table></figure></div><p>DHCP 使用四步握手（Discover → Offer → Request → ACK），通过 tcpdump 可以清晰看到每一步的交互过程。</p><h2 id="高级技巧"><a href="#高级技巧" class="headerlink" title="高级技巧"></a>高级技巧</h2><h3 id="1-限制包大小以提升性能"><a href="#1-限制包大小以提升性能" class="headerlink" title="1. 限制包大小以提升性能"></a>1. 限制包大小以提升性能</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 只抓取每个包的前 128 字节（头部信息）</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -s 128 -nn port 80</span><br></pre></td></tr></table></figure></div><p>在生产服务器上抓包时，建议设置 <code>-s</code> 来减小内存和磁盘开销，除非你需要分析应用层 payload。</p><h3 id="2-抓包并实时统计"><a href="#2-抓包并实时统计" class="headerlink" title="2. 抓包并实时统计"></a>2. 抓包并实时统计</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 每秒统计 HTTP 流量</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -nn -c 1000 <span class="string">&#x27;port 80&#x27;</span> 2&gt;/dev/null | awk <span class="string">&#x27;&#123;print $3&#125;&#x27;</span> | <span class="built_in">cut</span> -d. -f1-4 | <span class="built_in">sort</span> | <span class="built_in">uniq</span> -c | <span class="built_in">sort</span> -rn</span><br></pre></td></tr></table></figure></div><h3 id="3-后台抓包-轮转文件"><a href="#3-后台抓包-轮转文件" class="headerlink" title="3. 后台抓包 + 轮转文件"></a>3. 后台抓包 + 轮转文件</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 后台持续抓包，每 100MB 轮转一个文件，保留 10 个文件</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">nohup</span> tcpdump -i eth0 -nn -C 100 -W 10 -w /var/log/tcpdump/traffic.pcap -Z root &amp;</span><br></pre></td></tr></table></figure></div><h3 id="4-使用-tcpdump-做简单的带宽监控"><a href="#4-使用-tcpdump-做简单的带宽监控" class="headerlink" title="4. 使用 tcpdump 做简单的带宽监控"></a>4. 使用 tcpdump 做简单的带宽监控</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 每 10 秒统计一次流量</span></span><br><span class="line"><span class="keyword">while</span> <span class="literal">true</span>; <span class="keyword">do</span></span><br><span class="line">  <span class="built_in">sudo</span> tcpdump -i eth0 -nn -c 100 -t 2&gt;/dev/null | <span class="built_in">wc</span> -l</span><br><span class="line">  <span class="built_in">sleep</span> 10</span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure></div><h3 id="5-结合-Wireshark-进行图形化分析"><a href="#5-结合-Wireshark-进行图形化分析" class="headerlink" title="5. 结合 Wireshark 进行图形化分析"></a>5. 结合 Wireshark 进行图形化分析</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 服务器端抓包</span></span><br><span class="line"><span class="built_in">sudo</span> tcpdump -i eth0 -nn -s 0 -w capture.pcap host 192.168.1.100</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将文件传到本地，用 Wireshark 打开</span></span><br><span class="line"><span class="comment"># Wireshark 提供强大的协议解析、流量统计、对话分析等功能</span></span><br></pre></td></tr></table></figure></div><h2 id="输出格式解读"><a href="#输出格式解读" class="headerlink" title="输出格式解读"></a>输出格式解读</h2><p>tcpdump 默认输出格式如下：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">12:34:56.789012 IP 10.0.0.1.54321 &gt; 10.0.0.2.80: Flags [S], seq 12345:12345, win 65535, options [mss 1460], length 0</span><br></pre></td></tr></table></figure></div><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>字段</th><th>示例值</th><th>说明</th></tr></thead><tbody><tr><td>时间戳</td><td><code>12:34:56.789012</code></td><td>微秒级精度</td></tr><tr><td>协议</td><td><code>IP</code></td><td>链路层协议类型</td></tr><tr><td>源地址</td><td><code>10.0.0.1.54321</code></td><td>IP.端口</td></tr><tr><td>方向</td><td><code>></code></td><td>> 表示发送；< 表示接收</td></tr><tr><td>目标地址</td><td><code>10.0.0.2.80</code></td><td>IP.端口</td></tr><tr><td>TCP 标志</td><td><code>Flags [S]</code></td><td>S=SYN, F=FIN, R=RST, P=PSH, .=ACK</td></tr><tr><td>序列号</td><td><code>seq 12345:12345</code></td><td>起始:结束</td></tr><tr><td>窗口大小</td><td><code>win 65535</code></td><td>接收窗口大小</td></tr><tr><td>选项</td><td><code>options [mss 1460]</code></td><td>TCP 选项</td></tr><tr><td>长度</td><td><code>length 0</code></td><td>应用层数据长度</td></tr></tbody></table></div><h3 id="TCP-标志位速查"><a href="#TCP-标志位速查" class="headerlink" title="TCP 标志位速查"></a>TCP 标志位速查</h3><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>标志</th><th>缩写</th><th>含义</th></tr></thead><tbody><tr><td><code>[S]</code></td><td>SYN</td><td>连接请求（三次握手第一步）</td></tr><tr><td><code>[S.]</code></td><td>SYN-ACK</td><td>连接确认（三次握手第二步）</td></tr><tr><td><code>[.]</code></td><td>ACK</td><td>确认包</td></tr><tr><td><code>[P.]</code></td><td>PSH-ACK</td><td>推送数据（传输数据时最常见）</td></tr><tr><td><code>[F.]</code></td><td>FIN-ACK</td><td>连接关闭</td></tr><tr><td><code>[R]</code></td><td>RST</td><td>连接重置（通常表示异常）</td></tr><tr><td><code>[R.]</code></td><td>RST-ACK</td><td>带确认的重置</td></tr></tbody></table></div><h2 id="常见问题排查"><a href="#常见问题排查" class="headerlink" title="常见问题排查"></a>常见问题排查</h2><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>问题</th><th>原因</th><th>解决方案</th></tr></thead><tbody><tr><td>tcpdump: no suitable device found</td><td>权限不足或设备不存在</td><td>使用 <code>sudo</code> 运行；检查 <code>tcpdump -D</code></td></tr><tr><td>tcpdump: eth0: You don't have permission</td><td>非 root 用户</td><td>使用 <code>sudo</code> 或添加 CAP_NET_RAW 能力</td></tr><tr><td>捕获到大量无关包</td><td>过滤条件不精确</td><td>细化 BPF 过滤表达式</td></tr><tr><td>抓包文件过大</td><td>未限制大小或 snaplen</td><td>使用 <code>-s 128</code> 和 <code>-C</code> 轮转</td></tr><tr><td>输出显示乱码</td><td>二进制数据被直接输出</td><td>用 <code>-A</code>（文本）或 <code>-X</code>（HEX）控制</td></tr><tr><td>无法捕获 VLAN 流量</td><td>未启用 VLAN 标签解析</td><td>加 <code>-e</code> 显示链路层头部</td></tr><tr><td>tcpdump 消耗高 CPU</td><td>流量过大</td><td>设置 <code>-c</code> 限制包数；使用 BPF 精准过滤；考虑使用 ntopng 等工具</td></tr></tbody></table></div><h2 id="安全注意事项"><a href="#安全注意事项" class="headerlink" title="安全注意事项"></a>安全注意事项</h2><ol><li><strong>权限管理</strong>：tcpdump 需要 root 权限，生产环境不建议长期在后台运行，用完即停</li><li><strong>数据敏感性</strong>：抓包文件可能包含密码、Token 等敏感信息，妥善保管 <code>.pcap</code> 文件</li><li><strong>法律合规</strong>：在非自己控制的网络上抓包可能违反法律，务必获得授权</li><li><strong>性能影响</strong>：在高流量服务器上抓包会增加 CPU 和磁盘 I&#x2F;O 负载，建议：<ul><li>使用精准过滤条件缩小范围</li><li>限制 snaplen（<code>-s 128</code>）</li><li>避免写入慢速磁盘</li></ul></li><li><strong>日志轮转</strong>：长时间抓包务必使用 <code>-C</code>（文件大小轮转）和 <code>-W</code>（文件数量限制）</li></ol><h2 id="命令速查表"><a href="#命令速查表" class="headerlink" title="命令速查表"></a>命令速查表</h2><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>场景</th><th>命令</th></tr></thead><tbody><tr><td>查看 HTTP 请求内容</td><td><code>sudo tcpdump -i eth0 -A port 80</code></td></tr><tr><td>查看 DNS 查询</td><td><code>sudo tcpdump -i eth0 -nn port 53</code></td></tr><tr><td>监控与某个 IP 的所有流量</td><td><code>sudo tcpdump -i eth0 host 192.168.1.1</code></td></tr><tr><td>抓取 TCP 三次握手</td><td><code>sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn) != 0'</code></td></tr><tr><td>保存到文件供 Wireshark 分析</td><td><code>sudo tcpdump -i eth0 -s 0 -w capture.pcap</code></td></tr><tr><td>后台持续抓包（轮转）</td><td><code>sudo nohup tcpdump -i eth0 -C 100 -W 10 -w traffic.pcap &</code></td></tr><tr><td>实时带宽统计（粗略）</td><td><code>sudo tcpdump -i eth0 -nn -c 1000 -t 2>/dev/null &#124; wc -l</code></td></tr><tr><td>排除 SSH 会话自身干扰</td><td><code>sudo tcpdump -i eth0 not port 22</code></td></tr><tr><td>抓取特定进程流量（间接）</td><td><code>sudo tcpdump -i eth0 port $(sudo ss -tlnp &#124; grep nginx &#124; awk '&#123;print $4&#125;' &#124; cut -d: -f2)</code></td></tr><tr><td>检查 ICMP 丢包</td><td><code>sudo tcpdump -i eth0 -nn icmp</code></td></tr><tr><td>查看 DHCP 交互</td><td><code>sudo tcpdump -i eth0 -nn port 67 or port 68</code></td></tr><tr><td>分析 TCP 重传</td><td><code>sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-retrans) != 0'</code></td></tr></tbody></table></div><h2 id="扩展阅读工具"><a href="#扩展阅读工具" class="headerlink" title="扩展阅读工具"></a>扩展阅读工具</h2><p>tcpdump 适合快速诊断，但对于深入分析，可以配合以下工具：</p><ul><li><strong>Wireshark &#x2F; TShark</strong>：图形化&#x2F;命令行协议分析器，提供协议解码树、流量统计、IO 图表等高级功能</li><li><strong>ngrep</strong>：类似 grep 但针对网络包，支持正则匹配 payload</li><li><strong>nethogs</strong>：按进程显示网络带宽使用</li><li><strong>iftop</strong>：实时显示接口带宽（类似 top）</li><li><strong>bmon</strong>：带宽监控与可视化</li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>tcpdump 是 Linux 网络诊断工具箱中最核心的成员之一。掌握 tcpdump 不仅意味着会抓包，更重要的是理解 TCP&#x2F;IP 协议栈的工作原理。本文从基础安装到高级实战，系统性地介绍了 tcpdump 的完整用法。</p><p><strong>核心要点</strong>：</p><ul><li>始终用 <code>sudo</code> 运行，用 <code>-nn</code> 避免 DNS 和端口解析延迟</li><li>精准的 BPF 过滤表达式是高效排障的关键</li><li>生产环境抓包时注意性能和安全，善用 <code>-s</code>、<code>-C</code>、<code>-c</code> 选项</li><li><code>-w</code> 保存 pcap 文件后配合 Wireshark 图形化分析效率更高</li></ul><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-12-tcpdump-command-guide/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-12-tcpdump-command-guide/"/>
    <published>2026-06-12T14:15:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>在网络故障排查和性能调优中，<code>tcpdump</code> 是每位运维工程师和开发者的必备工具。它能够实时捕获和分析网络接口上传输]]>
    </summary>
    <title>Linux tcpdump 命令完全指南：网络包分析从入门到精通</title>
    <updated>2026-06-18T00:39:57.578Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="环境搭建" scheme="https://demo-blog.qusite.cn/tags/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/"/>
    <category term="DevOps" scheme="https://demo-blog.qusite.cn/tags/DevOps/"/>
    <category term="Kubernetes" scheme="https://demo-blog.qusite.cn/tags/Kubernetes/"/>
    <category term="kubeadm" scheme="https://demo-blog.qusite.cn/tags/kubeadm/"/>
    <category term="容器编排" scheme="https://demo-blog.qusite.cn/tags/%E5%AE%B9%E5%99%A8%E7%BC%96%E6%8E%92/"/>
    <content>
      <![CDATA[<blockquote><p>本文详细介绍如何在 Ubuntu 22.04 上使用 kubeadm 搭建一个生产级别的 Kubernetes 集群，涵盖环境准备、容器运行时安装、集群初始化、网络插件配置、Worker 节点加入以及集群管理工具安装。</p></blockquote><h2 id="一、Kubernetes-与-kubeadm-简介"><a href="#一、Kubernetes-与-kubeadm-简介" class="headerlink" title="一、Kubernetes 与 kubeadm 简介"></a>一、Kubernetes 与 kubeadm 简介</h2><p>Kubernetes（简称 K8s）是目前最流行的容器编排平台，而 kubeadm 是 Kubernetes 官方提供的集群快速搭建工具，它屏蔽了底层复杂的证书生成、组件配置和集群引导过程，使得我们能够在几分钟内搭建一个符合最佳实践的集群。</p><h3 id="核心架构概览"><a href="#核心架构概览" class="headerlink" title="核心架构概览"></a>核心架构概览</h3><p>一个标准的 Kubernetes 集群由以下核心组件组成：</p><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>组件类型</th><th>组件名称</th><th>功能说明</th></tr></thead><tbody><tr><td rowspan="4">Control Plane</td><td>kube-apiserver</td><td>集群 API 入口，所有组件和客户端的请求枢纽</td></tr><tr><td>kube-controller-manager</td><td>控制器管理器，维护集群期望状态</td></tr><tr><td>kube-scheduler</td><td>调度器，将 Pod 分配到合适的 Node</td></tr><tr><td>etcd</td><td>分布式键值存储，保存集群全部数据</td></tr><tr><td>Worker Node</td><td>kubelet</td><td>节点代理，负责 Pod 和容器的生命周期管理</td></tr><tr><td></td><td>kube-proxy</td><td>网络代理，实现 Service 的负载均衡和网络规则</td></tr><tr><td></td><td>CRI 运行时</td><td>容器运行时接口实现，如 containerd</td></tr></tbody></table></div><h2 id="二、环境准备"><a href="#二、环境准备" class="headerlink" title="二、环境准备"></a>二、环境准备</h2><h3 id="2-1-节点规划"><a href="#2-1-节点规划" class="headerlink" title="2.1 节点规划"></a>2.1 节点规划</h3><p>本指南以三台 Ubuntu 22.04 服务器为例（实际生产环境建议 Control Plane 至少 3 节点实现高可用）：</p><div class="opt-table"><table><thead><tr><th>主机名</th><th>IP 地址</th><th>角色</th><th>最低配置</th></tr></thead><tbody><tr><td>k8s-master</td><td>192.168.1.10</td><td>Control Plane</td><td>2C / 4G / 40GB</td></tr><tr><td>k8s-node1</td><td>192.168.1.11</td><td>Worker Node</td><td>2C / 4G / 40GB</td></tr><tr><td>k8s-node2</td><td>192.168.1.12</td><td>Worker Node</td><td>2C / 4G / 40GB</td></tr></tbody></table></div><h3 id="2-2-基础系统配置（所有节点）"><a href="#2-2-基础系统配置（所有节点）" class="headerlink" title="2.2 基础系统配置（所有节点）"></a>2.2 基础系统配置（所有节点）</h3><p>在 <em>所有节点</em> 上执行以下配置：</p><p><strong>a) 设置主机名与 hosts</strong></p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Control Plane</span></span><br><span class="line"><span class="built_in">sudo</span> hostnamectl set-hostname k8s-master</span><br><span class="line"></span><br><span class="line"><span class="comment"># Worker 节点分别执行</span></span><br><span class="line"><span class="built_in">sudo</span> hostnamectl set-hostname k8s-node1</span><br><span class="line"><span class="built_in">sudo</span> hostnamectl set-hostname k8s-node2</span><br></pre></td></tr></table></figure></div><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 所有节点添加 hosts 解析</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">tee</span> -a /etc/hosts &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line">192.168.1.10 k8s-master</span><br><span class="line">192.168.1.11 k8s-node1</span><br><span class="line">192.168.1.12 k8s-node2</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure></div><p><strong>b) 禁用 Swap</strong></p><p>Kubernetes 要求禁用 Swap，否则 kubelet 无法正常工作：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> swapoff -a</span><br><span class="line"><span class="built_in">sudo</span> sed -i <span class="string">&#x27;/ swap / s/^\(.*\)$/#\1/&#x27;</span> /etc/fstab</span><br></pre></td></tr></table></figure></div><p>验证：<code>free -h</code> 输出中 Swap 应为 0。</p><p><strong>c) 加载内核模块</strong></p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &lt;&lt;<span class="string">EOF | sudo tee /etc/modules-load.d/k8s.conf</span></span><br><span class="line"><span class="string">overlay</span></span><br><span class="line"><span class="string">br_netfilter</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">sudo</span> modprobe overlay</span><br><span class="line"><span class="built_in">sudo</span> modprobe br_netfilter</span><br></pre></td></tr></table></figure></div><p><strong>d) 配置内核参数</strong></p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> &lt;&lt;<span class="string">EOF | sudo tee /etc/sysctl.d/k8s.conf</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">net.bridge.bridge-nf-call-ip6tables = 1</span></span><br><span class="line"><span class="string">net.ipv4.ip_forward                 = 1</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">sudo</span> sysctl --system</span><br></pre></td></tr></table></figure></div><p><strong>e) 关闭防火墙（或放行必要端口）</strong></p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 简单起见关闭防火墙（生产环境建议精确放行端口）</span></span><br><span class="line"><span class="built_in">sudo</span> ufw <span class="built_in">disable</span></span><br></pre></td></tr></table></figure></div><p>如果需要在生产环境保留防火墙，请放行以下端口：</p><div class="opt-table"><table><thead><tr><th>节点角色</th><th>端口</th><th>用途</th></tr></thead><tbody><tr><td rowspan="5">Control Plane</td><td>6443</td><td>Kubernetes API Server</td></tr><tr><td>2379-2380</td><td>etcd 客户端/对等通信</td></tr><tr><td>10250</td><td>kubelet API</td></tr><tr><td>10259</td><td>kube-scheduler</td></tr><tr><td>10257</td><td>kube-controller-manager</td></tr><tr><td rowspan="2">所有节点</td><td>30000-32767</td><td>NodePort 服务端口范围</td></tr><tr><td>10250</td><td>kubelet</td></tr></tbody></table></div><h3 id="2-3-安装容器运行时（所有节点）"><a href="#2-3-安装容器运行时（所有节点）" class="headerlink" title="2.3 安装容器运行时（所有节点）"></a>2.3 安装容器运行时（所有节点）</h3><p>Kubernetes 1.24+ 已移除对 Docker 的默认支持，推荐使用 containerd：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装 containerd</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get update</span><br><span class="line"><span class="built_in">sudo</span> apt-get install -y containerd</span><br><span class="line"></span><br><span class="line"><span class="comment"># 生成默认配置</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/containerd</span><br><span class="line">containerd config default | <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/containerd/config.toml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启用 SystemdCgroup（关键！）</span></span><br><span class="line"><span class="built_in">sudo</span> sed -i <span class="string">&#x27;s/SystemdCgroup = false/SystemdCgroup = true/&#x27;</span> /etc/containerd/config.toml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用阿里云镜像加速（国内环境）</span></span><br><span class="line"><span class="built_in">sudo</span> sed -i <span class="string">&#x27;s|sandbox_image = &quot;registry.k8s.io/pause:3.8&quot;|sandbox_image = &quot;registry.aliyuncs.com/google_containers/pause:3.9&quot;|&#x27;</span> /etc/containerd/config.toml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重启 containerd</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl restart containerd</span><br><span class="line"><span class="built_in">sudo</span> systemctl <span class="built_in">enable</span> containerd</span><br></pre></td></tr></table></figure></div><h2 id="三、安装-kubeadm、kubelet-和-kubectl（所有节点）"><a href="#三、安装-kubeadm、kubelet-和-kubectl（所有节点）" class="headerlink" title="三、安装 kubeadm、kubelet 和 kubectl（所有节点）"></a>三、安装 kubeadm、kubelet 和 kubectl（所有节点）</h2><h3 id="3-1-添加-Kubernetes-APT-源"><a href="#3-1-添加-Kubernetes-APT-源" class="headerlink" title="3.1 添加 Kubernetes APT 源"></a>3.1 添加 Kubernetes APT 源</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt-get update</span><br><span class="line"><span class="built_in">sudo</span> apt-get install -y apt-transport-https ca-certificates curl gpg</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加阿里云镜像源（国内环境加速）</span></span><br><span class="line">curl -fsSL https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/deb/Release.key |</span><br><span class="line">  <span class="built_in">sudo</span> gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/deb/ /&quot;</span> |</span><br><span class="line">  <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/apt/sources.list.d/kubernetes.list</span><br></pre></td></tr></table></figure></div><h3 id="3-2-安装组件"><a href="#3-2-安装组件" class="headerlink" title="3.2 安装组件"></a>3.2 安装组件</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt-get update</span><br><span class="line"><span class="built_in">sudo</span> apt-get install -y kubelet=1.30.0-1.1 kubeadm=1.30.0-1.1 kubectl=1.30.0-1.1</span><br><span class="line"><span class="built_in">sudo</span> apt-mark hold kubelet kubeadm kubectl</span><br></pre></td></tr></table></figure></div><blockquote><p>使用 <code>apt-mark hold</code> 锁定版本，避免意外升级导致集群版本不一致。</p></blockquote><p>验证安装：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kubeadm version</span><br><span class="line">kubectl version --client</span><br></pre></td></tr></table></figure></div><h2 id="四、初始化-Control-Plane"><a href="#四、初始化-Control-Plane" class="headerlink" title="四、初始化 Control Plane"></a>四、初始化 Control Plane</h2><h3 id="4-1-生成配置文件并初始化"><a href="#4-1-生成配置文件并初始化" class="headerlink" title="4.1 生成配置文件并初始化"></a>4.1 生成配置文件并初始化</h3><p>在 Control Plane 节点（k8s-master）上执行：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 创建 kubeadm 配置文件</span></span><br><span class="line"><span class="built_in">cat</span> &lt;&lt;<span class="string">EOF | sudo tee kubeadm-config.yaml</span></span><br><span class="line"><span class="string">apiVersion: kubeadm.k8s.io/v1beta3</span></span><br><span class="line"><span class="string">kind: InitConfiguration</span></span><br><span class="line"><span class="string">localAPIEndpoint:</span></span><br><span class="line"><span class="string">  advertiseAddress: &quot;192.168.1.10&quot;</span></span><br><span class="line"><span class="string">  bindPort: 6443</span></span><br><span class="line"><span class="string">---</span></span><br><span class="line"><span class="string">apiVersion: kubeadm.k8s.io/v1beta3</span></span><br><span class="line"><span class="string">kind: ClusterConfiguration</span></span><br><span class="line"><span class="string">kubernetesVersion: &quot;v1.30.0&quot;</span></span><br><span class="line"><span class="string">imageRepository: &quot;registry.aliyuncs.com/google_containers&quot;</span></span><br><span class="line"><span class="string">networking:</span></span><br><span class="line"><span class="string">  podSubnet: &quot;10.244.0.0/16&quot;</span></span><br><span class="line"><span class="string">  serviceSubnet: &quot;10.96.0.0/12&quot;</span></span><br><span class="line"><span class="string">---</span></span><br><span class="line"><span class="string">apiVersion: kubeproxy.config.k8s.io/v1alpha1</span></span><br><span class="line"><span class="string">kind: KubeProxyConfiguration</span></span><br><span class="line"><span class="string">mode: &quot;iptables&quot;</span></span><br><span class="line"><span class="string">EOF</span></span><br></pre></td></tr></table></figure></div><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> kubeadm init --config=kubeadm-config.yaml</span><br></pre></td></tr></table></figure></div><h3 id="4-2-配置-kubectl"><a href="#4-2-配置-kubectl" class="headerlink" title="4.2 配置 kubectl"></a>4.2 配置 kubectl</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">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></div><h3 id="4-3-保存加入令牌"><a href="#4-3-保存加入令牌" class="headerlink" title="4.3 保存加入令牌"></a>4.3 保存加入令牌</h3><p>初始化成功后，屏幕会输出类似以下的信息，<strong>务必保存</strong>：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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">kubeadm join 192.168.1.10:6443 --token xxxxxx \</span><br><span class="line">    --discovery-token-ca-cert-hash sha256:xxxxxx</span><br></pre></td></tr></table></figure></div><p>如果令牌过期，可以在 Control Plane 上重新生成：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubeadm token create --print-join-command</span><br></pre></td></tr></table></figure></div><h2 id="五、安装网络插件"><a href="#五、安装网络插件" class="headerlink" title="五、安装网络插件"></a>五、安装网络插件</h2><p>Kubernetes 集群需要安装 CNI（Container Network Interface）插件来实现 Pod 间的网络通信。推荐使用 Flannel 或 Calico。</p><h3 id="5-1-部署-Flannel"><a href="#5-1-部署-Flannel" class="headerlink" title="5.1 部署 Flannel"></a>5.1 部署 Flannel</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 使用阿里云镜像加速（国内环境）</span></span><br><span class="line">curl -fsSL https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml -O</span><br><span class="line">sed -i <span class="string">&#x27;s|docker.io/flannel|registry.aliyuncs.com/k8sxio/flannel|g&#x27;</span> kube-flannel.yml</span><br><span class="line">kubectl apply -f kube-flannel.yml</span><br></pre></td></tr></table></figure></div><h3 id="5-2-验证网络状态"><a href="#5-2-验证网络状态" class="headerlink" title="5.2 验证网络状态"></a>5.2 验证网络状态</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看所有 Pod 状态</span></span><br><span class="line">kubectl get pods -n kube-flannel</span><br><span class="line">kubectl get pods -n kube-system</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看节点状态（Control Plane Ready）</span></span><br><span class="line">kubectl get nodes</span><br></pre></td></tr></table></figure></div><p>当 Control Plane 节点状态为 <code>Ready</code> 时，说明网络插件配置成功。</p><h2 id="六、Worker-节点加入集群"><a href="#六、Worker-节点加入集群" class="headerlink" title="六、Worker 节点加入集群"></a>六、Worker 节点加入集群</h2><p>在 <em>每个 Worker 节点</em> 上执行之前保存的 join 命令：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> kubeadm <span class="built_in">join</span> 192.168.1.10:6443 --token xxxxxx \</span><br><span class="line">    --discovery-token-ca-cert-hash sha256:xxxxxx</span><br></pre></td></tr></table></figure></div><p>回到 Control Plane 验证节点加入状态：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><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></div><p>预期输出：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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   ROLES           AGE   VERSION</span><br><span class="line">k8s-master    Ready    control-plane   10m   v1.30.0</span><br><span class="line">k8s-node1     Ready    &lt;none&gt;          2m    v1.30.0</span><br><span class="line">k8s-node2     Ready    &lt;none&gt;          1m    v1.30.0</span><br></pre></td></tr></table></figure></div><h2 id="七、集群验证"><a href="#七、集群验证" class="headerlink" title="七、集群验证"></a>七、集群验证</h2><h3 id="7-1-部署测试应用"><a href="#7-1-部署测试应用" class="headerlink" title="7.1 部署测试应用"></a>7.1 部署测试应用</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kubectl create deployment nginx --image=nginx:alpine --replicas=3</span><br><span class="line">kubectl expose deployment nginx --port=80 --<span class="built_in">type</span>=NodePort</span><br></pre></td></tr></table></figure></div><h3 id="7-2-检查-Pod-分布"><a href="#7-2-检查-Pod-分布" class="headerlink" title="7.2 检查 Pod 分布"></a>7.2 检查 Pod 分布</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看各节点上的 Pod</span></span><br><span class="line">kubectl get pods -o wide</span><br></pre></td></tr></table></figure></div><h3 id="7-3-测试服务访问"><a href="#7-3-测试服务访问" class="headerlink" title="7.3 测试服务访问"></a>7.3 测试服务访问</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 获取 NodePort</span></span><br><span class="line">kubectl get svc nginx</span><br><span class="line"></span><br><span class="line"><span class="comment"># 从任意节点访问</span></span><br><span class="line">curl http://任意节点IP:NodePort</span><br></pre></td></tr></table></figure></div><p>访问成功说明集群正常工作。</p><h2 id="八、集群管理工具安装"><a href="#八、集群管理工具安装" class="headerlink" title="八、集群管理工具安装"></a>八、集群管理工具安装</h2><h3 id="8-1-安装-Helm（包管理器）"><a href="#8-1-安装-Helm（包管理器）" class="headerlink" title="8.1 安装 Helm（包管理器）"></a>8.1 安装 Helm（包管理器）</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash</span><br><span class="line">helm version</span><br></pre></td></tr></table></figure></div><h3 id="8-2-安装-Kubernetes-Dashboard（可选）"><a href="#8-2-安装-Kubernetes-Dashboard（可选）" class="headerlink" title="8.2 安装 Kubernetes Dashboard（可选）"></a>8.2 安装 Kubernetes Dashboard（可选）</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装 Dashboard</span></span><br><span class="line">kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v3.0.1/charts/kubernetes-dashboard.yaml</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> &lt;&lt;<span class="string">EOF | kubectl apply -f -</span></span><br><span class="line"><span class="string">apiVersion: v1</span></span><br><span class="line"><span class="string">kind: ServiceAccount</span></span><br><span class="line"><span class="string">metadata:</span></span><br><span class="line"><span class="string">  name: admin-user</span></span><br><span class="line"><span class="string">  namespace: kubernetes-dashboard</span></span><br><span class="line"><span class="string">---</span></span><br><span class="line"><span class="string">apiVersion: rbac.authorization.k8s.io/v1</span></span><br><span class="line"><span class="string">kind: ClusterRoleBinding</span></span><br><span class="line"><span class="string">metadata:</span></span><br><span class="line"><span class="string">  name: admin-user</span></span><br><span class="line"><span class="string">roleRef:</span></span><br><span class="line"><span class="string">  apiGroup: rbac.authorization.k8s.io</span></span><br><span class="line"><span class="string">  kind: ClusterRole</span></span><br><span class="line"><span class="string">  name: cluster-admin</span></span><br><span class="line"><span class="string">subjects:</span></span><br><span class="line"><span class="string">- kind: ServiceAccount</span></span><br><span class="line"><span class="string">  name: admin-user</span></span><br><span class="line"><span class="string">  namespace: kubernetes-dashboard</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">kubectl -n kubernetes-dashboard create token admin-user</span><br></pre></td></tr></table></figure></div><p>Access Dashboard via: <code>http://ControlPlaneIP:NodePort</code></p><h3 id="8-3-安装-Metrics-Server"><a href="#8-3-安装-Metrics-Server" class="headerlink" title="8.3 安装 Metrics Server"></a>8.3 安装 Metrics Server</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如果证书问题导致无法启动，添加 --kubelet-insecure-tls 参数</span></span><br><span class="line">kubectl edit deployment metrics-server -n kube-system</span><br><span class="line"><span class="comment"># 在 args 中添加 --kubelet-insecure-tls</span></span><br></pre></td></tr></table></figure></div><h2 id="九、集群管理与监控命令速查"><a href="#九、集群管理与监控命令速查" class="headerlink" title="九、集群管理与监控命令速查"></a>九、集群管理与监控命令速查</h2><div class="opt-table"><table><thead><tr><th>操作场景</th><th>命令</th><th>说明</th></tr></thead><tbody><tr><td>节点管理</td><td><code>kubectl get nodes -o wide</code></td><td>查看所有节点详情</td></tr><tr><td>节点维护</td><td><code>kubectl cordon &lt;node&gt;</code></td><td>标记节点为不可调度</td></tr><tr><td>节点排空</td><td><code>kubectl drain &lt;node&gt; --ignore-daemonsets --delete-emptydir-data</code></td><td>迁移 Pod 后下线节点</td></tr><tr><td>Pod 管理</td><td><code>kubectl get pods -A -o wide</code></td><td>查看所有命名空间的 Pod 详情</td></tr><tr><td>Pod 日志</td><td><code>kubectl logs -f &lt;pod&gt; -n &lt;namespace&gt;</code></td><td>实时查看 Pod 日志</td></tr><tr><td>Pod 调试</td><td><code>kubectl exec -it &lt;pod&gt; -- /bin/sh</code></td><td>进入容器内部</td></tr><tr><td>集群信息</td><td><code>kubectl cluster-info</code></td><td>查看集群 API 地址</td></tr><tr><td>组件状态</td><td><code>kubectl get componentstatuses</code></td><td>查看 Control Plane 健康状态</td></tr><tr><td>资源监控</td><td><code>kubectl top nodes</code></td><td>查看节点资源使用情况</td></tr></tbody></table></div><h2 id="十、常见问题排查"><a href="#十、常见问题排查" class="headerlink" title="十、常见问题排查"></a>十、常见问题排查</h2><h3 id="10-1-kubelet-无法启动"><a href="#10-1-kubelet-无法启动" class="headerlink" title="10.1 kubelet 无法启动"></a>10.1 kubelet 无法启动</h3><p>检查 kubelet 日志：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">journalctl -xeu kubelet --no-pager | <span class="built_in">tail</span> -50</span><br></pre></td></tr></table></figure></div><p>常见原因：</p><ul><li>Swap 未禁用 → 检查 <code>free -h</code> 并重新执行 <code>swapoff -a</code></li><li>containerd 未正确配置 → 确保 <code>/etc/containerd/config.toml</code> 中 <code>SystemdCgroup = true</code></li><li>镜像拉取失败 → 检查 <code>crictl images</code> 确认 pause 镜像存在</li></ul><h3 id="10-2-节点-NotReady"><a href="#10-2-节点-NotReady" class="headerlink" title="10.2 节点 NotReady"></a>10.2 节点 NotReady</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl describe node k8s-node1</span><br></pre></td></tr></table></figure></div><p>常见原因及解决：</p><ul><li>CNI 插件未部署 → 安装 Flannel&#x2F;Calico</li><li>kubelet 证书过期 → <code>kubeadm reset &amp;&amp; kubeadm join ...</code></li><li>节点间网络不通 → 检查 iptables&#x2F;firewalld 状态</li></ul><h3 id="10-3-Pod-一直-Pending"><a href="#10-3-Pod-一直-Pending" class="headerlink" title="10.3 Pod 一直 Pending"></a>10.3 Pod 一直 Pending</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl describe pod &lt;pod-name&gt; -n &lt;namespace&gt;</span><br></pre></td></tr></table></figure></div><p>常见原因：</p><ul><li>节点资源不足 → <code>kubectl describe node</code> 检查可分配资源</li><li>没有匹配的节点标签&#x2F;污点 → 检查 <code>nodeSelector</code> 和 <code>tolerations</code></li><li>PVC 未绑定 → 检查 PV&#x2F;PVC 状态</li></ul><h3 id="10-4-集群重置（当需要重新初始化时）"><a href="#10-4-集群重置（当需要重新初始化时）" class="headerlink" title="10.4 集群重置（当需要重新初始化时）"></a>10.4 集群重置（当需要重新初始化时）</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 在所有需要重置的节点上执行</span></span><br><span class="line"><span class="built_in">sudo</span> kubeadm reset -f</span><br><span class="line"></span><br><span class="line"><span class="comment"># 清除网络配置</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">rm</span> -rf /etc/cni/net.d</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">rm</span> -rf <span class="variable">$HOME</span>/.kube/config</span><br><span class="line"><span class="built_in">sudo</span> iptables -F &amp;&amp; <span class="built_in">sudo</span> iptables -t nat -F &amp;&amp; <span class="built_in">sudo</span> iptables -t mangle -F</span><br></pre></td></tr></table></figure></div><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本文详细介绍了使用 kubeadm 在 Ubuntu 22.04 上搭建 Kubernetes v1.30 集群的完整流程，包括：</p><ol><li><strong>环境准备</strong>：禁用 Swap、加载内核模块、配置 sysctl、安装 containerd</li><li><strong>组件安装</strong>：kubeadm&#x2F;kubelet&#x2F;kubectl 安装与版本锁定</li><li><strong>集群初始化</strong>：kubeadm init 配置与 CNI 网络插件部署</li><li><strong>节点扩展</strong>：Worker 节点加入与验证</li><li><strong>工具安装</strong>：Helm&#x2F;Dashboard&#x2F;Metrics Server</li><li><strong>日常管理</strong>：命令速查与故障排查</li></ol><p>熟练掌握 kubeadm 部署流程是进入 Kubernetes 运维世界的第一步，后续可以进一步学习 Ingress Controller 配置、存储持久化方案、Helm Chart 编排以及 GitOps（ArgoCD&#x2F;Flux）等高级主题。</p><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-12-kubernetes-env-setup/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-12-kubernetes-env-setup/"/>
    <published>2026-06-12T13:13:00.000Z</published>
    <summary>
      <![CDATA[<blockquote>
<p>本文详细介绍如何在 Ubuntu 22.04 上使用 kubeadm 搭建一个生产级别的 Kubernetes 集群，涵盖环境准备、容器运行时安装、集群初始化、网络插件配置、Worker 节点加入以及集群管理工具安装。</p>
</blockquo]]>
    </summary>
    <title>Kubernetes 环境搭建完全指南（kubeadm 部署）</title>
    <updated>2026-06-18T00:39:57.574Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="技术分享" scheme="https://demo-blog.qusite.cn/categories/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/"/>
    <category term="Docker" scheme="https://demo-blog.qusite.cn/tags/Docker/"/>
    <category term="容器化" scheme="https://demo-blog.qusite.cn/tags/%E5%AE%B9%E5%99%A8%E5%8C%96/"/>
    <category term="DevOps" scheme="https://demo-blog.qusite.cn/tags/DevOps/"/>
    <category term="Docker Compose" scheme="https://demo-blog.qusite.cn/tags/Docker-Compose/"/>
    <category term="Linux配置" scheme="https://demo-blog.qusite.cn/tags/Linux%E9%85%8D%E7%BD%AE/"/>
    <content>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>Docker Compose 是定义和运行多容器 Docker 应用的重要工具。开发者通常在开发环境中使用 <code>docker-compose.yml</code> 快速启动服务，但将其直接迁移到生产环境会面临诸多挑战——安全、高可用、日志管理、备份恢复、性能调优等。</p><p>本文基于 Ubuntu 22.04 LTS + Docker Compose V2（<code>docker compose</code> 子命令，不再是独立二进制），从零搭建一个生产级的 Docker Compose 部署架构，涵盖安全加固、日志轮转、健康检查、备份策略、CI&#x2F;CD 集成和故障排查。</p><h2 id="一、生产环境与开发环境的差异"><a href="#一、生产环境与开发环境的差异" class="headerlink" title="一、生产环境与开发环境的差异"></a>一、生产环境与开发环境的差异</h2><style>.opt-table { overflow-x: auto; -webkit-overflow-scrolling: touch; }.opt-table table { width: 100%; border-collapse: collapse; border: 1px solid var(--third-background-color); }.opt-table th, .opt-table td { border: 1px solid var(--third-background-color); padding: 8px; text-align: left; }.opt-table thead tr { background: var(--second-background-color); }</style><div class="opt-table"><table><thead><tr><th>维度</th><th>开发环境</th><th>生产环境</th></tr></thead><tbody><tr><td>重启策略</td><td>无或 always</td><td>unless-stopped + healthcheck</td></tr><tr><td>日志</td><td>默认 json-file 无限制</td><td>日志轮转 + 集中式日志（Loki/ELK）</td></tr><tr><td>网络</td><td>默认 bridge</td><td>自定义 overlay/manual 网络 + 网络策略</td></tr><tr><td>持久化</td><td>匿名卷或 bind mount</td><td>命名卷 + 定时备份</td></tr><tr><td>密码</td><td>硬编码在 yml</td><td>.env 文件或 Docker Secrets</td></tr><tr><td>资源限制</td><td>无限制</td><td>明确 CPU/Memory reservations 和 limits</td></tr><tr><td>监控</td><td>无</td><td>资源监控 + 容器探活告警</td></tr></tbody></table></div><h2 id="二、安装最新版-Docker-与-Compose-V2"><a href="#二、安装最新版-Docker-与-Compose-V2" class="headerlink" title="二、安装最新版 Docker 与 Compose V2"></a>二、安装最新版 Docker 与 Compose V2</h2><p>首先确保系统已安装 Docker Engine 24+（推荐 27.x）和 Compose V2：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 卸载旧版本</span></span><br><span class="line"><span class="built_in">sudo</span> apt remove docker docker-engine docker.io containerd runc</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装依赖</span></span><br><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install -y ca-certificates curl gnupg lsb-release</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加 Docker 官方 GPG 密钥和源</span></span><br><span class="line">curl -fsSL https://download.docker.com/linux/ubuntu/gpg | <span class="built_in">sudo</span> gpg --dearmor -o /etc/apt/keyrings/docker.gpg</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;deb [arch=<span class="subst">$(dpkg --print-architecture)</span> signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu <span class="subst">$(lsb_release -cs)</span> stable&quot;</span> | <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/apt/sources.list.d/docker.list &gt; /dev/null</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 Docker Engine 和 Compose V2</span></span><br><span class="line"><span class="built_in">sudo</span> apt update</span><br><span class="line"><span class="built_in">sudo</span> apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将当前用户加入 docker 组（避免每次 sudo）</span></span><br><span class="line"><span class="built_in">sudo</span> usermod -aG docker <span class="variable">$USER</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证</span></span><br><span class="line">docker --version     <span class="comment"># Docker version 27.x</span></span><br><span class="line">docker compose version  <span class="comment"># Docker Compose version v2.x</span></span><br></pre></td></tr></table></figure></div><blockquote><p><strong>注意</strong>：生产环境不建议使用 <code>sudo</code> 运行 Docker，务必通过 docker 组管理权限。同时需严格审查哪些用户属于 docker 组——docker 组的成员拥有相当于 root 的权限。</p></blockquote><h2 id="三、基础安全加固"><a href="#三、基础安全加固" class="headerlink" title="三、基础安全加固"></a>三、基础安全加固</h2><h3 id="3-1-Docker-Daemon-配置"><a href="#3-1-Docker-Daemon-配置" class="headerlink" title="3.1 Docker Daemon 配置"></a>3.1 Docker Daemon 配置</h3><p>创建 <code>/etc/docker/daemon.json</code>：</p><div class="code-container" data-rel="Json"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;log-driver&quot;</span><span class="punctuation">:</span> <span class="string">&quot;json-file&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;log-opts&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;max-size&quot;</span><span class="punctuation">:</span> <span class="string">&quot;10m&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;max-file&quot;</span><span class="punctuation">:</span> <span class="string">&quot;3&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;live-restore&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;userland-proxy&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;iptables&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;storage-driver&quot;</span><span class="punctuation">:</span> <span class="string">&quot;overlay2&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;exec-opts&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="string">&quot;native.cgroupdriver=systemd&quot;</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;default-ulimits&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;nofile&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span> <span class="attr">&quot;Name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;nofile&quot;</span><span class="punctuation">,</span> <span class="attr">&quot;Hard&quot;</span><span class="punctuation">:</span> <span class="number">65535</span><span class="punctuation">,</span> <span class="attr">&quot;Soft&quot;</span><span class="punctuation">:</span> <span class="number">65535</span> <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></div><p>关键参数说明：</p><ul><li><code>live-restore: true</code>：Docker 守护进程重启时不停止运行中的容器。生产环境必开。</li><li><code>userland-proxy: false</code>：禁用用户态代理，减少攻击面，配合 <code>iptables: true</code> 使用。</li><li><code>default-ulimits</code>：为所有容器设置默认文件描述符限制。</li></ul><p>重启 Docker 使配置生效：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl daemon-reload</span><br><span class="line"><span class="built_in">sudo</span> systemctl restart docker</span><br></pre></td></tr></table></figure></div><h3 id="3-2-限制-Docker-Socket-访问"><a href="#3-2-限制-Docker-Socket-访问" class="headerlink" title="3.2 限制 Docker Socket 访问"></a>3.2 限制 Docker Socket 访问</h3><p>Docker Socket（<code>/var/run/docker.sock</code>）映射到容器内是极其危险的操作。如果确实需要（如 Traefik、Portainer），应严格限制：</p><ul><li>使用只读模式挂载 <code>docker.sock</code></li><li>在容器内以非 root 用户运行</li><li>使用 Docker Socket Proxy（如 <code>tecnativa/docker-socket-proxy</code>）提供安全访问层</li></ul><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安全做法：通过 socket-proxy 代理访问</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">docker-proxy:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">tecnativa/docker-socket-proxy:latest</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/var/run/docker.sock:/var/run/docker.sock:ro</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">CONTAINERS=1</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">NETWORKS=1</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">SERVICES=1</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">TASKS=1</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br></pre></td></tr></table></figure></div><h2 id="四、生产级-compose-yml-模板"><a href="#四、生产级-compose-yml-模板" class="headerlink" title="四、生产级 compose.yml 模板"></a>四、生产级 compose.yml 模板</h2><p>以下是一个包含 Nginx + PHP-FPM + MariaDB + Redis 的完整生产级 <code>compose.yml</code>：</p><div class="code-container" data-rel="Yaml"><figure class="iseeu 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><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># compose.yml</span></span><br><span class="line"><span class="attr">version:</span> <span class="string">&quot;3.9&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">nginx:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">nginx:1.27-alpine</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">app-nginx</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;80:80&quot;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;443:443&quot;</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./nginx/conf.d:/etc/nginx/conf.d:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./app:/var/www/html:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./nginx/ssl:/etc/nginx/ssl:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">static-data:/var/www/static</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">php</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">frontend</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;wget&quot;</span>, <span class="string">&quot;-qO-&quot;</span>, <span class="string">&quot;http://localhost:80/health&quot;</span>]</span><br><span class="line">      <span class="attr">interval:</span> <span class="string">30s</span></span><br><span class="line">      <span class="attr">timeout:</span> <span class="string">10s</span></span><br><span class="line">      <span class="attr">retries:</span> <span class="number">3</span></span><br><span class="line">      <span class="attr">start_period:</span> <span class="string">10s</span></span><br><span class="line">    <span class="attr">deploy:</span></span><br><span class="line">      <span class="attr">resources:</span></span><br><span class="line">        <span class="attr">limits:</span></span><br><span class="line">          <span class="attr">cpus:</span> <span class="string">&quot;0.5&quot;</span></span><br><span class="line">          <span class="attr">memory:</span> <span class="string">&quot;256M&quot;</span></span><br><span class="line">        <span class="attr">reservations:</span></span><br><span class="line">          <span class="attr">cpus:</span> <span class="string">&quot;0.25&quot;</span></span><br><span class="line">          <span class="attr">memory:</span> <span class="string">&quot;128M&quot;</span></span><br><span class="line">    <span class="attr">logging:</span></span><br><span class="line">      <span class="attr">driver:</span> <span class="string">&quot;json-file&quot;</span></span><br><span class="line">      <span class="attr">options:</span></span><br><span class="line">        <span class="attr">max-size:</span> <span class="string">&quot;10m&quot;</span></span><br><span class="line">        <span class="attr">max-file:</span> <span class="string">&quot;3&quot;</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">php:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">php:8.3-fpm-alpine</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">app-php</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./app:/var/www/html</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">php-socket:/var/run/php</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APP_ENV=production</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">DB_HOST=mariadb</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">REDIS_HOST=redis</span></span><br><span class="line">    <span class="attr">env_file:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">.env.production</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="attr">mariadb:</span></span><br><span class="line">        <span class="attr">condition:</span> <span class="string">service_healthy</span></span><br><span class="line">      <span class="attr">redis:</span></span><br><span class="line">        <span class="attr">condition:</span> <span class="string">service_healthy</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">frontend</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">backend</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;php-fpm&quot;</span>, <span class="string">&quot;-t&quot;</span>]</span><br><span class="line">      <span class="attr">interval:</span> <span class="string">30s</span></span><br><span class="line">      <span class="attr">timeout:</span> <span class="string">5s</span></span><br><span class="line">      <span class="attr">retries:</span> <span class="number">3</span></span><br><span class="line">      <span class="attr">start_period:</span> <span class="string">15s</span></span><br><span class="line">    <span class="attr">deploy:</span></span><br><span class="line">      <span class="attr">resources:</span></span><br><span class="line">        <span class="attr">limits:</span></span><br><span class="line">          <span class="attr">cpus:</span> <span class="string">&quot;1.0&quot;</span></span><br><span class="line">          <span class="attr">memory:</span> <span class="string">&quot;512M&quot;</span></span><br><span class="line">        <span class="attr">reservations:</span></span><br><span class="line">          <span class="attr">cpus:</span> <span class="string">&quot;0.5&quot;</span></span><br><span class="line">          <span class="attr">memory:</span> <span class="string">&quot;256M&quot;</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">mariadb:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">mariadb:11.4</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">app-mariadb</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">mariadb-data:/var/lib/mysql</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./db/init:/docker-entrypoint-initdb.d:ro</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">MARIADB_ROOT_PASSWORD_FILE:</span> <span class="string">/run/secrets/db_root_password</span></span><br><span class="line">    <span class="attr">env_file:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">.env.production</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">backend</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;healthcheck.sh&quot;</span>, <span class="string">&quot;--su=mysql&quot;</span>, <span class="string">&quot;--connect&quot;</span>, <span class="string">&quot;--innodb_initialized&quot;</span>]</span><br><span class="line">      <span class="attr">interval:</span> <span class="string">15s</span></span><br><span class="line">      <span class="attr">timeout:</span> <span class="string">10s</span></span><br><span class="line">      <span class="attr">retries:</span> <span class="number">5</span></span><br><span class="line">      <span class="attr">start_period:</span> <span class="string">60s</span></span><br><span class="line">    <span class="attr">deploy:</span></span><br><span class="line">      <span class="attr">resources:</span></span><br><span class="line">        <span class="attr">limits:</span></span><br><span class="line">          <span class="attr">cpus:</span> <span class="string">&quot;2.0&quot;</span></span><br><span class="line">          <span class="attr">memory:</span> <span class="string">&quot;2G&quot;</span></span><br><span class="line">        <span class="attr">reservations:</span></span><br><span class="line">          <span class="attr">cpus:</span> <span class="string">&quot;1.0&quot;</span></span><br><span class="line">          <span class="attr">memory:</span> <span class="string">&quot;1G&quot;</span></span><br><span class="line">    <span class="attr">secrets:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">db_root_password</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">db_password</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">redis:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">redis:7.4-alpine</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">app-redis</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br><span class="line">    <span class="attr">command:</span> <span class="string">&gt;</span></span><br><span class="line"><span class="string">      redis-server --requirepass $&#123;REDIS_PASSWORD&#125;</span></span><br><span class="line"><span class="string">                   --appendonly yes</span></span><br><span class="line"><span class="string">                   --appendfsync everysec</span></span><br><span class="line"><span class="string">                   --save 900 1</span></span><br><span class="line"><span class="string">                   --save 300 10</span></span><br><span class="line"><span class="string">                   --save 60 10000</span></span><br><span class="line"><span class="string"></span>    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">redis-data:/data</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">backend</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;redis-cli&quot;</span>, <span class="string">&quot;ping&quot;</span>]</span><br><span class="line">      <span class="attr">interval:</span> <span class="string">15s</span></span><br><span class="line">      <span class="attr">timeout:</span> <span class="string">5s</span></span><br><span class="line">      <span class="attr">retries:</span> <span class="number">3</span></span><br><span class="line">      <span class="attr">start_period:</span> <span class="string">10s</span></span><br><span class="line">    <span class="attr">deploy:</span></span><br><span class="line">      <span class="attr">resources:</span></span><br><span class="line">        <span class="attr">limits:</span></span><br><span class="line">          <span class="attr">cpus:</span> <span class="string">&quot;0.5&quot;</span></span><br><span class="line">          <span class="attr">memory:</span> <span class="string">&quot;256M&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">volumes:</span></span><br><span class="line">  <span class="attr">mariadb-data:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">local</span></span><br><span class="line">  <span class="attr">redis-data:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">local</span></span><br><span class="line">  <span class="attr">static-data:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">local</span></span><br><span class="line">  <span class="attr">php-socket:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">local</span></span><br><span class="line"></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line">  <span class="attr">frontend:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">bridge</span></span><br><span class="line">    <span class="attr">ipam:</span></span><br><span class="line">      <span class="attr">config:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">subnet:</span> <span class="string">&quot;172.20.0.0/24&quot;</span></span><br><span class="line">  <span class="attr">backend:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">bridge</span></span><br><span class="line">    <span class="attr">internal:</span> <span class="literal">true</span>  <span class="comment"># 后端网络无外部访问，提升安全性</span></span><br><span class="line">    <span class="attr">ipam:</span></span><br><span class="line">      <span class="attr">config:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="attr">subnet:</span> <span class="string">&quot;172.20.1.0/24&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">secrets:</span></span><br><span class="line">  <span class="attr">db_root_password:</span></span><br><span class="line">    <span class="attr">file:</span> <span class="string">./secrets/db_root_password.txt</span></span><br><span class="line">  <span class="attr">db_password:</span></span><br><span class="line">    <span class="attr">file:</span> <span class="string">./secrets/db_password.txt</span></span><br></pre></td></tr></table></figure></div><h2 id="五、关键配置详解"><a href="#五、关键配置详解" class="headerlink" title="五、关键配置详解"></a>五、关键配置详解</h2><h3 id="5-1-健康检查（Healthcheck）"><a href="#5-1-健康检查（Healthcheck）" class="headerlink" title="5.1 健康检查（Healthcheck）"></a>5.1 健康检查（Healthcheck）</h3><p>每个服务都应配置 <code>healthcheck</code>，让 Docker 能自动检测服务状态，配合 <code>depends_on.condition: service_healthy</code> 确保依赖服务启动后再启动当前服务。</p><p>健康检查参数速查：</p><div class="opt-table"><table><thead><tr><th>参数</th><th>说明</th><th>推荐值</th></tr></thead><tbody><tr><td>test</td><td>健康检查命令（需返回 0 表示健康）</td><td>根据服务类型定制</td></tr><tr><td>interval</td><td>检查间隔</td><td>15-30s</td></tr><tr><td>timeout</td><td>单次检查超时</td><td>5-10s</td></tr><tr><td>retries</td><td>连续失败次数</td><td>3-5</td></tr><tr><td>start_period</td><td>启动后的宽限期</td><td>根据服务启动时间而定</td></tr></tbody></table></div><h3 id="5-2-资源限制"><a href="#5-2-资源限制" class="headerlink" title="5.2 资源限制"></a>5.2 资源限制</h3><p><code>deploy.resources</code> 设置容器的 CPU 和内存上限，防止某个容器耗尽主机资源导致雪崩。</p><ul><li><code>limits</code>：硬上限，超过则 OOM kill</li><li><code>reservations</code>：软预留，调度时保证至少分配这些资源</li></ul><h3 id="5-3-网络隔离"><a href="#5-3-网络隔离" class="headerlink" title="5.3 网络隔离"></a>5.3 网络隔离</h3><p>使用 <strong>两个网络</strong> 实现分层隔离：</p><ul><li><code>frontend</code>：Nginx 等对外暴露的服务在此网络</li><li><code>backend</code>：内部服务（DB、Redis）使用 <code>internal: true</code>，完全隔离外部访问</li></ul><p>只有 <code>php</code> 服务同时加入 <code>frontend</code> 和 <code>backend</code> 网络，作为应用层的数据通道。</p><h3 id="5-4-Docker-Secrets"><a href="#5-4-Docker-Secrets" class="headerlink" title="5.4 Docker Secrets"></a>5.4 Docker Secrets</h3><p>敏感信息（数据库密码、API 密钥等）不应写死在 compose.yml 或环境变量中。使用 Docker Secrets：</p><ul><li>创建 <code>./secrets/db_password.txt</code> 文件（一行明文）</li><li>在 compose 中通过 <code>secrets:</code> 声明</li><li>在 service 中通过 <code>secrets:</code> 引用</li><li>密码读取方式：<code>MARIADB_ROOT_PASSWORD_FILE: /run/secrets/db_root_password</code></li></ul><h2 id="六、日志管理"><a href="#六、日志管理" class="headerlink" title="六、日志管理"></a>六、日志管理</h2><h3 id="6-1-容器日志轮转"><a href="#6-1-容器日志轮转" class="headerlink" title="6.1 容器日志轮转"></a>6.1 容器日志轮转</h3><p>必须在 Docker Daemon 或每个服务级别设置日志轮转，防止日志撑爆磁盘：</p><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="attr">logging:</span></span><br><span class="line">  <span class="attr">driver:</span> <span class="string">&quot;json-file&quot;</span></span><br><span class="line">  <span class="attr">options:</span></span><br><span class="line">    <span class="attr">max-size:</span> <span class="string">&quot;10m&quot;</span></span><br><span class="line">    <span class="attr">max-file:</span> <span class="string">&quot;3&quot;</span></span><br></pre></td></tr></table></figure></div><h3 id="6-2-集中式日志方案"><a href="#6-2-集中式日志方案" class="headerlink" title="6.2 集中式日志方案"></a>6.2 集中式日志方案</h3><p>推荐使用 Loki + Promtail（轻量）或 ELK（功能丰富）：</p><div class="code-container" data-rel="Yaml"><figure class="iseeu highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">loki:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">grafana/loki:3.0</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./loki-config.yml:/etc/loki/local-config.yml:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">loki-data:/loki</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;3100:3100&quot;</span></span><br><span class="line">    <span class="attr">command:</span> <span class="string">-config.file=/etc/loki/local-config.yml</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">promtail:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">grafana/promtail:3.0</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/var/lib/docker/containers:/var/lib/docker/containers:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./promtail-config.yml:/etc/promtail/config.yml:ro</span></span><br><span class="line">    <span class="attr">command:</span> <span class="string">-config.file=/etc/promtail/config.yml</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br></pre></td></tr></table></figure></div><h3 id="6-3-日志清理脚本"><a href="#6-3-日志清理脚本" class="headerlink" title="6.3 日志清理脚本"></a>6.3 日志清理脚本</h3><p>即便配置了轮转，长期运行的服务器仍可能出现日志残留。建议配合定时任务清理：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># /usr/local/bin/clean-docker-logs.sh</span></span><br><span class="line"><span class="comment"># 清理 3 天前的容器日志文件</span></span><br><span class="line">find /var/lib/docker/containers -name <span class="string">&quot;*-json.log&quot;</span> -mtime +3 -delete</span><br><span class="line">journalctl --vacuum-time=7d</span><br></pre></td></tr></table></figure></div><p>添加到 crontab：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">0 3 * * * /usr/local/bin/clean-docker-logs.sh</span><br></pre></td></tr></table></figure></div><h2 id="七、数据备份与恢复"><a href="#七、数据备份与恢复" class="headerlink" title="七、数据备份与恢复"></a>七、数据备份与恢复</h2><h3 id="7-1-数据库自动备份"><a href="#7-1-数据库自动备份" class="headerlink" title="7.1 数据库自动备份"></a>7.1 数据库自动备份</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># /usr/local/bin/backup-mariadb.sh</span></span><br><span class="line">BACKUP_DIR=/data/backups/mariadb</span><br><span class="line">TIMESTAMP=$(<span class="built_in">date</span> +%Y%m%d_%H%M%S)</span><br><span class="line">RETENTION_DAYS=30</span><br><span class="line">DB_PASSWORD=$(<span class="built_in">cat</span> /opt/docker-app/secrets/db_root_password.txt)</span><br><span class="line"></span><br><span class="line"><span class="built_in">mkdir</span> -p <span class="variable">$BACKUP_DIR</span></span><br><span class="line"></span><br><span class="line">docker <span class="built_in">exec</span> app-mariadb mysqldump \</span><br><span class="line">  --all-databases \</span><br><span class="line">  --single-transaction \</span><br><span class="line">  --routines \</span><br><span class="line">  --triggers \</span><br><span class="line">  --events \</span><br><span class="line">  -u root -p<span class="string">&quot;<span class="variable">$DB_PASSWORD</span>&quot;</span> \</span><br><span class="line">  | gzip &gt; <span class="variable">$BACKUP_DIR</span>/full_backup_<span class="variable">$TIMESTAMP</span>.sql.gz</span><br><span class="line"></span><br><span class="line"><span class="comment"># 保留最近 30 天</span></span><br><span class="line">find <span class="variable">$BACKUP_DIR</span> -name <span class="string">&quot;*.sql.gz&quot;</span> -mtime +<span class="variable">$RETENTION_DAYS</span> -delete</span><br><span class="line"></span><br><span class="line"><span class="comment"># 同步到远程备份服务器</span></span><br><span class="line">rsync -avz --delete <span class="variable">$BACKUP_DIR</span>/ backup@remote-server:/data/backups/mariadb/</span><br></pre></td></tr></table></figure></div><p>添加到 crontab：</p><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">0 2 * * * /usr/local/bin/backup-mariadb.sh</span><br></pre></td></tr></table></figure></div><h3 id="7-2-容器卷备份"><a href="#7-2-容器卷备份" class="headerlink" title="7.2 容器卷备份"></a>7.2 容器卷备份</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># 备份 Docker 命名卷到 tar.gz</span></span><br><span class="line">docker run --<span class="built_in">rm</span> \</span><br><span class="line">  -v mariadb-data:/data \</span><br><span class="line">  -v /data/backups/volumes:/backup \</span><br><span class="line">  alpine tar czf /backup/mariadb-data_$(<span class="built_in">date</span> +%Y%m%d).tar.gz -C /data .</span><br></pre></td></tr></table></figure></div><h3 id="7-3-恢复流程"><a href="#7-3-恢复流程" class="headerlink" title="7.3 恢复流程"></a>7.3 恢复流程</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 数据库恢复</span></span><br><span class="line">gunzip &lt; full_backup_20260612_020000.sql.gz | docker <span class="built_in">exec</span> -i app-mariadb mysql -u root -p<span class="string">&quot;<span class="variable">$PASSWORD</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 卷恢复</span></span><br><span class="line">docker run --<span class="built_in">rm</span> \</span><br><span class="line">  -v mariadb-data:/data \</span><br><span class="line">  -v /data/backups/volumes:/backup \</span><br><span class="line">  alpine tar xzf /backup/mariadb-data_20260612.tar.gz -C /data</span><br></pre></td></tr></table></figure></div><h2 id="八、部署与-CI-CD-集成"><a href="#八、部署与-CI-CD-集成" class="headerlink" title="八、部署与 CI&#x2F;CD 集成"></a>八、部署与 CI&#x2F;CD 集成</h2><h3 id="8-1-项目目录结构"><a href="#8-1-项目目录结构" class="headerlink" title="8.1 项目目录结构"></a>8.1 项目目录结构</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line">/opt/docker-app/</span><br><span class="line">├── compose.yml</span><br><span class="line">├── .env.production        # 环境变量（不进版本库）</span><br><span class="line">├── secrets/               # Docker Secrets（不进版本库）</span><br><span class="line">│   ├── db_root_password.txt</span><br><span class="line">│   └── db_password.txt</span><br><span class="line">├── nginx/</span><br><span class="line">│   ├── conf.d/</span><br><span class="line">│   └── ssl/</span><br><span class="line">├── app/                   # 应用代码</span><br><span class="line">├── db/</span><br><span class="line">│   └── init/              # 初始化 SQL</span><br><span class="line">├── scripts/</span><br><span class="line">│   ├── backup.sh</span><br><span class="line">│   └── deploy.sh</span><br><span class="line">└── monitoring/</span><br><span class="line">    ├── loki-config.yml</span><br><span class="line">    └── promtail-config.yml</span><br></pre></td></tr></table></figure></div><h3 id="8-2-零停机部署脚本"><a href="#8-2-零停机部署脚本" class="headerlink" title="8.2 零停机部署脚本"></a>8.2 零停机部署脚本</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># /opt/docker-app/scripts/deploy.sh</span></span><br><span class="line"><span class="built_in">set</span> -e</span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> /opt/docker-app</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[1/4] 拉取最新代码...&quot;</span></span><br><span class="line">git pull origin main</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[2/4] 构建新镜像...&quot;</span></span><br><span class="line">docker compose build --pull</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[3/4] 滚动更新服务...&quot;</span></span><br><span class="line"><span class="comment"># 先更新无状态服务</span></span><br><span class="line">docker compose up -d --no-deps --scale nginx=2 nginx</span><br><span class="line">docker compose up -d --no-deps php</span><br><span class="line"></span><br><span class="line"><span class="comment"># 等待健康检查通过</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[4/4] 等待健康检查...&quot;</span></span><br><span class="line"><span class="built_in">sleep</span> 15</span><br><span class="line"></span><br><span class="line"><span class="comment"># 清理旧容器</span></span><br><span class="line">docker image prune -f</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;部署完成！&quot;</span></span><br></pre></td></tr></table></figure></div><h3 id="8-3-GitHub-Actions-自动部署"><a href="#8-3-GitHub-Actions-自动部署" class="headerlink" title="8.3 GitHub Actions 自动部署"></a>8.3 GitHub Actions 自动部署</h3><div class="code-container" data-rel="Yaml"><figure class="iseeu 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></pre></td><td class="code"><pre><span class="line"><span class="comment"># .github/workflows/deploy.yml</span></span><br><span class="line"><span class="attr">name:</span> <span class="string">Deploy</span> <span class="string">to</span> <span class="string">Production</span></span><br><span class="line"></span><br><span class="line"><span class="attr">on:</span></span><br><span class="line">  <span class="attr">push:</span></span><br><span class="line">    <span class="attr">branches:</span> [<span class="string">main</span>]</span><br><span class="line"></span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line">  <span class="attr">deploy:</span></span><br><span class="line">    <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line">    <span class="attr">steps:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">uses:</span> <span class="string">actions/checkout@v4</span></span><br><span class="line"></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Copy</span> <span class="string">files</span> <span class="string">via</span> <span class="string">SSH</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">appleboy/scp-action@v0.1.7</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">host:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.DEPLOY_HOST</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          <span class="attr">username:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.DEPLOY_USER</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          <span class="attr">key:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.DEPLOY_KEY</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          <span class="attr">source:</span> <span class="string">&quot;.&quot;</span></span><br><span class="line">          <span class="attr">target:</span> <span class="string">&quot;/opt/docker-app&quot;</span></span><br><span class="line"></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Execute</span> <span class="string">deploy</span> <span class="string">script</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">appleboy/ssh-action@v1.0.3</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">host:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.DEPLOY_HOST</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          <span class="attr">username:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.DEPLOY_USER</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          <span class="attr">key:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.DEPLOY_KEY</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          <span class="attr">script:</span> <span class="string">cd</span> <span class="string">/opt/docker-app</span> <span class="string">&amp;&amp;</span> <span class="string">bash</span> <span class="string">scripts/deploy.sh</span></span><br></pre></td></tr></table></figure></div><h2 id="九、监控与告警"><a href="#九、监控与告警" class="headerlink" title="九、监控与告警"></a>九、监控与告警</h2><h3 id="9-1-本地资源监控"><a href="#9-1-本地资源监控" class="headerlink" title="9.1 本地资源监控"></a>9.1 本地资源监控</h3><div class="code-container" data-rel="Bash"><figure class="iseeu highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看所有容器资源使用</span></span><br><span class="line">docker stats --no-stream</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看特定服务日志</span></span><br><span class="line">docker compose logs --<span class="built_in">tail</span>=100 -f nginx</span><br><span class="line"></span><br><span class="line"><span class="comment"># 磁盘空间预警</span></span><br><span class="line"><span class="built_in">df</span> -h | grep -E <span class="string">&quot;overlay|/dev/sda&quot;</span> </span><br></pre></td></tr></table></figure></div><h3 id="9-2-cAdvisor-Prometheus-集成"><a href="#9-2-cAdvisor-Prometheus-集成" class="headerlink" title="9.2 cAdvisor + Prometheus 集成"></a>9.2 cAdvisor + Prometheus 集成</h3><div class="code-container" data-rel="Yaml"><figure class="iseeu 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">services:</span></span><br><span class="line">  <span class="attr">cadvisor:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">gcr.io/cadvisor/cadvisor:latest</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">cadvisor</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/:/rootfs:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/var/run:/var/run:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/sys:/sys:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/var/lib/docker:/var/lib/docker:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/dev/disk/:/dev/disk:ro</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;8080:8080&quot;</span></span><br><span class="line">    <span class="attr">privileged:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">monitoring</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">node_exporter:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">prom/node-exporter:latest</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">node-exporter</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">unless-stopped</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/proc:/host/proc:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/sys:/host/sys:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/:/rootfs:ro</span></span><br><span class="line">    <span class="attr">command:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&#x27;--path.procfs=/host/proc&#x27;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&#x27;--path.sysfs=/host/sys&#x27;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&#x27;--path.rootfs=/rootfs&#x27;</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;9100:9100&quot;</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">monitoring</span></span><br><span class="line"></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line">  <span class="attr">monitoring:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">bridge</span></span><br></pre></td></tr></table></figure></div><h2 id="十、常见问题排查"><a href="#十、常见问题排查" class="headerlink" title="十、常见问题排查"></a>十、常见问题排查</h2><div class="opt-table"><table><thead><tr><th>问题</th><th>原因</th><th>解决方案</th></tr></thead><tbody><tr><td>容器不断重启</td><td>健康检查失败或配置错误</td><td><code>docker compose logs [service]</code> 查看具体错误</td></tr><tr><td>端口被占用</td><td>其他服务占用了映射端口</td><td><code>ss -tlnp | grep :80</code> 查看占用进程</td></tr><tr><td>磁盘空间满</td><td>日志或镜像占用</td><td><code>docker system prune -af</code> 清理；<code>docker compose logs --tail=0</code> 清空日志</td></tr><tr><td>数据库连不上</td><td>网络配置或认证问题</td><td>确认网络是否正确；检查 secrets 文件是否一致</td></tr><tr><td>容器内时区不对</td><td>未设置 TZ 环境变量</td><td>添加 <code>environment: TZ: Asia/Shanghai</code></td></tr><tr><td>PHP 写文件报错</td><td>权限不一致</td><td>确认 UID/GID 映射；使用 <code>user: "1000:1000"</code></td></tr><tr><td>Docker 守护进程无法启动</td><td>daemon.json 语法错误</td><td><code>dockerd --validate</code> 检查配置</td></tr><tr><td>swap 导致 OOM</td><td>内存限制 + swap 交互</td><td>在 <code>daemon.json</code> 中禁用 swap：设置 <code>"swappiness": 0</code></td></tr></tbody></table></div><h2 id="十一、安全最佳实践清单"><a href="#十一、安全最佳实践清单" class="headerlink" title="十一、安全最佳实践清单"></a>十一、安全最佳实践清单</h2><ol><li><strong>最小权限原则</strong>：容器内使用非 root 用户运行进程（<code>RUN adduser -D appuser &amp;&amp; USER appuser</code>）</li><li><strong>只读文件系统</strong>：不需要写权限的目录使用 <code>:ro</code> 挂载</li><li><strong>镜像签名验证</strong>：使用 Docker Content Trust（<code>export DOCKER_CONTENT_TRUST=1</code>）</li><li><strong>定期更新基础镜像</strong>：<code>docker compose build --pull &amp;&amp; docker compose up -d</code></li><li><strong>安全扫描</strong>：集成 Trivy 或 Docker Scout 扫描镜像漏洞</li><li><strong>网络策略</strong>：后端服务使用 <code>internal: true</code> 网络</li><li><strong>密钥管理</strong>：Docker Secrets 替代明文环境变量</li><li><strong>审计日志</strong>：启用 Docker Daemon 的 auditd 规则</li><li><strong>资源配额</strong>：所有容器设置 CPU&#x2F;Memory limits</li><li><strong>备份恢复演练</strong>：定期测试备份数据能否正常恢复</li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Docker Compose 并非仅适用于开发环境，通过合理的配置和加固，完全可以在生产环境中安全、稳定地运行。本文从安装、安全加固、生产级配置模板、日志管理、数据备份、CI&#x2F;CD 集成到监控告警，覆盖了完整的生产化流程。</p><p>关键在于记住几个核心原则：<strong>安全隔离、资源限制、日志管理、健康检查、定期备份</strong>。遵循这些原则，Docker Compose 可以成为中小规模生产环境的高效部署方案。</p><p>对于更大规模的集群场景，可考虑升级到 Docker Swarm 或 Kubernetes，但 Docker Compose 的配置思维和最佳实践在这些平台同样适用。</p><hr><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-12-docker-compose-production-guide/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-12-docker-compose-production-guide/"/>
    <published>2026-06-12T12:11:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>Docker Compose 是定义和运行多容器 Docker 应用的重要工具。开发者通常在开发环境中使用 <code>docker-com]]>
    </summary>
    <title>Docker Compose 生产环境配置完全指南</title>
    <updated>2026-06-18T00:39:57.574Z</updated>
  </entry>
  <entry>
    <author>
      <name>心雨</name>
    </author>
    <category term="日记" scheme="https://demo-blog.qusite.cn/categories/%E6%97%A5%E8%AE%B0/"/>
    <category term="日记" scheme="https://demo-blog.qusite.cn/tags/%E6%97%A5%E8%AE%B0/"/>
    <category term="技术学习" scheme="https://demo-blog.qusite.cn/tags/%E6%8A%80%E6%9C%AF%E5%AD%A6%E4%B9%A0/"/>
    <category term="周记" scheme="https://demo-blog.qusite.cn/tags/%E5%91%A8%E8%AE%B0/"/>
    <content>
      <![CDATA[<h2 id="写在前面"><a href="#写在前面" class="headerlink" title="写在前面"></a>写在前面</h2><p>今天是 2026 年 6 月 12 日，一个值得载入史册的日子——SpaceX 正式登陆纳斯达克，成为人类历史上规模最大的 IPO。而我，也在博客上记录了整整一周的技术学习与写作。此刻坐在电脑前，窗外天色已暗，思绪万千。</p><hr><h2 id="SpaceX-上市首日观察"><a href="#SpaceX-上市首日观察" class="headerlink" title="SpaceX 上市首日观察"></a>SpaceX 上市首日观察</h2><p>上午开盘时我还在忙着写 PostgreSQL 教程，但打开交易软件看到”SPACE”代码亮起的那一刻，还是忍不住停下手头的工作看了几分钟。发行价 $120，开盘后一度冲高到 $138，收盘涨幅约 15%，市值突破 2 万亿美元。说实话，这个数字大得让人难以想象。</p><p>埃隆·马斯克在纳斯达克敲钟时没有穿西装，还是一如既往的黑色 T 恤配休闲外套。他在简短的发言中提到：”这次 IPO 不是终点，而是加速器。星舰的每月发射频率将在明年提升到 50 次以上，同时我们正在推进轨道 AI 数据中心的建设。”</p><p>让我印象最深的是，他还专门感谢了那些从 SpaceX 早期就相信他的人们。回想 2002 年他创立 SpaceX 时，大多数人认为可回收火箭是天方夜谭。24 年后的今天，SpaceX 已经将发射成本降低了 90% 以上，彻底改写了航天工业的规则。</p><p>这让我想起博客里的”长期主义”话题——真正改变世界的事情，从来都不是一蹴而就的。</p><hr><h2 id="本周技术写作回顾"><a href="#本周技术写作回顾" class="headerlink" title="本周技术写作回顾"></a>本周技术写作回顾</h2><p>这周（6 月 8 日到 12 日）我写了不少技术文章，趁今晚做一个梳理：</p><table><thead><tr><th>日期</th><th>文章</th><th>类型</th></tr></thead><tbody><tr><td>6月8日</td><td>Linux 磁盘管理与 LVM 配置指南</td><td>配置指南</td></tr><tr><td>6月8日</td><td>MariaDB 环境搭建指南</td><td>环境搭建</td></tr><tr><td>6月8日</td><td>Linux find 命令完全指南</td><td>工具使用</td></tr><tr><td>6月9日</td><td>Linux rsync 命令完全指南</td><td>工具使用</td></tr><tr><td>6月9日</td><td>Prometheus + Grafana 监控环境搭建指南</td><td>环境搭建</td></tr><tr><td>6月9日</td><td>Linux 用户与权限管理指南</td><td>配置指南</td></tr><tr><td>6月9日</td><td>LEMP 环境搭建指南</td><td>环境搭建</td></tr><tr><td>6月9日</td><td>Linux 内核参数调优指南</td><td>配置指南</td></tr><tr><td>6月10日</td><td>ELK Stack 环境搭建指南</td><td>环境搭建</td></tr><tr><td>6月10日</td><td>Linux 软件包管理指南</td><td>配置指南</td></tr><tr><td>6月10日</td><td>Linux tmux 终端复用器完全指南</td><td>工具使用</td></tr><tr><td>6月11日</td><td>Jenkins CI&#x2F;CD 自动化部署指南</td><td>环境搭建</td></tr><tr><td>6月11日</td><td>Linux 系统启动流程与 GRUB 配置指南</td><td>配置指南</td></tr><tr><td>6月11日</td><td>Linux lsof 命令完全指南</td><td>工具使用</td></tr><tr><td>6月12日</td><td>Nginx 高级配置指南</td><td>配置指南</td></tr><tr><td>6月12日</td><td>PostgreSQL 环境搭建指南</td><td>环境搭建</td></tr><tr><td>6月12日</td><td>Linux strace 命令完全指南</td><td>工具使用</td></tr><tr><td>6月12日</td><td>WireGuard VPN 配置指南</td><td>配置指南</td></tr><tr><td>6月12日</td><td>Go 语言开发环境搭建指南</td><td>环境搭建</td></tr><tr><td>6月12日</td><td>Linux nmap 命令完全指南</td><td>工具使用</td></tr></tbody></table><p>梳理下来发现，这周主要覆盖了两个方向：<strong>Linux 服务配置</strong>和<strong>开发环境搭建</strong>，再加上几个常用工具的详细教程。回顾这个过程，有几件事值得记录：</p><h3 id="1-“教”是最好的”学”"><a href="#1-“教”是最好的”学”" class="headerlink" title="1. “教”是最好的”学”"></a>1. “教”是最好的”学”</h3><p>写 Jenkins CI&#x2F;CD 那篇文章时，我花了不少时间研究 Pipeline 的声明式语法和共享库机制。虽然在工作中也用过 Jenkins，但写教程时不得不去深挖每个细节——比如 <code>buildDiscarder</code> 的配置参数、<code>timestamps</code> 插件的日志时间戳含义等。写完之后，我对 Jenkins 的理解明显上了一个台阶。</p><h3 id="2-内容质量的自我审视"><a href="#2-内容质量的自我审视" class="headerlink" title="2. 内容质量的自我审视"></a>2. 内容质量的自我审视</h3><p>这周写了 20 篇技术文章，平均每篇 1500-2000 字。数量上确实不少，但质量方面还有提升空间：</p><ul><li>有些文章在表格呈现上可以更丰富（特别是命令速查表）</li><li>实战场景的案例可以更加贴近真实运维需求</li><li>缺少”踩坑记录”——实际部署中遇到的那些问题往往才是最有价值的内容</li></ul><h3 id="3-技术的广度与深度"><a href="#3-技术的广度与深度" class="headerlink" title="3. 技术的广度与深度"></a>3. 技术的广度与深度</h3><p>从 LVM 磁盘管理到 Prometheus 监控，从 Jenkins CI&#x2F;CD 到 WireGuard VPN，这周的技术跨度确实够大的。这种”广度优先”的学习方式好处是视野开阔，但缺点也很明显——每个方向都只能停留在入门到中级的水平。</p><p>下周我打算在某个方向上进行”深度突破”——可能是容器编排（Kubernetes）或者配置管理工具（Ansible），选一个方向扎深一点。</p><hr><h2 id="关于博客本身的一些事"><a href="#关于博客本身的一些事" class="headerlink" title="关于博客本身的一些事"></a>关于博客本身的一些事</h2><p>这周除了写文章，我还花时间做了一些博客运维方面的工作：</p><ol><li><strong>标签整理</strong>：之前文章标签比较随意，这周我统一了标签命名规范，删除了重复标签</li><li><strong>封面图统一</strong>：给之前没有封面图的文章补充了合适的 Unsplash 图片</li><li><strong>构建性能</strong>：随着文章数量增加到 70 余篇，Hexo 构建时间从几秒增加到十几秒。目前还能接受，但如果继续增长到 200 篇以上，可能需要考虑增量构建或者换更快的主题</li></ol><hr><h2 id="下周计划"><a href="#下周计划" class="headerlink" title="下周计划"></a>下周计划</h2><p>下一个技术深挖方向我倾向于 <strong>Kubernetes</strong>。原因有三：</p><ul><li>容器编排是现代运维的核心技能，几乎每个中大型项目都离不开 K8s</li><li>之前写的 Docker 教程、Jenkins CI&#x2F;CD、监控体系都可以和 K8s 串联起来，形成完整的技术栈</li><li>学习 K8s 的最佳方式也是写教程——从安装部署到 Pod&#x2F;Service&#x2F;Deployment 的基础概念，再到 Ingress、ConfigMap、PV&#x2F;PVC 等进阶内容，可以形成一个系列</li></ul><p>除了 K8s，还有一些前端相关的优化任务也想推进：</p><ul><li><input disabled="" type="checkbox"> 博客暗色模式的配色再优化（目前的蓝色调偏冷，想微调到蓝紫色系）</li><li><input disabled="" type="checkbox"> 调研 Hexo 搜索插件（无后端搜索方案，如 algolia 或 local search）</li><li><input disabled="" type="checkbox"> 阅读两篇关于 Kubernetes 网络模型（CNI）的深度文章</li></ul><hr><h2 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a>结尾</h2><p>这一周，从周一忙碌的 Linux 教程写作，到周五见证 SpaceX 创造历史的 IPO，整个过程充实而丰富。</p><p>我想起之前在日记里写到的”长期主义”——SpaceX 用了 24 年才走到 IPO 这一天，而我们每天学习一点点、写一点点，日积月累的力量同样不可小觑。</p><p>周末打算休息一下，去外面走走。毕竟劳逸结合才是持久之道。</p><p>晚安。</p><hr><p><em>本文由AI辅助生成，内容仅供参考</em></p>]]>
    </content>
    <id>https://demo-blog.qusite.cn/2026-06-12-friday-night-diary/</id>
    <link href="https://demo-blog.qusite.cn/2026-06-12-friday-night-diary/"/>
    <published>2026-06-12T11:09:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="写在前面"><a href="#写在前面" class="headerlink" title="写在前面"></a>写在前面</h2><p>今天是 2026 年 6 月 12 日，一个值得载入史册的日子——SpaceX 正式登陆纳斯达克，成为人类历史上规模最大的]]>
    </summary>
    <title>周五夜晚：SpaceX上市首日回顾与本周学习总结</title>
    <updated>2026-06-18T00:39:57.574Z</updated>
  </entry>
</feed>
