<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Kevin&#39;s Notes</title>
  
  <subtitle>Quick notes</subtitle>
  <link href="https://freemankevin.uk/atom.xml" rel="self"/>
  
  <link href="https://freemankevin.uk/"/>
  <updated>2026-05-21T06:03:03.318Z</updated>
  <id>https://freemankevin.uk/</id>
  
  <author>
    <name>Freeman Kevin</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Windows 容器开发环境搭建指南</title>
    <link href="https://freemankevin.uk/2026/05/21/windows-container-setup/"/>
    <id>https://freemankevin.uk/2026/05/21/windows-container-setup/</id>
    <published>2026-05-21T02:00:00.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p>容器技术本质上是 Linux-native 的，依赖 cgroups、namespaces、overlayfs 等内核特性，而 Windows 内核并不具备这些能力。因此所有在 Windows 上运行容器的方案，本质上都是在解决”如何在 Windows 上运行 Linux”这个问题。本文对比主流方案的优劣，并提供一套基于 WSL2 + Docker Engine 的稳定、免费、零授权风险的实践配置。</p><span id="more"></span><div class="note info"><p>本文面向习惯命令行操作的 DevOps 工程师和开发者。如果你依赖 GUI 管理容器，Docker Desktop 或 Rancher Desktop 可能更适合你的使用习惯。</p></div><hr><h2 id="方案对比：Docker-Desktop-Podman-Rancher-Desktop"><a href="#方案对比：Docker-Desktop-Podman-Rancher-Desktop" class="headerlink" title="方案对比：Docker Desktop &#x2F; Podman &#x2F; Rancher Desktop"></a>方案对比：Docker Desktop &#x2F; Podman &#x2F; Rancher Desktop</h2><h3 id="Docker-Desktop-——-好用但有授权风险"><a href="#Docker-Desktop-——-好用但有授权风险" class="headerlink" title="Docker Desktop —— 好用但有授权风险"></a>Docker Desktop —— 好用但有授权风险</h3><p>Docker Desktop 内置 Linux VM、GUI、CLI、Compose，开箱即用，是过去几年的事实标准。但 2022 年 Docker 修改订阅条款后，员工数超过 250 人或年收入超过 1000 万美元的企业必须付费订阅。对于中大型公司，法务部门通常会直接封杀，存在合规风险。</p><blockquote><p>收费的是 Docker Desktop 这个 GUI 应用，Docker Engine 本身仍是 Apache 2.0 开源免费，这个区别很重要。</p></blockquote><h3 id="Podman-on-Windows-——-理想丰满，现实骨感"><a href="#Podman-on-Windows-——-理想丰满，现实骨感" class="headerlink" title="Podman on Windows —— 理想丰满，现实骨感"></a>Podman on Windows —— 理想丰满，现实骨感</h3><p>Podman 的核心优势（Daemonless、Rootless、OCI 兼容、与 systemd 深度集成）在 Linux 上非常突出，但在 Windows 上需要通过 Podman Machine（QEMU&#x2F;WSL2 VM）运行：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Windows 命令行</span><br><span class="line">      ↓</span><br><span class="line">Podman CLI (Windows)</span><br><span class="line">      ↓</span><br><span class="line">Podman Machine (QEMU/WSL2 VM)</span><br><span class="line">      ↓</span><br><span class="line">Linux 内核</span><br><span class="line">      ↓</span><br><span class="line">Container</span><br></pre></td></tr></table></figure><p>这层 VM 抽象带来了一系列实际问题：Volume 挂载路径转换不稳定、Machine 启动偶尔卡死、rootless 在 VM 下端口绑定受限（&lt;1024 失败）、Docker Compose 生态兼容性存在缺口。Podman 的主战场是 Linux，在 Windows 上使用需要接受这些 trade-off。</p><h3 id="Rancher-Desktop-——-看似全能，实则复杂"><a href="#Rancher-Desktop-——-看似全能，实则复杂" class="headerlink" title="Rancher Desktop —— 看似全能，实则复杂"></a>Rancher Desktop —— 看似全能，实则复杂</h3><p>Rancher Desktop Apache 2.0 完全开源，SUSE 背书，支持 containerd&#x2F;dockerd 切换。但实际使用中存在几个痛点：</p><ul><li>默认 CLI 是 nerdctl，虽语法基本兼容，但细节有差异</li><li>镜像存储与 Docker 完全隔离，与其他工具链不互通</li><li>同样运行 Linux VM（Lima），资源占用与 Docker Desktop 相当</li><li>国内网络加速需要手动修改配置文件，没有简单 GUI 入口</li></ul><p>对于习惯命令行的工程师，Rancher Desktop 的 GUI 价值有限，反而增加了一层复杂度。</p><hr><h2 id="推荐方案：WSL2-Docker-Engine"><a href="#推荐方案：WSL2-Docker-Engine" class="headerlink" title="推荐方案：WSL2 + Docker Engine"></a>推荐方案：WSL2 + Docker Engine</h2><p>这是目前 Windows 上跑容器最干净、最稳定、零授权风险的方案。</p><h3 id="架构原理"><a href="#架构原理" class="headerlink" title="架构原理"></a>架构原理</h3><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Windows Terminal / PowerShell</span><br><span class="line">          ↓</span><br><span class="line">    WSL2 (Linux 内核)</span><br><span class="line">          ↓</span><br><span class="line">   Docker Engine (dockerd)</span><br><span class="line">          ↓</span><br><span class="line">      Container</span><br></pre></td></tr></table></figure><p>Docker Engine 直接运行在 WSL2 的 Linux 内核上，没有额外的 VM 抽象层，性能和稳定性接近原生 Linux。</p><h3 id="方案对比总结"><a href="#方案对比总结" class="headerlink" title="方案对比总结"></a>方案对比总结</h3><table><thead><tr><th>维度</th><th>Docker Desktop</th><th>Podman</th><th>Rancher Desktop</th><th><strong>WSL2 + Docker Engine</strong></th></tr></thead><tbody><tr><td>授权风险</td><td>大公司需付费</td><td>免费</td><td>免费</td><td><strong>零风险</strong></td></tr><tr><td>Windows 稳定性</td><td>好</td><td>差</td><td>一般</td><td><strong>好</strong></td></tr><tr><td>Docker 生态兼容</td><td>完整</td><td>需配置</td><td>需切换</td><td><strong>完整</strong></td></tr><tr><td>Compose 支持</td><td>原生</td><td>兼容层</td><td>兼容层</td><td><strong>原生</strong></td></tr><tr><td>资源占用</td><td>高</td><td>高</td><td>高</td><td><strong>低</strong></td></tr><tr><td>配置复杂度</td><td>低</td><td>高</td><td>中</td><td>中（一次性）</td></tr><tr><td>适合人群</td><td>通用</td><td>Linux 用户</td><td>GUI 需求者</td><td><strong>DevOps &#x2F; 命令行</strong></td></tr></tbody></table><hr><h2 id="完整配置步骤"><a href="#完整配置步骤" class="headerlink" title="完整配置步骤"></a>完整配置步骤</h2><h3 id="Step-1：启用-WSL2"><a href="#Step-1：启用-WSL2" class="headerlink" title="Step 1：启用 WSL2"></a>Step 1：启用 WSL2</h3><p>以管理员身份打开 PowerShell：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 启用 WSL 和虚拟机平台</span></span><br><span class="line">dism.exe /online /<span class="built_in">enable-feature</span> /featurename:Microsoft<span class="literal">-Windows-Subsystem-Linux</span> /all /norestart</span><br><span class="line">dism.exe /online /<span class="built_in">enable-feature</span> /featurename:VirtualMachinePlatform /all /norestart</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重启电脑后，设置 WSL 默认版本为 2</span></span><br><span class="line">wsl <span class="literal">--set-default-version</span> <span class="number">2</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 Ubuntu（或 Kali，按需选择）</span></span><br><span class="line">wsl <span class="literal">--install</span> <span class="literal">-d</span> Ubuntu<span class="literal">-22</span>.<span class="number">04</span></span><br></pre></td></tr></table></figure><p>验证安装：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">wsl <span class="literal">--list</span> <span class="literal">--verbose</span></span><br><span class="line"><span class="comment"># NAME            STATE           VERSION</span></span><br><span class="line"><span class="comment"># Ubuntu-22.04    Running         2      ← 确认是 VERSION 2</span></span><br></pre></td></tr></table></figure><h3 id="Step-2：WSL2-资源限制（可选但推荐）"><a href="#Step-2：WSL2-资源限制（可选但推荐）" class="headerlink" title="Step 2：WSL2 资源限制（可选但推荐）"></a>Step 2：WSL2 资源限制（可选但推荐）</h3><p>默认 WSL2 会吃掉大量内存，在 <code>C:\Users\&lt;你的用户名&gt;\.wslconfig</code> 创建配置文件：</p><figure class="highlight ini"><table><tr><td class="code"><pre><span class="line"><span class="section">[wsl2]</span></span><br><span class="line"><span class="attr">memory</span>=<span class="number">4</span>GB          <span class="comment"># 限制最大内存，根据你的机器调整</span></span><br><span class="line"><span class="attr">processors</span>=<span class="number">4</span>        <span class="comment"># 限制 CPU 核心数</span></span><br><span class="line"><span class="attr">swap</span>=<span class="number">2</span>GB</span><br><span class="line"><span class="attr">localhostForwarding</span>=<span class="literal">true</span>   <span class="comment"># 允许 Windows 通过 localhost 访问 WSL2 端口</span></span><br></pre></td></tr></table></figure><p>修改后重启 WSL2：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">wsl <span class="literal">--shutdown</span></span><br><span class="line">wsl</span><br></pre></td></tr></table></figure><h3 id="Step-3：在-WSL2-里安装-Docker-Engine"><a href="#Step-3：在-WSL2-里安装-Docker-Engine" class="headerlink" title="Step 3：在 WSL2 里安装 Docker Engine"></a>Step 3：在 WSL2 里安装 Docker Engine</h3><p>进入 WSL2 终端：</p><figure class="highlight bash"><table><tr><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 2&gt;/dev/null</span><br><span class="line"></span><br><span class="line"><span class="comment"># 删掉损坏的 key 和源</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">rm</span> -f /etc/apt/keyrings/docker.gpg</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">rm</span> -f /etc/apt/sources.list.d/docker.list</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> install -m 0755 -d /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"># 验证 key 是否正常</span></span><br><span class="line"><span class="built_in">sudo</span> gpg --dry-run --quiet --import --import-options import-show /etc/apt/keyrings/docker.gpg</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加 Docker 软件源</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></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="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><span class="line"></span><br><span class="line"><span class="comment"># 启动 Docker</span></span><br><span class="line"><span class="built_in">sudo</span> service docker start</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证</span></span><br><span class="line">docker run hello-world</span><br></pre></td></tr></table></figure><p><strong>让 Docker 随 WSL2 自动启动</strong>，在 <code>~/.bashrc</code> 或 <code>~/.zshrc</code> 末尾添加：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Auto-start Docker daemon in WSL2</span></span><br><span class="line"><span class="keyword">if</span> [ <span class="string">&quot;<span class="subst">$(service docker status 2&gt;&amp;1 | grep -c &#x27;not running&#x27;)</span>&quot;</span> -eq 1 ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">sudo</span> service docker start &gt; /dev/null 2&gt;&amp;1</span><br><span class="line"><span class="keyword">fi</span></span><br></pre></td></tr></table></figure><h3 id="Step-4：配置代理（国内使用关键一步）"><a href="#Step-4：配置代理（国内使用关键一步）" class="headerlink" title="Step 4：配置代理（国内使用关键一步）"></a>Step 4：配置代理（国内使用关键一步）</h3><p>WSL2 有自己的网络栈，不会自动继承 Windows 的代理设置。</p><p><strong>找到 Windows 宿主机的 IP（WSL2 网关）：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 方法一</span></span><br><span class="line"><span class="built_in">cat</span> /etc/resolv.conf | grep nameserver | awk <span class="string">&#x27;&#123;print $2&#125;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 方法二</span></span><br><span class="line">ip route | grep default | awk <span class="string">&#x27;&#123;print $3&#125;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 通常输出类似 172.x.x.1</span></span><br></pre></td></tr></table></figure><p><strong>在 <code>~/.bashrc</code> 或 <code>~/.zshrc</code> 里添加代理配置：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># WSL2 Proxy Configuration</span></span><br><span class="line">WINDOWS_HOST=$(<span class="built_in">cat</span> /etc/resolv.conf | grep nameserver | awk <span class="string">&#x27;&#123;print $2&#125;&#x27;</span>)</span><br><span class="line">PROXY_PORT=7890   <span class="comment"># 替换成你的代理端口</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">export</span> http_proxy=<span class="string">&quot;http://<span class="variable">$&#123;WINDOWS_HOST&#125;</span>:<span class="variable">$&#123;PROXY_PORT&#125;</span>&quot;</span></span><br><span class="line"><span class="built_in">export</span> https_proxy=<span class="string">&quot;http://<span class="variable">$&#123;WINDOWS_HOST&#125;</span>:<span class="variable">$&#123;PROXY_PORT&#125;</span>&quot;</span></span><br><span class="line"><span class="built_in">export</span> no_proxy=<span class="string">&quot;localhost,127.0.0.1,::1&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Git 代理</span></span><br><span class="line">git config --global http.proxy <span class="string">&quot;http://<span class="variable">$&#123;WINDOWS_HOST&#125;</span>:<span class="variable">$&#123;PROXY_PORT&#125;</span>&quot;</span></span><br><span class="line">git config --global https.proxy <span class="string">&quot;http://<span class="variable">$&#123;WINDOWS_HOST&#125;</span>:<span class="variable">$&#123;PROXY_PORT&#125;</span>&quot;</span></span><br></pre></td></tr></table></figure><p><strong>给 Docker Daemon 单独配置代理</strong>（docker pull 走 daemon，不走 shell 环境变量）：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/systemd/system/docker.service.d</span><br><span class="line"></span><br><span class="line"><span class="built_in">cat</span> &gt; /etc/systemd/system/docker.service.d/proxy.conf &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line">[Service]</span><br><span class="line">Environment=<span class="string">&quot;HTTP_PROXY=http://&lt;WSL2_GATEWAY_IP&gt;:&lt;PROXY_PORT&gt;&quot;</span></span><br><span class="line">Environment=<span class="string">&quot;HTTPS_PROXY=http://&lt;WSL2_GATEWAY_IP&gt;:&lt;PROXY_PORT&gt;&quot;</span></span><br><span class="line">Environment=<span class="string">&quot;NO_PROXY=localhost,127.0.0.1&quot;</span></span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line"><span class="comment"># WSL2 里没有 systemd，用 service 重启</span></span><br><span class="line"><span class="built_in">sudo</span> service docker restart</span><br></pre></td></tr></table></figure><blockquote><p>将 <code>&lt;WSL2_GATEWAY_IP&gt;</code> 替换为上一步获取到的 WSL2 网关 IP，<code>&lt;PROXY_PORT&gt;</code> 替换为你的代理工具实际端口。</p></blockquote><p><strong>WSL2 里三套代理互不相干，都要单独配：</strong></p><table><thead><tr><th>作用域</th><th>配置方式</th><th>用途</th></tr></thead><tbody><tr><td>Shell</td><td><code>export http_proxy=...</code></td><td>curl &#x2F; wget &#x2F; git</td></tr><tr><td>apt</td><td><code>/etc/apt/apt.conf.d/proxy.conf</code></td><td>apt install</td></tr><tr><td>Docker daemon</td><td><code>/etc/systemd/system/docker.service.d/proxy.conf</code></td><td>docker pull</td></tr></tbody></table><p><strong>apt 代理配置示例：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cat</span> &gt; /etc/apt/apt.conf.d/proxy.conf &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line">Acquire::http::Proxy <span class="string">&quot;http://&lt;WSL2_GATEWAY_IP&gt;:&lt;PROXY_PORT&gt;&quot;</span>;</span><br><span class="line">Acquire::https::Proxy <span class="string">&quot;http://&lt;WSL2_GATEWAY_IP&gt;:&lt;PROXY_PORT&gt;&quot;</span>;</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><p><strong>Git 精准代理（只代理 GitHub，国内仓库不受影响）：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">git config --global http.https://github.com.proxy http://&lt;WSL2_GATEWAY_IP&gt;:&lt;PROXY_PORT&gt;</span><br></pre></td></tr></table></figure><h3 id="Step-5：配置镜像加速（代理-Fallback）"><a href="#Step-5：配置镜像加速（代理-Fallback）" class="headerlink" title="Step 5：配置镜像加速（代理 Fallback）"></a>Step 5：配置镜像加速（代理 Fallback）</h3><p>如果代理不稳定，配置镜像加速作为备用：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/docker/daemon.json &gt; /dev/null &lt;&lt;<span class="string">EOF</span></span><br><span class="line"><span class="string">&#123;</span></span><br><span class="line"><span class="string">  &quot;registry-mirrors&quot;: [</span></span><br><span class="line"><span class="string">    &quot;https://docker.1panel.live&quot;,</span></span><br><span class="line"><span class="string">    &quot;https://hub.rat.dev&quot;,</span></span><br><span class="line"><span class="string">    &quot;https://dockerpull.com&quot;</span></span><br><span class="line"><span class="string">  ],</span></span><br><span class="line"><span class="string">  &quot;log-driver&quot;: &quot;json-file&quot;,</span></span><br><span class="line"><span class="string">  &quot;log-opts&quot;: &#123;</span></span><br><span class="line"><span class="string">    &quot;max-size&quot;: &quot;10m&quot;,</span></span><br><span class="line"><span class="string">    &quot;max-file&quot;: &quot;3&quot;</span></span><br><span class="line"><span class="string">  &#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">sudo</span> service docker restart</span><br><span class="line">docker info | grep -A5 <span class="string">&quot;Registry Mirrors&quot;</span></span><br></pre></td></tr></table></figure><h3 id="Step-6：配置-VSCode-Remote-WSL"><a href="#Step-6：配置-VSCode-Remote-WSL" class="headerlink" title="Step 6：配置 VSCode Remote WSL"></a>Step 6：配置 VSCode Remote WSL</h3><p>安装 VSCode 插件：</p><ul><li><code>ms-vscode-remote.remote-wsl</code></li><li><code>ms-vscode-remote.vscode-remote-extensionpack</code></li></ul><p>使用方式：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 在 WSL2 终端里直接打开项目</span></span><br><span class="line"><span class="built_in">cd</span> ~/projects/my-app</span><br><span class="line">code .    <span class="comment"># VSCode 自动以 Remote WSL 模式打开</span></span><br></pre></td></tr></table></figure><p>VSCode 在 Remote WSL 模式下，终端、文件系统、Git、调试器全部运行在 Linux 环境里，体验和本地 Linux 开发一致。</p><hr><h2 id="可选：Portainer-——-需要-GUI-时的选择"><a href="#可选：Portainer-——-需要-GUI-时的选择" class="headerlink" title="可选：Portainer —— 需要 GUI 时的选择"></a>可选：Portainer —— 需要 GUI 时的选择</h2><p>如果偶尔需要可视化管理容器和镜像，可以部署 Portainer：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker volume create portainer_data</span><br><span class="line"></span><br><span class="line">docker run -d \</span><br><span class="line">  --name portainer \</span><br><span class="line">  --restart always \</span><br><span class="line">  -p 9000:9000 \</span><br><span class="line">  -v /var/run/docker.sock:/var/run/docker.sock \</span><br><span class="line">  -v portainer_data:/data \</span><br><span class="line">  portainer/portainer-ce:latest</span><br></pre></td></tr></table></figure><p>浏览器打开 <code>http://localhost:9000</code>，即可获得完整的容器、镜像、Volume、网络管理界面。</p><hr><h2 id="最终工作流"><a href="#最终工作流" class="headerlink" title="最终工作流"></a>最终工作流</h2><p>配置完成后，日常使用：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 打开 Windows Terminal，切换到 WSL2</span></span><br><span class="line"><span class="comment"># 或直接在 VSCode Remote WSL 终端里操作</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 拉镜像</span></span><br><span class="line">docker pull postgres:16-alpine</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><span class="line"></span><br><span class="line"><span class="comment"># 看日志</span></span><br><span class="line">docker compose logs -f app</span><br><span class="line"></span><br><span class="line"><span class="comment"># 清理</span></span><br><span class="line">docker system prune -af</span><br></pre></td></tr></table></figure><p>体验和纯 Linux 环境操作没有本质区别。</p><hr><h2 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h2><p>Windows 上做容器开发，核心矛盾是 Windows 环境与 Linux-native 技术栈之间的阻抗失配。各种工具本质上都是在填这个坑：</p><ul><li><strong>Docker Desktop</strong>：填得最好，但要钱</li><li><strong>Podman &#x2F; Rancher Desktop</strong>：免费，但填得不够平整</li><li><strong>WSL2 + Docker Engine</strong>：绕过这个坑，直接在 Linux 里跑</li></ul><p>对于习惯命令行的工程师，GUI 是可选项而非必选项。这套方案一次配置，长期受益，没有授权风险，没有额外的抽象层，就是在 Windows 上搭了一个干净的 Linux 容器环境。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;容器技术本质上是 Linux-native 的，依赖 cgroups、namespaces、overlayfs 等内核特性，而 Windows 内核并不具备这些能力。因此所有在 Windows 上运行容器的方案，本质上都是在解决”如何在 Windows 上运行 Linux”这个问题。本文对比主流方案的优劣，并提供一套基于 WSL2 + Docker Engine 的稳定、免费、零授权风险的实践配置。&lt;/p&gt;</summary>
    
    
    
    <category term="DevOps" scheme="https://freemankevin.uk/categories/DevOps/"/>
    
    <category term="Container" scheme="https://freemankevin.uk/categories/DevOps/Container/"/>
    
    
    <category term="DevOps" scheme="https://freemankevin.uk/tags/DevOps/"/>
    
    <category term="Docker" scheme="https://freemankevin.uk/tags/Docker/"/>
    
    <category term="Windows" scheme="https://freemankevin.uk/tags/Windows/"/>
    
    <category term="Container" scheme="https://freemankevin.uk/tags/Container/"/>
    
    <category term="WSL2" scheme="https://freemankevin.uk/tags/WSL2/"/>
    
  </entry>
  
  <entry>
    <title>Nexus Repository Manager 启动失败排查全记录</title>
    <link href="https://freemankevin.uk/2026/05/11/nexus-troubleshooting/"/>
    <id>https://freemankevin.uk/2026/05/11/nexus-troubleshooting/</id>
    <published>2026-05-11T03:00:00.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p>某天早上收到告警，Nexus 制品仓库无法访问。登录服务器检查，systemd 报告服务状态正常，实则 Java 进程根本不存在，端口未监听。本文记录完整的排查与修复过程。</p><span id="more"></span><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ systemctl status nexus</span><br><span class="line">Active: active (exited)   <span class="comment"># 假正常</span></span><br><span class="line"></span><br><span class="line">$ ps aux | grep java | grep nexus</span><br><span class="line"><span class="comment"># 空，Java 进程不存在</span></span><br><span class="line"></span><br><span class="line">$ ss -tlnp | grep 8081</span><br><span class="line"><span class="comment"># 空，端口未监听</span></span><br><span class="line"></span><br><span class="line">$ curl -s -o /dev/null -w <span class="string">&quot;%&#123;http_code&#125;&quot;</span> http://localhost:8081</span><br><span class="line">000  <span class="comment"># 连接拒绝</span></span><br></pre></td></tr></table></figure><p><code>active (exited)</code> 是 init.d 风格的 SysV 脚本包装下的常见假象——启动脚本执行完就退出了，但它拉起的 Java 进程随后悄悄崩溃，systemd 毫无感知。</p><hr><h2 id="排查过程"><a href="#排查过程" class="headerlink" title="排查过程"></a>排查过程</h2><h3 id="第一步：定位真实安装路径"><a href="#第一步：定位真实安装路径" class="headerlink" title="第一步：定位真实安装路径"></a>第一步：定位真实安装路径</h3><p>Nexus 并未安装在默认路径，需要先找到实际位置：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cat</span> /etc/rc.d/init.d/nexus | grep -E <span class="string">&#x27;NEXUS_HOME|data-dir|work&#x27;</span></span><br><span class="line">find / -name <span class="string">&quot;sonatype-work&quot;</span> -<span class="built_in">type</span> d 2&gt;/dev/null</span><br></pre></td></tr></table></figure><p>确认路径：</p><ul><li>程序目录：<code>/opt/nexus/nexus-3.19.1-01</code></li><li>数据目录：<code>/data/nexus/sonatype-work/nexus3</code></li></ul><h3 id="第二步：查看应用日志"><a href="#第二步：查看应用日志" class="headerlink" title="第二步：查看应用日志"></a>第二步：查看应用日志</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">tail</span> -n 100 /data/nexus/sonatype-work/nexus3/log/nexus.log</span><br></pre></td></tr></table></figure><p>日志只有 WARN 级别的 SSL 错误，全是 <code>maven-osgeo</code> 代理仓库的 <code>SSLHandshakeException</code>，没有 ERROR 或启动失败的痕迹。说明这次崩溃发生在日志系统初始化<strong>之后</strong>但写入<strong>之前</strong>，或者是更深层的问题。</p><h3 id="第三步：前台运行，直接看报错"><a href="#第三步：前台运行，直接看报错" class="headerlink" title="第三步：前台运行，直接看报错"></a>第三步：前台运行，直接看报错</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">su - nexus -s /bin/bash -c <span class="string">&quot;/opt/nexus/nexus-3.19.1-01/bin/nexus run&quot;</span> 2&gt;&amp;1 | <span class="built_in">head</span> -50</span><br></pre></td></tr></table></figure><p>终端立即出现关键错误：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">ERROR - java.io.FileNotFoundException:</span><br><span class="line">  /data/nexus/sonatype-work/nexus3/db/component/component.24003.wal</span><br><span class="line">  (Permission denied)</span><br><span class="line"></span><br><span class="line">ERROR - Cannot open local storage &#x27;/data/nexus/sonatype-work/nexus3/db/component&#x27; with mode=rw</span><br></pre></td></tr></table></figure><p><strong>根因找到</strong>：OrientDB 的 WAL（Write-Ahead Log）文件权限异常，nexus 用户无法写入。</p><h3 id="第四步：验证权限问题"><a href="#第四步：验证权限问题" class="headerlink" title="第四步：验证权限问题"></a>第四步：验证权限问题</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">ls</span> -la /data/nexus/sonatype-work/nexus3/db/component/*.wal</span><br><span class="line"><span class="comment"># -rw-r--r-- 1 nexus nexus ...   ← 644，nexus 用户只有读权限</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">ls</span> -la /data/nexus/sonatype-work/nexus3/db/config/*.wal</span><br><span class="line"><span class="comment"># -rw-r--r-- 1 nexus nexus ...   ← 同样是 644</span></span><br></pre></td></tr></table></figure><p>OrientDB 需要对 WAL 文件有<strong>写权限</strong>才能以 <code>rw</code> 模式打开存储。</p><hr><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>1</td><td>WAL 文件 Permission Denied</td><td>某次 root 用户直接操作了 db 目录（备份、手动修复等），导致文件归属或权限被改写</td></tr><tr><td>2</td><td>lock &#x2F; karaf.pid 残留</td><td>上次异常退出未正常清理锁文件，Nexus 启动时认为实例已运行，直接退出</td></tr><tr><td>3</td><td>systemd 无法追踪进程</td><td>使用 <code>Type=forking</code> + PIDFile，但 Nexus 写 PID 文件有延迟，systemd 判定启动失败并触发 Restart 循环</td></tr></tbody></table><hr><h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><h3 id="修复一：恢复数据库文件权限"><a href="#修复一：恢复数据库文件权限" class="headerlink" title="修复一：恢复数据库文件权限"></a>修复一：恢复数据库文件权限</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 递归修复所有文件归属</span></span><br><span class="line"><span class="built_in">chown</span> -R nexus:nexus /data/nexus/sonatype-work/nexus3/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 修复目录和文件权限</span></span><br><span class="line">find /data/nexus/sonatype-work/nexus3/db -<span class="built_in">type</span> d -<span class="built_in">exec</span> <span class="built_in">chmod</span> 755 &#123;&#125; \;</span><br><span class="line">find /data/nexus/sonatype-work/nexus3/db -<span class="built_in">type</span> f -<span class="built_in">exec</span> <span class="built_in">chmod</span> 664 &#123;&#125; \;</span><br></pre></td></tr></table></figure><h3 id="修复二：清理残留锁文件"><a href="#修复二：清理残留锁文件" class="headerlink" title="修复二：清理残留锁文件"></a>修复二：清理残留锁文件</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">rm</span> -f /data/nexus/sonatype-work/nexus3/lock</span><br><span class="line"><span class="built_in">rm</span> -f /data/nexus/sonatype-work/nexus3/karaf.pid</span><br><span class="line"><span class="built_in">rm</span> -f /data/nexus/sonatype-work/nexus3/port</span><br></pre></td></tr></table></figure><h3 id="修复三：重写为原生-systemd-服务"><a href="#修复三：重写为原生-systemd-服务" class="headerlink" title="修复三：重写为原生 systemd 服务"></a>修复三：重写为原生 systemd 服务</h3><p>原来的 init.d 包装脚本有两个核心缺陷：</p><ul><li>systemd 无法感知实际的 Java 进程状态</li><li><code>Type=forking</code> 依赖 PID 文件时序，不稳定</li></ul><p><strong>正确做法</strong>：使用 <code>Type=simple</code> + <code>nexus run</code>（前台模式），让 systemd 直接管理 Java 进程。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 禁用旧的 init.d 服务</span></span><br><span class="line">chkconfig nexus off</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建原生 systemd unit 文件</span></span><br><span class="line"><span class="built_in">cat</span> &gt; /etc/systemd/system/nexus.service &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line">[Unit]</span><br><span class="line">Description=Sonatype Nexus Repository Manager</span><br><span class="line">After=network.target</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">Type=simple</span><br><span class="line">LimitNOFILE=65536</span><br><span class="line">User=nexus</span><br><span class="line">Group=nexus</span><br><span class="line">Environment=JAVA_HOME=/opt/jdk1.8.0_74</span><br><span class="line"></span><br><span class="line"><span class="comment"># 每次启动前自动清理残留锁文件</span></span><br><span class="line">ExecStartPre=/bin/bash -c <span class="string">&quot;rm -f /data/nexus/sonatype-work/nexus3/lock \</span></span><br><span class="line"><span class="string">  /data/nexus/sonatype-work/nexus3/karaf.pid \</span></span><br><span class="line"><span class="string">  /data/nexus/sonatype-work/nexus3/port&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用 run 以前台方式运行，systemd 可直接追踪进程</span></span><br><span class="line">ExecStart=/opt/nexus/nexus-3.19.1-01/bin/nexus run</span><br><span class="line">ExecStop=/opt/nexus/nexus-3.19.1-01/bin/nexus stop</span><br><span class="line"></span><br><span class="line"><span class="comment"># 异常退出后自动重启</span></span><br><span class="line">Restart=on-failure</span><br><span class="line">RestartSec=30</span><br><span class="line">TimeoutStartSec=300</span><br><span class="line">TimeoutStopSec=120</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</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">systemctl daemon-reload</span><br><span class="line">systemctl <span class="built_in">enable</span> nexus   <span class="comment"># 开机自启</span></span><br><span class="line">systemctl start nexus</span><br></pre></td></tr></table></figure><hr><h2 id="验证结果"><a href="#验证结果" class="headerlink" title="验证结果"></a>验证结果</h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ systemctl status nexus</span><br><span class="line">● nexus.service - Sonatype Nexus Repository Manager</span><br><span class="line">   Active: active (running) since Thu 2026-05-07 11:06:19 CST</span><br><span class="line">   Main PID: 28549 (java)        <span class="comment"># 真实 Java 进程</span></span><br><span class="line">   Memory: 3.1G</span><br><span class="line"></span><br><span class="line">$ ss -tlnp | grep 8081</span><br><span class="line">LISTEN  0  50  *:8081  *:*  <span class="built_in">users</span>:((&quot;java&quot;,pid=<span class="number">28549</span>,fd=<span class="number">953</span>))</span><br><span class="line"></span><br><span class="line">$ curl -s -o /dev/null -w <span class="string">&quot;%&#123;http_code&#125;&quot;</span> http://localhost:8081</span><br><span class="line">200</span><br></pre></td></tr></table></figure><hr><h2 id="遗留优化：SSL-证书问题"><a href="#遗留优化：SSL-证书问题" class="headerlink" title="遗留优化：SSL 证书问题"></a>遗留优化：SSL 证书问题</h2><p>服务恢复后，日志中仍持续出现 <code>maven-osgeo</code> 代理仓库的 SSL 错误：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">SSLHandshakeException: PKIX path building failed</span><br><span class="line">→ unable to find valid certification path to requested target</span><br></pre></td></tr></table></figure><p>原因是 JDK 1.8.0_74（2016年构建）的信任链中没有 <code>repo.osgeo.org</code> 的新证书。</p><p><strong>方案 A（推荐）</strong>：在 Web UI 中将 <code>maven-osgeo</code> 的 Remote URL 替换为可用镜像，或直接禁用该仓库。</p><p><strong>方案 B</strong>：手动将证书导入 JDK 信任库：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">openssl s_client -connect repo.osgeo.org:443 -showcerts &lt;/dev/null 2&gt;/dev/null \</span><br><span class="line">  | openssl x509 -outform PEM &gt; /tmp/osgeo.crt</span><br><span class="line"></span><br><span class="line">/opt/jdk1.8.0_74/bin/keytool -import \</span><br><span class="line">  -<span class="built_in">alias</span> osgeo-cert \</span><br><span class="line">  -keystore /opt/jdk1.8.0_74/jre/lib/security/cacerts \</span><br><span class="line">  -file /tmp/osgeo.crt \</span><br><span class="line">  -storepass changeit -noprompt</span><br><span class="line"></span><br><span class="line">systemctl restart nexus</span><br></pre></td></tr></table></figure><hr><h2 id="经验总结"><a href="#经验总结" class="headerlink" title="经验总结"></a>经验总结</h2><p><strong>排查思路</strong>：</p><ol><li><code>active (exited)</code> ≠ 服务正常，必须验证实际进程和端口</li><li>应用日志没有新内容时，用前台运行模式（<code>run</code>）直接看终端输出</li><li><code>Permission Denied</code> 类错误优先检查文件归属，而非权限位</li></ol><p><strong>防御措施</strong>：</p><ul><li>任何对 Nexus 数据目录的运维操作，完成后必须执行 <code>chown -R nexus:nexus</code></li><li>将 SysV init.d 服务迁移为原生 systemd unit，获得真实的进程生命周期管理</li><li><code>ExecStartPre</code> 自动清理锁文件，消除异常重启后的残留问题</li><li>定期检查 <code>systemctl status nexus</code> 是否真的有 <code>Main PID</code></li></ul><hr><p><em>排查日期：2026-05-07</em><br><em>环境：CentOS 7.6 &#x2F; Nexus OSS 3.19.1-01 &#x2F; JDK 1.8.0_74</em></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;某天早上收到告警，Nexus 制品仓库无法访问。登录服务器检查，systemd 报告服务状态正常，实则 Java 进程根本不存在，端口未监听。本文记录完整的排查与修复过程。&lt;/p&gt;</summary>
    
    
    
    <category term="DevOps" scheme="https://freemankevin.uk/categories/DevOps/"/>
    
    
    <category term="Nexus" scheme="https://freemankevin.uk/tags/Nexus/"/>
    
    <category term="Troubleshooting" scheme="https://freemankevin.uk/tags/Troubleshooting/"/>
    
    <category term="Java" scheme="https://freemankevin.uk/tags/Java/"/>
    
    <category term="systemd" scheme="https://freemankevin.uk/tags/systemd/"/>
    
  </entry>
  
  <entry>
    <title>Jenkins Slave 节点重建后 SSH 认证失败的排查与恢复</title>
    <link href="https://freemankevin.uk/2026/05/11/jenkins-slave-ssh-auth-recovery/"/>
    <id>https://freemankevin.uk/2026/05/11/jenkins-slave-ssh-auth-recovery/</id>
    <published>2026-05-11T02:00:00.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p>生产服务器意外崩溃，重新申请了相同 IP 的机器并重做了免密登录，但 Jenkins slave 节点持续离线，日志显示 SSH 认证失败。本文记录完整的排查与恢复过程。</p><span id="more"></span><h2 id="问题现象"><a href="#问题现象" class="headerlink" title="问题现象"></a>问题现象</h2><p>打开 Jenkins → Nodes → slave-01 → Log，看到如下循环报错：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">[05/07/26 17:11:54] [SSH] Opening SSH connection to 10.0.0.10:22.</span><br><span class="line">Searching for 10.0.0.10 in /root/.ssh/known_hosts</span><br><span class="line">Searching for 10.0.0.10:22 in /root/.ssh/known_hosts</span><br><span class="line">[05/07/26 17:11:54] [SSH] SSH host key matches key in Known Hosts file.</span><br><span class="line">ERROR: Failed to authenticate as root. Wrong password.</span><br><span class="line">(credentialId:jenkins-slave-01/method:password)</span><br><span class="line">[05/07/26 17:11:57] [SSH] Authentication failed.</span><br><span class="line">Authentication failed.</span><br><span class="line">[05/07/26 17:11:57] Launch failed – cleaning up connection</span><br><span class="line">[05/07/26 17:11:57] [SSH] Connection closed.</span><br></pre></td></tr></table></figure><p>节点状态显示为 <strong>offline</strong>，每隔几分钟自动重试，均以失败告终。</p><hr><h2 id="根因分析"><a href="#根因分析" class="headerlink" title="根因分析"></a>根因分析</h2><p>很多人第一反应是”新机器缺少 Java 环境”，但仔细阅读日志，<strong>连接在认证阶段就已失败</strong>，根本没有到达 JVM 启动环节。</p><p>真正的问题链条如下：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">旧机器崩溃</span><br><span class="line">    ↓</span><br><span class="line">新机器申请（相同 IP：10.0.0.10）</span><br><span class="line">    ↓</span><br><span class="line">重做了系统层面的 SSH 免密（authorized_keys）</span><br><span class="line">    ↓</span><br><span class="line">但 Jenkins 的 Credential 存储的是「密码」而非「SSH Key」</span><br><span class="line">    ↓</span><br><span class="line">新机器 root 密码 ≠ Jenkins 存储的旧密码</span><br><span class="line">    ↓</span><br><span class="line">认证失败，节点无法上线</span><br></pre></td></tr></table></figure><p>关键日志特征：<code>method:password</code> —— 说明 Jenkins 走的是密码认证，不是 SSH Key 认证，所以手动配的免密对 Jenkins 完全没有生效。</p><hr><h2 id="完整恢复步骤"><a href="#完整恢复步骤" class="headerlink" title="完整恢复步骤"></a>完整恢复步骤</h2><h3 id="Step-1-—-验证网络和-SSH-基础连通性"><a href="#Step-1-—-验证网络和-SSH-基础连通性" class="headerlink" title="Step 1 — 验证网络和 SSH 基础连通性"></a>Step 1 — 验证网络和 SSH 基础连通性</h3><p>先在 Jenkins Master 上确认能正常 SSH 登录新机器：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ssh root@10.0.0.10</span><br></pre></td></tr></table></figure><p>如果提示 <code>WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED</code>，说明新机器的主机指纹和 <code>known_hosts</code> 里的旧记录冲突，需要先清理：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 删除旧指纹</span></span><br><span class="line">ssh-keygen -R 10.0.0.10</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重新连接，接受新指纹</span></span><br><span class="line">ssh root@10.0.0.10</span><br></pre></td></tr></table></figure><blockquote><p>这一步经常被忽略，但 Jenkins 的 <code>KnownHostsFileKeyVerificationStrategy</code> 依赖本机 known_hosts，指纹不匹配会导致连接直接被拒绝。</p></blockquote><hr><h3 id="Step-2-—-切换为-SSH-Key-认证（推荐，一劳永逸）"><a href="#Step-2-—-切换为-SSH-Key-认证（推荐，一劳永逸）" class="headerlink" title="Step 2 — 切换为 SSH Key 认证（推荐，一劳永逸）"></a>Step 2 — 切换为 SSH Key 认证（推荐，一劳永逸）</h3><p><strong>2.1 生成或复用 Jenkins Master 的密钥对</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 检查是否已有密钥</span></span><br><span class="line"><span class="built_in">ls</span> ~/.ssh/id_rsa</span><br><span class="line"></span><br><span class="line"><span class="comment"># 没有则生成</span></span><br><span class="line">ssh-keygen -t rsa -b 4096 -C <span class="string">&quot;jenkins-master&quot;</span> -f ~/.ssh/id_rsa -N <span class="string">&quot;&quot;</span></span><br></pre></td></tr></table></figure><p><strong>2.2 将公钥写入新 slave 机器</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ssh-copy-id root@10.0.0.10</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> ~/.ssh/id_rsa.pub | ssh root@10.0.0.10 \</span><br><span class="line">  <span class="string">&quot;mkdir -p ~/.ssh &amp;&amp; chmod 700 ~/.ssh &amp;&amp; cat &gt;&gt; ~/.ssh/authorized_keys &amp;&amp; chmod 600 ~/.ssh/authorized_keys&quot;</span></span><br></pre></td></tr></table></figure><p><strong>2.3 验证免密登录</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ssh -o PasswordAuthentication=no root@10.0.0.10 <span class="string">&quot;echo OK&quot;</span></span><br><span class="line"><span class="comment"># 输出 OK 则成功</span></span><br></pre></td></tr></table></figure><hr><h3 id="Step-3-—-更新-Jenkins-Credential"><a href="#Step-3-—-更新-Jenkins-Credential" class="headerlink" title="Step 3 — 更新 Jenkins Credential"></a>Step 3 — 更新 Jenkins Credential</h3><p>进入 Jenkins Web UI：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Manage Jenkins → Credentials → System → Global credentials</span><br><span class="line">→ 找到 jenkins-slave-01 → 点击修改</span><br></pre></td></tr></table></figure><p>将凭据类型从 <strong>Username with password</strong> 修改为 <strong>SSH Username with private key</strong>：</p><table><thead><tr><th>字段</th><th>值</th></tr></thead><tbody><tr><td>Kind</td><td>SSH Username with private key</td></tr><tr><td>Username</td><td>root</td></tr><tr><td>Private Key</td><td>选择 Enter directly，粘贴 <code>~/.ssh/id_rsa</code> 私钥内容</td></tr><tr><td>Passphrase</td><td>生成时设置了则填写，否则留空</td></tr></tbody></table><p>私钥内容获取：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cat</span> ~/.ssh/id_rsa</span><br><span class="line"><span class="comment"># 复制全部内容，包括 -----BEGIN/END----- 行</span></span><br></pre></td></tr></table></figure><hr><h3 id="Step-4-—-确认-slave-节点的-Java-环境"><a href="#Step-4-—-确认-slave-节点的-Java-环境" class="headerlink" title="Step 4 — 确认 slave 节点的 Java 环境"></a>Step 4 — 确认 slave 节点的 Java 环境</h3><p>认证问题解决后，Jenkins 会尝试通过 SSH 在 slave 上启动 agent。<br>查看 slave 节点的 Configure 页面，找到 <code>JavaPath</code> 配置项：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">/opt/jdk-17/bin/java</span><br></pre></td></tr></table></figure><p>在新机器上确认该路径存在：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">ls</span> /opt/jdk-17/bin/java</span><br><span class="line">java -version</span><br></pre></td></tr></table></figure><p>如果路径不存在，有两种处理方式：</p><p><strong>方式 A：安装 Java 到相同路径</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 下载对应版本的 JDK（以 Eclipse Temurin 为例）</span></span><br><span class="line">wget https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.15%2B6/OpenJDK17U-jdk_x64_linux_hotspot_17.0.15_6.tar.gz</span><br><span class="line"><span class="built_in">mkdir</span> -p /opt</span><br><span class="line"> tar -xzf OpenJDK17U-jdk_x64_linux_hotspot_17.0.15_6.tar.gz -C /opt/</span><br></pre></td></tr></table></figure><p><strong>方式 B：安装系统 Java 并更新 Jenkins 配置</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Ubuntu/Debian</span></span><br><span class="line">apt update &amp;&amp; apt install -y openjdk-17-jdk</span><br><span class="line"></span><br><span class="line"><span class="comment"># CentOS/RHEL</span></span><br><span class="line">yum install -y java-17-openjdk</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取实际路径</span></span><br><span class="line"><span class="built_in">which</span> java         <span class="comment"># 或 update-alternatives --list java</span></span><br></pre></td></tr></table></figure><p>然后在 Jenkins slave 节点 Configure → <code>JavaPath</code> 中填写新路径。</p><hr><h3 id="Step-5-—-重启-slave-节点连接"><a href="#Step-5-—-重启-slave-节点连接" class="headerlink" title="Step 5 — 重启 slave 节点连接"></a>Step 5 — 重启 slave 节点连接</h3><p>在 Jenkins slave 节点页面点击 <strong>Launch agent</strong> 或等待自动重试，观察 Log 输出：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">[SSH] Opening SSH connection to 10.0.0.10:22.</span><br><span class="line">[SSH] SSH host key matches key in Known Hosts file. Connection will be allowed.</span><br><span class="line">[SSH] Authentication successful.</span><br><span class="line">Remoting version: ...</span><br><span class="line">Agent successfully connected and online</span><br></pre></td></tr></table></figure><p>看到 <code>Authentication successful</code> 和 <code>online</code> 即恢复成功。</p><hr><h2 id="问题复盘"><a href="#问题复盘" class="headerlink" title="问题复盘"></a>问题复盘</h2><table><thead><tr><th>排查点</th><th>状态</th><th>说明</th></tr></thead><tbody><tr><td>网络连通性</td><td>正常</td><td>SSH 端口 22 正常</td></tr><tr><td>known_hosts 指纹</td><td>需清理</td><td>新机器指纹变更，旧记录需删除</td></tr><tr><td>Jenkins Credential 类型</td><td>根本原因</td><td>password 方式，密码与新机器不符</td></tr><tr><td>slave 上的 Java 环境</td><td>需确认</td><td>新机器需重新安装并确认路径一致</td></tr></tbody></table><hr><h2 id="经验总结"><a href="#经验总结" class="headerlink" title="经验总结"></a>经验总结</h2><p><strong>1. 优先使用 SSH Key 认证，而不是密码</strong></p><p>密码认证在机器重建时必然失效；SSH Key 认证只要提前同步公钥，重建后无需修改 Jenkins 任何配置。</p><p><strong>2. 机器重建后必须清理 known_hosts</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ssh-keygen -R &lt;ip&gt;</span><br></pre></td></tr></table></figure><p>这一步是 checklist 里必须有的一项，否则即使认证方式正确，指纹不匹配也会导致连接被拒绝。</p><p><strong>3. 将 slave 初始化写成脚本</strong></p><p>新机器上线时一键初始化，避免手工遗漏：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># jenkins-slave-init.sh</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">set</span> -e</span><br><span class="line"></span><br><span class="line">JAVA_INSTALL_DIR=<span class="string">&quot;/opt&quot;</span></span><br><span class="line">JENKINS_MASTER_PUBKEY=<span class="string">&quot;ssh-rsa AAAA... jenkins-master&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[1/4] Installing Java...&quot;</span></span><br><span class="line">apt update -qq &amp;&amp; apt install -y openjdk-17-jdk</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[2/4] Setting up SSH authorized_keys...&quot;</span></span><br><span class="line"><span class="built_in">mkdir</span> -p ~/.ssh &amp;&amp; <span class="built_in">chmod</span> 700 ~/.ssh</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;<span class="variable">$JENKINS_MASTER_PUBKEY</span>&quot;</span> &gt;&gt; ~/.ssh/authorized_keys</span><br><span class="line"><span class="built_in">chmod</span> 600 ~/.ssh/authorized_keys</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[3/4] Creating Jenkins workspace directory...&quot;</span></span><br><span class="line"><span class="built_in">mkdir</span> -p /data/jenkins/workspace</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;[4/4] Done. Java path: <span class="subst">$(which java)</span>&quot;</span></span><br><span class="line">java -version</span><br></pre></td></tr></table></figure><p><strong>4. 考虑使用 Jenkins Configuration as Code（JCasC）</strong></p><p>将 slave 节点配置纳入版本控制，机器重建后配置自动恢复，彻底消除人工操作失误的可能。</p><hr><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><span class="exturl" data-url="aHR0cHM6Ly9wbHVnaW5zLmplbmtpbnMuaW8vc3NoLXNsYXZlcy8=">Jenkins SSH Build Agents Plugin<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9hZG9wdGl1bS5uZXQvdGVtdXJpbi9yZWxlYXNlcy8=">Eclipse Temurin JDK Downloads<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9wbHVnaW5zLmplbmtpbnMuaW8vY29uZmlndXJhdGlvbi1hcy1jb2RlLw==">Jenkins Configuration as Code Plugin<i class="fa fa-external-link-alt"></i></span></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;生产服务器意外崩溃，重新申请了相同 IP 的机器并重做了免密登录，但 Jenkins slave 节点持续离线，日志显示 SSH 认证失败。本文记录完整的排查与恢复过程。&lt;/p&gt;</summary>
    
    
    
    <category term="DevOps" scheme="https://freemankevin.uk/categories/DevOps/"/>
    
    
    <category term="DevOps" scheme="https://freemankevin.uk/tags/DevOps/"/>
    
    <category term="Jenkins" scheme="https://freemankevin.uk/tags/Jenkins/"/>
    
    <category term="SSH" scheme="https://freemankevin.uk/tags/SSH/"/>
    
    <category term="Troubleshooting" scheme="https://freemankevin.uk/tags/Troubleshooting/"/>
    
  </entry>
  
  <entry>
    <title>Podman CLI on Windows 安装与配置指南</title>
    <link href="https://freemankevin.uk/2026/04/30/podman-windows-setup/"/>
    <id>https://freemankevin.uk/2026/04/30/podman-windows-setup/</id>
    <published>2026-04-30T06:51:00.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p>Podman 是 Docker 的开源替代方案，在 Windows 上通过 WSL2 虚拟机运行容器。本文档详细阐述 Podman on Windows 的完整部署流程，包括安装配置、代理设置、私有仓库信任、开机自启动及日常维护等关键环节，适用于需要在 Windows 环境下使用容器技术的开发与运维场景。</p><span id="more"></span><p><strong>适用版本与环境说明：</strong></p><ul><li>Podman: 5.x（本文示例版本）</li><li>操作系统: Windows 10&#x2F;11（需启用 WSL2）</li><li>代理软件: v2rayN（或其他支持局域网访问的代理）</li><li>私有仓库: Harbor（HTTP 或自签名证书）</li><li>更新日期: 2026-04-30（建议关注 Podman GitHub Releases）</li></ul><div class="note info"><p>Podman on Windows 通过 WSL2 虚拟机运行，与 Docker Desktop 的架构类似但无需付费许可。本文配置示例基于 Podman 5.x 版本，不同版本配置参数可能略有差异。</p></div><h2 id="Podman-架构概述"><a href="#Podman-架构概述" class="headerlink" title="Podman 架构概述"></a>Podman 架构概述</h2><h3 id="核心概念"><a href="#核心概念" class="headerlink" title="核心概念"></a>核心概念</h3><p>Podman on Windows 采用以下架构：</p><table><thead><tr><th>组件</th><th>功能</th><th>说明</th></tr></thead><tbody><tr><td>Podman CLI</td><td>命令行客户端</td><td>与 Docker CLI 命令兼容</td></tr><tr><td>Podman Machine</td><td>WSL2 虚拟机</td><td>容器运行环境</td></tr><tr><td>containerd</td><td>容器运行时</td><td>管理容器生命周期</td></tr><tr><td>crun&#x2F;runc</td><td>OCI 运行时</td><td>创建和运行容器</td></tr></tbody></table><h3 id="与-Docker-的差异"><a href="#与-Docker-的差异" class="headerlink" title="与 Docker 的差异"></a>与 Docker 的差异</h3><table><thead><tr><th>特性</th><th>Podman</th><th>Docker Desktop</th></tr></thead><tbody><tr><td>运行模式</td><td>无守护进程（daemonless）</td><td>需要 dockerd 守护进程</td></tr><tr><td>Root 权限</td><td>支持 rootless 模式</td><td>默认需要 root</td></tr><tr><td>Pod 支持</td><td>原生支持 Kubernetes Pod</td><td>需要额外工具</td></tr><tr><td>许可费用</td><td>开源免费</td><td>企业版收费</td></tr><tr><td>架构</td><td>WSL2 轻量虚拟机</td><td>WSL2 + Hyper-V</td></tr></tbody></table><h2 id="安装-Podman"><a href="#安装-Podman" class="headerlink" title="安装 Podman"></a>安装 Podman</h2><h3 id="方式一：winget（推荐）"><a href="#方式一：winget（推荐）" class="headerlink" title="方式一：winget（推荐）"></a>方式一：winget（推荐）</h3><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">winget install RedHat.Podman</span><br></pre></td></tr></table></figure><h3 id="方式二：手动下载"><a href="#方式二：手动下载" class="headerlink" title="方式二：手动下载"></a>方式二：手动下载</h3><p>前往 <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2NvbnRhaW5lcnMvcG9kbWFuL3JlbGVhc2VzL2xhdGVzdA==">Podman Releases<i class="fa fa-external-link-alt"></i></span> 下载最新 <code>.exe</code> 安装包。</p><p>安装完成后验证：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">podman <span class="literal">--version</span></span><br></pre></td></tr></table></figure><hr><h2 id="初始化-Podman-Machine"><a href="#初始化-Podman-Machine" class="headerlink" title="初始化 Podman Machine"></a>初始化 Podman Machine</h2><p>Podman on Windows 通过 WSL2 虚拟机运行，需要初始化一个 Machine 实例。</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">podman machine init</span><br><span class="line"></span><br><span class="line">podman machine <span class="built_in">set</span> <span class="literal">--rootful</span></span><br><span class="line"></span><br><span class="line">podman machine <span class="built_in">start</span></span><br><span class="line"></span><br><span class="line">podman machine list</span><br></pre></td></tr></table></figure><p><strong>预期输出：</strong></p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">NAME                     VM TYPE     CREATED        LAST UP            CPUS   MEMORY   DISK SIZE</span><br><span class="line">podman-machine-default*  wsl         X minutes ago  Currently running  8      2GiB     100GiB</span><br></pre></td></tr></table></figure><p><strong>参数说明：</strong></p><table><thead><tr><th>参数</th><th>说明</th><th>推荐值</th></tr></thead><tbody><tr><td><code>--rootful</code></td><td>以 root 用户运行容器</td><td>生产环境推荐，兼容性更好</td></tr><tr><td><code>--cpus</code></td><td>分配 CPU 核数</td><td>默认 8</td></tr><tr><td><code>--memory</code></td><td>分配内存大小</td><td>默认 2GiB</td></tr><tr><td><code>--disk-size</code></td><td>虚拟磁盘大小</td><td>默认 100GiB</td></tr></tbody></table><hr><h2 id="清理系统代理环境变量"><a href="#清理系统代理环境变量" class="headerlink" title="清理系统代理环境变量"></a>清理系统代理环境变量</h2><div class="note warning"><p>Windows 系统代理会被传入 VM，如果代理软件监听的是 <code>127.0.0.1</code>，在 VM 内会指向虚拟机本身而非宿主机，导致连接失败，必须清除。</p></div><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="built_in">Set-ItemProperty</span> <span class="literal">-Path</span> <span class="string">&quot;HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings&quot;</span> <span class="literal">-Name</span> ProxyEnable <span class="literal">-Value</span> <span class="number">0</span></span><br><span class="line"><span class="built_in">Set-ItemProperty</span> <span class="literal">-Path</span> <span class="string">&quot;HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings&quot;</span> <span class="literal">-Name</span> ProxyServer <span class="literal">-Value</span> <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line">[<span class="type">System.Environment</span>]::SetEnvironmentVariable(<span class="string">&quot;HTTP_PROXY&quot;</span>, <span class="variable">$null</span>, <span class="string">&quot;Machine&quot;</span>)</span><br><span class="line">[<span class="type">System.Environment</span>]::SetEnvironmentVariable(<span class="string">&quot;HTTPS_PROXY&quot;</span>, <span class="variable">$null</span>, <span class="string">&quot;Machine&quot;</span>)</span><br><span class="line"></span><br><span class="line">[<span class="type">System.Environment</span>]::SetEnvironmentVariable(<span class="string">&quot;HTTP_PROXY&quot;</span>, <span class="variable">$null</span>, <span class="string">&quot;User&quot;</span>)</span><br><span class="line">[<span class="type">System.Environment</span>]::SetEnvironmentVariable(<span class="string">&quot;HTTPS_PROXY&quot;</span>, <span class="variable">$null</span>, <span class="string">&quot;User&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">Remove-Item</span> Env:HTTP_PROXY <span class="literal">-ErrorAction</span> SilentlyContinue</span><br><span class="line"><span class="built_in">Remove-Item</span> Env:HTTPS_PROXY <span class="literal">-ErrorAction</span> SilentlyContinue</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="variable">$env:HTTP_PROXY</span></span><br><span class="line"><span class="built_in">echo</span> <span class="variable">$env:HTTPS_PROXY</span></span><br></pre></td></tr></table></figure><hr><h2 id="配置-VM-内部代理"><a href="#配置-VM-内部代理" class="headerlink" title="配置 VM 内部代理"></a>配置 VM 内部代理</h2><p>Podman Machine 运行在 WSL2 中，需要在 VM 内部配置代理，且代理地址必须使用宿主机在 WSL 网卡上的 IP。</p><h3 id="查找宿主机-WSL-IP"><a href="#查找宿主机-WSL-IP" class="headerlink" title="查找宿主机 WSL IP"></a>查找宿主机 WSL IP</h3><p>在 Windows 侧执行：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">ipconfig</span><br></pre></td></tr></table></figure><p>找到 <code>vEthernet (WSL)</code> 对应的 IPv4 地址，通常为 <code>172.20.128.1</code>。</p><h3 id="开启代理软件局域网访问"><a href="#开启代理软件局域网访问" class="headerlink" title="开启代理软件局域网访问"></a>开启代理软件局域网访问</h3><p>以 v2rayN 为例：</p><p><strong>设置 → Core 基础设置 → 允许来自局域网的连接 → On → 确定 → 重启服务</strong></p><h3 id="写入-VM-代理配置"><a href="#写入-VM-代理配置" class="headerlink" title="写入 VM 代理配置"></a>写入 VM 代理配置</h3><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">podman machine ssh</span><br></pre></td></tr></table></figure><p>进入 VM 后执行（将 <code>172.20.128.1</code> 替换为你的实际 WSL IP，<code>10808</code> 替换为你的代理端口）：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">tee</span> /etc/profile.d/default-env.sh &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line"><span class="built_in">export</span> http_proxy=http://172.20.128.1:10808</span><br><span class="line"><span class="built_in">export</span> https_proxy=http://172.20.128.1:10808</span><br><span class="line"><span class="built_in">export</span> HTTP_PROXY=http://172.20.128.1:10808</span><br><span class="line"><span class="built_in">export</span> HTTPS_PROXY=http://172.20.128.1:10808</span><br><span class="line"><span class="built_in">export</span> no_proxy=localhost,127.0.0.1,::1,&lt;HARBOR_IP&gt;</span><br><span class="line"><span class="built_in">export</span> NO_PROXY=localhost,127.0.0.1,::1,&lt;HARBOR_IP&gt;</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line"><span class="built_in">cat</span> /etc/profile.d/default-env.sh</span><br><span class="line"></span><br><span class="line"><span class="built_in">exit</span></span><br></pre></td></tr></table></figure><h3 id="重启-Machine-使配置生效"><a href="#重启-Machine-使配置生效" class="headerlink" title="重启 Machine 使配置生效"></a>重启 Machine 使配置生效</h3><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">podman machine stop</span><br><span class="line">podman machine <span class="built_in">start</span></span><br></pre></td></tr></table></figure><hr><h2 id="配置私有-Harbor-仓库信任"><a href="#配置私有-Harbor-仓库信任" class="headerlink" title="配置私有 Harbor 仓库信任"></a>配置私有 Harbor 仓库信任</h2><p>内网 Harbor 通常使用 HTTP 或自签名证书，需要添加 insecure 信任。</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">podman machine ssh</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">tee</span> /etc/containers/registries.conf.d/harbor.conf &lt;&lt; <span class="string">&#x27;EOF&#x27;</span></span><br><span class="line">[[registry]]</span><br><span class="line">location = <span class="string">&quot;&lt;HARBOR_IP&gt;&quot;</span></span><br><span class="line">insecure = <span class="literal">true</span></span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line"><span class="built_in">cat</span> /etc/containers/registries.conf.d/harbor.conf</span><br><span class="line"></span><br><span class="line"><span class="built_in">exit</span></span><br></pre></td></tr></table></figure><div class="note info"><p><code>&lt;HARBOR_IP&gt;</code> 已在 <code>NO_PROXY</code> 中，访问私有仓库会自动绕过代理，直连内网。</p></div><hr><h2 id="配置开机自启动"><a href="#配置开机自启动" class="headerlink" title="配置开机自启动"></a>配置开机自启动</h2><p>Podman Machine 默认不随 Windows 启动，通过计划任务实现自动启动。</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="variable">$action</span> = <span class="built_in">New-ScheduledTaskAction</span> <span class="literal">-Execute</span> <span class="string">&quot;podman&quot;</span> <span class="literal">-Argument</span> <span class="string">&quot;machine start&quot;</span></span><br><span class="line"><span class="variable">$trigger</span> = <span class="built_in">New-ScheduledTaskTrigger</span> <span class="literal">-AtLogOn</span></span><br><span class="line"><span class="variable">$settings</span> = <span class="built_in">New-ScheduledTaskSettingsSet</span> <span class="literal">-ExecutionTimeLimit</span> (<span class="built_in">New-TimeSpan</span> <span class="literal">-Minutes</span> <span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">Register-ScheduledTask</span> <span class="literal">-TaskName</span> <span class="string">&quot;PodmanMachineStart&quot;</span> `</span><br><span class="line">  <span class="literal">-Action</span> <span class="variable">$action</span> `</span><br><span class="line">  <span class="literal">-Trigger</span> <span class="variable">$trigger</span> `</span><br><span class="line">  <span class="literal">-Settings</span> <span class="variable">$settings</span> `</span><br><span class="line">  <span class="literal">-RunLevel</span> Highest `</span><br><span class="line">  <span class="literal">-Force</span></span><br></pre></td></tr></table></figure><p>验证注册成功：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="built_in">Get-ScheduledTask</span> <span class="literal">-TaskName</span> <span class="string">&quot;PodmanMachineStart&quot;</span></span><br></pre></td></tr></table></figure><p>取消自启动：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="built_in">Unregister-ScheduledTask</span> <span class="literal">-TaskName</span> <span class="string">&quot;PodmanMachineStart&quot;</span> <span class="literal">-Confirm</span>:<span class="variable">$false</span></span><br></pre></td></tr></table></figure><div class="note info"><p>触发时机为用户登录时。若需要真正的开机启动（无需登录），将 <code>-AtLogOn</code> 改为 <code>-AtStartup</code> 并配置 Windows 自动登录。</p></div><hr><h2 id="验证完整环境"><a href="#验证完整环境" class="headerlink" title="验证完整环境"></a>验证完整环境</h2><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">podman machine list</span><br><span class="line"></span><br><span class="line">podman pull docker.io/library/nginx:latest</span><br><span class="line"></span><br><span class="line">podman pull &lt;HARBOR_IP&gt;/&lt;your<span class="literal">-image</span>&gt;:&lt;tag&gt;</span><br><span class="line"></span><br><span class="line">podman run <span class="literal">--rm</span> nginx:latest <span class="built_in">echo</span> <span class="string">&quot;Podman is working!&quot;</span></span><br></pre></td></tr></table></figure><hr><h2 id="日常维护命令"><a href="#日常维护命令" class="headerlink" title="日常维护命令"></a>日常维护命令</h2><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">podman machine <span class="built_in">start</span></span><br><span class="line">podman machine stop</span><br><span class="line">podman machine stop &amp;&amp; podman machine <span class="built_in">start</span></span><br><span class="line"></span><br><span class="line">podman machine ssh</span><br><span class="line"></span><br><span class="line">podman images</span><br><span class="line"></span><br><span class="line">podman <span class="built_in">ps</span></span><br><span class="line"></span><br><span class="line">podman <span class="built_in">ps</span> <span class="literal">-a</span></span><br><span class="line"></span><br><span class="line">podman container prune</span><br><span class="line"></span><br><span class="line">podman image prune</span><br></pre></td></tr></table></figure><hr><h2 id="故障排查指南"><a href="#故障排查指南" class="headerlink" title="故障排查指南"></a>故障排查指南</h2><h3 id="常见问题与解决方案"><a href="#常见问题与解决方案" class="headerlink" title="常见问题与解决方案"></a>常见问题与解决方案</h3><table><thead><tr><th>错误信息</th><th>原因</th><th>解决方案</th></tr></thead><tbody><tr><td><code>proxyconnect tcp: connection refused</code></td><td>代理软件未运行或端口错误</td><td>启动代理软件，确认端口一致</td></tr><tr><td><code>proxyconnect tcp: 127.0.0.1:xxxx</code></td><td>Windows 系统代理传入 VM</td><td>执行「清理系统代理环境变量」步骤</td></tr><tr><td><code>Trying to pull...</code> 无响应</td><td>代理未开启局域网访问</td><td>v2rayN 开启「允许来自局域网的连接」</td></tr><tr><td><code>permission denied /var/run/docker.sock</code></td><td>非 rootful 模式</td><td><code>podman machine set --rootful</code></td></tr><tr><td><code>VM already exists</code></td><td>Machine 未完全清理</td><td><code>podman machine rm --force podman-machine-default</code></td></tr></tbody></table><hr><h2 id="参考资源"><a href="#参考资源" class="headerlink" title="参考资源"></a>参考资源</h2><h3 id="官方文档"><a href="#官方文档" class="headerlink" title="官方文档"></a>官方文档</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9wb2RtYW4uaW8v">Podman 官方文档<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2NvbnRhaW5lcnMvcG9kbWFuL2Jsb2IvbWFpbi9kb2NzL3R1dG9yaWFscy9wb2RtYW4tZm9yLXdpbmRvd3MubWQ=">Podman Windows 安装指南<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2NvbnRhaW5lcnMvcG9kbWFuL2Jsb2IvbWFpbi9kb2NzL3R1dG9yaWFscy9wb2RtYW4tbWFjaGluZS5tZA==">Podman Machine 配置<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2NvbnRhaW5lcnMvaW1hZ2UvYmxvYi9tYWluL2RvY3MvY29udGFpbmVycy1yZWdpc3RyaWVzLmNvbmYuNS5tZA==">containers&#x2F;registries.conf 配置<i class="fa fa-external-link-alt"></i></span></li></ul><h3 id="相关工具"><a href="#相关工具" class="headerlink" title="相关工具"></a>相关工具</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9sZWFybi5taWNyb3NvZnQuY29tL3poLWNuL3dpbmRvd3Mvd3NsLw==">WSL2 官方文档<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tLzJkdXN0L3YycmF5Tg==">v2rayN GitHub<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2dvaGFyYm9yL2hhcmJvcg==">Harbor 部署指南<i class="fa fa-external-link-alt"></i></span></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;Podman 是 Docker 的开源替代方案，在 Windows 上通过 WSL2 虚拟机运行容器。本文档详细阐述 Podman on Windows 的完整部署流程，包括安装配置、代理设置、私有仓库信任、开机自启动及日常维护等关键环节，适用于需要在 Windows 环境下使用容器技术的开发与运维场景。&lt;/p&gt;</summary>
    
    
    
    <category term="DevOps" scheme="https://freemankevin.uk/categories/DevOps/"/>
    
    <category term="Container" scheme="https://freemankevin.uk/categories/DevOps/Container/"/>
    
    
    <category term="Docker" scheme="https://freemankevin.uk/tags/Docker/"/>
    
    <category term="Windows" scheme="https://freemankevin.uk/tags/Windows/"/>
    
    <category term="Podman" scheme="https://freemankevin.uk/tags/Podman/"/>
    
    <category term="WSL2" scheme="https://freemankevin.uk/tags/WSL2/"/>
    
  </entry>
  
  <entry>
    <title>Windows 小狼毫输入法（Rime）安装配置指南</title>
    <link href="https://freemankevin.uk/2026/04/24/weasel-rime-setup/"/>
    <id>https://freemankevin.uk/2026/04/24/weasel-rime-setup/</id>
    <published>2026-04-24T02:36:58.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p>小狼毫（Weasel）是 Rime 输入法在 Windows 平台上的实现。Rime 是一款开源、高度可定制的输入法引擎，支持多种输入方案（拼音、双拼、五笔等），深受技术用户喜爱。本文将介绍小狼毫的安装、基础配置和进阶用法。</p><span id="more"></span><p><strong>适用版本与环境说明：</strong></p><ul><li>操作系统: Windows 10&#x2F;11</li><li>输入法版本: 小狼毫 (Weasel) 0.15+</li><li>更新日期: 2026-04-24</li></ul><div class="note info"><p>Rime 是跨平台的输入法引擎：</p><ul><li>Windows: 小狼毫 (Weasel)</li><li>macOS: 鼠须管 (Squirrel)</li><li>Linux: 中州韵 (ibus-rime &#x2F; fcitx5-rime)</li></ul></div><hr><h2 id="安装步骤"><a href="#安装步骤" class="headerlink" title="安装步骤"></a>安装步骤</h2><h3 id="方式一：官方下载"><a href="#方式一：官方下载" class="headerlink" title="方式一：官方下载"></a>方式一：官方下载</h3><p>访问 Rime 官网下载安装包：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">https://rime.im/download/</span><br></pre></td></tr></table></figure><p>下载后双击安装程序，按提示完成安装。</p><h3 id="方式二：包管理器安装（推荐）"><a href="#方式二：包管理器安装（推荐）" class="headerlink" title="方式二：包管理器安装（推荐）"></a>方式二：包管理器安装（推荐）</h3><p>使用 Windows 包管理器安装：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 使用 winget</span></span><br><span class="line">winget install RIME.Weasel</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或使用 scoop</span></span><br><span class="line">scoop install weasel</span><br></pre></td></tr></table></figure><div class="note warning"><p>安装完成后需要重启系统或注销后重新登录，输入法才能正常加载。</p></div><hr><h2 id="基础配置"><a href="#基础配置" class="headerlink" title="基础配置"></a>基础配置</h2><h3 id="配置文件位置"><a href="#配置文件位置" class="headerlink" title="配置文件位置"></a>配置文件位置</h3><p>小狼毫的用户配置文件位于：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">%APPDATA%\Rime\</span><br></pre></td></tr></table></figure><p>主要的配置文件：</p><table><thead><tr><th>文件名</th><th>说明</th></tr></thead><tbody><tr><td><code>default.custom.yaml</code></td><td>全局配置（候选词数量、输入方案等）</td></tr><tr><td><code>weasel.custom.yaml</code></td><td>外观配置（配色、字体、布局）</td></tr><tr><td><code>user.yaml</code></td><td>用户信息</td></tr></tbody></table><h3 id="最小化配置"><a href="#最小化配置" class="headerlink" title="最小化配置"></a>最小化配置</h3><h4 id="创建-default-custom-yaml"><a href="#创建-default-custom-yaml" class="headerlink" title="创建 default.custom.yaml"></a>创建 <code>default.custom.yaml</code></h4><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">patch:</span></span><br><span class="line">  <span class="comment"># 候选词数量</span></span><br><span class="line">  <span class="attr">&quot;menu/page_size&quot;:</span> <span class="number">5</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment"># 配色方案</span></span><br><span class="line">  <span class="attr">style/color_scheme:</span> <span class="string">clean_white</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment"># 输入方案列表</span></span><br><span class="line">  <span class="attr">schema_list:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">schema:</span> <span class="string">luna_pinyin_simp</span>  <span class="comment"># 简体拼音</span></span><br></pre></td></tr></table></figure><h4 id="创建-weasel-custom-yaml"><a href="#创建-weasel-custom-yaml" class="headerlink" title="创建 weasel.custom.yaml"></a>创建 <code>weasel.custom.yaml</code></h4><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">patch:</span></span><br><span class="line">  <span class="comment"># 配色方案</span></span><br><span class="line">  <span class="attr">&quot;style/color_scheme&quot;:</span> <span class="string">minimal_white</span></span><br><span class="line">  <span class="attr">&quot;style/horizontal&quot;:</span> <span class="literal">true</span>  <span class="comment"># 横向候选栏</span></span><br><span class="line">  <span class="attr">&quot;style/font_face&quot;:</span> <span class="string">&quot;Segoe UI, Microsoft YaHei&quot;</span></span><br><span class="line">  <span class="attr">&quot;style/font_point&quot;:</span> <span class="number">12</span></span><br><span class="line">  <span class="attr">&quot;style/layout/border&quot;:</span> <span class="number">0</span></span><br><span class="line">  <span class="attr">&quot;style/layout/margin_x&quot;:</span> <span class="number">12</span></span><br><span class="line">  <span class="attr">&quot;style/layout/margin_y&quot;:</span> <span class="number">12</span></span><br><span class="line">  <span class="attr">&quot;style/layout/spacing&quot;:</span> <span class="number">10</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment"># 自定义配色：简约白</span></span><br><span class="line">  <span class="attr">&quot;preset_color_schemes/minimal_white&quot;:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">&quot;简约白 / Minimal White&quot;</span></span><br><span class="line">    <span class="attr">author:</span> <span class="string">&quot;Custom&quot;</span></span><br><span class="line">    <span class="attr">back_color:</span> <span class="number">0xFFFFFF</span></span><br><span class="line">    <span class="attr">border_color:</span> <span class="number">0xE0E0E0</span></span><br><span class="line">    <span class="attr">text_color:</span> <span class="number">0x424242</span></span><br><span class="line">    <span class="attr">hilited_text_color:</span> <span class="number">0x000000</span></span><br><span class="line">    <span class="attr">hilited_back_color:</span> <span class="number">0xF5F5F5</span></span><br><span class="line">    <span class="attr">candidate_text_color:</span> <span class="number">0x606060</span></span><br><span class="line">    <span class="attr">hilited_candidate_text_color:</span> <span class="number">0x000000</span></span><br><span class="line">    <span class="attr">hilited_candidate_back_color:</span> <span class="number">0xEEEEEE</span></span><br></pre></td></tr></table></figure><h3 id="部署配置"><a href="#部署配置" class="headerlink" title="部署配置"></a>部署配置</h3><p>修改配置文件后，需要重新部署才能生效：</p><ol><li>右键点击任务栏小狼毫图标</li><li>选择 <strong>重新部署</strong></li><li>等待部署完成（几秒钟）</li></ol><hr><h2 id="快速上手"><a href="#快速上手" class="headerlink" title="快速上手"></a>快速上手</h2><h3 id="常用快捷键"><a href="#常用快捷键" class="headerlink" title="常用快捷键"></a>常用快捷键</h3><table><thead><tr><th>快捷键</th><th>功能</th></tr></thead><tbody><tr><td><code>Ctrl + ~</code></td><td>切换输入方案</td></tr><tr><td><code>Ctrl + Shift + 1</code></td><td>中英文切换</td></tr><tr><td><code>Ctrl + Shift + F</code></td><td>繁简转换</td></tr><tr><td><code>Shift</code></td><td>临时英文模式</td></tr><tr><td><code>Ctrl + .</code></td><td>切换中西文标点</td></tr></tbody></table><h3 id="切换输入方案"><a href="#切换输入方案" class="headerlink" title="切换输入方案"></a>切换输入方案</h3><p>安装后默认使用明月拼音，可通过以下方式切换：</p><ol><li>按 <code>Ctrl + ~</code> 打开方案选单</li><li>输入方案编号选择</li><li>或右键托盘图标 → 输入方案设定</li></ol><hr><h2 id="进阶配置"><a href="#进阶配置" class="headerlink" title="进阶配置"></a>进阶配置</h2><h3 id="同步配置到-GitHub"><a href="#同步配置到-GitHub" class="headerlink" title="同步配置到 GitHub"></a>同步配置到 GitHub</h3><p>使用 Git 管理配置文件，实现多设备同步：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cd</span> <span class="variable">$env:APPDATA</span>\Rime</span><br><span class="line"></span><br><span class="line"><span class="comment"># 初始化 Git 仓库</span></span><br><span class="line">git init</span><br><span class="line">git add .</span><br><span class="line">git commit <span class="literal">-m</span> <span class="string">&quot;Init Rime config&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 关联远程仓库</span></span><br><span class="line">git remote add origin https://github.com/your<span class="literal">-username</span>/rime<span class="literal">-config</span>.git</span><br><span class="line">git branch <span class="literal">-M</span> main</span><br><span class="line">git push <span class="literal">-u</span> origin main</span><br></pre></td></tr></table></figure><p>在其他设备上恢复配置：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cd</span> <span class="variable">$env:APPDATA</span>\Rime</span><br><span class="line">git clone https://github.com/your<span class="literal">-username</span>/rime<span class="literal">-config</span>.git .</span><br></pre></td></tr></table></figure><h3 id="词库扩展"><a href="#词库扩展" class="headerlink" title="词库扩展"></a>词库扩展</h3><h4 id="使用雾凇拼音词库"><a href="#使用雾凇拼音词库" class="headerlink" title="使用雾凇拼音词库"></a>使用雾凇拼音词库</h4><p>雾凇拼音是一个高质量的简体拼音词库：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 克隆词库</span></span><br><span class="line"><span class="built_in">cd</span> <span class="variable">$env:TEMP</span></span><br><span class="line">git clone https://github.com/iDvel/rime<span class="literal">-ice</span>.git</span><br><span class="line"></span><br><span class="line"><span class="comment"># 复制配置文件到 Rime 目录</span></span><br><span class="line"><span class="built_in">Copy-Item</span> <span class="literal">-Recurse</span> <span class="literal">-Force</span> <span class="string">&quot;<span class="variable">$env:TEMP</span>\rime-ice\*&quot;</span> <span class="string">&quot;<span class="variable">$env:APPDATA</span>\Rime\&quot;</span></span><br></pre></td></tr></table></figure><p>复制后重新部署即可生效。</p><h4 id="自定义词库"><a href="#自定义词库" class="headerlink" title="自定义词库"></a>自定义词库</h4><p>在用户目录创建 <code>custom_phrase.txt</code>：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"># 编码&lt;Tab&gt;词组</span><br><span class="line">rime    小狼毫</span><br><span class="line">github  GitHub</span><br></pre></td></tr></table></figure><p>在 <code>luna_pinyin.custom.yaml</code> 中引入：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">patch:</span></span><br><span class="line">  <span class="attr">&quot;translator/dictionary&quot;:</span> <span class="string">luna_pinyin</span></span><br><span class="line">  <span class="attr">&quot;translator/prism&quot;:</span> <span class="string">luna_pinyin_simp</span></span><br><span class="line">  <span class="attr">&quot;translator/custom_phrase&quot;:</span> <span class="string">&quot;custom_phrase.txt&quot;</span></span><br></pre></td></tr></table></figure><h3 id="添加更多输入方案"><a href="#添加更多输入方案" class="headerlink" title="添加更多输入方案"></a>添加更多输入方案</h3><p>内置输入方案：</p><table><thead><tr><th>方案</th><th>说明</th></tr></thead><tbody><tr><td><code>luna_pinyin</code></td><td>明月拼音（繁体）</td></tr><tr><td><code>luna_pinyin_simp</code></td><td>明月拼音（简体）</td></tr><tr><td><code>double_pinyin</code></td><td>自然码双拼</td></tr><tr><td><code>double_pinyin_flypy</code></td><td>小鹤双拼</td></tr><tr><td><code>wubi_pinyin</code></td><td>五笔拼音混输</td></tr><tr><td><code>terra_pinyin</code></td><td>地球拼音</td></tr></tbody></table><p>在 <code>default.custom.yaml</code> 中添加：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">patch:</span></span><br><span class="line">  <span class="attr">schema_list:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">schema:</span> <span class="string">luna_pinyin_simp</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">schema:</span> <span class="string">double_pinyin_flypy</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">schema:</span> <span class="string">wubi_pinyin</span></span><br></pre></td></tr></table></figure><hr><h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><h3 id="Q1-输入法候选框不显示？"><a href="#Q1-输入法候选框不显示？" class="headerlink" title="Q1: 输入法候选框不显示？"></a>Q1: 输入法候选框不显示？</h3><p>检查小狼毫服务是否运行：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 重启服务</span></span><br><span class="line">net stop WeaselService</span><br><span class="line">net <span class="built_in">start</span> WeaselService</span><br></pre></td></tr></table></figure><p>或在任务管理器中重启 <code>WeaselServer.exe</code>。</p><h3 id="Q2-配置修改后无效？"><a href="#Q2-配置修改后无效？" class="headerlink" title="Q2: 配置修改后无效？"></a>Q2: 配置修改后无效？</h3><ol><li>确保文件编码为 UTF-8</li><li>检查 YAML 格式是否正确（注意缩进）</li><li>重新部署配置</li></ol><h3 id="Q3-如何设置默认英文模式？"><a href="#Q3-如何设置默认英文模式？" class="headerlink" title="Q3: 如何设置默认英文模式？"></a>Q3: 如何设置默认英文模式？</h3><p>在 <code>default.custom.yaml</code> 中添加：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">patch:</span></span><br><span class="line">  <span class="attr">&quot;switches/@0/reset&quot;:</span> <span class="number">1</span>  <span class="comment"># 0 为中文，1 为英文</span></span><br></pre></td></tr></table></figure><h3 id="Q4-如何关闭模糊音？"><a href="#Q4-如何关闭模糊音？" class="headerlink" title="Q4: 如何关闭模糊音？"></a>Q4: 如何关闭模糊音？</h3><p>在 <code>luna_pinyin.custom.yaml</code> 中设置：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">patch:</span></span><br><span class="line">  <span class="attr">&quot;speller/algebra&quot;:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">erase/^xx$/</span>  <span class="comment"># 移除模糊音配置</span></span><br></pre></td></tr></table></figure><h3 id="Q5-如何备份用户词频？"><a href="#Q5-如何备份用户词频？" class="headerlink" title="Q5: 如何备份用户词频？"></a>Q5: 如何备份用户词频？</h3><p>用户词频存储在以下文件：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">%APPDATA%\Rime\luna_pinyin.userdb\</span><br></pre></td></tr></table></figure><p>使用 Git 同步或定期备份此目录。</p><hr><h2 id="配色方案参考"><a href="#配色方案参考" class="headerlink" title="配色方案参考"></a>配色方案参考</h2><h3 id="简约白"><a href="#简约白" class="headerlink" title="简约白"></a>简约白</h3><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">&quot;preset_color_schemes/minimal_white&quot;:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">&quot;简约白&quot;</span></span><br><span class="line">  <span class="attr">back_color:</span> <span class="number">0xFFFFFF</span></span><br><span class="line">  <span class="attr">border_color:</span> <span class="number">0xE0E0E0</span></span><br><span class="line">  <span class="attr">text_color:</span> <span class="number">0x424242</span></span><br><span class="line">  <span class="attr">hilited_candidate_text_color:</span> <span class="number">0x000000</span></span><br><span class="line">  <span class="attr">hilited_candidate_back_color:</span> <span class="number">0xEEEEEE</span></span><br><span class="line">  <span class="attr">candidate_text_color:</span> <span class="number">0x606060</span></span><br></pre></td></tr></table></figure><h3 id="深色模式"><a href="#深色模式" class="headerlink" title="深色模式"></a>深色模式</h3><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">&quot;preset_color_schemes/minimal_dark&quot;:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">&quot;简约黑&quot;</span></span><br><span class="line">  <span class="attr">back_color:</span> <span class="number">0x2B2B2B</span></span><br><span class="line">  <span class="attr">border_color:</span> <span class="number">0x3C3C3C</span></span><br><span class="line">  <span class="attr">text_color:</span> <span class="number">0xD4D4D4</span></span><br><span class="line">  <span class="attr">hilited_candidate_text_color:</span> <span class="number">0xFFFFFF</span></span><br><span class="line">  <span class="attr">hilited_candidate_back_color:</span> <span class="number">0x3C3C3C</span></span><br><span class="line">  <span class="attr">candidate_text_color:</span> <span class="number">0x808080</span></span><br></pre></td></tr></table></figure><h3 id="跟随系统"><a href="#跟随系统" class="headerlink" title="跟随系统"></a>跟随系统</h3><p>在 <code>weasel.custom.yaml</code> 中设置：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">patch:</span></span><br><span class="line">  <span class="attr">&quot;style/color_scheme_dark&quot;:</span> <span class="string">minimal_dark</span>  <span class="comment"># 深色模式配色</span></span><br><span class="line">  <span class="attr">&quot;style/color_scheme&quot;:</span> <span class="string">minimal_white</span>        <span class="comment"># 浅色模式配色</span></span><br></pre></td></tr></table></figure><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>小狼毫作为 Rime 在 Windows 平台的实现，提供了高度可定制的输入体验。通过配置文件可以精细控制候选词数量、外观样式、输入方案等。配合 Git 同步，可以轻松在多台设备间共享配置和词库。对于追求效率和个性化的用户来说，小狼毫是一个值得尝试的选择。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;小狼毫（Weasel）是 Rime 输入法在 Windows 平台上的实现。Rime 是一款开源、高度可定制的输入法引擎，支持多种输入方案（拼音、双拼、五笔等），深受技术用户喜爱。本文将介绍小狼毫的安装、基础配置和进阶用法。&lt;/p&gt;</summary>
    
    
    
    <category term="Windows" scheme="https://freemankevin.uk/categories/Windows/"/>
    
    
    <category term="Windows" scheme="https://freemankevin.uk/tags/Windows/"/>
    
    <category term="输入法" scheme="https://freemankevin.uk/tags/%E8%BE%93%E5%85%A5%E6%B3%95/"/>
    
    <category term="Rime" scheme="https://freemankevin.uk/tags/Rime/"/>
    
    <category term="小狼毫" scheme="https://freemankevin.uk/tags/%E5%B0%8F%E7%8B%BC%E6%AF%AB/"/>
    
  </entry>
  
  <entry>
    <title>Windows Tiny10 恢复中文语言包与微软拼音输入法完整指南</title>
    <link href="https://freemankevin.uk/2026/04/24/tiny10-chinese-support/"/>
    <id>https://freemankevin.uk/2026/04/24/tiny10-chinese-support/</id>
    <published>2026-04-24T02:17:18.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p>Tiny10 是 Windows 10 的精简版本，移除了大量预装组件以减小系统体积。然而，这也导致了中文语言包、输入法和字体等组件的缺失，使得中文显示乱码，影响日常使用。本文将详细介绍如何在 Tiny10 系统中恢复中文支持，包括语言包安装、输入法配置和字体修复。</p><span id="more"></span><p><strong>适用版本与环境说明：</strong></p><ul><li>操作系统: Windows Tiny10（基于 Windows 10 LTSC 精简）</li><li>更新日期: 2026-04-24</li><li>需要管理员权限</li></ul><div class="note warning"><p>Tiny10 移除了部分系统功能，某些 PowerShell 命令可能不可用。如果遇到命令执行失败，请尝试使用 DISM 替代方案。</p></div><hr><h2 id="问题背景"><a href="#问题背景" class="headerlink" title="问题背景"></a>问题背景</h2><p>在 Tiny10 系统中，由于精简了语言包和输入法组件，会出现以下问题：</p><ol><li><strong>中文乱码</strong>：命令行、编辑器中的中文显示为乱码</li><li><strong>无中文输入法</strong>：无法输入中文</li><li><strong>系统区域设置缺失</strong>：无法切换到中文环境</li></ol><hr><h2 id="方案一：命令行修复（推荐）"><a href="#方案一：命令行修复（推荐）" class="headerlink" title="方案一：命令行修复（推荐）"></a>方案一：命令行修复（推荐）</h2><h3 id="1-安装中文语言包"><a href="#1-安装中文语言包" class="headerlink" title="1. 安装中文语言包"></a>1. 安装中文语言包</h3><p><strong>方法一：使用 PowerShell（推荐）</strong></p><p>以管理员身份运行 PowerShell：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 添加中文语言到语言列表</span></span><br><span class="line"><span class="variable">$LanguageList</span> = <span class="built_in">Get-WinUserLanguageList</span></span><br><span class="line"><span class="variable">$LanguageList</span>.Add(<span class="string">&quot;zh-CN&quot;</span>)</span><br><span class="line"><span class="built_in">Set-WinUserLanguageList</span> <span class="variable">$LanguageList</span> <span class="literal">-Force</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装语言功能（字体、OCR等）</span></span><br><span class="line"><span class="built_in">Install-Language</span> <span class="literal">-Language</span> zh<span class="literal">-CN</span></span><br></pre></td></tr></table></figure><p><strong>方法二：使用 DISM（备用）</strong></p><p>如果上述命令不可用（Tiny10 可能移除了该功能），使用 DISM：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 查看可用语言包</span></span><br><span class="line">DISM /Online /<span class="built_in">Get-Capabilities</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装中文语言包和字体</span></span><br><span class="line">DISM /Online /<span class="built_in">Add-Capability</span> /CapabilityName:Language.Basic~~~zh<span class="literal">-CN</span>~<span class="number">0.0</span>.<span class="number">1.0</span></span><br><span class="line">DISM /Online /<span class="built_in">Add-Capability</span> /CapabilityName:Language.Fonts.Hans~~~und<span class="literal">-HANS</span>~<span class="number">0.0</span>.<span class="number">1.0</span></span><br><span class="line">DISM /Online /<span class="built_in">Add-Capability</span> /CapabilityName:Language.Handwriting~~~zh<span class="literal">-CN</span>~<span class="number">0.0</span>.<span class="number">1.0</span></span><br><span class="line">DISM /Online /<span class="built_in">Add-Capability</span> /CapabilityName:Language.OCR~~~zh<span class="literal">-CN</span>~<span class="number">0.0</span>.<span class="number">1.0</span></span><br><span class="line">DISM /Online /<span class="built_in">Add-Capability</span> /CapabilityName:Language.TextToSpeech~~~zh<span class="literal">-CN</span>~<span class="number">0.0</span>.<span class="number">1.0</span></span><br></pre></td></tr></table></figure><hr><h3 id="2-恢复微软拼音输入法"><a href="#2-恢复微软拼音输入法" class="headerlink" title="2. 恢复微软拼音输入法"></a>2. 恢复微软拼音输入法</h3><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 确保语言包已安装</span></span><br><span class="line">DISM /Online /<span class="built_in">Add-Capability</span> /CapabilityName:Language.TextToSpeech~~~zh<span class="literal">-CN</span>~<span class="number">0.0</span>.<span class="number">1.0</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加微软拼音输入法</span></span><br><span class="line"><span class="variable">$langList</span> = <span class="built_in">Get-WinUserLanguageList</span></span><br><span class="line"><span class="variable">$langList</span>[<span class="number">0</span>].InputMethodTips.Clear()</span><br><span class="line"><span class="variable">$langList</span>[<span class="number">0</span>].InputMethodTips.Add(<span class="string">&#x27;0804:00000804&#x27;</span>)  <span class="comment"># 微软拼音</span></span><br><span class="line"><span class="built_in">Set-WinUserLanguageList</span> <span class="variable">$langList</span> <span class="literal">-Force</span></span><br></pre></td></tr></table></figure><hr><h3 id="3-修复字体（解决乱码问题）"><a href="#3-修复字体（解决乱码问题）" class="headerlink" title="3. 修复字体（解决乱码问题）"></a>3. 修复字体（解决乱码问题）</h3><p>如果中文仍然显示乱码，可能是缺少中文字体。</p><p><strong>方法一：从正常 Windows 系统复制字体</strong></p><p>从正常的 Windows 10 系统复制以下字体文件到 Tiny10：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">源路径: C:\Windows\Fonts\</span><br><span class="line">目标路径: C:\Windows\Fonts\</span><br><span class="line"></span><br><span class="line">需要复制的字体:</span><br><span class="line">- msyh.ttc (微软雅黑)</span><br><span class="line">- msyhbd.ttc (微软雅黑 Bold)</span><br><span class="line">- simhei.ttf (黑体)</span><br><span class="line">- simsun.ttc (宋体)</span><br></pre></td></tr></table></figure><p><strong>方法二：安装开源字体</strong></p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 下载 Noto Sans CJK SC 字体</span></span><br><span class="line"><span class="built_in">Invoke-WebRequest</span> <span class="literal">-Uri</span> <span class="string">&quot;https://github.com/googlefonts/noto-cjk/raw/main/Sans/OTF/SimplifiedChinese/NotoSansCJKsc-Regular.otf&quot;</span> <span class="literal">-OutFile</span> <span class="string">&quot;<span class="variable">$env:TEMP</span>\NotoSans.otf&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">Copy-Item</span> <span class="string">&quot;<span class="variable">$env:TEMP</span>\NotoSans.otf&quot;</span> <span class="string">&quot;C:\Windows\Fonts\&quot;</span></span><br><span class="line"><span class="built_in">New-ItemProperty</span> <span class="literal">-Path</span> <span class="string">&quot;HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts&quot;</span> <span class="literal">-Name</span> <span class="string">&quot;Noto Sans CJK SC (TrueType)&quot;</span> <span class="literal">-Value</span> <span class="string">&quot;NotoSans.otf&quot;</span> <span class="literal">-PropertyType</span> String</span><br></pre></td></tr></table></figure><hr><h3 id="4-设置系统区域"><a href="#4-设置系统区域" class="headerlink" title="4. 设置系统区域"></a>4. 设置系统区域</h3><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 设置系统区域为中文</span></span><br><span class="line"><span class="built_in">Set-WinSystemLocale</span> <span class="literal">-SystemLocale</span> zh<span class="literal">-CN</span></span><br><span class="line"><span class="built_in">Set-WinUILanguageOverride</span> <span class="literal">-Language</span> zh<span class="literal">-CN</span></span><br><span class="line"><span class="built_in">Set-Culture</span> <span class="literal">-CultureInfo</span> zh<span class="literal">-CN</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置非 Unicode 程序的语言</span></span><br><span class="line"><span class="built_in">Set-WinSystemLocale</span> zh<span class="literal">-CN</span></span><br></pre></td></tr></table></figure><div class="note info"><p>设置完成后需要重启系统才能生效。</p></div><hr><h2 id="方案二：离线包安装（无网络环境）"><a href="#方案二：离线包安装（无网络环境）" class="headerlink" title="方案二：离线包安装（无网络环境）"></a>方案二：离线包安装（无网络环境）</h2><p>如果系统无法联网，可以使用离线安装方式。</p><h3 id="1-准备离线包"><a href="#1-准备离线包" class="headerlink" title="1. 准备离线包"></a>1. 准备离线包</h3><p>从正常 Windows 10 系统复制语言包文件：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">源路径: C:\Windows\servicing\LCU\</span><br><span class="line">或者从微软官方下载 Language Pack ISO</span><br></pre></td></tr></table></figure><h3 id="2-使用-DISM-离线安装"><a href="#2-使用-DISM-离线安装" class="headerlink" title="2. 使用 DISM 离线安装"></a>2. 使用 DISM 离线安装</h3><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 假设语言包存放在 D:\LanguagePack 目录</span></span><br><span class="line">DISM /Online /<span class="built_in">Add-Package</span> /PackagePath:<span class="string">&quot;D:\LanguagePack\Microsoft-Windows-LanguageFeatures-Basic-zh-cn-Package.cab&quot;</span></span><br><span class="line">DISM /Online /<span class="built_in">Add-Package</span> /PackagePath:<span class="string">&quot;D:\LanguagePack\Microsoft-Windows-LanguageFeatures-Fonts-Hans-Package.cab&quot;</span></span><br></pre></td></tr></table></figure><hr><h2 id="方案三：GUI-方式（备选）"><a href="#方案三：GUI-方式（备选）" class="headerlink" title="方案三：GUI 方式（备选）"></a>方案三：GUI 方式（备选）</h2><p>如果命令行方式遇到问题，可以尝试图形界面操作：</p><ol><li>打开 <strong>Settings → Time &amp; Language → Language</strong></li><li>点击 <strong>Add a language</strong></li><li>选择 <strong>中文（简体，中国）</strong></li><li>点击 <strong>Options</strong> → <strong>Download language pack</strong></li><li>重启系统</li></ol><hr><h2 id="验证安装"><a href="#验证安装" class="headerlink" title="验证安装"></a>验证安装</h2><p>重启系统后，执行以下命令验证：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 检查已安装的语言包</span></span><br><span class="line"><span class="built_in">Get-WinUserLanguageList</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查系统语言</span></span><br><span class="line"><span class="built_in">Get-WinSystemLocale</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><br><span class="line"></span><br><span class="line"><span class="comment"># 设置命令行为 UTF-8 编码</span></span><br><span class="line">chcp <span class="number">65001</span></span><br></pre></td></tr></table></figure><hr><h2 id="备选方案：便携版输入法"><a href="#备选方案：便携版输入法" class="headerlink" title="备选方案：便携版输入法"></a>备选方案：便携版输入法</h2><p>如果以上方法都无法恢复微软拼音输入法，可以考虑使用第三方便携版输入法：</p><h3 id="小小输入法（绿色版）"><a href="#小小输入法（绿色版）" class="headerlink" title="小小输入法（绿色版）"></a>小小输入法（绿色版）</h3><ul><li>官网: <span class="exturl" data-url="aHR0cHM6Ly95b25nLmRnb2QubmV0Lw==">https://yong.dgod.net/<i class="fa fa-external-link-alt"></i></span></li><li>特点: 无需安装，不依赖系统组件</li><li>支持拼音、五笔等多种输入方式</li></ul><h3 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h3><ol><li>下载便携版压缩包</li><li>解压到任意目录</li><li>运行主程序即可使用</li></ol><hr><h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><h3 id="Q1-DISM-命令执行失败？"><a href="#Q1-DISM-命令执行失败？" class="headerlink" title="Q1: DISM 命令执行失败？"></a>Q1: DISM 命令执行失败？</h3><p>检查 Windows Update 服务是否正常运行：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 启动 Windows Update 服务</span></span><br><span class="line">net <span class="built_in">start</span> wuauserv</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或者设置为自动启动</span></span><br><span class="line"><span class="built_in">sc</span> config wuauserv <span class="built_in">start</span>= auto</span><br><span class="line">net <span class="built_in">start</span> wuauserv</span><br></pre></td></tr></table></figure><h3 id="Q2-字体安装后仍然乱码？"><a href="#Q2-字体安装后仍然乱码？" class="headerlink" title="Q2: 字体安装后仍然乱码？"></a>Q2: 字体安装后仍然乱码？</h3><ol><li>检查控制面板 → 区域 → 管理 → 更改系统区域设置</li><li>勾选 “Beta 版: 使用 Unicode UTF-8 提供全球语言支持”</li><li>重启系统</li></ol><h3 id="Q3-输入法切换快捷键无效？"><a href="#Q3-输入法切换快捷键无效？" class="headerlink" title="Q3: 输入法切换快捷键无效？"></a>Q3: 输入法切换快捷键无效？</h3><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 检查输入法设置</span></span><br><span class="line"><span class="built_in">Get-WinUserLanguageList</span> | <span class="built_in">Select-Object</span> InputMethodTips</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></pre></td></tr></table></figure><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Tiny10 作为精简版系统，虽然体积小、运行快，但也牺牲了一些实用性组件。通过本文介绍的方法，可以恢复中文语言支持，解决中文乱码问题，并重新获得中文输入能力。建议优先使用命令行方式（方案一），如遇网络问题则使用离线安装（方案二），最后可考虑便携版输入法作为备选方案。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;Tiny10 是 Windows 10 的精简版本，移除了大量预装组件以减小系统体积。然而，这也导致了中文语言包、输入法和字体等组件的缺失，使得中文显示乱码，影响日常使用。本文将详细介绍如何在 Tiny10 系统中恢复中文支持，包括语言包安装、输入法配置和字体修复。&lt;/p&gt;</summary>
    
    
    
    <category term="Windows" scheme="https://freemankevin.uk/categories/Windows/"/>
    
    
    <category term="Windows" scheme="https://freemankevin.uk/tags/Windows/"/>
    
    <category term="Tiny10" scheme="https://freemankevin.uk/tags/Tiny10/"/>
    
    <category term="中文支持" scheme="https://freemankevin.uk/tags/%E4%B8%AD%E6%96%87%E6%94%AF%E6%8C%81/"/>
    
    <category term="输入法" scheme="https://freemankevin.uk/tags/%E8%BE%93%E5%85%A5%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>Docker 微服务架构安全实践指南</title>
    <link href="https://freemankevin.uk/2026/04/17/docker-microservice-security/"/>
    <id>https://freemankevin.uk/2026/04/17/docker-microservice-security/</id>
    <published>2026-04-17T03:00:00.000Z</published>
    <updated>2026-05-21T06:03:03.314Z</updated>
    
    <content type="html"><![CDATA[<p>在 Docker 容器化微服务架构中,安全是一个不可忽视的重要环节。本文将分享一套完整的 Docker 微服务环境安全加固方案,涵盖端口暴露最小化、网络隔离、敏感信息管理以及多层防御策略。通过本指南,你可以有效缩减 90%+ 的攻击面,提升整体系统安全性。</p><span id="more"></span><p><strong>适用版本与环境说明：</strong></p><ul><li>Docker Engine: 20.10.x 及以上版本</li><li>Docker Compose: 2.x 及以上版本</li><li>操作系统: Ubuntu 20.04+&#x2F;Debian 11+&#x2F;CentOS 7.9+</li><li>内核版本: 建议 4.18+ 以支持完整的网络和安全特性</li><li>更新日期: 2026-04-17（建议每季度检查 Docker 安全公告）</li></ul><h2 id="核心安全原则"><a href="#核心安全原则" class="headerlink" title="核心安全原则"></a>核心安全原则</h2><h2 id="核心安全原则-1"><a href="#核心安全原则-1" class="headerlink" title="核心安全原则"></a>核心安全原则</h2><h3 id="端口最小化暴露原则"><a href="#端口最小化暴露原则" class="headerlink" title="端口最小化暴露原则"></a>端口最小化暴露原则</h3><p>在容器化环境中,端口暴露应遵循最小权限原则:</p><table><thead><tr><th>端口类型</th><th>是否映射到宿主机</th><th>说明</th></tr></thead><tbody><tr><td>22&#x2F;tcp (SSH)</td><td>✅ 是</td><td>系统管理必需</td></tr><tr><td>80&#x2F;tcp (HTTP)</td><td>✅ 是</td><td>Web 业务入口</td></tr><tr><td>443&#x2F;tcp (HTTPS)</td><td>✅ 是</td><td>安全 Web 入口(推荐)</td></tr><tr><td>数据库端口 (5432, 3306等)</td><td>❌ 否</td><td>仅容器内部访问</td></tr><tr><td>缓存端口 (6379, 11211等)</td><td>❌ 否</td><td>仅容器内部访问</td></tr><tr><td>注册中心端口 (8848, 8500等)</td><td>❌ 否</td><td>仅容器内部访问</td></tr><tr><td>后端服务端口</td><td>❌ 否</td><td>通过网关转发</td></tr><tr><td>管理后台端口</td><td>❌ 否</td><td>通过反向代理或VPN访问</td></tr></tbody></table><h3 id="网络分层架构"><a href="#网络分层架构" class="headerlink" title="网络分层架构"></a>网络分层架构</h3><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">                 [ 用户/外部网络 ]</span><br><span class="line">                        |</span><br><span class="line">                        | HTTP/HTTPS (80/443)</span><br><span class="line">                        v</span><br><span class="line">               [ Nginx 容器 (唯一入口) ]</span><br><span class="line">                        |</span><br><span class="line">           ---( Docker 内部网络: apps、middleware等 )---</span><br><span class="line">                        |</span><br><span class="line">                        v</span><br><span class="line">             [ gateway 容器 (网关) ]</span><br><span class="line">                    /   |   \</span><br><span class="line">                   /    |    \  (通过容器名称转发)</span><br><span class="line">                  v     v     v</span><br><span class="line">[ auth-service ]  [ user-service ]  [ business-service ]</span><br><span class="line">     |             |                |</span><br><span class="line">     |             |                |</span><br><span class="line">     +-------------+----------------+</span><br><span class="line">                   |</span><br><span class="line">                   v</span><br><span class="line">       [ 中间件层 ]</span><br><span class="line">     为了安全，以上所有容器均无端口映射到外部</span><br></pre></td></tr></table></figure><p><strong>网络分层说明</strong>:</p><ol><li><strong>外部入口层</strong>: 仅开放 HTTP(80) 和 HTTPS(443) 端口,所有流量必须通过 Nginx</li><li><strong>网关层</strong>: API Gateway 负责路由转发和权限验证</li><li><strong>应用服务层</strong>: 各业务微服务,通过容器名称互相调用</li><li><strong>中间件层</strong>: 数据库、缓存、注册中心等基础服务,严格内部访问</li></ol><div class="note warning"><p><strong>重要说明</strong>:<br>在 Docker Compose 环境中,服务间通信应使用<strong>容器名称</strong>(<code>container_name</code>)而非服务名称(<code>service name</code>)。容器名称是容器在网络中的唯一标识,确保服务间能够正确解析和访问。</p></div><p><strong>安全策略</strong>:</p><ul><li>所有内部服务容器均无端口映射到宿主机</li><li>外部请求只能到达 Nginx 容器</li><li>内部服务通过 Docker 网络隔离,无法直接从外部访问</li></ul><h2 id="宿主机防火墙配置"><a href="#宿主机防火墙配置" class="headerlink" title="宿主机防火墙配置"></a>宿主机防火墙配置</h2><h3 id="启用-UFW-防火墙"><a href="#启用-UFW-防火墙" class="headerlink" title="启用 UFW 防火墙"></a>启用 UFW 防火墙</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 启用 UFW 防火墙</span></span><br><span class="line"><span class="built_in">sudo</span> ufw <span class="built_in">enable</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> 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"># 仅开放必要端口</span></span><br><span class="line"><span class="built_in">sudo</span> ufw allow 22/tcp comment <span class="string">&#x27;SSH Management&#x27;</span></span><br><span class="line"><span class="built_in">sudo</span> ufw allow 80/tcp comment <span class="string">&#x27;HTTP Web Entry&#x27;</span></span><br><span class="line"><span class="built_in">sudo</span> ufw allow 443/tcp comment <span class="string">&#x27;HTTPS Web Entry&#x27;</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> ufw status verbose</span><br></pre></td></tr></table></figure><p>预期输出:</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Status: active</span><br><span class="line">Default: deny (incoming), allow (outgoing)</span><br><span class="line"></span><br><span class="line">To                         Action      From</span><br><span class="line">--                         ------      ----</span><br><span class="line">22/tcp                     ALLOW IN    Anywhere</span><br><span class="line">80/tcp                     ALLOW IN    Anywhere</span><br><span class="line">443/tcp                    ALLOW IN    Anywhere</span><br></pre></td></tr></table></figure><h2 id="Docker-网络架构配置"><a href="#Docker-网络架构配置" class="headerlink" title="Docker 网络架构配置"></a>Docker 网络架构配置</h2><h3 id="创建隔离网络"><a href="#创建隔离网络" class="headerlink" title="创建隔离网络"></a>创建隔离网络</h3><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># docker-compose.yml 顶层网络配置</span></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line">  <span class="comment"># 前端接入层网络</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">internal:</span> <span class="literal">false</span>  <span class="comment"># 允许外部访问</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment"># 应用服务层网络</span></span><br><span class="line">  <span class="attr">apps:</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><br><span class="line">  <span class="comment"># 中间件层网络</span></span><br><span class="line">  <span class="attr">middleware:</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><br><span class="line">  <span class="comment"># 模型服务层网络</span></span><br><span class="line">  <span class="attr">ai-services:</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><br></pre></td></tr></table></figure><h3 id="服务网络归属原则"><a href="#服务网络归属原则" class="headerlink" title="服务网络归属原则"></a>服务网络归属原则</h3><table><thead><tr><th>服务类型</th><th>网络归属</th><th>端口映射</th></tr></thead><tbody><tr><td>Nginx (反向代理)</td><td>frontend + apps</td><td>80:80, 443:443</td></tr><tr><td>API Gateway</td><td>apps + middleware</td><td>无</td></tr><tr><td>Java 微服务</td><td>apps + middleware</td><td>无</td></tr><tr><td>Python 后端</td><td>apps + ai-services</td><td>无</td></tr><tr><td>PostgreSQL</td><td>middleware + apps</td><td>无</td></tr><tr><td>Redis</td><td>middleware + apps</td><td>无</td></tr><tr><td>Nacos</td><td>middleware + apps</td><td>无</td></tr><tr><td>MinIO</td><td>middleware + apps</td><td>无</td></tr><tr><td>AI 模型服务</td><td>ai-services + apps</td><td>无</td></tr></tbody></table><h3 id="跨-Compose-文件的外部网络配置"><a href="#跨-Compose-文件的外部网络配置" class="headerlink" title="跨 Compose 文件的外部网络配置"></a>跨 Compose 文件的外部网络配置</h3><p>当服务分布在不同 Docker Compose 文件中时,需要使用外部网络实现互联互通。<strong>关键步骤</strong>:</p><ol><li><strong>查看现有 Docker 网络</strong>:</li></ol><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 查看所有 Docker 网络</span></span><br><span class="line">docker network <span class="built_in">ls</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 输出示例:</span></span><br><span class="line"><span class="comment"># NETWORK ID     NAME                      DRIVER    SCOPE</span></span><br><span class="line"><span class="comment"># abc123def456   installapps_apps          bridge    local</span></span><br><span class="line"><span class="comment"># def789ghi012   middleware                bridge    local</span></span><br></pre></td></tr></table></figure><ol start="2"><li><strong>在 Compose 文件中引用外部网络</strong>:</li></ol><figure class="highlight yaml"><table><tr><td class="code"><pre><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.29.0-alpine</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">nginx</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;80:80&quot;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;443:443&quot;</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">TZ=Asia/Shanghai</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">installapps_apps</span>  <span class="comment"># 引用外部网络(来自其他 compose 文件)</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;nginx&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">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">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./conf/mime.types:/etc/nginx/mime.types:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./conf/nginx.conf:/etc/nginx/nginx.conf:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./conf/web.conf:/etc/nginx/conf.d/default.conf:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./data/nginx/html:/usr/share/nginx/html</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./data/nginx/logs:/var/log/nginx:rw</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line"></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line">  <span class="attr">installapps_apps:</span></span><br><span class="line">    <span class="attr">external:</span> <span class="literal">true</span>  <span class="comment"># 声明为外部网络</span></span><br><span class="line">  <span class="attr">middleware:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">bridge</span></span><br></pre></td></tr></table></figure><div class="note danger"><p>外部网络的名称必须与 <code>docker network ls</code> 中显示的名称完全一致。</p></div><h2 id="端口映射配置规范"><a href="#端口映射配置规范" class="headerlink" title="端口映射配置规范"></a>端口映射配置规范</h2><h3 id="正确示例-仅映射必要端口"><a href="#正确示例-仅映射必要端口" class="headerlink" title="正确示例:仅映射必要端口"></a>正确示例:仅映射必要端口</h3><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="comment"># 唯一对外入口</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.29-alpine</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">nginx</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="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">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">apps</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># 后端服务:不映射端口</span></span><br><span class="line">  <span class="attr">gateway:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/gateway:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">gateway</span></span><br><span class="line">    <span class="comment"># ports: 删除所有端口映射</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">apps</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># 数据库:不映射端口</span></span><br><span class="line">  <span class="attr">postgres:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/postgres:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">postgres</span></span><br><span class="line">    <span class="comment"># ports: 删除所有端口映射</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># 缓存:不映射端口</span></span><br><span class="line">  <span class="attr">redis:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/redis:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">redis</span></span><br><span class="line">    <span class="comment"># ports: 删除所有端口映射</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br></pre></td></tr></table></figure><div class="note info"><p><strong>关键点</strong>:</p><ul><li><code>ports</code> 配置中的端口是<strong>容器自身服务端口</strong>,如 Nginx 默认 80、PostgreSQL 默认 5432</li><li>容器间通信使用 <code>container_name</code> 作为主机名,而非 <code>service name</code></li></ul></div><h3 id="错误示例-过度暴露端口"><a href="#错误示例-过度暴露端口" class="headerlink" title="错误示例:过度暴露端口"></a>错误示例:过度暴露端口</h3><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 危险!不要这样配置</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">postgres:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">postgres:17</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">postgres</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;5432:5432&quot;</span>  <span class="comment"># ⚠️ 数据库端口暴露在外</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:8</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">redis</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;6379:6379&quot;</span>  <span class="comment"># ⚠️ 缓存端口暴露在外</span></span><br><span class="line">  </span><br><span class="line">  <span class="attr">backend:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">backend:latest</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">backend</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 class="comment"># ⚠️ 后端端口暴露在外</span></span><br></pre></td></tr></table></figure><h2 id="敏感信息安全处理"><a href="#敏感信息安全处理" class="headerlink" title="敏感信息安全处理"></a>敏感信息安全处理</h2><h3 id="配置文件脱敏规范"><a href="#配置文件脱敏规范" class="headerlink" title="配置文件脱敏规范"></a>配置文件脱敏规范</h3><h4 id="镜像名称脱敏"><a href="#镜像名称脱敏" class="headerlink" title="镜像名称脱敏"></a>镜像名称脱敏</h4><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># ❌ 原始配置(含敏感信息)</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">image:</span> <span class="string">&quot;mycompany/app-server:v1.2.3&quot;</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&quot;registry.internal.com/project/backend:abc123&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ✅ 脱敏后配置</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">image:</span> <span class="string">&quot;&lt;your-registry&gt;/&lt;image-name&gt;:&lt;tag&gt;&quot;</span></span><br><span class="line">    <span class="comment"># 或使用环境变量</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&quot;$&#123;REGISTRY&#125;/$&#123;IMAGE_NAME&#125;:$&#123;IMAGE_TAG&#125;&quot;</span></span><br></pre></td></tr></table></figure><h4 id="密码凭证脱敏"><a href="#密码凭证脱敏" class="headerlink" title="密码凭证脱敏"></a>密码凭证脱敏</h4><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># ❌ 原始配置(硬编码密码)</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">postgres:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">postgres</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">POSTGRES_PASSWORD:</span> <span class="string">&quot;MyP@ssw0rd123&quot;</span></span><br><span class="line">  </span><br><span class="line">  <span class="attr">nacos:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">nacos</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">SPRING_CLOUD_NACOS_PASSWORD:</span> <span class="string">&quot;Nacos@123.com&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ✅ 方案一:使用环境变量文件</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">postgres:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">postgres</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.postgres</span>  <span class="comment"># 添加到 .gitignore</span></span><br><span class="line">  </span><br><span class="line">  <span class="attr">nacos:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">nacos</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.nacos</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ✅ 方案二:使用 Docker Secrets(Swarm模式)</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">postgres:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">postgres</span></span><br><span class="line">    <span class="attr">secrets:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">postgres_password</span></span><br><span class="line"><span class="attr">secrets:</span></span><br><span class="line">  <span class="attr">postgres_password:</span></span><br><span class="line">    <span class="attr">external:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ✅ 方案三:使用变量引用</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">postgres:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">postgres</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">POSTGRES_PASSWORD:</span> <span class="string">$&#123;POSTGRES_PASSWORD&#125;</span></span><br><span class="line"><span class="comment"># .env 文件(不提交到版本库)</span></span><br><span class="line"><span class="comment"># POSTGRES_PASSWORD=&lt;strong-password&gt;</span></span><br></pre></td></tr></table></figure><h4 id="IP-地址和域名脱敏"><a href="#IP-地址和域名脱敏" class="headerlink" title="IP 地址和域名脱敏"></a>IP 地址和域名脱敏</h4><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># ❌ 原始配置</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">container_name:</span> <span class="string">app</span></span><br><span class="line">    <span class="attr">extra_hosts:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;server01.internal:192.168.1.100&quot;</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">SPRING_CLOUD_NACOS_DISCOVERY_IP:</span> <span class="string">&quot;192.168.1.100&quot;</span></span><br><span class="line">      <span class="attr">SERVER_URL:</span> <span class="string">&quot;https://api.example.com&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ✅ 脱敏后配置</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">container_name:</span> <span class="string">app</span></span><br><span class="line">    <span class="attr">extra_hosts:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;&lt;hostname&gt;:&lt;ip-address&gt;&quot;</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">SPRING_CLOUD_NACOS_DISCOVERY_IP:</span> <span class="string">&quot;$&#123;SERVER_IP&#125;&quot;</span></span><br><span class="line">      <span class="attr">SERVER_URL:</span> <span class="string">&quot;$&#123;API_BASE_URL&#125;&quot;</span></span><br></pre></td></tr></table></figure><h3 id="gitignore-配置"><a href="#gitignore-配置" class="headerlink" title=".gitignore 配置"></a>.gitignore 配置</h3><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"># 敏感配置文件</span><br><span class="line">.env</span><br><span class="line">.env.*</span><br><span class="line">*.env</span><br><span class="line">secrets/</span><br><span class="line"></span><br><span class="line"># 包含敏感信息的配置</span><br><span class="line">docker-compose.override.yml</span><br><span class="line">docker-compose.prod.yml</span><br><span class="line"></span><br><span class="line"># 日志文件(可能含敏感信息)</span><br><span class="line">logs/</span><br><span class="line">*.log</span><br></pre></td></tr></table></figure><h3 id="环境变量模板文件"><a href="#环境变量模板文件" class="headerlink" title="环境变量模板文件"></a>环境变量模板文件</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># .env.template(提交到版本库)</span></span><br><span class="line"><span class="comment"># 复制此文件为 .env 并填写实际值</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 数据库配置</span></span><br><span class="line">POSTGRES_DB=&lt;database-name&gt;</span><br><span class="line">POSTGRES_USER=&lt;database-user&gt;</span><br><span class="line">POSTGRES_PASSWORD=&lt;strong-password&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># Nacos 配置</span></span><br><span class="line">NACOS_USERNAME=&lt;nacos-user&gt;</span><br><span class="line">NACOS_PASSWORD=&lt;nacos-password&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># MinIO 配置</span></span><br><span class="line">MINIO_ROOT_USER=&lt;minio-user&gt;</span><br><span class="line">MINIO_ROOT_PASSWORD=&lt;minio-password&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># Redis 配置</span></span><br><span class="line">REDIS_PASSWORD=&lt;redis-password&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 服务发现配置</span></span><br><span class="line">SERVER_IP=&lt;your-server-ip&gt;</span><br><span class="line">GATEWAY_PORT=&lt;gateway-port&gt;</span><br></pre></td></tr></table></figure><h2 id="Nginx-安全请求头配置"><a href="#Nginx-安全请求头配置" class="headerlink" title="Nginx 安全请求头配置"></a>Nginx 安全请求头配置</h2><h3 id="基础安全头配置"><a href="#基础安全头配置" class="headerlink" title="基础安全头配置"></a>基础安全头配置</h3><figure class="highlight nginx"><table><tr><td class="code"><pre><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_tokens</span> <span class="literal">off</span>;  <span class="comment"># 隐藏 Nginx 版本号</span></span><br><span class="line">    <span class="attribute">absolute_redirect</span> <span class="literal">off</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># 防止 MIME 类型嗅探</span></span><br><span class="line">    <span class="attribute">add_header</span> X-Content-Type-Options <span class="string">&quot;nosniff&quot;</span> always;</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># XSS 防护</span></span><br><span class="line">    <span class="attribute">add_header</span> X-XSS-Protection <span class="string">&quot;1; mode=block&quot;</span> always;</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># 防止点击劫持</span></span><br><span class="line">    <span class="attribute">add_header</span> X-Frame-Options <span class="string">&quot;DENY&quot;</span> always;</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># 引用策略</span></span><br><span class="line">    <span class="attribute">add_header</span> Referrer-Policy <span class="string">&quot;strict-origin-when-cross-origin&quot;</span> always;</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># 下载安全</span></span><br><span class="line">    <span class="attribute">add_header</span> X-Download-Options <span class="string">&quot;noopen&quot;</span> always;</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># 跨域策略</span></span><br><span class="line">    <span class="attribute">add_header</span> X-Permitted-Cross-Domain-Policies <span class="string">&quot;none&quot;</span> always;</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># 内容安全策略(根据实际需求调整)</span></span><br><span class="line">    <span class="attribute">add_header</span> Content-Security-Policy <span class="string">&quot;default-src &#x27;self&#x27;; script-src &#x27;self&#x27;; style-src &#x27;self&#x27; &#x27;unsafe-inline&#x27;; img-src &#x27;self&#x27; data: https:; font-src &#x27;self&#x27; data:; connect-src &#x27;self&#x27; http: https:; frame-ancestors &#x27;none&#x27;;&quot;</span> always;</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># HSTS(需配合 HTTPS 使用)</span></span><br><span class="line">    <span class="attribute">add_header</span> Strict-Transport-Security <span class="string">&quot;max-age=31536000; includeSubDomains&quot;</span> always;</span><br><span class="line">    </span><br><span class="line">    <span class="section">location</span> / &#123;</span><br><span class="line">        <span class="attribute">root</span> /usr/share/nginx/html;</span><br><span class="line">        <span class="attribute">index</span> index.html;</span><br><span class="line">        <span class="attribute">try_files</span> <span class="variable">$uri</span> <span class="variable">$uri</span>/ /index.html;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment"># 后端 API 代理(通过容器名称访问,不暴露端口)</span></span><br><span class="line">    <span class="section">location</span> /api/ &#123;</span><br><span class="line">        <span class="attribute">proxy_pass</span> http://gateway:8080/;  <span class="comment"># 使用容器名称</span></span><br><span class="line">        <span class="attribute">proxy_buffering</span> <span class="literal">off</span>;</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">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>说明</strong>: Nginx 反向代理配置中使用的是<strong>容器名称</strong>(<code>gateway</code>),这是容器在网络中的标识符,确保请求能正确路由到目标容器。</p><h3 id="安全请求头验证"><a href="#安全请求头验证" class="headerlink" title="安全请求头验证"></a>安全请求头验证</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 验证安全头是否生效</span></span><br><span class="line">curl -I http://&lt;your-server&gt;/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 预期输出应包含所有安全头</span></span><br><span class="line">HTTP/1.1 200 OK</span><br><span class="line">Server: nginx</span><br><span class="line">X-Content-Type-Options: nosniff</span><br><span class="line">X-XSS-Protection: 1; mode=block</span><br><span class="line">X-Frame-Options: DENY</span><br><span class="line">Referrer-Policy: strict-origin-when-cross-origin</span><br><span class="line">X-Download-Options: noopen</span><br><span class="line">X-Permitted-Cross-Domain-Policies: none</span><br><span class="line">Content-Security-Policy: default-src <span class="string">&#x27;self&#x27;</span>; ...</span><br><span class="line">Strict-Transport-Security: max-age=31536000; includeSubDomains</span><br></pre></td></tr></table></figure><h2 id="服务间通信配置"><a href="#服务间通信配置" class="headerlink" title="服务间通信配置"></a>服务间通信配置</h2><h3 id="连接地址标准化"><a href="#连接地址标准化" class="headerlink" title="连接地址标准化"></a>连接地址标准化</h3><table><thead><tr><th>连接场景</th><th>❌ 错误配置</th><th>✅ 正确配置</th></tr></thead><tbody><tr><td>Java 连接 Nacos</td><td><code>&lt;ip&gt;:38848</code></td><td><code>nacos:8848</code></td></tr><tr><td>Java 连接 PostgreSQL</td><td><code>&lt;ip&gt;:35433</code></td><td><code>postgres:5432</code></td></tr><tr><td>Java 连接 Redis</td><td><code>&lt;ip&gt;:36379</code></td><td><code>redis:6379</code></td></tr><tr><td>Nginx 转发请求</td><td><code>http://&lt;ip&gt;:8080</code></td><td><code>http://gateway:8080</code></td></tr><tr><td>服务注册地址</td><td>宿主机 IP</td><td>容器内部 IP(自动)</td></tr></tbody></table><p><strong>核心原则</strong>: 所有服务间通信使用<strong>容器名称</strong>作为主机名,Docker 内部 DNS 会自动解析为容器的内部 IP 地址。</p><h3 id="配置示例"><a href="#配置示例" class="headerlink" title="配置示例"></a>配置示例</h3><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="comment"># API 网关</span></span><br><span class="line">  <span class="attr">gateway:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/gateway:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">gateway</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">apps</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="comment"># 服务发现:使用容器名称</span></span><br><span class="line">      <span class="attr">SPRING_CLOUD_NACOS_CONFIG_SERVER_ADDR:</span> <span class="string">nacos:8848</span></span><br><span class="line">      <span class="attr">SPRING_CLOUD_NACOS_DISCOVERY_SERVER_ADDR:</span> <span class="string">nacos:8848</span></span><br><span class="line">      <span class="comment"># 数据库:使用容器名称</span></span><br><span class="line">      <span class="attr">SPRING_DATASOURCE_URL:</span> <span class="string">jdbc:postgresql://postgres:5432/&lt;db-name&gt;</span></span><br><span class="line">      <span class="comment"># 缓存:使用容器名称</span></span><br><span class="line">      <span class="attr">SPRING_REDIS_HOST:</span> <span class="string">redis</span></span><br><span class="line">      <span class="attr">SPRING_REDIS_PORT:</span> <span class="number">6379</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># 业务服务</span></span><br><span class="line">  <span class="attr">app-service:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/app-service:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">app-service</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">apps</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="comment"># 通过网关访问其他服务</span></span><br><span class="line">      <span class="attr">SERVICE_URL:</span> <span class="string">http://gateway:8080</span></span><br><span class="line">      <span class="comment"># 直接访问中间件</span></span><br><span class="line">      <span class="attr">DATABASE_URL:</span> <span class="string">postgres://postgres:5432/&lt;db-name&gt;</span></span><br><span class="line">      <span class="attr">CACHE_URL:</span> <span class="string">redis://redis:6379</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># 中间件</span></span><br><span class="line">  <span class="attr">postgres:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/postgres:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">postgres</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line">    <span class="comment"># 不映射端口,仅容器内访问</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">&lt;your-registry&gt;/redis:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">redis</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line">    <span class="comment"># 不映射端口,仅容器内访问</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">nacos:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/nacos:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">nacos</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line">    <span class="comment"># 不映射端口,仅容器内访问</span></span><br></pre></td></tr></table></figure><h2 id="安全审计检查清单"><a href="#安全审计检查清单" class="headerlink" title="安全审计检查清单"></a>安全审计检查清单</h2><h3 id="端口暴露检查"><a href="#端口暴露检查" class="headerlink" title="端口暴露检查"></a>端口暴露检查</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 检查 Docker 端口映射</span></span><br><span class="line">docker ps --format <span class="string">&quot;table &#123;&#123;.Names&#125;&#125;\t&#123;&#123;.Ports&#125;&#125;&quot;</span> | grep -v <span class="string">&quot;^NAMES&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 仅应看到:</span></span><br><span class="line"><span class="comment"># nginx    0.0.0.0:80-&gt;80/tcp, 0.0.0.0:443-&gt;443/tcp</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> netstat -tulnp | grep LISTEN</span><br><span class="line"></span><br><span class="line"><span class="comment"># 应仅看到: 22, 80, 443</span></span><br></pre></td></tr></table></figure><h3 id="网络隔离检查"><a href="#网络隔离检查" class="headerlink" title="网络隔离检查"></a>网络隔离检查</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 查看容器网络</span></span><br><span class="line">docker network <span class="built_in">ls</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看网络详情</span></span><br><span class="line">docker network inspect apps</span><br><span class="line">docker network inspect middleware</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> -it &lt;container-name&gt; ping postgres</span><br><span class="line">docker <span class="built_in">exec</span> -it &lt;container-name&gt; ping redis</span><br><span class="line">docker <span class="built_in">exec</span> -it &lt;container-name&gt; ping nacos</span><br></pre></td></tr></table></figure><h3 id="防火墙规则检查"><a href="#防火墙规则检查" class="headerlink" title="防火墙规则检查"></a>防火墙规则检查</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 检查 UFW 状态</span></span><br><span class="line"><span class="built_in">sudo</span> ufw status verbose</span><br><span class="line"></span><br><span class="line"><span class="comment"># 应显示:</span></span><br><span class="line"><span class="comment"># Default: deny (incoming), allow (outgoing)</span></span><br><span class="line"><span class="comment"># 22/tcp ALLOW IN Anywhere</span></span><br><span class="line"><span class="comment"># 80/tcp ALLOW IN Anywhere</span></span><br><span class="line"><span class="comment"># 443/tcp ALLOW IN Anywhere</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 从外部扫描端口(应在其他机器上执行)</span></span><br><span class="line">nmap -p 22,80,443,5432,6379,8848 &lt;your-server-ip&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 应仅看到 22, 80, 443 为 open</span></span><br></pre></td></tr></table></figure><h3 id="敏感信息检查"><a href="#敏感信息检查" class="headerlink" title="敏感信息检查"></a>敏感信息检查</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 检查配置文件中的敏感信息</span></span><br><span class="line">grep -r <span class="string">&quot;password\|Password\|PASSWORD&quot;</span> docker-compose*.yml</span><br><span class="line">grep -r <span class="string">&quot;secret\|Secret\|SECRET&quot;</span> docker-compose*.yml</span><br><span class="line">grep -r <span class="string">&quot;[0-9]\&#123;1,3\&#125;\.[0-9]\&#123;1,3\&#125;\.[0-9]\&#123;1,3\&#125;\.[0-9]\&#123;1,3\&#125;&quot;</span> docker-compose*.yml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查 .env 文件是否被忽略</span></span><br><span class="line">git status | grep -i <span class="built_in">env</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 确认 .gitignore 包含敏感文件</span></span><br><span class="line"><span class="built_in">cat</span> .gitignore | grep -E <span class="string">&quot;\.env|secret&quot;</span></span><br></pre></td></tr></table></figure><h2 id="完整配置模板"><a href="#完整配置模板" class="headerlink" title="完整配置模板"></a>完整配置模板</h2><h3 id="docker-compose-yml-模板"><a href="#docker-compose-yml-模板" class="headerlink" title="docker-compose.yml 模板"></a>docker-compose.yml 模板</h3><figure class="highlight yaml"><table><tr><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="comment"># 网络配置</span></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">apps:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">bridge</span></span><br><span class="line">  <span class="attr">middleware:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">bridge</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 通用配置</span></span><br><span class="line"><span class="attr">x-common-config:</span> <span class="string">&amp;common-config</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">networks:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">apps</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">services:</span></span><br><span class="line">  <span class="comment"># ============ 前端层 ============</span></span><br><span class="line">  <span class="attr">nginx:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/nginx:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">nginx</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="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">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">apps</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./conf/nginx.conf:/etc/nginx/nginx.conf:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./conf/web.conf:/etc/nginx/conf.d/default.conf:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./data/certs:/etc/ssl/private:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./data/html:/usr/share/nginx/html</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;nginx&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">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">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">gateway</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># ============ 网关层 ============</span></span><br><span class="line">  <span class="attr">gateway:</span></span><br><span class="line">    <span class="string">&lt;&lt;:</span> <span class="string">*common-config</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/gateway:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">gateway</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">apps</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">SPRING_CLOUD_NACOS_CONFIG_SERVER_ADDR:</span> <span class="string">nacos:8848</span></span><br><span class="line">      <span class="attr">SPRING_CLOUD_NACOS_DISCOVERY_SERVER_ADDR:</span> <span class="string">nacos:8848</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.gateway</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">nacos</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># ============ 应用层 ============</span></span><br><span class="line">  <span class="attr">app-service:</span></span><br><span class="line">    <span class="string">&lt;&lt;:</span> <span class="string">*common-config</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/app-service:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">app-service</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">apps</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</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.app</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># ============ 中间件层 ============</span></span><br><span class="line">  <span class="attr">postgres:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/postgres:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">postgres</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</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">POSTGRES_DB:</span> <span class="string">$&#123;POSTGRES_DB&#125;</span></span><br><span class="line">      <span class="attr">POSTGRES_USER:</span> <span class="string">$&#123;POSTGRES_USER&#125;</span></span><br><span class="line">      <span class="attr">POSTGRES_PASSWORD:</span> <span class="string">$&#123;POSTGRES_PASSWORD&#125;</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./data/postgres:/var/lib/postgresql/data</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;pg_isready&quot;</span>, <span class="string">&quot;-U&quot;</span>, <span class="string">&quot;$&#123;POSTGRES_USER&#125;&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><br><span class="line">  <span class="attr">redis:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/redis:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">redis</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line">    <span class="comment"># 无端口映射</span></span><br><span class="line">    <span class="attr">command:</span> [<span class="string">&quot;redis-server&quot;</span>, <span class="string">&quot;/usr/local/etc/redis/redis.conf&quot;</span>]</span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./conf/redis.conf:/usr/local/etc/redis/redis.conf</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./data/redis:/data</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">10s</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><br><span class="line">  <span class="attr">nacos:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&lt;your-registry&gt;/nacos:&lt;tag&gt;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">nacos</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</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">MODE:</span> <span class="string">standalone</span></span><br><span class="line">      <span class="attr">SPRING_DATASOURCE_PLATFORM:</span> <span class="string">mysql</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.nacos</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./data/nacos:/home/nacos/data</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-SHELL&quot;</span>, <span class="string">&quot;curl -f http://localhost:8848/nacos/&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">60s</span></span><br></pre></td></tr></table></figure><h3 id="环境变量文件模板"><a href="#环境变量文件模板" class="headerlink" title="环境变量文件模板"></a>环境变量文件模板</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># .env.gateway</span></span><br><span class="line">SPRING_CLOUD_NACOS_USERNAME=&lt;nacos-username&gt;</span><br><span class="line">SPRING_CLOUD_NACOS_PASSWORD=&lt;nacos-password&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># .env.app</span></span><br><span class="line">DATABASE_URL=jdbc:postgresql://postgres:5432/&lt;db-name&gt;</span><br><span class="line">DATABASE_USER=&lt;db-user&gt;</span><br><span class="line">DATABASE_PASSWORD=&lt;db-password&gt;</span><br><span class="line">REDIS_HOST=redis</span><br><span class="line">REDIS_PORT=6379</span><br><span class="line">REDIS_PASSWORD=&lt;redis-password&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># .env.nacos</span></span><br><span class="line">MYSQL_SERVICE_HOST=&lt;mysql-host&gt;</span><br><span class="line">MYSQL_SERVICE_PORT=&lt;mysql-port&gt;</span><br><span class="line">MYSQL_SERVICE_USER=&lt;mysql-user&gt;</span><br><span class="line">MYSQL_SERVICE_PASSWORD=&lt;mysql-password&gt;</span><br></pre></td></tr></table></figure><h2 id="故障排查诊断流程"><a href="#故障排查诊断流程" class="headerlink" title="故障排查诊断流程"></a>故障排查诊断流程</h2><h3 id="网络隔离故障诊断"><a href="#网络隔离故障诊断" class="headerlink" title="网络隔离故障诊断"></a>网络隔离故障诊断</h3><p><strong>诊断流程图：</strong></p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">┌─────────────────────────────────────────────────────────────┐</span><br><span class="line">│                    网络故障诊断流程                           │</span><br><span class="line">└─────────────────────────────────────────────────────────────┘</span><br><span class="line">                           │</span><br><span class="line">                           ▼</span><br><span class="line">        ┌──────────────────────────────────┐</span><br><span class="line">        │  1. 检查容器是否在同一网络        │</span><br><span class="line">        │     docker network inspect &lt;net&gt; │</span><br><span class="line">        └──────────────────────────────────┘</span><br><span class="line">                           │</span><br><span class="line">                  ┌────────┴────────┐</span><br><span class="line">                  │                 │</span><br><span class="line">              同一网络          不同网络</span><br><span class="line">                  │                 │</span><br><span class="line">                  ▼                 ▼</span><br><span class="line">        ┌──────────────┐   ┌──────────────────┐</span><br><span class="line">        │ 2. 测试连通性 │   │ 加入正确网络     │</span><br><span class="line">        │ ping/dig     │   │ docker network   │</span><br><span class="line">        │ curl         │   │ connect          │</span><br><span class="line">        └──────────────┘   └──────────────────┘</span><br><span class="line">                  │</span><br><span class="line">                  ▼</span><br><span class="line">        ┌──────────────────────────┐</span><br><span class="line">        │  3. 检查端口映射配置      │</span><br><span class="line">        │     docker ps --format   │</span><br><span class="line">        └──────────────────────────┘</span><br><span class="line">                  │</span><br><span class="line">         ┌────────┴─────────┐</span><br><span class="line">         │                  │</span><br><span class="line">      端口未映射          端口已映射</span><br><span class="line">      (预期状态)          (检查是否必要)</span><br><span class="line">         │                  │</span><br><span class="line">         ▼                  ▼</span><br><span class="line">  ┌────────────┐    ┌──────────────────┐</span><br><span class="line">  │ 服务正常    │    │ 评估安全风险     │</span><br><span class="line">  └────────────┐    │ 考虑移除映射     │</span><br><span class="line">                  └──────────────────┘</span><br></pre></td></tr></table></figure><p><strong>诊断命令链：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># ===== 第一阶段：网络连通性检查 =====</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 1. 查看所有网络</span></span><br><span class="line">docker network <span class="built_in">ls</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 检查特定网络中的容器</span></span><br><span class="line">docker network inspect apps</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 测试容器间连通性</span></span><br><span class="line">docker <span class="built_in">exec</span> -it gateway ping postgres</span><br><span class="line">docker <span class="built_in">exec</span> -it gateway ping redis</span><br><span class="line">docker <span class="built_in">exec</span> -it gateway ping nacos</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 检查 DNS 解析</span></span><br><span class="line">docker <span class="built_in">exec</span> -it gateway dig postgres</span><br><span class="line">docker <span class="built_in">exec</span> -it gateway nslookup redis</span><br><span class="line"></span><br><span class="line"><span class="comment"># ===== 第二阶段：端口暴露检查 =====</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 查看所有容器端口映射</span></span><br><span class="line">docker ps --format <span class="string">&quot;table &#123;&#123;.Names&#125;&#125;\t&#123;&#123;.Ports&#125;&#125;&quot;</span></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> netstat -tulnp | grep LISTEN</span><br><span class="line"><span class="built_in">sudo</span> ss -tulnp | grep LISTEN</span><br><span class="line"></span><br><span class="line"><span class="comment"># 7. 从外部扫描端口（在其他机器上执行）</span></span><br><span class="line">nmap -p 22,80,443,5432,6379,8848 &lt;server-ip&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># ===== 第三阶段：防火墙检查 =====</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 8. 检查 UFW 状态</span></span><br><span class="line"><span class="built_in">sudo</span> ufw status verbose</span><br><span class="line"></span><br><span class="line"><span class="comment"># 9. 检查 iptables 规则</span></span><br><span class="line"><span class="built_in">sudo</span> iptables -L -n -v</span><br><span class="line"></span><br><span class="line"><span class="comment"># 10. 检查 Docker iptables 规则</span></span><br><span class="line"><span class="built_in">sudo</span> iptables -t nat -L DOCKER -n -v</span><br></pre></td></tr></table></figure><h3 id="常见故障案例"><a href="#常见故障案例" class="headerlink" title="常见故障案例"></a>常见故障案例</h3><h4 id="案例-1：服务间无法通信"><a href="#案例-1：服务间无法通信" class="headerlink" title="案例 1：服务间无法通信"></a>案例 1：服务间无法通信</h4><p><strong>现象：</strong> Java 微服务无法连接 Nacos 或数据库</p><p><strong>排查步骤：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 确认容器在同一网络</span></span><br><span class="line">docker inspect gateway | grep -A 20 <span class="string">&quot;Networks&quot;</span></span><br><span class="line">docker inspect nacos | grep -A 20 <span class="string">&quot;Networks&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 检查容器名称</span></span><br><span class="line">docker ps --format <span class="string">&quot;&#123;&#123;.Names&#125;&#125;&quot;</span> | grep -E <span class="string">&quot;gateway|nacos|postgres&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 测试 DNS 解析</span></span><br><span class="line">docker <span class="built_in">exec</span> -it gateway getent hosts nacos</span><br><span class="line"><span class="comment"># 如果返回空，说明 DNS 解析失败</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 检查网络配置</span></span><br><span class="line">docker network inspect apps --format <span class="string">&#x27;&#123;&#123;range .Containers&#125;&#125;&#123;&#123;.Name&#125;&#125;: &#123;&#123;.IPv4Address&#125;&#125;&#123;&#123;end&#125;&#125;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 临时修复：手动添加 hosts</span></span><br><span class="line"><span class="comment"># 在 docker-compose.yml 中添加：</span></span><br><span class="line">extra_hosts:</span><br><span class="line">  - <span class="string">&quot;nacos:&lt;nacos-ip&gt;&quot;</span></span><br></pre></td></tr></table></figure><p><strong>根因分析：</strong></p><ul><li>容器不在同一网络（最常见）</li><li>容器名称不匹配（docker-compose.yml 中 container_name 配置错误）</li><li>Docker 内部 DNS 缓存问题（重启 Docker Daemon）</li></ul><h4 id="案例-2：外部无法访问服务"><a href="#案例-2：外部无法访问服务" class="headerlink" title="案例 2：外部无法访问服务"></a>案例 2：外部无法访问服务</h4><p><strong>现象：</strong> 外部请求无法到达 Nginx 或返回 502</p><p><strong>排查步骤：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 检查 Nginx 容器状态</span></span><br><span class="line">docker ps | grep nginx</span><br><span class="line">docker logs nginx --<span class="built_in">tail</span> 100</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 检查 Nginx 配置语法</span></span><br><span class="line">docker <span class="built_in">exec</span> nginx nginx -t</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 测试 Nginx 到后端的连通性</span></span><br><span class="line">docker <span class="built_in">exec</span> nginx curl -v http://gateway:8080/</span><br><span class="line"><span class="comment"># 如果失败，说明 Nginx 无法访问后端</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 检查端口映射</span></span><br><span class="line">docker port nginx</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> ufw status | grep -E <span class="string">&quot;80|443&quot;</span></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> netstat -tulnp | grep -E <span class="string">&quot;:80|:443&quot;</span></span><br></pre></td></tr></table></figure><p><strong>根因分析：</strong></p><ul><li>Nginx 端口未正确映射到宿主机</li><li>防火墙规则阻止了外部访问</li><li>Nginx 配置中使用了错误的后端地址（IP而非容器名称）</li></ul><h4 id="案例-3：敏感信息泄露"><a href="#案例-3：敏感信息泄露" class="headerlink" title="案例 3：敏感信息泄露"></a>案例 3：敏感信息泄露</h4><p><strong>现象：</strong> git status 显示 .env 文件或密码出现在日志中</p><p><strong>排查步骤：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 检查 .gitignore 配置</span></span><br><span class="line"><span class="built_in">cat</span> .gitignore | grep -E <span class="string">&quot;\.env|secret&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 检查是否有敏感文件被提交</span></span><br><span class="line">git <span class="built_in">log</span> --all --full-history -- <span class="string">&quot;*.env&quot;</span></span><br><span class="line">git <span class="built_in">log</span> --all --full-history -- <span class="string">&quot;*password*&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 检查容器日志中的敏感信息</span></span><br><span class="line">docker logs &lt;container&gt; | grep -i <span class="string">&quot;password&quot;</span></span><br><span class="line">docker logs &lt;container&gt; | grep -E <span class="string">&quot;[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 检查 docker-compose.yml 硬编码密码</span></span><br><span class="line">grep -r <span class="string">&quot;password\|Password\|PASSWORD&quot;</span> docker-compose*.yml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 清理 Git 历史（如果已提交）</span></span><br><span class="line"><span class="comment"># 使用 BFG Repo-Cleaner 或 git filter-branch</span></span><br></pre></td></tr></table></figure><p><strong>修复方案：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 更新 .gitignore</span></span><br><span class="line"><span class="built_in">cat</span> &gt;&gt; .gitignore &lt;&lt; <span class="string">EOF</span></span><br><span class="line"><span class="string">.env</span></span><br><span class="line"><span class="string">.env.*</span></span><br><span class="line"><span class="string">*.env</span></span><br><span class="line"><span class="string">secrets/</span></span><br><span class="line"><span class="string">docker-compose.override.yml</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 从 Git 中移除已提交的敏感文件</span></span><br><span class="line">git <span class="built_in">rm</span> --cached .<span class="built_in">env</span></span><br><span class="line">git <span class="built_in">rm</span> --cached docker-compose.override.yml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 使用环境变量替代硬编码密码</span></span><br><span class="line"><span class="comment"># 编辑 docker-compose.yml，改为：</span></span><br><span class="line">environment:</span><br><span class="line">  POSTGRES_PASSWORD: <span class="variable">$&#123;POSTGRES_PASSWORD&#125;</span></span><br></pre></td></tr></table></figure><h2 id="参考资源"><a href="#参考资源" class="headerlink" title="参考资源"></a>参考资源</h2><h3 id="官方文档"><a href="#官方文档" class="headerlink" title="官方文档"></a>官方文档</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLmRvY2tlci5jb20v">Docker 官方文档<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLmRvY2tlci5jb20vZW5naW5lL3NlY3VyaXR5Lw==">Docker 安全最佳实践<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLmRvY2tlci5jb20vbmV0d29yay8=">Docker 网络配置指南<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLmRvY2tlci5jb20vY29tcG9zZS8=">Docker Compose 官方文档<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9uZ2lueC5vcmcvZW4vZG9jcy8=">Nginx 官方文档<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9uZ2lueC5vcmcvZW4vZG9jcy9odHRwL2NvbmZpZ3VyaW5nX2h0dHBzX3NlcnZlcnMuaHRtbA==">Nginx 安全配置指南<i class="fa fa-external-link-alt"></i></span></li></ul><h3 id="安全标准与最佳实践"><a href="#安全标准与最佳实践" class="headerlink" title="安全标准与最佳实践"></a>安全标准与最佳实践</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly93d3cuY2lzZWN1cml0eS5vcmcvYmVuY2htYXJrL2RvY2tlcg==">CIS Docker Benchmark<i class="fa fa-external-link-alt"></i></span> - Docker 安全配置基准</li><li><span class="exturl" data-url="aHR0cHM6Ly9jaGVhdHNoZWV0c2VyaWVzLm93YXNwLm9yZy9jaGVhdHNoZWV0cy9Eb2NrZXJfU2VjdXJpdHlfQ2hlYXRfU2hlZXQuaHRtbA==">OWASP Docker 安全<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLmRvY2tlci5jb20vc2NvdXQv">Docker 安全扫描指南<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2tvbnN0cnVrdG9pZC9Eb2NrZXItc2VjdXJpdHktY29uZmlndXJhdGlvbi1jaGVja2xpc3Q=">容器安全检查清单<i class="fa fa-external-link-alt"></i></span></li></ul><h3 id="工具与扫描器"><a href="#工具与扫描器" class="headerlink" title="工具与扫描器"></a>工具与扫描器</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2FxdWFzZWN1cml0eS90cml2eQ==">Trivy - 容器漏洞扫描器<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2RvY2tlci9kb2NrZXItYmVuY2gtc2VjdXJpdHk=">Docker Bench for Security<i class="fa fa-external-link-alt"></i></span> - Docker 安全审计脚本</li><li><span class="exturl" data-url="aHR0cHM6Ly9mYWxjby5vcmcv">Falco - 容器运行时安全<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3F1YXkvY2xhaXI=">Clair - 镜像漏洞分析<i class="fa fa-external-link-alt"></i></span></li></ul><h3 id="网络与隔离"><a href="#网络与隔离" class="headerlink" title="网络与隔离"></a>网络与隔离</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLmRvY2tlci5jb20vbmV0d29yay8jbmV0d29yay1kcml2ZXJz">Docker 网络架构详解<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLmRvY2tlci5jb20vbmV0d29yay8jZG5zLXNlcnZpY2Vz">Docker 内部网络 DNS<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly93d3cuY25pLmRldi8=">CNI 网络插件规范<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9tYW43Lm9yZy9saW51eC9tYW4tcGFnZXMvbWFuNy9uZXR3b3JrX25hbWVzcGFjZXMuNy5odG1s">Linux 网络 namespaces<i class="fa fa-external-link-alt"></i></span></li></ul><h3 id="社区资源"><a href="#社区资源" class="headerlink" title="社区资源"></a>社区资源</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL21vYnkvbW9ieQ==">Docker GitHub 仓库<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLmRvY2tlci5jb20vc2VjdXJpdHkv">Docker 安全公告<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2g1YnAvc2VydmVyLWNvbmZpZ3Mtbmdpbng=">Nginx 安全头配置<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2RvY2tlci1saWJyYXJ5L29mZmljaWFsLWltYWdlcy9kaXNjdXNzaW9ucw==">docker-microservice-security GitHub 讨论<i class="fa fa-external-link-alt"></i></span></li></ul><h3 id="进阶阅读"><a href="#进阶阅读" class="headerlink" title="进阶阅读"></a>进阶阅读</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9jb250YWluZXItc29sdXRpb25zLmNvbS9kb2NrZXItc2VjdXJpdHktYmVzdC1wcmFjdGljZXMv">《Docker 安全最佳实践》电子书<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2NuY2Yvc2lnLXNlY3VyaXR5">云原生安全白皮书<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9sd24ubmV0L0FydGljbGVzLzUzMTExNC8=">容器隔离技术深度解析<i class="fa fa-external-link-alt"></i></span></li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><h3 id="核心安全措施"><a href="#核心安全措施" class="headerlink" title="核心安全措施"></a>核心安全措施</h3><ol><li><strong>端口最小化</strong>: 仅开放 80&#x2F;443 (Web) 和 22 (SSH)</li><li><strong>网络隔离</strong>: 所有服务通过 Docker 内部网络通信</li><li><strong>配置脱敏</strong>: 使用环境变量和 secrets 管理敏感信息</li><li><strong>安全请求头</strong>: Nginx 注入完整的安全响应头</li><li><strong>防火墙双重防护</strong>: Docker 网络隔离 + 宿主机 UFW 防火墙</li><li><strong>服务发现</strong>: 使用容器名称而非 IP 地址</li><li><strong>定期审计</strong>: 执行安全检查脚本</li></ol><h3 id="安全收益"><a href="#安全收益" class="headerlink" title="安全收益"></a>安全收益</h3><ul><li><strong>攻击面缩减 90%+</strong>: 数据库、缓存、后端服务端口完全隐藏</li><li><strong>网络嗅探防护</strong>: 内部流量在容器网络内闭环</li><li><strong>配置安全性</strong>: 敏感信息不入代码库</li><li><strong>可维护性提升</strong>: 服务发现机制自动适应环境变化</li><li><strong>符合最佳实践</strong>: 遵循云原生安全部署标准</li></ul><p>通过本指南的实施,你可以构建一个安全、可靠的 Docker 微服务架构环境,有效降低安全风险,保护业务系统免受外部威胁。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;在 Docker 容器化微服务架构中,安全是一个不可忽视的重要环节。本文将分享一套完整的 Docker 微服务环境安全加固方案,涵盖端口暴露最小化、网络隔离、敏感信息管理以及多层防御策略。通过本指南,你可以有效缩减 90%+ 的攻击面,提升整体系统安全性。&lt;/p&gt;</summary>
    
    
    
    <category term="Docker" scheme="https://freemankevin.uk/categories/Docker/"/>
    
    
    <category term="Docker" scheme="https://freemankevin.uk/tags/Docker/"/>
    
    <category term="Security" scheme="https://freemankevin.uk/tags/Security/"/>
    
    <category term="Microservice" scheme="https://freemankevin.uk/tags/Microservice/"/>
    
    <category term="Network" scheme="https://freemankevin.uk/tags/Network/"/>
    
  </entry>
  
  <entry>
    <title>Kubernetes 生产级部署完整指南（kubeadm）</title>
    <link href="https://freemankevin.uk/2025/11/13/k8s-kubeadm/"/>
    <id>https://freemankevin.uk/2025/11/13/k8s-kubeadm/</id>
    <published>2025-11-13T09:47:25.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p>Kubernetes 是云原生应用编排的核心平台。本文档提供生产级 Kubernetes 集群部署方案，涵盖架构设计、环境准备、组件安装、网络配置、安全加固、性能优化和故障排查等全流程内容，适用于学习和生产环境。</p><span id="more"></span><p><strong>适用版本与环境说明：</strong></p><ul><li>Kubernetes: 1.28.x - 1.33.x（本文以 v1.33.6 为示例）</li><li>Containerd: 1.7.x 及以上版本</li><li>Flannel: v0.27.x 及以上版本</li><li>操作系统: Debian 12 (Trixie)&#x2F;Ubuntu 22.04+&#x2F;CentOS 7.9+&#x2F;Rocky Linux 9+</li><li>内核版本: 建议 5.4+ 以支持完整的容器网络特性</li><li>更新日期: 2025-11-13（建议关注 Kubernetes 官方版本更新公告）</li></ul><div class="note warning"><p>Kubernetes 版本迭代较快，部署前请访问 <span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL3JlbGVhc2VzLw==">Kubernetes Releases<i class="fa fa-external-link-alt"></i></span> 查看最新稳定版本和版本兼容性矩阵。</p></div><h2 id="Kubernetes-架构概述"><a href="#Kubernetes-架构概述" class="headerlink" title="Kubernetes 架构概述"></a>Kubernetes 架构概述</h2><h2 id="Kubernetes-架构概述-1"><a href="#Kubernetes-架构概述-1" class="headerlink" title="Kubernetes 架构概述"></a>Kubernetes 架构概述</h2><h3 id="Control-Plane-组件"><a href="#Control-Plane-组件" class="headerlink" title="Control Plane 组件"></a>Control Plane 组件</h3><table><thead><tr><th>组件</th><th>功能</th><th>生产要求</th></tr></thead><tbody><tr><td>kube-apiserver</td><td>集群 API 入口，认证授权</td><td>3+ 副本，负载均衡</td></tr><tr><td>etcd</td><td>分布式键值存储，保存集群状态</td><td>3+ 节点，定期备份</td></tr><tr><td>kube-scheduler</td><td>Pod 调度决策</td><td>多副本，Leader选举</td></tr><tr><td>kube-controller-manager</td><td>控制器管理（Deployment、Node等）</td><td>多副本，Leader选举</td></tr><tr><td>cloud-controller-manager</td><td>云平台集成控制器</td><td>可选，云环境必需</td></tr></tbody></table><h3 id="Worker-Node-组件"><a href="#Worker-Node-组件" class="headerlink" title="Worker Node 组件"></a>Worker Node 组件</h3><table><thead><tr><th>组件</th><th>功能</th><th>配置要点</th></tr></thead><tbody><tr><td>kubelet</td><td>节点代理，与 API Server 通信</td><td>配置资源预留</td></tr><tr><td>kube-proxy</td><td>服务代理，实现 Service</td><td>iptables&#x2F;IPVS 模式</td></tr><tr><td>Container Runtime</td><td>容器运行时（containerd&#x2F;Docker）</td><td>systemd cgroup 驱动</td></tr></tbody></table><h3 id="网络模型"><a href="#网络模型" class="headerlink" title="网络模型"></a>网络模型</h3><p>Kubernetes 网络需满足四个要求：</p><ol><li>所有 Pod 不使用 NAT 即可相互通信</li><li>所有 Node 不使用 NAT 即可与所有 Pod 通信</li><li>Pod 看到的自身 IP 与其他 Pod 看到的 IP 相同</li><li>Service 的 ClusterIP 可在集群内访问</li></ol><h2 id="部署架构"><a href="#部署架构" class="headerlink" title="部署架构"></a>部署架构</h2><h3 id="单控制平面架构（测试环境）"><a href="#单控制平面架构（测试环境）" class="headerlink" title="单控制平面架构（测试环境）"></a>单控制平面架构（测试环境）</h3><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">┌─────────────────────────────────────────┐</span><br><span class="line">│  Control Plane (192.168.199.135)        │</span><br><span class="line">│  ├─ kube-apiserver (6443)               │</span><br><span class="line">│  ├─ etcd (2379-2380)                    │</span><br><span class="line">│  ├─ kube-scheduler                      │</span><br><span class="line">│  ├─ kube-controller-manager             │</span><br><span class="line">│  └─ kubelet                             │</span><br><span class="line">└─────────────────────────────────────────┘</span><br><span class="line">           │</span><br><span class="line">           │ Pod Network (10.244.0.0/16)</span><br><span class="line">           │</span><br><span class="line">┌─────────────────────────────────────────┐</span><br><span class="line">│  Worker Node (192.168.199.136)          │</span><br><span class="line">│  ├─ kubelet                             │</span><br><span class="line">│  ├─ kube-proxy                          │</span><br><span class="line">│  └─ Pods (业务应用)                      │</span><br><span class="line">└─────────────────────────────────────────┘</span><br></pre></td></tr></table></figure><h3 id="高可用架构（生产环境）"><a href="#高可用架构（生产环境）" class="headerlink" title="高可用架构（生产环境）"></a>高可用架构（生产环境）</h3><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">┌────────────────────────────────────────────────────┐</span><br><span class="line">│         Load Balancer (HAProxy/Nginx)              │</span><br><span class="line">│                 VIP: 192.168.1.100                 │</span><br><span class="line">└────────────────────────────────────────────────────┘</span><br><span class="line">        │                    │                    │</span><br><span class="line">        ▼                    ▼                    ▼</span><br><span class="line">┌──────────────┐  ┌──────────────┐  ┌──────────────┐</span><br><span class="line">│ Master 1     │  │ Master 2     │  │ Master 3     │</span><br><span class="line">│ API Server   │  │ API Server   │  │ API Server   │</span><br><span class="line">│ etcd         │  │ etcd         │  │ etcd         │</span><br><span class="line">└──────────────┘  └──────────────┘  └──────────────┘</span><br><span class="line">        │                    │                    │</span><br><span class="line">        └────────────────────┴────────────────────┘</span><br><span class="line">                           │</span><br><span class="line">        ┌──────────────────┼──────────────────┐</span><br><span class="line">        ▼                  ▼                  ▼</span><br><span class="line">┌──────────────┐  ┌──────────────┐  ┌──────────────┐</span><br><span class="line">│ Worker 1     │  │ Worker 2     │  │ Worker 3     │</span><br><span class="line">└──────────────┘  └──────────────┘  └──────────────┘</span><br></pre></td></tr></table></figure><p><strong>高可用要点：</strong></p><ul><li>etcd 集群：3 或 5 节点，奇数配置</li><li>API Server：多副本 + 负载均衡</li><li>控制器：内置 Leader 选举机制</li><li>网络：跨节点 Pod 通信，Service 负载均衡</li></ul><hr><h2 id="前置要求"><a href="#前置要求" class="headerlink" title="前置要求"></a>前置要求</h2><h3 id="硬件资源配置"><a href="#硬件资源配置" class="headerlink" title="硬件资源配置"></a>硬件资源配置</h3><table><thead><tr><th>环境</th><th>CPU</th><th>内存</th><th>存储</th><th>说明</th></tr></thead><tbody><tr><td>测试环境</td><td>2核</td><td>2GB</td><td>20GB</td><td>最小配置，仅用于学习</td></tr><tr><td>开发环境</td><td>4核</td><td>4GB</td><td>50GB</td><td>推荐配置，支持轻量应用</td></tr><tr><td>生产环境</td><td>8核+</td><td>16GB+</td><td>100GB+</td><td>SSD存储，独立etcd</td></tr><tr><td>大规模集群</td><td>16核+</td><td>32GB+</td><td>200GB+</td><td>高IO性能，专用磁盘</td></tr></tbody></table><p><strong>生产环境补充建议：</strong></p><ul><li>Master节点：CPU预留1核，内存预留2GB给系统进程</li><li>Worker节点：根据应用负载动态调整</li><li>etcd数据：独立SSD磁盘，避免IO竞争</li><li>网络带宽：至少1Gbps，生产推荐10Gbps</li></ul><h3 id="网络配置要求"><a href="#网络配置要求" class="headerlink" title="网络配置要求"></a>网络配置要求</h3><h4 id="必需开放的端口"><a href="#必需开放的端口" class="headerlink" title="必需开放的端口"></a>必需开放的端口</h4><p><strong>Control Plane节点：</strong></p><table><thead><tr><th>端口</th><th>协议</th><th>服务</th><th>说明</th></tr></thead><tbody><tr><td>6443</td><td>TCP</td><td>API Server</td><td>Kubernetes API入口</td></tr><tr><td>2379-2380</td><td>TCP</td><td>etcd</td><td>etcd服务端口</td></tr><tr><td>10250</td><td>TCP</td><td>Kubelet</td><td>节点状态和日志</td></tr><tr><td>10251</td><td>TCP</td><td>Scheduler</td><td>调度器端口</td></tr><tr><td>10252</td><td>TCP</td><td>Controller</td><td>控制器端口</td></tr><tr><td>10257</td><td>TCP</td><td>kube-controller-manager</td><td>安全端口</td></tr><tr><td>10259</td><td>TCP</td><td>kube-scheduler</td><td>安全端口</td></tr></tbody></table><p><strong>Worker节点：</strong></p><table><thead><tr><th>端口</th><th>协议</th><th>服务</th><th>说明</th></tr></thead><tbody><tr><td>10250</td><td>TCP</td><td>Kubelet</td><td>节点通信</td></tr><tr><td>10256</td><td>TCP</td><td>kube-proxy</td><td>代理健康检查</td></tr><tr><td>30000-32767</td><td>TCP</td><td>NodePort</td><td>服务暴露端口</td></tr></tbody></table><h4 id="网络插件端口"><a href="#网络插件端口" class="headerlink" title="网络插件端口"></a>网络插件端口</h4><table><thead><tr><th>网络插件</th><th>端口</th><th>说明</th></tr></thead><tbody><tr><td>Flannel</td><td>8285&#x2F;8472</td><td>VXLAN通信</td></tr><tr><td>Calico</td><td>179&#x2F;4789</td><td>BGP&#x2F;VXLAN</td></tr><tr><td>Cilium</td><td>4240&#x2F;8472</td><td>健康检查&#x2F;VXLAN</td></tr></tbody></table><h3 id="系统检查清单"><a href="#系统检查清单" class="headerlink" title="系统检查清单"></a>系统检查清单</h3><p>执行以下检查确保系统就绪：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 验证 MAC 地址唯一性</span></span><br><span class="line">ip <span class="built_in">link</span> | grep <span class="built_in">link</span>/ether</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 验证 product_uuid 唯一性</span></span><br><span class="line"><span class="built_in">cat</span> /sys/class/dmi/id/product_uuid</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 确认 Swap 已禁用</span></span><br><span class="line">free | grep Swap</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 验证时间同步</span></span><br><span class="line">timedatectl status</span><br><span class="line">systemctl status systemd-timesyncd</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 检查内核版本（建议 5.4+）</span></span><br><span class="line"><span class="built_in">uname</span> -r</span><br><span class="line"></span><br><span class="line"><span class="comment"># 6. 检查系统资源</span></span><br><span class="line"><span class="built_in">df</span> -h</span><br><span class="line">free -g</span><br><span class="line">lscpu</span><br></pre></td></tr></table></figure><hr><h2 id="安装步骤"><a href="#安装步骤" class="headerlink" title="安装步骤"></a>安装步骤</h2><h3 id="配置-APT-源（两台-VM）"><a href="#配置-APT-源（两台-VM）" class="headerlink" title="配置 APT 源（两台 VM）"></a>配置 APT 源（两台 VM）</h3><p>使用清华 TUNA 镜像加速软件包下载：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">nano /etc/apt/sources.list</span><br></pre></td></tr></table></figure><p>替换为以下内容：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">deb https://mirrors.tuna.tsinghua.edu.cn/debian/ trixie main contrib non-free-firmware</span><br><span class="line">deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ trixie main contrib non-free-firmware</span><br><span class="line"></span><br><span class="line">deb https://mirrors.tuna.tsinghua.edu.cn/debian/ trixie-updates main contrib non-free-firmware</span><br><span class="line">deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ trixie-updates main contrib non-free-firmware</span><br><span class="line"></span><br><span class="line">deb https://mirrors.tuna.tsinghua.edu.cn/debian/ trixie-backports main contrib non-free-firmware</span><br><span class="line">deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ trixie-backports main contrib non-free-firmware</span><br><span class="line"></span><br><span class="line">deb https://mirrors.tuna.tsinghua.edu.cn/debian-security/ trixie-security main contrib non-free-firmware</span><br><span class="line">deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security/ trixie-security main contrib non-free-firmware</span><br></pre></td></tr></table></figure><h3 id="禁用-Swap（两台-VM）"><a href="#禁用-Swap（两台-VM）" class="headerlink" title="禁用 Swap（两台 VM）"></a>禁用 Swap（两台 VM）</h3><p>Kubelet 无法在启用 Swap 的系统上运行：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 立即禁用</span></span><br><span class="line"><span class="built_in">sudo</span> swapoff -a</span><br><span class="line"></span><br><span class="line"><span class="comment"># 永久禁用（编辑 fstab 文件）</span></span><br><span class="line"><span class="built_in">sudo</span> sed -i <span class="string">&#x27;/ swap / s/^\(.*\)$/#\1/g&#x27;</span> /etc/fstab</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证（应输出 0）</span></span><br><span class="line">free | grep Swap | awk <span class="string">&#x27;&#123;print $2&#125;&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="安装并配置容器运行时（两台-VM）"><a href="#安装并配置容器运行时（两台-VM）" class="headerlink" title="安装并配置容器运行时（两台 VM）"></a>安装并配置容器运行时（两台 VM）</h3><p>使用 Containerd 作为容器运行时（Kubernetes 1.24+ 推荐）：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 加载必需的内核模块</span></span><br><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><span class="line"></span><br><span class="line"><span class="comment"># 2. 配置内核参数（生产级调优）</span></span><br><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"># Kubernetes 必需参数</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"></span></span><br><span class="line"><span class="string"># 性能优化参数</span></span><br><span class="line"><span class="string">net.core.somaxconn                  = 65535</span></span><br><span class="line"><span class="string">net.ipv4.tcp_max_syn_backlog        = 8192</span></span><br><span class="line"><span class="string">net.core.netdev_max_backlog         = 5000</span></span><br><span class="line"><span class="string">vm.swappiness                       = 10</span></span><br><span class="line"><span class="string">vm.max_map_count                    = 262144</span></span><br><span class="line"><span class="string">fs.file-max                         = 655350</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><span class="line"></span><br><span class="line"><span class="comment"># 3. 安装 Containerd</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 containerd</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> <span class="built_in">mkdir</span> -p /etc/containerd</span><br><span class="line"><span class="built_in">sudo</span> 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"># 5. 关键配置优化（生产必需）</span></span><br><span class="line"><span class="built_in">sudo</span> sed -i <span class="string">&#x27;s/SystemdCgroup = false/SystemdCgroup = true/g&#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|registry.k8s.io/pause:3\.[0-9]\+|registry.aliyuncs.com/google_containers/pause:3.10|g&#x27;</span> /etc/containerd/config.toml</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> systemctl <span class="built_in">enable</span> --now containerd</span><br><span class="line"><span class="built_in">sudo</span> systemctl status containerd</span><br><span class="line"><span class="built_in">sudo</span> ctr version</span><br><span class="line"></span><br><span class="line"><span class="comment"># 7. 验证配置</span></span><br><span class="line"><span class="built_in">sudo</span> ctr config dump | grep -A5 <span class="string">&quot;plugins&quot;</span></span><br></pre></td></tr></table></figure><p><strong>Containerd 生产级配置详解：</strong></p><figure class="highlight toml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># /etc/containerd/config.toml 关键片段</span></span><br><span class="line"><span class="section">[plugins.&quot;io.containerd.grpc.v1.cri&quot;]</span></span><br><span class="line">  <span class="attr">enable_tls_streaming</span> = <span class="literal">false</span></span><br><span class="line">  </span><br><span class="line">  <span class="section">[plugins.&quot;io.containerd.grpc.v1.cri&quot;.containerd]</span></span><br><span class="line">    <span class="attr">snapshotter</span> = <span class="string">&quot;overlayfs&quot;</span></span><br><span class="line">    <span class="attr">default_runtime_name</span> = <span class="string">&quot;runc&quot;</span></span><br><span class="line">    </span><br><span class="line">    <span class="section">[plugins.&quot;io.containerd.grpc.v1.cri&quot;.containerd.runtimes.runc]</span></span><br><span class="line">      <span class="attr">runtime_type</span> = <span class="string">&quot;io.containerd.runc.v2&quot;</span></span><br><span class="line">      </span><br><span class="line">      <span class="section">[plugins.&quot;io.containerd.grpc.v1.cri&quot;.containerd.runtimes.runc.options]</span></span><br><span class="line">        <span class="attr">SystemdCgroup</span> = <span class="literal">true</span>  <span class="comment"># Kubernetes 必需</span></span><br><span class="line">        </span><br><span class="line">  <span class="section">[plugins.&quot;io.containerd.grpc.v1.cri&quot;.registry]</span></span><br><span class="line">    <span class="section">[plugins.&quot;io.containerd.grpc.v1.cri&quot;.registry.mirrors]</span></span><br><span class="line">      <span class="section">[plugins.&quot;io.containerd.grpc.v1.cri&quot;.registry.mirrors.&quot;docker.io&quot;]</span></span><br><span class="line">        <span class="attr">endpoint</span> = [<span class="string">&quot;https://registry.aliyuncs.com&quot;</span>]</span><br></pre></td></tr></table></figure><h3 id="安装-Kubeadm、Kubelet、Kubectl（两台-VM）"><a href="#安装-Kubeadm、Kubelet、Kubectl（两台-VM）" class="headerlink" title="安装 Kubeadm、Kubelet、Kubectl（两台 VM）"></a>安装 Kubeadm、Kubelet、Kubectl（两台 VM）</h3><p>添加 Kubernetes 官方仓库并安装 v1.33 版本：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 安装必需的工具</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 apt-transport-https ca-certificates curl gnupg</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 添加 Kubernetes 官方 GPG 密钥</span></span><br><span class="line">curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | <span class="built_in">sudo</span> gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 添加 Kubernetes v1.33 APT 仓库</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /&#x27;</span> | <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/apt/sources.list.d/kubernetes.list</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 刷新缓存</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get update</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 安装指定版本</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get install -y kubelet=1.33.* kubeadm=1.33.* kubectl=1.33.*</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> apt-mark hold kubelet kubeadm kubectl</span><br><span class="line"></span><br><span class="line"><span class="comment"># 7. 验证安装</span></span><br><span class="line">kubeadm version</span><br></pre></td></tr></table></figure><h3 id="初始化-Control-Plane（仅-VM-1-Master-节点）"><a href="#初始化-Control-Plane（仅-VM-1-Master-节点）" class="headerlink" title="初始化 Control Plane（仅 VM 1 - Master 节点）"></a>初始化 Control Plane（仅 VM 1 - Master 节点）</h3><p><strong>前置条件：</strong> 记录 Master 节点的 IP 地址（本例为 <code>192.168.199.135</code>）</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 初始化集群</span></span><br><span class="line"><span class="built_in">sudo</span> kubeadm init \</span><br><span class="line">  --apiserver-advertise-address=192.168.199.135 \</span><br><span class="line">  --pod-network-cidr=10.244.0.0/16 \</span><br><span class="line">  --kubernetes-version v1.33.6 \</span><br><span class="line">  --image-repository registry.aliyuncs.com/google_containers</span><br></pre></td></tr></table></figure><div class="note warning"><p>初始化完成后，终端会输出：</p><ul><li>kubectl 配置命令</li><li><strong><code>kubeadm join</code> 命令</strong>（必须保存供 Worker 节点使用）</li></ul></div><h3 id="配置-Kubectl（仅-VM-1）"><a href="#配置-Kubectl（仅-VM-1）" class="headerlink" title="配置 Kubectl（仅 VM 1）"></a>配置 Kubectl（仅 VM 1）</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 为当前用户配置 kubectl</span></span><br><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><span class="line"></span><br><span class="line"><span class="comment"># 验证 Control Plane（节点状态应为 NotReady，等待网络插件）</span></span><br><span class="line">kubectl get nodes</span><br></pre></td></tr></table></figure><h3 id="Worker-Node-加入集群（仅-VM-2）"><a href="#Worker-Node-加入集群（仅-VM-2）" class="headerlink" title="Worker Node 加入集群（仅 VM 2）"></a>Worker Node 加入集群（仅 VM 2）</h3><p>在 VM 2 上执行步骤 5 中保存的 <code>kubeadm join</code> 命令：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">sudo</span> kubeadm <span class="built_in">join</span> 192.168.199.135:6443 --token &lt;YOUR_TOKEN&gt; \</span><br><span class="line">  --discovery-token-ca-cert-hash sha256:&lt;YOUR_HASH&gt;</span><br></pre></td></tr></table></figure><div class="note info"><p><code>&lt;YOUR_TOKEN&gt;</code> 和 <code>&lt;YOUR_HASH&gt;</code> 来自步骤 5 的输出。</p></div><h3 id="部署网络插件-Flannel（VM-1-或任意有-kubectl-访问的节点）"><a href="#部署网络插件-Flannel（VM-1-或任意有-kubectl-访问的节点）" class="headerlink" title="部署网络插件 - Flannel（VM 1 或任意有 kubectl 访问的节点）"></a>部署网络插件 - Flannel（VM 1 或任意有 kubectl 访问的节点）</h3><p>Kubernetes 需要网络插件实现 Pod 间通信。我们使用 Flannel：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 部署 Flannel CNI</span></span><br><span class="line">kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml</span><br><span class="line"></span><br><span class="line"><span class="comment"># 等待 1-2 分钟，然后验证</span></span><br><span class="line">kubectl get pods -n kube-system | grep flannel</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证所有系统 Pod 运行正常</span></span><br><span class="line">kubectl get pods -n kube-system</span><br></pre></td></tr></table></figure><h3 id="预加载-Flannel-镜像（两台-VM-可选但推荐）"><a href="#预加载-Flannel-镜像（两台-VM-可选但推荐）" class="headerlink" title="预加载 Flannel 镜像（两台 VM - 可选但推荐）"></a>预加载 Flannel 镜像（两台 VM - 可选但推荐）</h3><p>如果网络不稳定或镜像下载缓慢，可提前在两台 VM 上加载 Flannel 镜像：</p><p><strong>方案一：直接拉取镜像</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 使用 ctr 直接拉取镜像到 containerd</span></span><br><span class="line"><span class="built_in">sudo</span> ctr image pull ghcr.io/flannel-io/flannel:v0.27.4</span><br><span class="line"><span class="built_in">sudo</span> ctr image pull ghcr.io/flannel-io/flannel-cni-plugin:v1.8.0-flannel1</span><br></pre></td></tr></table></figure><p><strong>方案二：本地打包后导入</strong></p><p>如果镜像源不可达，可在能访问外网的机器上下载后导入：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 在能访问外网的机器上执行</span></span><br><span class="line"><span class="comment"># 1. 拉取镜像</span></span><br><span class="line">docker pull ghcr.io/flannel-io/flannel:v0.27.4</span><br><span class="line">docker pull ghcr.io/flannel-io/flannel-cni-plugin:v1.8.0-flannel1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 打包成 tar 文件</span></span><br><span class="line">docker save -o flannel_images.tar \</span><br><span class="line">  ghcr.io/flannel-io/flannel:v0.27.4 \</span><br><span class="line">  ghcr.io/flannel-io/flannel-cni-plugin:v1.8.0-flannel1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将 flannel_images.tar 文件复制到两台 VM，然后执行：</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 在每台 VM 上导入镜像</span></span><br><span class="line"><span class="comment"># 导入到 k8s.io 命名空间</span></span><br><span class="line"><span class="built_in">sudo</span> ctr --namespace k8s.io image import flannel_images.tar</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> ctr images list | grep flannel</span><br><span class="line"><span class="built_in">sudo</span> ctr --namespace k8s.io images list | grep flannel</span><br></pre></td></tr></table></figure><h3 id="修复-CNI-插件路径（两台-VM）"><a href="#修复-CNI-插件路径（两台-VM）" class="headerlink" title="修复 CNI 插件路径（两台 VM）"></a>修复 CNI 插件路径（两台 VM）</h3><p>如果 CoreDNS Pod 仍无法启动，执行以下修复：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 创建 CNI 标准目录</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /usr/lib/cni</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 创建 Flannel 插件的符号链接</span></span><br><span class="line"><span class="built_in">cd</span> /usr/lib/cni/</span><br><span class="line"><span class="keyword">for</span> plugin <span class="keyword">in</span> /opt/cni/bin/*; <span class="keyword">do</span></span><br><span class="line">  <span class="built_in">sudo</span> <span class="built_in">ln</span> -sf <span class="string">&quot;<span class="variable">$plugin</span>&quot;</span> <span class="string">&quot;<span class="subst">$(basename $plugin)</span>&quot;</span></span><br><span class="line"><span class="keyword">done</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">ls</span> -lh /usr/lib/cni/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 重启 Kubelet</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl restart kubelet</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 验证 Pod 状态</span></span><br><span class="line">kubectl get pods -n kube-system</span><br></pre></td></tr></table></figure><hr><h2 id="集群验证"><a href="#集群验证" class="headerlink" title="集群验证"></a>集群验证</h2><h3 id="最终验证（VM-1）"><a href="#最终验证（VM-1）" class="headerlink" title="最终验证（VM 1）"></a>最终验证（VM 1）</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 检查所有节点状态（应全为 Ready）</span></span><br><span class="line">kubectl get nodes</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 检查所有系统 Pod（应全为 Running）</span></span><br><span class="line">kubectl get pods -n kube-system</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 查看集群信息</span></span><br><span class="line">kubectl cluster-info</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 运行测试 Pod</span></span><br><span class="line">kubectl run test-pod --image=nginx --port=80</span><br><span class="line">kubectl get pods</span><br><span class="line">kubectl delete pod test-pod</span><br></pre></td></tr></table></figure><h3 id="常见验证命令"><a href="#常见验证命令" class="headerlink" title="常见验证命令"></a>常见验证命令</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 查看节点详细信息</span></span><br><span class="line">kubectl describe node &lt;NODE_NAME&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看集群资源</span></span><br><span class="line">kubectl top nodes</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看系统事件</span></span><br><span class="line">kubectl get events -n kube-system</span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查 API 服务器状态</span></span><br><span class="line">kubectl get cs  <span class="comment"># 已弃用，但可用于诊断</span></span><br></pre></td></tr></table></figure><hr><h2 id="故障排除"><a href="#故障排除" class="headerlink" title="故障排除"></a>故障排除</h2><h3 id="故障诊断流程图"><a href="#故障诊断流程图" class="headerlink" title="故障诊断流程图"></a>故障诊断流程图</h3><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">┌─────────────────────────────────────────────────────────────┐</span><br><span class="line">│                 Kubernetes 集群故障诊断流程                   │</span><br><span class="line">└─────────────────────────────────────────────────────────────┘</span><br><span class="line">                           │</span><br><span class="line">                           ▼</span><br><span class="line">        ┌──────────────────────────────────┐</span><br><span class="line">        │  1. 检查节点状态                  │</span><br><span class="line">        │     kubectl get nodes            │</span><br><span class="line">        └──────────────────────────────────┘</span><br><span class="line">                           │</span><br><span class="line">                  ┌────────┴────────┐</span><br><span class="line">                  │                 │</span><br><span class="line">              Ready             NotReady</span><br><span class="line">                  │                 │</span><br><span class="line">                  ▼                 ▼</span><br><span class="line">        ┌──────────────┐   ┌──────────────────┐</span><br><span class="line">        │ 2. 检查Pod   │   │ 检查 kubelet     │</span><br><span class="line">        │    状态      │   │ 日志和网络插件   │</span><br><span class="line">        └──────────────┘   └──────────────────┘</span><br><span class="line">                  │                 │</span><br><span class="line">                  ▼                 ▼</span><br><span class="line">        ┌──────────────────┐ ┌──────────────────┐</span><br><span class="line">        │ 3. 检查系统组件   │ │ 重启 kubelet     │</span><br><span class="line">        │    Pod 状态      │ │ 修复 CNI 配置    │</span><br><span class="line">        └──────────────────┘ └──────────────────┘</span><br><span class="line">                  │</span><br><span class="line">         ┌────────┴─────────┐</span><br><span class="line">         │                  │</span><br><span class="line">       Running            Pending/CrashLoopBackOff</span><br><span class="line">         │                  │</span><br><span class="line">         ▼                  ▼</span><br><span class="line">  ┌────────────┐    ┌──────────────────┐</span><br><span class="line">  │ 集群正常    │    │ 检查 Pod 日志    │</span><br><span class="line">  └────────────┐    │ 修复镜像/配置    │</span><br><span class="line">                  └──────────────────┘</span><br></pre></td></tr></table></figure><h3 id="诊断命令链"><a href="#诊断命令链" class="headerlink" title="诊断命令链"></a>诊断命令链</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># ===== 第一阶段：节点状态检查 =====</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 1. 查看所有节点状态</span></span><br><span class="line">kubectl get nodes -o wide</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 查看节点详细信息</span></span><br><span class="line">kubectl describe node &lt;node-name&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 检查节点资源使用</span></span><br><span class="line">kubectl top nodes</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 检查 kubelet 状态（在节点上执行）</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl status kubelet</span><br><span class="line"><span class="built_in">sudo</span> journalctl -u kubelet -n 100 --no-pager</span><br><span class="line"></span><br><span class="line"><span class="comment"># ===== 第二阶段：系统 Pod 检查 =====</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 查看所有系统 Pod</span></span><br><span class="line">kubectl get pods -n kube-system -o wide</span><br><span class="line"></span><br><span class="line"><span class="comment"># 6. 查看特定 Pod 详情</span></span><br><span class="line">kubectl describe pod &lt;pod-name&gt; -n kube-system</span><br><span class="line"></span><br><span class="line"><span class="comment"># 7. 查看 Pod 日志</span></span><br><span class="line">kubectl logs &lt;pod-name&gt; -n kube-system</span><br><span class="line">kubectl logs &lt;pod-name&gt; -n kube-system --previous  <span class="comment"># 查看上一个容器的日志</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 8. 检查组件状态</span></span><br><span class="line">kubectl get componentstatuses</span><br><span class="line"></span><br><span class="line"><span class="comment"># ===== 第三阶段：网络检查 =====</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 9. 检查网络插件状态</span></span><br><span class="line">kubectl get pods -n kube-system | grep -E <span class="string">&quot;flannel|calico|cilium&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 10. 检查 CNI 配置（在节点上执行）</span></span><br><span class="line"><span class="built_in">ls</span> -la /etc/cni/net.d/</span><br><span class="line"><span class="built_in">cat</span> /etc/cni/net.d/*.conf</span><br><span class="line"></span><br><span class="line"><span class="comment"># 11. 检查 Flannel 配置</span></span><br><span class="line">kubectl logs -n kube-system &lt;flannel-pod-name&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 12. 测试 Pod 间通信</span></span><br><span class="line">kubectl run test-pod --image=busybox --restart=Never --<span class="built_in">rm</span> -it -- ping &lt;pod-ip&gt;</span><br></pre></td></tr></table></figure><h3 id="问题：节点处于-NotReady-状态"><a href="#问题：节点处于-NotReady-状态" class="headerlink" title="问题：节点处于 NotReady 状态"></a>问题：节点处于 NotReady 状态</h3><p><strong>原因分析：</strong></p><ol><li>网络插件未部署或未就绪</li><li>kubelet 服务异常</li><li>CNI 配置错误</li><li>容器运行时异常</li></ol><p><strong>解决方案：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 检查 Flannel Pod 状态</span></span><br><span class="line">kubectl get pods -n kube-system | grep flannel</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 查看 Flannel Pod 日志</span></span><br><span class="line">kubectl logs -n kube-system &lt;FLANNEL_POD_NAME&gt;</span><br><span class="line">kubectl describe pod -n kube-system &lt;FLANNEL_POD_NAME&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 检查 kubelet 日志（在 NotReady 节点上执行）</span></span><br><span class="line"><span class="built_in">sudo</span> journalctl -u kubelet -f</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 检查 containerd 状态</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl status containerd</span><br><span class="line"><span class="built_in">sudo</span> journalctl -u containerd -n 50</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 重启 kubelet（在节点上执行）</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl restart kubelet</span><br><span class="line"></span><br><span class="line"><span class="comment"># 6. 检查 CNI 插件路径</span></span><br><span class="line"><span class="built_in">ls</span> -la /opt/cni/bin/</span><br><span class="line"><span class="built_in">ls</span> -la /etc/cni/net.d/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 7. 如果 CNI 插件缺失，重新部署</span></span><br><span class="line">kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml</span><br></pre></td></tr></table></figure><p><strong>验证修复：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 等待 1-2 分钟后检查</span></span><br><span class="line">kubectl get nodes</span><br><span class="line"><span class="comment"># 应显示 Ready 状态</span></span><br></pre></td></tr></table></figure><h3 id="问题：CoreDNS-Pod-处于-Pending-状态"><a href="#问题：CoreDNS-Pod-处于-Pending-状态" class="headerlink" title="问题：CoreDNS Pod 处于 Pending 状态"></a>问题：CoreDNS Pod 处于 Pending 状态</h3><p><strong>原因分析：</strong></p><ol><li>CNI 插件路径配置不正确</li><li>网络插件未就绪</li><li>节点资源不足</li></ol><p><strong>解决方案：</strong> 执行步骤 9 的修复步骤</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 创建 CNI 标准目录（在所有节点执行）</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /usr/lib/cni</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 创建符号链接</span></span><br><span class="line"><span class="built_in">cd</span> /usr/lib/cni/</span><br><span class="line"><span class="keyword">for</span> plugin <span class="keyword">in</span> /opt/cni/bin/*; <span class="keyword">do</span></span><br><span class="line">  <span class="built_in">sudo</span> <span class="built_in">ln</span> -sf <span class="string">&quot;<span class="variable">$plugin</span>&quot;</span> <span class="string">&quot;<span class="subst">$(basename $plugin)</span>&quot;</span></span><br><span class="line"><span class="keyword">done</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">ls</span> -lh /usr/lib/cni/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 重启 Kubelet（在所有节点执行）</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl restart kubelet</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 检查 CoreDNS Pod 状态</span></span><br><span class="line">kubectl get pods -n kube-system | grep coredns</span><br><span class="line"></span><br><span class="line"><span class="comment"># 6. 如果仍处于 Pending，检查调度限制</span></span><br><span class="line">kubectl describe pod -n kube-system &lt;coredns-pod-name&gt;</span><br></pre></td></tr></table></figure><h3 id="问题：kubeadm-join-失败"><a href="#问题：kubeadm-join-失败" class="headerlink" title="问题：kubeadm join 失败"></a>问题：kubeadm join 失败</h3><p><strong>原因分析：</strong></p><ol><li>Token 过期（默认 24 小时有效）</li><li>CA 证书哈希不匹配</li><li>Master 节点 API Server 不可达</li><li>端口 6443 被防火墙阻止</li></ol><p><strong>解决方案：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 在 Master 节点生成新 Token</span></span><br><span class="line">kubeadm token create --print-join-command</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 检查 Token 列表</span></span><br><span class="line">kubeadm token list</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 获取 CA 证书哈希（如果 Token 有效但哈希错误）</span></span><br><span class="line">openssl x509 -pubkey -<span class="keyword">in</span> /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2&gt;/dev/null | openssl dgst -sha256 -hex | sed <span class="string">&#x27;s/^.* //&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 手动构建 join 命令</span></span><br><span class="line">kubeadm <span class="built_in">join</span> &lt;master-ip&gt;:6443 --token &lt;token&gt; --discovery-token-ca-cert-hash sha256:&lt;<span class="built_in">hash</span>&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 检查网络连通性（在 Worker 节点执行）</span></span><br><span class="line">ping &lt;master-ip&gt;</span><br><span class="line">curl -k https://&lt;master-ip&gt;:6443/version</span><br><span class="line"></span><br><span class="line"><span class="comment"># 6. 检查防火墙规则（在 Master 节点执行）</span></span><br><span class="line"><span class="built_in">sudo</span> ufw status | grep 6443</span><br><span class="line"><span class="built_in">sudo</span> iptables -L -n | grep 6443</span><br></pre></td></tr></table></figure><h3 id="问题：Pod-无法启动（镜像拉取失败）"><a href="#问题：Pod-无法启动（镜像拉取失败）" class="headerlink" title="问题：Pod 无法启动（镜像拉取失败）"></a>问题：Pod 无法启动（镜像拉取失败）</h3><p><strong>原因分析：</strong></p><ol><li>镜像仓库不可达</li><li>镜像不存在或版本错误</li><li>需要认证但未配置 Secret</li><li>网络策略阻止下载</li></ol><p><strong>解决方案：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 检查镜像拉取错误</span></span><br><span class="line">kubectl describe pod &lt;pod-name&gt; -n &lt;namespace&gt;</span><br><span class="line"><span class="comment"># 查看 Events 部分的错误信息</span></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> ctr image pull &lt;image-name&gt;</span><br><span class="line"><span class="comment"># 或</span></span><br><span class="line">docker pull &lt;image-name&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 配置镜像加速（containerd）</span></span><br><span class="line"><span class="comment"># 编辑 /etc/containerd/config.toml</span></span><br><span class="line">[plugins.<span class="string">&quot;io.containerd.grpc.v1.cri&quot;</span>.registry.mirrors.<span class="string">&quot;docker.io&quot;</span>]</span><br><span class="line">endpoint = [<span class="string">&quot;https://registry.aliyuncs.com&quot;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># 4. 重启 containerd</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl restart containerd</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 配置私有仓库认证</span></span><br><span class="line">kubectl create secret docker-registry regcred \</span><br><span class="line">  --docker-server=&lt;registry-server&gt; \</span><br><span class="line">  --docker-username=&lt;username&gt; \</span><br><span class="line">  --docker-password=&lt;password&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 6. 在 Pod 或 Deployment 中引用 Secret</span></span><br><span class="line">spec:</span><br><span class="line">  imagePullSecrets:</span><br><span class="line">  - name: regcred</span><br></pre></td></tr></table></figure><h3 id="获取调试日志"><a href="#获取调试日志" class="headerlink" title="获取调试日志"></a>获取调试日志</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 查看 Kubelet 日志</span></span><br><span class="line"><span class="built_in">sudo</span> journalctl -u kubelet -f</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> journalctl -u containerd -f</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看 kube-apiserver 日志</span></span><br><span class="line">kubectl logs -n kube-system kube-apiserver-&lt;master-node-name&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看 kube-scheduler 日志</span></span><br><span class="line">kubectl logs -n kube-system kube-scheduler-&lt;master-node-name&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看 kube-controller-manager 日志</span></span><br><span class="line">kubectl logs -n kube-system kube-controller-manager-&lt;master-node-name&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看 etcd 日志</span></span><br><span class="line">kubectl logs -n kube-system etcd-&lt;master-node-name&gt;</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> crictl logs &lt;container-id&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看 Pod 事件</span></span><br><span class="line">kubectl get events -n kube-system --sort-by=<span class="string">&#x27;.lastTimestamp&#x27;</span></span><br></pre></td></tr></table></figure><hr><h2 id="常用命令参考"><a href="#常用命令参考" class="headerlink" title="常用命令参考"></a>常用命令参考</h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 集群管理</span></span><br><span class="line">kubectl get nodes                          <span class="comment"># 列出所有节点</span></span><br><span class="line">kubectl get pods -A                        <span class="comment"># 列出所有 Pod</span></span><br><span class="line">kubectl get svc -A                         <span class="comment"># 列出所有服务</span></span><br><span class="line">kubectl get events -n kube-system         <span class="comment"># 查看系统事件</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 节点管理</span></span><br><span class="line">kubectl cordon &lt;NODE_NAME&gt;                <span class="comment"># 禁止 Pod 调度到该节点</span></span><br><span class="line">kubectl uncordon &lt;NODE_NAME&gt;              <span class="comment"># 允许 Pod 调度到该节点</span></span><br><span class="line">kubectl drain &lt;NODE_NAME&gt;                 <span class="comment"># 驱逐节点上的所有 Pod</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 日志查看</span></span><br><span class="line">kubectl logs -n kube-system &lt;POD_NAME&gt;   <span class="comment"># 查看 Pod 日志</span></span><br><span class="line">kubectl describe pod &lt;POD_NAME&gt;           <span class="comment"># 查看 Pod 详细信息</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 集群信息</span></span><br><span class="line">kubectl cluster-info                      <span class="comment"># 查看集群信息</span></span><br><span class="line">kubectl api-resources                     <span class="comment"># 查看所有 API 资源</span></span><br></pre></td></tr></table></figure><h2 id="参考资源"><a href="#参考资源" class="headerlink" title="参考资源"></a>参考资源</h2><h3 id="官方文档"><a href="#官方文档" class="headerlink" title="官方文档"></a>官方文档</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3Mv">Kubernetes 官方文档<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3Mvc2V0dXAvcHJvZHVjdGlvbi1lbnZpcm9ubWVudC90b29scy9rdWJlYWRtLw==">kubeadm 官方指南<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvcmVmZXJlbmNlL3NldHVwLXRvb2xzL2t1YmVhZG0v">kubeadm 配置参考<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3Mvc2V0dXAvcmVsZWFzZS92ZXJzaW9uLXNrZXctcG9saWN5Lw==">Kubernetes 版本支持政策<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3Mvc2V0dXAvcmVsZWFzZS9ub3Rlcy8=">Kubernetes 发行说明<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2ZsYW5uZWwtaW8vZmxhbm5lbA==">Flannel 官方文档<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9jb250YWluZXJkLmlvLw==">Containerd 官方文档<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2NvbnRhaW5lcmQvY29udGFpbmVyZC9ibG9iL21haW4vZG9jcy9jcmkvdXNhZ2UubWQ=">Containerd 配置指南<i class="fa fa-external-link-alt"></i></span></li></ul><h3 id="安全与加固"><a href="#安全与加固" class="headerlink" title="安全与加固"></a>安全与加固</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly93d3cuY2lzZWN1cml0eS5vcmcvYmVuY2htYXJrL2t1YmVybmV0ZXM=">CIS Kubernetes Benchmark<i class="fa fa-external-link-alt"></i></span> - Kubernetes 安全配置基准</li><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvY29uY2VwdHMvc2VjdXJpdHkv">Kubernetes 安全最佳实践<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvY29uY2VwdHMvc2VjdXJpdHkvcG9kLXNlY3VyaXR5LXN0YW5kYXJkcy8=">Pod Security Standards<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvdGFza3MvZGVidWcvZGVidWctY2x1c3Rlci9hdWRpdC8=">Kubernetes 安全审计<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvcmVmZXJlbmNlL2FjY2Vzcy1hdXRobi1hdXRoei9yYmFjLw==">RBAC 配置指南<i class="fa fa-external-link-alt"></i></span></li></ul><h3 id="网络与-CNI"><a href="#网络与-CNI" class="headerlink" title="网络与 CNI"></a>网络与 CNI</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvY29uY2VwdHMvY2x1c3Rlci1hZG1pbmlzdHJhdGlvbi9uZXR3b3JraW5nLw==">Kubernetes 网络模型<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2NvbnRhaW5lcm5ldHdvcmtpbmcvY25p">CNI 插件规范<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2ZsYW5uZWwtaW8vZmxhbm5lbC9ibG9iL21hc3Rlci9Eb2N1bWVudGF0aW9uL2t1YmVybmV0ZXMubWQ=">Flannel 网络配置<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLnRpZ2VyYS5pby9jYWxpY28vbGF0ZXN0L2Fib3V0L2NhbGljby8=">Calico 网络策略<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9jaWxpdW0uaW8v">Cilium 网络方案<i class="fa fa-external-link-alt"></i></span></li></ul><h3 id="高可用与运维"><a href="#高可用与运维" class="headerlink" title="高可用与运维"></a>高可用与运维</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3Mvc2V0dXAvcHJvZHVjdGlvbi1lbnZpcm9ubWVudC90b29scy9rdWJlYWRtL2hhLXRvcG9sb2d5Lw==">Kubernetes 高可用拓扑<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9ldGNkLmlvL2RvY3MvbGF0ZXN0L29wLWd1aWRlLw==">etcd 运维指南<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvdGFza3MvYWRtaW5pc3Rlci1jbHVzdGVyL2JhY2stdXAtZXRjZC8=">Kubernetes 备份与恢复<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvY29uY2VwdHMvY2x1c3Rlci1hZG1pbmlzdHJhdGlvbi9zeXN0ZW0tbWV0cmljcy8=">Kubernetes 监控架构<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9rdWJlcm5ldGVzLmlvL2RvY3MvcmVmZXJlbmNlL2NvbW1hbmQtbGluZS10b29scy1yZWZlcmVuY2Uva3ViZWxldC8=">kubelet 配置参考<i class="fa fa-external-link-alt"></i></span></li></ul><h3 id="社区与工具"><a href="#社区与工具" class="headerlink" title="社区与工具"></a>社区与工具</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2t1YmVybmV0ZXMva3ViZXJuZXRlcw==">Kubernetes GitHub 仓库<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2t1YmVybmV0ZXMva3ViZWFkbQ==">kubeadm GitHub<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2t1YmVybmV0ZXMvZW5oYW5jZW1lbnRz">Kubernetes Enhancement Proposals (KEP)<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9zbGFjay5rOHMuaW8v">Kubernetes Slack 社区<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2t1YmVybmV0ZXMva3ViZXJuZXRlcy9pc3N1ZXM=">Kubernetes Issue 跟踪<i class="fa fa-external-link-alt"></i></span></li></ul><h3 id="进阶阅读"><a href="#进阶阅读" class="headerlink" title="进阶阅读"></a>进阶阅读</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2t1YmVybmV0ZXMva3ViZXJuZXRlcw==">《Kubernetes 权威指南》<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly93d3cuY25jZi5pby8=">云原生计算基金会 (CNCF)<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2NuY2Yvc2lnLXNlY3VyaXR5L3RyZWUvbWFpbi9zZWN1cml0eS13aGl0ZXBhcGVy">Kubernetes 安全白皮书<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2tlbHNleWhpZ2h0b3dlci9rdWJlcm5ldGVzLXRoZS1oYXJkLXdheQ==">生产级 Kubernetes 部署检查清单<i class="fa fa-external-link-alt"></i></span></li></ul><hr><h2 id="生产环境优化配置"><a href="#生产环境优化配置" class="headerlink" title="生产环境优化配置"></a>生产环境优化配置</h2><h3 id="Kubelet-资源预留"><a href="#Kubelet-资源预留" class="headerlink" title="Kubelet 资源预留"></a>Kubelet 资源预留</h3><p>编辑 <code>/var/lib/kubelet/config.yaml</code>（或通过 kubeadm 配置）：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">kubelet.config.k8s.io/v1beta1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">KubeletConfiguration</span></span><br><span class="line"><span class="attr">systemReserved:</span></span><br><span class="line">  <span class="attr">cpu:</span> <span class="string">&quot;500m&quot;</span></span><br><span class="line">  <span class="attr">memory:</span> <span class="string">&quot;1Gi&quot;</span></span><br><span class="line">  <span class="attr">ephemeral-storage:</span> <span class="string">&quot;10Gi&quot;</span></span><br><span class="line"><span class="attr">kubeReserved:</span></span><br><span class="line">  <span class="attr">cpu:</span> <span class="string">&quot;500m&quot;</span></span><br><span class="line">  <span class="attr">memory:</span> <span class="string">&quot;1Gi&quot;</span></span><br><span class="line">  <span class="attr">ephemeral-storage:</span> <span class="string">&quot;10Gi&quot;</span></span><br><span class="line"><span class="attr">evictionHard:</span></span><br><span class="line">  <span class="attr">memory.available:</span> <span class="string">&quot;500Mi&quot;</span></span><br><span class="line">  <span class="attr">nodefs.available:</span> <span class="string">&quot;10%&quot;</span></span><br><span class="line">  <span class="attr">nodefs.inodesFree:</span> <span class="string">&quot;5%&quot;</span></span><br><span class="line">  <span class="attr">imagefs.available:</span> <span class="string">&quot;10%&quot;</span></span><br><span class="line"><span class="attr">maxPods:</span> <span class="number">110</span></span><br><span class="line"><span class="attr">imageGCHighThresholdPercent:</span> <span class="number">85</span></span><br><span class="line"><span class="attr">imageGCLowThresholdPercent:</span> <span class="number">80</span></span><br></pre></td></tr></table></figure><p><strong>应用配置：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart kubelet</span><br><span class="line">kubectl describe node | grep -A5 <span class="string">&quot;Allocated resources&quot;</span></span><br></pre></td></tr></table></figure><h3 id="API-Server-性能调优"><a href="#API-Server-性能调优" class="headerlink" title="API Server 性能调优"></a>API Server 性能调优</h3><p>高并发场景配置（添加到 kubeadm init 参数）：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">sudo</span> kubeadm init \</span><br><span class="line">  --apiserver-advertise-address=192.168.199.135 \</span><br><span class="line">  --pod-network-cidr=10.244.0.0/16 \</span><br><span class="line">  --kubernetes-version v1.33.6 \</span><br><span class="line">  --image-repository registry.aliyuncs.com/google_containers \</span><br><span class="line">  --apiserver-extra-args=--max-requests-inflight=800 \</span><br><span class="line">  --apiserver-extra-args=--max-mutating-requests-inflight=400 \</span><br><span class="line">  --apiserver-extra-args=--default-not-ready-toleration-seconds=300 \</span><br><span class="line">  --apiserver-extra-args=--default-unreachable-toleration-seconds=300</span><br></pre></td></tr></table></figure><h3 id="etcd-性能优化"><a href="#etcd-性能优化" class="headerlink" title="etcd 性能优化"></a>etcd 性能优化</h3><p>编辑 <code>/etc/kubernetes/manifests/etcd.yaml</code>：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">containers:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">command:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">etcd</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">--snapshot-count=10000</span>  <span class="comment"># 提高快照频率</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">--heartbeat-interval=200</span>  <span class="comment"># 心跳间隔（毫秒）</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">--election-timeout=2000</span>  <span class="comment"># 选举超时（毫秒）</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">--quota-backend-bytes=8589934592</span>  <span class="comment"># 8GB 存储限制</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">--auto-compaction-retention=1h</span>  <span class="comment"># 自动压缩</span></span><br></pre></td></tr></table></figure><hr><h2 id="安全加固配置"><a href="#安全加固配置" class="headerlink" title="安全加固配置"></a>安全加固配置</h2><h3 id="RBAC-最小权限原则"><a href="#RBAC-最小权限原则" class="headerlink" title="RBAC 最小权限原则"></a>RBAC 最小权限原则</h3><p>创建命名空间管理员角色：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">rbac.authorization.k8s.io/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Role</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">namespace:</span> <span class="string">production</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">namespace-admin</span></span><br><span class="line"><span class="attr">rules:</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">apiGroups:</span> [<span class="string">&quot;&quot;</span>, <span class="string">&quot;apps&quot;</span>, <span class="string">&quot;extensions&quot;</span>]</span><br><span class="line">  <span class="attr">resources:</span> [<span class="string">&quot;*&quot;</span>]</span><br><span class="line">  <span class="attr">verbs:</span> [<span class="string">&quot;get&quot;</span>, <span class="string">&quot;list&quot;</span>, <span class="string">&quot;watch&quot;</span>, <span class="string">&quot;create&quot;</span>, <span class="string">&quot;update&quot;</span>, <span class="string">&quot;patch&quot;</span>, <span class="string">&quot;delete&quot;</span>]</span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">apiVersion:</span> <span class="string">rbac.authorization.k8s.io/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">RoleBinding</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">namespace:</span> <span class="string">production</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">namespace-admin-binding</span></span><br><span class="line"><span class="attr">subjects:</span></span><br><span class="line"><span class="bullet">-</span> <span class="attr">kind:</span> <span class="string">User</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">dev-user</span></span><br><span class="line">  <span class="attr">apiGroup:</span> <span class="string">rbac.authorization.k8s.io</span></span><br><span class="line"><span class="attr">roleRef:</span></span><br><span class="line">  <span class="attr">kind:</span> <span class="string">Role</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">namespace-admin</span></span><br><span class="line">  <span class="attr">apiGroup:</span> <span class="string">rbac.authorization.k8s.io</span></span><br></pre></td></tr></table></figure><h3 id="Pod-安全策略（PSP）"><a href="#Pod-安全策略（PSP）" class="headerlink" title="Pod 安全策略（PSP）"></a>Pod 安全策略（PSP）</h3><p>使用 Pod Security Standards：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">Namespace</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">production</span></span><br><span class="line">  <span class="attr">labels:</span></span><br><span class="line">    <span class="attr">pod-security.kubernetes.io/enforce:</span> <span class="string">restricted</span></span><br><span class="line">    <span class="attr">pod-security.kubernetes.io/enforce-version:</span> <span class="string">latest</span></span><br><span class="line">    <span class="attr">pod-security.kubernetes.io/audit:</span> <span class="string">restricted</span></span><br><span class="line">    <span class="attr">pod-security.kubernetes.io/audit-version:</span> <span class="string">latest</span></span><br><span class="line">    <span class="attr">pod-security.kubernetes.io/warn:</span> <span class="string">restricted</span></span><br><span class="line">    <span class="attr">pod-security.kubernetes.io/warn-version:</span> <span class="string">latest</span></span><br></pre></td></tr></table></figure><h3 id="网络策略（Network-Policy）"><a href="#网络策略（Network-Policy）" class="headerlink" title="网络策略（Network Policy）"></a>网络策略（Network Policy）</h3><p>限制命名空间间通信：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">networking.k8s.io/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">NetworkPolicy</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">default-deny</span></span><br><span class="line">  <span class="attr">namespace:</span> <span class="string">production</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">podSelector:</span> &#123;&#125;</span><br><span class="line">  <span class="attr">policyTypes:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">Ingress</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">Egress</span></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">apiVersion:</span> <span class="string">networking.k8s.io/v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">NetworkPolicy</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">allow-same-namespace</span></span><br><span class="line">  <span class="attr">namespace:</span> <span class="string">production</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">podSelector:</span> &#123;&#125;</span><br><span class="line">  <span class="attr">ingress:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">from:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">podSelector:</span> &#123;&#125;</span><br><span class="line">  <span class="attr">egress:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">to:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">podSelector:</span> &#123;&#125;</span><br></pre></td></tr></table></figure><h3 id="集群证书轮换"><a href="#集群证书轮换" class="headerlink" title="集群证书轮换"></a>集群证书轮换</h3><p>证书有效期检查与更新：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 检查证书有效期</span></span><br><span class="line">kubeadm certs check-expiration</span><br><span class="line"></span><br><span class="line"><span class="comment"># 更新证书（自动续期1年）</span></span><br><span class="line">kubeadm certs renew all</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">kill</span> -s SIGHUP $(pidof kube-apiserver)</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">kill</span> -s SIGHUP $(pidof kube-controller-manager)</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">kill</span> -s SIGHUP $(pidof kube-scheduler)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 更新客户端证书</span></span><br><span class="line"><span class="built_in">cp</span> /etc/kubernetes/admin.conf ~/.kube/config</span><br></pre></td></tr></table></figure><hr><h2 id="监控与运维"><a href="#监控与运维" class="headerlink" title="监控与运维"></a>监控与运维</h2><h3 id="集群健康检查脚本"><a href="#集群健康检查脚本" class="headerlink" title="集群健康检查脚本"></a>集群健康检查脚本</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cat</span> &lt;&lt; <span class="string">&#x27;EOF&#x27;</span> &gt; k8s-health-check.sh</span><br><span class="line"><span class="comment">#!/bin/bash</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;=== Kubernetes Cluster Health Check ===&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;1. Node Status:&quot;</span></span><br><span class="line">kubectl get nodes -o wide</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;2. System Pods Status:&quot;</span></span><br><span class="line">kubectl get pods -n kube-system</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;3. Resource Usage:&quot;</span></span><br><span class="line">kubectl top nodes</span><br><span class="line">kubectl top pods -A --sort-by=memory | <span class="built_in">head</span> -n 10</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;4. Certificate Expiration:&quot;</span></span><br><span class="line">kubeadm certs check-expiration</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;5. Component Health:&quot;</span></span><br><span class="line">kubectl get componentstatuses</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;6. Recent Events:&quot;</span></span><br><span class="line">kubectl get events -A --sort-by=<span class="string">&#x27;.lastTimestamp&#x27;</span> | <span class="built_in">tail</span> -n 20</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;7. Cluster Info:&quot;</span></span><br><span class="line">kubectl cluster-info</span><br><span class="line">EOF</span><br><span class="line"><span class="built_in">chmod</span> +x k8s-health-check.sh</span><br><span class="line">./k8s-health-check.sh</span><br></pre></td></tr></table></figure><h3 id="etcd-备份与恢复"><a href="#etcd-备份与恢复" class="headerlink" title="etcd 备份与恢复"></a>etcd 备份与恢复</h3><p><strong>备份脚本：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cat</span> &lt;&lt; <span class="string">&#x27;EOF&#x27;</span> &gt; etcd-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/etcd&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><br><span class="line">ETCDCTL_API=3 etcdctl snapshot save <span class="variable">$&#123;BACKUP_DIR&#125;</span>/etcd-snapshot-<span class="variable">$&#123;DATE&#125;</span>.db \</span><br><span class="line">  --cacert=/etc/kubernetes/pki/etcd/ca.crt \</span><br><span class="line">  --cert=/etc/kubernetes/pki/etcd/server.crt \</span><br><span class="line">  --key=/etc/kubernetes/pki/etcd/server.key</span><br><span class="line"></span><br><span class="line"><span class="comment"># 保留最近7天的备份</span></span><br><span class="line">find <span class="variable">$&#123;BACKUP_DIR&#125;</span> -name <span class="string">&quot;*.db&quot;</span> -mtime +7 -delete</span><br><span class="line">EOF</span><br><span class="line"><span class="built_in">chmod</span> +x etcd-backup.sh</span><br></pre></td></tr></table></figure><p><strong>恢复流程：</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 1. 停止所有控制平面组件</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl stop kubelet</span><br><span class="line"><span class="built_in">sudo</span> crictl stopp $(<span class="built_in">sudo</span> crictl pods -q)</span><br><span class="line"><span class="built_in">sudo</span> crictl rmp $(<span class="built_in">sudo</span> crictl pods -q)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 恢复 etcd 数据</span></span><br><span class="line">ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd/etcd-snapshot.db \</span><br><span class="line">  --data-dir=/var/lib/etcd-restore</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 更新 etcd manifest</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mv</span> /var/lib/etcd /var/lib/etcd-old</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mv</span> /var/lib/etcd-restore/member /var/lib/etcd</span><br><span class="line"><span class="built_in">sudo</span> systemctl start kubelet</span><br></pre></td></tr></table></figure><h3 id="日志收集配置"><a href="#日志收集配置" class="headerlink" title="日志收集配置"></a>日志收集配置</h3><p>配置 Fluent Bit：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">apiVersion:</span> <span class="string">v1</span></span><br><span class="line"><span class="attr">kind:</span> <span class="string">ConfigMap</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">fluent-bit-config</span></span><br><span class="line">  <span class="attr">namespace:</span> <span class="string">kube-system</span></span><br><span class="line"><span class="attr">data:</span></span><br><span class="line">  <span class="attr">fluent-bit.conf:</span> <span class="string">|</span></span><br><span class="line"><span class="string">    [SERVICE]</span></span><br><span class="line"><span class="string">      Flush         1</span></span><br><span class="line"><span class="string">      Log_Level     info</span></span><br><span class="line"><span class="string">      Parsers_File  parsers.conf</span></span><br><span class="line"><span class="string"></span>    </span><br><span class="line">    [<span class="string">INPUT</span>]</span><br><span class="line">      <span class="string">Name</span>              <span class="string">tail</span></span><br><span class="line">      <span class="string">Path</span>              <span class="string">/var/log/containers/*.log</span></span><br><span class="line">      <span class="string">Parser</span>            <span class="string">cri</span></span><br><span class="line">      <span class="string">Tag</span>               <span class="string">kube.*</span></span><br><span class="line">      <span class="string">Mem_Buf_Limit</span>     <span class="string">10MB</span></span><br><span class="line">    </span><br><span class="line">    [<span class="string">FILTER</span>]</span><br><span class="line">      <span class="string">Name</span>                <span class="string">kubernetes</span></span><br><span class="line">      <span class="string">Match</span>               <span class="string">kube.*</span></span><br><span class="line">      <span class="string">Kube_URL</span>            <span class="string">https://kubernetes.default.svc:443</span></span><br><span class="line">      <span class="string">Kube_CA_File</span>        <span class="string">/var/run/secrets/kubernetes.io/serviceaccount/ca.crt</span></span><br><span class="line">      <span class="string">Kube_Token_File</span>     <span class="string">/var/run/secrets/kubernetes.io/serviceaccount/token</span></span><br><span class="line">    </span><br><span class="line">    [<span class="string">OUTPUT</span>]</span><br><span class="line">      <span class="string">Name</span>            <span class="string">forward</span></span><br><span class="line">      <span class="string">Match</span>           <span class="string">*</span></span><br><span class="line">      <span class="string">Host</span>            <span class="string">fluentd-server</span></span><br><span class="line">      <span class="string">Port</span>            <span class="number">24224</span></span><br></pre></td></tr></table></figure><hr><h2 id="最佳实践建议"><a href="#最佳实践建议" class="headerlink" title="最佳实践建议"></a>最佳实践建议</h2><h3 id="镜像管理"><a href="#镜像管理" class="headerlink" title="镜像管理"></a>镜像管理</h3><ul><li>使用私有仓库（Harbor、Nexus）</li><li>镜像扫描（Trivy、Clair）</li><li>版本锁定（避免使用 latest）</li><li>预加载关键镜像到节点</li></ul><h3 id="资源管理"><a href="#资源管理" class="headerlink" title="资源管理"></a>资源管理</h3><ul><li>设置合理的 requests&#x2F;limits</li><li>使用 LimitRange 和 ResourceQuota</li><li>配置 Horizontal Pod Autoscaler (HPA)</li><li>启用 Vertical Pod Autoscaler (VPA)</li></ul><h3 id="网络配置"><a href="#网络配置" class="headerlink" title="网络配置"></a>网络配置</h3><ul><li>选择合适的 CNI 插件</li><li>配置网络策略隔离</li><li>使用 Service Mesh（Istio）进行流量管理</li><li>监控网络性能指标</li></ul><h3 id="存储管理"><a href="#存储管理" class="headerlink" title="存储管理"></a>存储管理</h3><ul><li>使用动态存储 provisioning</li><li>配置 StorageClass 多级别存储</li><li>定期备份 PVC 数据</li><li>监控存储使用情况</li></ul><h3 id="高可用配置"><a href="#高可用配置" class="headerlink" title="高可用配置"></a>高可用配置</h3><ul><li>多 Master 节点（至少3个）</li><li>etcd 集群独立部署（大规模场景）</li><li>配置 Pod 反亲和性</li><li>使用 PodDisruptionBudget (PDB)</li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;Kubernetes 是云原生应用编排的核心平台。本文档提供生产级 Kubernetes 集群部署方案，涵盖架构设计、环境准备、组件安装、网络配置、安全加固、性能优化和故障排查等全流程内容，适用于学习和生产环境。&lt;/p&gt;</summary>
    
    
    
    <category term="DevOps" scheme="https://freemankevin.uk/categories/DevOps/"/>
    
    <category term="Kubernetes" scheme="https://freemankevin.uk/categories/DevOps/Kubernetes/"/>
    
    
    <category term="Kubernetes" scheme="https://freemankevin.uk/tags/Kubernetes/"/>
    
    <category term="Containerd" scheme="https://freemankevin.uk/tags/Containerd/"/>
    
    <category term="Production" scheme="https://freemankevin.uk/tags/Production/"/>
    
  </entry>
  
  <entry>
    <title>LVM 统一存储架构与数据迁移完整实践指南</title>
    <link href="https://freemankevin.uk/2025/09/16/lvm/"/>
    <id>https://freemankevin.uk/2025/09/16/lvm/</id>
    <published>2025-09-16T02:10:00.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p>LVM（Logical Volume Manager）是企业级Linux存储管理的核心解决方案，提供灵活的存储池管理和动态扩展能力。本指南涵盖从传统分区到LVM的完整迁移实践、架构设计、性能优化和数据安全保障，适用于生产环境存储重构和容量规划。</p><span id="more"></span><h2 id="LVM-存储架构设计"><a href="#LVM-存储架构设计" class="headerlink" title="LVM 存储架构设计"></a>LVM 存储架构设计</h2><h3 id="LVM-三层架构模型"><a href="#LVM-三层架构模型" class="headerlink" title="LVM 三层架构模型"></a>LVM 三层架构模型</h3><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">应用层           文件系统 (ext4/xfs/btrfs)</span><br><span class="line">                 ↓ 挂载点</span><br><span class="line">逻辑层   ←       逻辑卷 (Logical Volume)</span><br><span class="line">                 └─ 可动态调整大小</span><br><span class="line">                 └─ 支持快照功能</span><br><span class="line">                 └─ 提供条带化/镜像</span><br><span class="line">组管理层 ←       卷组 (Volume Group)</span><br><span class="line">                 └─ 存储池聚合管理</span><br><span class="line">                 └─ PE分配单位</span><br><span class="line">                 └─ 空间动态分配</span><br><span class="line">物理层   ←       物理卷 (Physical Volume)</span><br><span class="line">                 └─ 物理设备初始化</span><br><span class="line">                 └─ LVM标签写入</span><br><span class="line">                 └─ 元数据区域</span><br><span class="line">硬件层           物理磁盘 (HDD/SSD/NVMe)</span><br><span class="line">                 └─ 本地存储设备</span><br><span class="line">                 └─ SAN存储设备</span><br></pre></td></tr></table></figure><h3 id="核心概念解析"><a href="#核心概念解析" class="headerlink" title="核心概念解析"></a>核心概念解析</h3><table><thead><tr><th>概念</th><th>说明</th><th>生产应用</th></tr></thead><tbody><tr><td><strong>PV (Physical Volume)</strong></td><td>物理卷，LVM的基础构建块</td><td>多磁盘整合</td></tr><tr><td><strong>VG (Volume Group)</strong></td><td>卷组，存储池聚合</td><td>统一管理</td></tr><tr><td><strong>LV (Logical Volume)</strong></td><td>逻辑卷，虚拟分区</td><td>动态扩展</td></tr><tr><td><strong>PE (Physical Extent)</strong></td><td>物理块，最小分配单位</td><td>默认4MB</td></tr><tr><td><strong>LE (Logical Extent)</strong></td><td>逻辑块，映射到PE</td><td>空间映射</td></tr></tbody></table><h3 id="LVM-生产优势"><a href="#LVM-生产优势" class="headerlink" title="LVM 生产优势"></a>LVM 生产优势</h3><table><thead><tr><th>优势</th><th>传统分区</th><th>LVM方案</th><th>生产价值</th></tr></thead><tbody><tr><td>动态扩展</td><td>不支持</td><td>完全支持</td><td>在线扩容</td></tr><tr><td>存储池化</td><td>独立分区</td><td>统一池化</td><td>资源优化</td></tr><tr><td>快照功能</td><td>无</td><td>完整支持</td><td>数据保护</td></tr><tr><td>条带化</td><td>不支持</td><td>IO性能提升</td><td>高性能</td></tr><tr><td>镜像</td><td>不支持</td><td>RAID1镜像</td><td>高可用</td></tr></tbody></table><h2 id="项目背景与需求分析"><a href="#项目背景与需求分析" class="headerlink" title="项目背景与需求分析"></a>项目背景与需求分析</h2><h3 id="原始环境状况"><a href="#原始环境状况" class="headerlink" title="原始环境状况"></a>原始环境状况</h3><p>我们的服务器配置如下：</p><ul><li>系统盘：SDA 446.6GB（根分区、EFI分区）</li><li>数据盘1：NVMe0n1 3.5TB（已分区，挂载到 <code>/data</code>）</li><li>数据盘2：NVMe1n1 3.5TB（未使用）</li></ul><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">NAME               MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS</span><br><span class="line">sda                  8:0    0 446.6G  0 disk</span><br><span class="line">├─sda1               8:1    0     1G  0 part /boot/efi</span><br><span class="line">├─sda2               8:2    0 445.6G  0 part /</span><br><span class="line">└─sda3               8:3    0    65M  0 part</span><br><span class="line">nvme0n1            259:0    0   3.5T  0 disk</span><br><span class="line">└─nvme0n1p1        259:3    0 931.3G  0 part /data</span><br><span class="line">nvme1n1            259:1    0   3.5T  0 disk</span><br></pre></td></tr></table></figure><h3 id="面临的问题"><a href="#面临的问题" class="headerlink" title="面临的问题"></a>面临的问题</h3><ol><li><strong>存储分散</strong>：数据分散在 <code>/data</code> 和 <code>/home</code> 等多个挂载点</li><li><strong>扩展困难</strong>：传统分区无法动态调整大小</li><li><strong>资源浪费</strong>：NVMe1n1 完全未使用</li><li><strong>管理复杂</strong>：多个独立分区增加了管理复杂度</li></ol><h3 id="目标架构设计"><a href="#目标架构设计" class="headerlink" title="目标架构设计"></a>目标架构设计</h3><p>设计一个统一的LVM存储架构：</p><ul><li>将两块NVMe盘整合为单一卷组（Volume Group）</li><li>创建大容量逻辑卷，提供约7TB可用空间</li><li>通过软链接保持应用程序路径兼容性</li><li>实现存储的统一管理和动态扩展能力</li></ul><h2 id="LVM技术原理深度解析"><a href="#LVM技术原理深度解析" class="headerlink" title="LVM技术原理深度解析"></a>LVM技术原理深度解析</h2><h3 id="LVM架构层次"><a href="#LVM架构层次" class="headerlink" title="LVM架构层次"></a>LVM架构层次</h3><p>LVM采用三层架构设计，从底层到上层分别是：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">应用层          文件系统 (ext4/xfs)</span><br><span class="line">逻辑层    ←     逻辑卷 (Logical Volume)</span><br><span class="line">组管理层  ←     卷组 (Volume Group)  </span><br><span class="line">物理层    ←     物理卷 (Physical Volume)</span><br><span class="line">硬件层          物理磁盘 (/dev/nvme0n1, /dev/nvme1n1)</span><br></pre></td></tr></table></figure><h4 id="Physical-Volume-PV"><a href="#Physical-Volume-PV" class="headerlink" title="Physical Volume (PV)"></a>Physical Volume (PV)</h4><p>物理卷是LVM的基础构建块，将物理存储设备（硬盘、分区）转换为LVM可管理的格式：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># PV创建过程中的关键操作</span></span><br><span class="line">pvcreate /dev/nvme1n1</span><br><span class="line"><span class="comment"># 在磁盘开头写入LVM标签和元数据</span></span><br><span class="line"><span class="comment"># 划分PE (Physical Extent) 单位，默认4MB</span></span><br></pre></td></tr></table></figure><h4 id="Volume-Group-VG"><a href="#Volume-Group-VG" class="headerlink" title="Volume Group (VG)"></a>Volume Group (VG)</h4><p>卷组将多个物理卷聚合为统一的存储池：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">vgcreate data_vg /dev/nvme1n1</span><br><span class="line"><span class="comment"># 创建卷组元数据</span></span><br><span class="line"><span class="comment"># 建立PE到VG的映射关系</span></span><br><span class="line"><span class="comment"># 提供统一的存储地址空间</span></span><br></pre></td></tr></table></figure><h4 id="Logical-Volume-LV"><a href="#Logical-Volume-LV" class="headerlink" title="Logical Volume (LV)"></a>Logical Volume (LV)</h4><p>逻辑卷是用户实际使用的存储单元，具有以下特性：</p><ul><li><strong>动态扩展</strong>：可在线扩展容量</li><li><strong>快照支持</strong>：支持一致性备份</li><li><strong>条带化</strong>：支持多磁盘并行I&#x2F;O</li></ul><h3 id="LVM-vs-传统分区对比"><a href="#LVM-vs-传统分区对比" class="headerlink" title="LVM vs 传统分区对比"></a>LVM vs 传统分区对比</h3><table><thead><tr><th>特性</th><th>传统分区</th><th>LVM</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>支持CoW快照</td></tr><tr><td>性能</td><td>单磁盘性能</td><td>支持条带化提升性能</td></tr><tr><td>管理复杂度</td><td>简单</td><td>中等，但功能强大</td></tr></tbody></table><h2 id="实施方案详细步骤"><a href="#实施方案详细步骤" class="headerlink" title="实施方案详细步骤"></a>实施方案详细步骤</h2><h3 id="阶段一：LVM基础设施构建"><a href="#阶段一：LVM基础设施构建" class="headerlink" title="阶段一：LVM基础设施构建"></a>阶段一：LVM基础设施构建</h3><h4 id="1-1-创建物理卷"><a href="#1-1-创建物理卷" class="headerlink" title="1.1 创建物理卷"></a>1.1 创建物理卷</h4><p>首先将NVMe1n1磁盘转换为LVM物理卷：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 创建物理卷，写入LVM元数据</span></span><br><span class="line">pvcreate /dev/nvme1n1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证PV创建结果</span></span><br><span class="line">pvdisplay /dev/nvme1n1</span><br></pre></td></tr></table></figure><p>物理卷创建过程中，LVM会在磁盘开头写入以下信息：</p><ul><li>LVM标签（LVM2_member）</li><li>物理卷UUID</li><li>卷组名称</li><li>PE大小和数量</li></ul><h4 id="1-2-创建卷组"><a href="#1-2-创建卷组" class="headerlink" title="1.2 创建卷组"></a>1.2 创建卷组</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 创建卷组，将PV加入存储池</span></span><br><span class="line">vgcreate data_vg /dev/nvme1n1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看卷组信息</span></span><br><span class="line">vgdisplay data_vg</span><br></pre></td></tr></table></figure><p>卷组创建后的关键参数：</p><ul><li><strong>PE Size</strong>: 4.00 MiB（默认）</li><li><strong>Total PE</strong>: 约915,707个PE</li><li><strong>Allocatable</strong>: 是否可分配空间</li></ul><h4 id="1-3-创建逻辑卷"><a href="#1-3-创建逻辑卷" class="headerlink" title="1.3 创建逻辑卷"></a>1.3 创建逻辑卷</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 创建逻辑卷，使用所有可用空间</span></span><br><span class="line">lvcreate -l 100%FREE -n data1_lv data_vg</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证逻辑卷状态</span></span><br><span class="line">lvdisplay /dev/data_vg/data1_lv</span><br></pre></td></tr></table></figure><p>关键参数说明：</p><ul><li><code>-l 100%FREE</code>: 使用所有可用的逻辑分区单元</li><li><code>-n data1_lv</code>: 指定逻辑卷名称</li><li><code>data_vg</code>: 目标卷组名称</li></ul><h4 id="1-4-文件系统创建"><a href="#1-4-文件系统创建" class="headerlink" title="1.4 文件系统创建"></a>1.4 文件系统创建</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 创建ext4文件系统</span></span><br><span class="line">mkfs.ext4 /dev/data_vg/data1_lv</span><br><span class="line"></span><br><span class="line"><span class="comment"># 优化参数（可选）</span></span><br><span class="line">mkfs.ext4 -b 4096 -E stride=32,stripe-width=64 /dev/data_vg/data1_lv</span><br></pre></td></tr></table></figure><h3 id="阶段二：数据迁移策略与实施"><a href="#阶段二：数据迁移策略与实施" class="headerlink" title="阶段二：数据迁移策略与实施"></a>阶段二：数据迁移策略与实施</h3><h4 id="2-1-迁移准备工作"><a href="#2-1-迁移准备工作" class="headerlink" title="2.1 迁移准备工作"></a>2.1 迁移准备工作</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 创建挂载点</span></span><br><span class="line"><span class="built_in">mkdir</span> /data1</span><br><span class="line">mount /dev/data_vg/data1_lv /data1</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> /data1/data_backup</span><br><span class="line"><span class="built_in">mkdir</span> /data1/home_backup</span><br></pre></td></tr></table></figure><h4 id="2-2-数据完整性迁移"><a href="#2-2-数据完整性迁移" class="headerlink" title="2.2 数据完整性迁移"></a>2.2 数据完整性迁移</h4><p>使用rsync进行增量同步，保证数据一致性：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 迁移/data数据，保持所有属性</span></span><br><span class="line"><span class="built_in">nohup</span> rsync -avxHAX --progress \</span><br><span class="line">    --exclude=<span class="string">&#x27;lost+found&#x27;</span> \</span><br><span class="line">    /data/ /data1/data_backup/ \</span><br><span class="line">    &gt; /data1/data_backup.log 2&gt;&amp;1 &amp;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 迁移/home数据（确保没有用户登陆，已登陆用户请踢出）</span></span><br><span class="line"><span class="built_in">nohup</span> rsync -avxHAX --progress \</span><br><span class="line">    --exclude=<span class="string">&#x27;lost+found&#x27;</span> \</span><br><span class="line">    /home/ /data1/home_backup/ \</span><br><span class="line">    &gt; /data1/home_backup.log 2&gt;&amp;1 &amp;</span><br></pre></td></tr></table></figure><p>rsync参数详解：</p><ul><li><code>-a</code>: 归档模式，保持权限、时间戳等</li><li><code>-v</code>: 详细输出</li><li><code>-x</code>: 不跨文件系统</li><li><code>-H</code>: 保持硬链接</li><li><code>-A</code>: 保持ACL</li><li><code>-X</code>: 保持扩展属性</li><li><code>--progress</code>: 显示进度</li></ul><h4 id="2-3-数据完整性验证"><a href="#2-3-数据完整性验证" class="headerlink" title="2.3 数据完整性验证"></a>2.3 数据完整性验证</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 比较文件数量</span></span><br><span class="line">find /data -<span class="built_in">type</span> f | <span class="built_in">wc</span> -l</span><br><span class="line">find /data1/data_backup -<span class="built_in">type</span> f | <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"><span class="built_in">du</span> -sh /data</span><br><span class="line"><span class="built_in">du</span> -sh /data1/data_backup</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用校验和验证（可选，耗时较长）</span></span><br><span class="line">find /data -<span class="built_in">type</span> f -<span class="built_in">exec</span> <span class="built_in">md5sum</span> &#123;&#125; \; | <span class="built_in">sort</span> &gt; /tmp/original.md5</span><br><span class="line"><span class="built_in">cd</span> /data1/data_backup</span><br><span class="line">find . -<span class="built_in">type</span> f -<span class="built_in">exec</span> <span class="built_in">md5sum</span> &#123;&#125; \; | <span class="built_in">sort</span> &gt; /tmp/backup.md5</span><br><span class="line">diff /tmp/original.md5 /tmp/backup.md5</span><br></pre></td></tr></table></figure><h3 id="阶段三：系统切换与进程处理"><a href="#阶段三：系统切换与进程处理" class="headerlink" title="阶段三：系统切换与进程处理"></a>阶段三：系统切换与进程处理</h3><h4 id="3-1-进程排查与处理"><a href="#3-1-进程排查与处理" class="headerlink" title="3.1 进程排查与处理"></a>3.1 进程排查与处理</h4><p>在卸载原分区前，必须确保没有进程占用：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 查找占用/data的进程</span></span><br><span class="line">lsof +D /data</span><br><span class="line"></span><br><span class="line"><span class="comment"># 示例输出分析</span></span><br><span class="line">COMMAND       PID USER   FD   TYPE DEVICE   SIZE/OFF     NODE NAME</span><br><span class="line">sftp-serv 1528862 root    3r   REG  259,3 8776906927 11273975 /data/opt/...</span><br></pre></td></tr></table></figure><p>发现SFTP进程正在传输大文件，这解释了为什么”静态文件”会有进程占用。</p><h4 id="3-2-优雅停止服务"><a href="#3-2-优雅停止服务" class="headerlink" title="3.2 优雅停止服务"></a>3.2 优雅停止服务</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 停止相关服务</span></span><br><span class="line">systemctl stop docker</span><br><span class="line"></span><br><span class="line"><span class="comment"># 强制终止占用进程（谨慎使用）</span></span><br><span class="line">fuser -km /data</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或者单独终止特定进程</span></span><br><span class="line"><span class="built_in">kill</span> -15 1528862  <span class="comment"># 温和终止</span></span><br><span class="line"><span class="built_in">kill</span> -9 1528862   <span class="comment"># 强制终止</span></span><br></pre></td></tr></table></figure><h4 id="3-3-安全卸载与切换"><a href="#3-3-安全卸载与切换" class="headerlink" title="3.3 安全卸载与切换"></a>3.3 安全卸载与切换</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 备份fstab</span></span><br><span class="line"><span class="built_in">cp</span> /etc/fstab /etc/fstab.backup</span><br><span class="line"></span><br><span class="line"><span class="comment"># 卸载原分区</span></span><br><span class="line">umount /data</span><br><span class="line"><span class="comment"># 如果busy，使用懒卸载</span></span><br><span class="line">umount -l /data</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重命名原目录（保留备份）</span></span><br><span class="line"><span class="built_in">mv</span> /data /data.old</span><br><span class="line"><span class="built_in">mv</span> /home /home.old</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建软链接</span></span><br><span class="line"><span class="built_in">ln</span> -s /data1/data_backup /data</span><br><span class="line"><span class="built_in">ln</span> -s /data1/home_backup /home</span><br></pre></td></tr></table></figure><h3 id="阶段四：存储池扩展"><a href="#阶段四：存储池扩展" class="headerlink" title="阶段四：存储池扩展"></a>阶段四：存储池扩展</h3><h4 id="4-1-第二块磁盘处理"><a href="#4-1-第二块磁盘处理" class="headerlink" title="4.1 第二块磁盘处理"></a>4.1 第二块磁盘处理</h4><p>NVMe0n1已有分区表，需要清理：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 清除分区表和文件系统签名</span></span><br><span class="line">wipefs -a /dev/nvme0n1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 输出示例</span></span><br><span class="line">/dev/nvme0n1: 8 bytes were erased at offset 0x00000200 (gpt): 45 46 49 20 50 41 52 54</span><br><span class="line">/dev/nvme0n1: 8 bytes were erased at offset 0x37e3ee55e00 (gpt): 45 46 49 20 50 41 52 54</span><br><span class="line">/dev/nvme0n1: 2 bytes were erased at offset 0x000001fe (PMBR): 55 aa</span><br></pre></td></tr></table></figure><h4 id="4-2-扩展LVM存储池"><a href="#4-2-扩展LVM存储池" class="headerlink" title="4.2 扩展LVM存储池"></a>4.2 扩展LVM存储池</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 将新磁盘加入物理卷</span></span><br><span class="line">pvcreate /dev/nvme0n1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 扩展卷组</span></span><br><span class="line">vgextend data_vg /dev/nvme0n1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 扩展逻辑卷</span></span><br><span class="line">lvextend -l +100%FREE /dev/data_vg/data1_lv</span><br><span class="line"></span><br><span class="line"><span class="comment"># 扩展文件系统</span></span><br><span class="line">resize2fs /dev/data_vg/data1_lv</span><br></pre></td></tr></table></figure><h4 id="4-3-验证扩展结果"><a href="#4-3-验证扩展结果" class="headerlink" title="4.3 验证扩展结果"></a>4.3 验证扩展结果</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 查看存储状态</span></span><br><span class="line">pvdisplay</span><br><span class="line">vgdisplay data_vg</span><br><span class="line">lvdisplay /dev/data_vg/data1_lv</span><br><span class="line"><span class="built_in">df</span> -Th</span><br></pre></td></tr></table></figure><h3 id="阶段五：系统配置与验证"><a href="#阶段五：系统配置与验证" class="headerlink" title="阶段五：系统配置与验证"></a>阶段五：系统配置与验证</h3><h4 id="5-1-更新系统配置"><a href="#5-1-更新系统配置" class="headerlink" title="5.1 更新系统配置"></a>5.1 更新系统配置</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 更新fstab，添加新挂载项</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;/dev/data_vg/data1_lv /data1 ext4 defaults 0 2&quot;</span> &gt;&gt; /etc/fstab</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证fstab语法</span></span><br><span class="line">mount -a</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;LVM（Logical Volume Manager）是企业级Linux存储管理的核心解决方案，提供灵活的存储池管理和动态扩展能力。本指南涵盖从传统分区到LVM的完整迁移实践、架构设计、性能优化和数据安全保障，适用于生产环境存储重构和容量规划。&lt;/p&gt;</summary>
    
    
    
    <category term="Linux" scheme="https://freemankevin.uk/categories/Linux/"/>
    
    <category term="Storage" scheme="https://freemankevin.uk/categories/Linux/Storage/"/>
    
    
    <category term="DevOps" scheme="https://freemankevin.uk/tags/DevOps/"/>
    
    <category term="Storage" scheme="https://freemankevin.uk/tags/Storage/"/>
    
    <category term="Migration" scheme="https://freemankevin.uk/tags/Migration/"/>
    
    <category term="LVM" scheme="https://freemankevin.uk/tags/LVM/"/>
    
  </entry>
  
  <entry>
    <title>Harbor 多架构镜像管理完整指南</title>
    <link href="https://freemankevin.uk/2025/08/13/docker-manifest/"/>
    <id>https://freemankevin.uk/2025/08/13/docker-manifest/</id>
    <published>2025-08-13T02:40:00.000Z</published>
    <updated>2026-05-21T06:03:03.314Z</updated>
    
    <content type="html"><![CDATA[<p>在现代容器化环境中，多架构支持变得越来越重要。随着 ARM64 架构在服务器和边缘设备中的普及，我们需要构建和管理支持多种 CPU 架构的容器镜像。本文将详细介绍如何在 Harbor 私有镜像仓库中管理多架构镜像，包括配置、推送和创建 manifest 列表的完整流程。</p><span id="more"></span><h2 id="环境说明"><a href="#环境说明" class="headerlink" title="环境说明"></a>环境说明</h2><ul><li><strong>Harbor 版本</strong>: 自建 Harbor 私有仓库</li><li><strong>部署方式</strong>: HTTPS 模式，使用自签名证书，443 端口</li><li><strong>Docker 版本</strong>: 支持 manifest 功能的版本</li><li><strong>目标架构</strong>: AMD64 和 ARM64</li></ul><h2 id="问题背景"><a href="#问题背景" class="headerlink" title="问题背景"></a>问题背景</h2><p>在实际项目中，我们遇到了以下挑战：</p><ol><li>需要将单架构镜像转换为多架构镜像</li><li>Harbor 使用自签名 HTTPS 证书，需要正确配置 Docker 客户端</li><li>Docker manifest 功能需要特定的配置和操作流程</li><li>需要批量处理多个版本的镜像</li></ol><h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><h3 id="1-Harbor-证书配置"><a href="#1-Harbor-证书配置" class="headerlink" title="1. Harbor 证书配置"></a>1. Harbor 证书配置</h3><h4 id="问题现象"><a href="#问题现象" class="headerlink" title="问题现象"></a>问题现象</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">Get <span class="string">&quot;http://110.1.20.3/v2/&quot;</span>: dial tcp 110.1.20.3:80: connect: connection refused</span><br></pre></td></tr></table></figure><p>这个错误表明 Docker 客户端尝试使用 HTTP 协议连接 Harbor，但 Harbor 实际运行在 HTTPS 模式。</p><h4 id="解决步骤"><a href="#解决步骤" class="headerlink" title="解决步骤"></a>解决步骤</h4><p><strong>Step 1: 配置客户端证书</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 创建证书目录</span></span><br><span class="line"><span class="built_in">mkdir</span> -p /etc/docker/certs.d/110.1.20.3/</span><br><span class="line"></span><br><span class="line"><span class="comment"># 复制 Harbor CA 证书和服务器证书</span></span><br><span class="line">\<span class="built_in">cp</span> -rvf /data/opt/installharbor/certs/&#123;ca.crt,harbor.crt&#125; /etc/docker/certs.d/110.1.20.3/</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> /etc/docker/certs.d/110.1.20.3/</span><br><span class="line"><span class="built_in">chmod</span> 644 ca.crt harbor.crt</span><br></pre></td></tr></table></figure><p><strong>Step 2: 配置 Docker daemon</strong></p><p>编辑 <code>/etc/docker/daemon.json</code>：</p><figure class="highlight json"><table><tr><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;registry-mirrors&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="string">&quot;https://docker.m.daocloud.io&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="string">&quot;http://docker.1panel.live&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="string">&quot;https://docker.agsv.top&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="string">&quot;https://docker.agsvpt.work&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="string">&quot;https://dockerpull.com&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="string">&quot;https://dockerproxy.cn&quot;</span></span><br><span class="line">  <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;debug&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;insecure-registries&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="string">&quot;110.1.20.3&quot;</span></span><br><span class="line">  <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;ip-forward&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;ipv6&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;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;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-level&quot;</span><span class="punctuation">:</span> <span class="string">&quot;warn&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;100m&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;2&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;selinux-enabled&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;experimental&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;data-root&quot;</span><span class="punctuation">:</span> <span class="string">&quot;/data/docker_dir&quot;</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><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;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><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p><strong>关键配置说明：</strong></p><ul><li><code>&quot;experimental&quot;: true</code> - 启用 manifest 功能</li><li><code>&quot;insecure-registries&quot;: [&quot;110.1.20.3&quot;]</code> - 信任自签名证书</li></ul><p><strong>Step 3: 重启服务</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 重启 Docker</span></span><br><span class="line">systemctl daemon-reload </span><br><span class="line">systemctl restart docker</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重启 Harbor（同台机器部署需要）</span></span><br><span class="line"><span class="built_in">cd</span> /data/opt/installharbor/</span><br><span class="line">bash install.sh</span><br></pre></td></tr></table></figure><h3 id="2-常见证书问题解决"><a href="#2-常见证书问题解决" class="headerlink" title="2. 常见证书问题解决"></a>2. 常见证书问题解决</h3><h4 id="问题1：证书文件扩展名错误"><a href="#问题1：证书文件扩展名错误" class="headerlink" title="问题1：证书文件扩展名错误"></a>问题1：证书文件扩展名错误</h4><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">missing key ca.key for client certificate ca.cert. CA certificates must use the extension .crt</span><br></pre></td></tr></table></figure><p><strong>解决方法：</strong></p><ul><li>Docker 要求 CA 证书必须使用 <code>.crt</code> 扩展名</li><li>客户端证书目录不应包含私钥文件（<code>.key</code> 文件）</li></ul><p><strong>正确的证书目录结构：</strong></p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">/etc/docker/certs.d/110.1.20.3/</span><br><span class="line">├── ca.crt          # CA 证书（必需）</span><br><span class="line">└── harbor.crt      # Harbor 服务器证书（可选）</span><br></pre></td></tr></table></figure><h4 id="问题2：Docker-daemon-配置错误"><a href="#问题2：Docker-daemon-配置错误" class="headerlink" title="问题2：Docker daemon 配置错误"></a>问题2：Docker daemon 配置错误</h4><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">json: cannot unmarshal string into Go struct field Config.experimental of type bool</span><br></pre></td></tr></table></figure><p><strong>解决方法：</strong></p><figure class="highlight json"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 错误写法</span></span><br><span class="line"><span class="attr">&quot;experimental&quot;</span><span class="punctuation">:</span> <span class="string">&quot;enabled&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 正确写法</span></span><br><span class="line"><span class="attr">&quot;experimental&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span></span><br></pre></td></tr></table></figure><h3 id="3-多架构镜像管理脚本"><a href="#3-多架构镜像管理脚本" class="headerlink" title="3. 多架构镜像管理脚本"></a>3. 多架构镜像管理脚本</h3><p>创建自动化脚本 <code>pushImages.sh</code> 来批量处理镜像：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># ===================================</span></span><br><span class="line"><span class="comment"># 批量处理：打 tag + 推送 + 创建多架构 manifest</span></span><br><span class="line"><span class="comment"># 支持 HTTPS Harbor 自签名证书</span></span><br><span class="line"><span class="comment"># ===================================</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="comment"># Harbor 配置</span></span><br><span class="line">HARBOR_HOST=<span class="string">&quot;110.1.20.3&quot;</span></span><br><span class="line">REPO_PREFIX=<span class="string">&quot;<span class="variable">$&#123;HARBOR_HOST&#125;</span>/library&quot;</span></span><br><span class="line">VERSIONS=(<span class="string">&quot;3.11.3&quot;</span> <span class="string">&quot;3.10.1&quot;</span> <span class="string">&quot;3.9.2&quot;</span> <span class="string">&quot;3.8.5&quot;</span>)</span><br><span class="line">ARCHES=(<span class="string">&quot;amd64&quot;</span> <span class="string">&quot;arm64&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 是否删除旧标签（可选）</span></span><br><span class="line">DELETE_OLD_TAGS=<span class="literal">false</span></span><br><span class="line"></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;📡 Harbor 地址: https://<span class="variable">$&#123;HARBOR_HOST&#125;</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查登录状态</span></span><br><span class="line"><span class="keyword">if</span> ! docker login https://<span class="variable">$&#123;HARBOR_HOST&#125;</span> 2&gt;/dev/null; <span class="keyword">then</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;⚠️  Docker 未登录到 Harbor，请先登录：&quot;</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;   docker login https://<span class="variable">$&#123;HARBOR_HOST&#125;</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"># 1. 先为所有镜像打新标签并推送</span></span><br><span class="line"><span class="keyword">for</span> version <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;VERSIONS[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">  <span class="keyword">for</span> <span class="built_in">arch</span> <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;ARCHES[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">    OLD_TAG=<span class="string">&quot;<span class="variable">$&#123;REPO_PREFIX&#125;</span>/java-gdal-local-<span class="variable">$&#123;arch&#125;</span>:<span class="variable">$&#123;version&#125;</span>&quot;</span></span><br><span class="line">    NEW_TAG=<span class="string">&quot;<span class="variable">$&#123;REPO_PREFIX&#125;</span>/java-gdal-local:<span class="variable">$&#123;version&#125;</span>-<span class="variable">$&#123;arch&#125;</span>&quot;</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> docker inspect <span class="string">&quot;<span class="variable">$OLD_TAG</span>&quot;</span> &amp;&gt; /dev/null; <span class="keyword">then</span></span><br><span class="line">      <span class="built_in">echo</span> <span class="string">&quot;🏷️  打标签: <span class="variable">$OLD_TAG</span> -&gt; <span class="variable">$NEW_TAG</span>&quot;</span></span><br><span class="line">      docker tag <span class="string">&quot;<span class="variable">$OLD_TAG</span>&quot;</span> <span class="string">&quot;<span class="variable">$NEW_TAG</span>&quot;</span></span><br><span class="line">      </span><br><span class="line">      <span class="built_in">echo</span> <span class="string">&quot;📤 推送: <span class="variable">$NEW_TAG</span>&quot;</span></span><br><span class="line">      docker push <span class="string">&quot;<span class="variable">$NEW_TAG</span>&quot;</span></span><br><span class="line">      </span><br><span class="line">      <span class="keyword">if</span> [ <span class="string">&quot;<span class="variable">$DELETE_OLD_TAGS</span>&quot;</span> = <span class="literal">true</span> ]; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&quot;🗑️  删除旧标签: <span class="variable">$OLD_TAG</span>&quot;</span></span><br><span class="line">        docker rmi <span class="string">&quot;<span class="variable">$OLD_TAG</span>&quot;</span> || <span class="literal">true</span></span><br><span class="line">      <span class="keyword">fi</span></span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      <span class="built_in">echo</span> <span class="string">&quot;⚠️  镜像不存在，跳过: <span class="variable">$OLD_TAG</span>&quot;</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">  <span class="keyword">done</span></span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 为每个版本创建多架构 manifest</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;🔧 开始创建多架构 manifest...&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> version <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;VERSIONS[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">  MANIFEST_TAG=<span class="string">&quot;<span class="variable">$&#123;REPO_PREFIX&#125;</span>/java-gdal-local:<span class="variable">$&#123;version&#125;</span>&quot;</span></span><br><span class="line">  TAG_AMD64=<span class="string">&quot;<span class="variable">$&#123;REPO_PREFIX&#125;</span>/java-gdal-local:<span class="variable">$&#123;version&#125;</span>-amd64&quot;</span></span><br><span class="line">  TAG_ARM64=<span class="string">&quot;<span class="variable">$&#123;REPO_PREFIX&#125;</span>/java-gdal-local:<span class="variable">$&#123;version&#125;</span>-arm64&quot;</span></span><br><span class="line">  </span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;📦 创建多架构镜像清单: <span class="variable">$MANIFEST_TAG</span>&quot;</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment"># 删除可能存在的旧 manifest</span></span><br><span class="line">  docker manifest <span class="built_in">rm</span> <span class="string">&quot;<span class="variable">$MANIFEST_TAG</span>&quot;</span> 2&gt;/dev/null || <span class="literal">true</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment"># 创建 manifest</span></span><br><span class="line">  docker manifest create <span class="string">&quot;<span class="variable">$MANIFEST_TAG</span>&quot;</span> \</span><br><span class="line">    --amend <span class="string">&quot;<span class="variable">$TAG_AMD64</span>&quot;</span> \</span><br><span class="line">    --amend <span class="string">&quot;<span class="variable">$TAG_ARM64</span>&quot;</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment"># 添加平台信息（关键步骤）</span></span><br><span class="line">  docker manifest annotate <span class="string">&quot;<span class="variable">$MANIFEST_TAG</span>&quot;</span> <span class="string">&quot;<span class="variable">$TAG_AMD64</span>&quot;</span> --os linux --<span class="built_in">arch</span> amd64</span><br><span class="line">  docker manifest annotate <span class="string">&quot;<span class="variable">$MANIFEST_TAG</span>&quot;</span> <span class="string">&quot;<span class="variable">$TAG_ARM64</span>&quot;</span> --os linux --<span class="built_in">arch</span> arm64</span><br><span class="line">  </span><br><span class="line">  <span class="comment"># 推送 manifest</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;📤 推送多架构镜像: <span class="variable">$MANIFEST_TAG</span>&quot;</span></span><br><span class="line">  docker manifest push <span class="string">&quot;<span class="variable">$MANIFEST_TAG</span>&quot;</span></span><br><span class="line">  </span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;✅ 完成: <span class="variable">$MANIFEST_TAG</span>&quot;</span></span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></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"><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"><span class="keyword">for</span> version <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;VERSIONS[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;   docker pull <span class="variable">$&#123;HARBOR_HOST&#125;</span>/library/java-gdal-local:<span class="variable">$&#123;version&#125;</span>&quot;</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure><h3 id="4-手动操作流程"><a href="#4-手动操作流程" class="headerlink" title="4. 手动操作流程"></a>4. 手动操作流程</h3><p>如果需要手动创建多架构镜像，可以按以下步骤：</p><p><strong>Step 1: 登录 Harbor</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker login 110.1.20.3</span><br><span class="line"><span class="comment"># 或者</span></span><br><span class="line">docker login -u admin -p Harbor12345@Gmail.com 110.1.20.3</span><br></pre></td></tr></table></figure><p><strong>Step 2: 推送单架构镜像</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 为现有镜像打新标签</span></span><br><span class="line">docker tag 110.1.20.3/library/java-gdal-local-amd64:3.8.5 \</span><br><span class="line">           110.1.20.3/library/java-gdal-local:3.8.5-amd64</span><br><span class="line"></span><br><span class="line">docker tag 110.1.20.3/library/java-gdal-local-arm64:3.8.5 \</span><br><span class="line">           110.1.20.3/library/java-gdal-local:3.8.5-arm64</span><br><span class="line"></span><br><span class="line"><span class="comment"># 推送镜像</span></span><br><span class="line">docker push 110.1.20.3/library/java-gdal-local:3.8.5-amd64</span><br><span class="line">docker push 110.1.20.3/library/java-gdal-local:3.8.5-arm64</span><br></pre></td></tr></table></figure><p><strong>Step 3: 创建多架构 manifest</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 创建 manifest</span></span><br><span class="line">docker manifest create 110.1.20.3/library/java-gdal-local:3.8.5 \</span><br><span class="line">  --amend 110.1.20.3/library/java-gdal-local:3.8.5-amd64 \</span><br><span class="line">  --amend 110.1.20.3/library/java-gdal-local:3.8.5-arm64</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加平台信息（重要！）</span></span><br><span class="line">docker manifest annotate 110.1.20.3/library/java-gdal-local:3.8.5 \</span><br><span class="line">  110.1.20.3/library/java-gdal-local:3.8.5-amd64 --os linux --<span class="built_in">arch</span> amd64</span><br><span class="line"></span><br><span class="line">docker manifest annotate 110.1.20.3/library/java-gdal-local:3.8.5 \</span><br><span class="line">  110.1.20.3/library/java-gdal-local:3.8.5-arm64 --os linux --<span class="built_in">arch</span> arm64</span><br><span class="line"></span><br><span class="line"><span class="comment"># 推送 manifest（注意：使用 manifest push，不是普通 push）</span></span><br><span class="line">docker manifest push 110.1.20.3/library/java-gdal-local:3.8.5</span><br></pre></td></tr></table></figure><p><strong>Step 4: 验证结果</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 查看 manifest 信息</span></span><br><span class="line">docker manifest inspect 110.1.20.3/library/java-gdal-local:3.8.5</span><br><span class="line"></span><br><span class="line"><span class="comment"># 测试拉取（会根据当前平台自动选择架构）</span></span><br><span class="line">docker pull 110.1.20.3/library/java-gdal-local:3.8.5</span><br></pre></td></tr></table></figure><h3 id="5-故障排除"><a href="#5-故障排除" class="headerlink" title="5. 故障排除"></a>5. 故障排除</h3><h4 id="常见错误及解决方法"><a href="#常见错误及解决方法" class="headerlink" title="常见错误及解决方法"></a>常见错误及解决方法</h4><p><strong>1. 证书相关错误</strong></p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">x509: certificate signed by unknown authority</span><br></pre></td></tr></table></figure><p><strong>解决：</strong> 确保正确配置了 CA 证书或使用 <code>insecure-registries</code></p><p><strong>2. Manifest 推送错误</strong></p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">tag does not exist: 110.1.20.3/library/java-gdal-local:3.8.5</span><br></pre></td></tr></table></figure><p><strong>解决：</strong> 使用 <code>docker manifest push</code> 而不是 <code>docker push</code></p><p><strong>3. 实验性功能未启用</strong></p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">docker manifest is only supported when experimental cli features are enabled</span><br></pre></td></tr></table></figure><p><strong>解决：</strong> 在 <code>daemon.json</code> 中设置 <code>&quot;experimental&quot;: true</code></p><h4 id="检查清单"><a href="#检查清单" class="headerlink" title="检查清单"></a>检查清单</h4><ul><li><input disabled="" type="checkbox"> Docker daemon 配置了 <code>&quot;experimental&quot;: true</code></li><li><input disabled="" type="checkbox"> 证书文件使用正确的扩展名（<code>.crt</code>）</li><li><input disabled="" type="checkbox"> 证书目录不包含私钥文件</li><li><input disabled="" type="checkbox"> 已正确登录 Harbor</li><li><input disabled="" type="checkbox"> 单架构镜像已成功推送</li><li><input disabled="" type="checkbox"> 使用 <code>docker manifest push</code> 推送 manifest</li></ul><h2 id="完整配置脚本"><a href="#完整配置脚本" class="headerlink" title="完整配置脚本"></a>完整配置脚本</h2><p>将所有配置步骤整合成一个脚本：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># Harbor 多架构镜像配置脚本</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;🔧 配置 Harbor 多架构镜像支持...&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;📜 配置客户端证书...&quot;</span></span><br><span class="line"><span class="built_in">mkdir</span> -p /etc/docker/certs.d/110.1.20.3/</span><br><span class="line">\<span class="built_in">cp</span> -rvf /data/opt/installharbor/certs/&#123;ca.crt,harbor.crt&#125; /etc/docker/certs.d/110.1.20.3/</span><br><span class="line"><span class="built_in">cd</span> /etc/docker/certs.d/110.1.20.3/</span><br><span class="line"><span class="built_in">chmod</span> 644 ca.crt harbor.crt</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 重启 Docker</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;🔄 重启 Docker 服务...&quot;</span></span><br><span class="line">systemctl daemon-reload </span><br><span class="line">systemctl restart docker</span><br><span class="line"></span><br><span class="line"><span class="comment"># 3. 重启 Harbor（同台机器上需要）</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;🔄 重启 Harbor...&quot;</span></span><br><span class="line"><span class="built_in">cd</span> /data/opt/installharbor/</span><br><span class="line">bash install.sh</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;⏳ 等待服务启动...&quot;</span></span><br><span class="line"><span class="built_in">sleep</span> 30</span><br><span class="line"></span><br><span class="line"><span class="comment"># 5. 测试配置</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;🧪 测试配置...&quot;</span></span><br><span class="line">docker login 110.1.20.3</span><br><span class="line"></span><br><span class="line"><span class="comment"># 6. 创建测试 manifest</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;📦 创建测试 manifest...&quot;</span></span><br><span class="line">docker manifest create 110.1.20.3/library/java-gdal-local:3.8.5 \</span><br><span class="line">  110.1.20.3/library/java-gdal-local:3.8.5-amd64 \</span><br><span class="line">  110.1.20.3/library/java-gdal-local:3.8.5-arm64</span><br><span class="line"></span><br><span class="line">docker manifest annotate 110.1.20.3/library/java-gdal-local:3.8.5 \</span><br><span class="line">  110.1.20.3/library/java-gdal-local:3.8.5-amd64 --os linux --<span class="built_in">arch</span> amd64</span><br><span class="line"></span><br><span class="line">docker manifest annotate 110.1.20.3/library/java-gdal-local:3.8.5 \</span><br><span class="line">  110.1.20.3/library/java-gdal-local:3.8.5-arm64 --os linux --<span class="built_in">arch</span> arm64</span><br><span class="line"></span><br><span class="line">docker manifest push 110.1.20.3/library/java-gdal-local:3.8.5</span><br><span class="line"></span><br><span class="line"><span class="comment"># 7. 验证结果</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;✅ 验证结果...&quot;</span></span><br><span class="line">docker manifest inspect 110.1.20.3/library/java-gdal-local:3.8.5</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><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过本文的配置和脚本，我们成功解决了在自建 Harbor 中管理多架构镜像的问题。关键要点包括：</p><ol><li><strong>正确配置 HTTPS 证书</strong>：使用正确的文件名和权限</li><li><strong>启用实验性功能</strong>：Docker manifest 需要实验性功能支持</li><li><strong>理解 manifest 操作</strong>：区分 <code>docker push</code> 和 <code>docker manifest push</code></li><li><strong>自动化流程</strong>：使用脚本批量处理多个版本和架构</li></ol><p>这套方案可以帮助团队高效地管理多架构容器镜像，支持在不同 CPU 架构的环境中无缝部署应用。</p><h2 id="参考资源"><a href="#参考资源" class="headerlink" title="参考资源"></a>参考资源</h2><ul><li><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLmRvY2tlci5jb20vYnVpbGQvYnVpbGRpbmcvbXVsdGktcGxhdGZvcm0v">Docker Multi-platform images<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLmRvY2tlci5jb20vZW5naW5lL3JlZmVyZW5jZS9jb21tYW5kbGluZS9tYW5pZmVzdC8=">Docker manifest command<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9nb2hhcmJvci5pby9kb2NzLw==">Harbor Documentation<i class="fa fa-external-link-alt"></i></span></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;在现代容器化环境中，多架构支持变得越来越重要。随着 ARM64 架构在服务器和边缘设备中的普及，我们需要构建和管理支持多种 CPU 架构的容器镜像。本文将详细介绍如何在 Harbor 私有镜像仓库中管理多架构镜像，包括配置、推送和创建 manifest 列表的完整流程。&lt;/p&gt;</summary>
    
    
    
    <category term="Docker" scheme="https://freemankevin.uk/categories/Docker/"/>
    
    
    <category term="Docker" scheme="https://freemankevin.uk/tags/Docker/"/>
    
    <category term="Harbor" scheme="https://freemankevin.uk/tags/Harbor/"/>
    
    <category term="Manifest" scheme="https://freemankevin.uk/tags/Manifest/"/>
    
    <category term="Multi-Architecture" scheme="https://freemankevin.uk/tags/Multi-Architecture/"/>
    
  </entry>
  
  <entry>
    <title>MinIO 站点复制部署与测试：同步与故障恢复</title>
    <link href="https://freemankevin.uk/2025/05/13/docker-minio/"/>
    <id>https://freemankevin.uk/2025/05/13/docker-minio/</id>
    <published>2025-05-13T08:38:00.000Z</published>
    <updated>2026-05-21T06:03:03.314Z</updated>
    
    <content type="html"><![CDATA[<p> MinIO 是一个高性能的分布式对象存储系统，其站点复制（Site Replication）功能支持跨集群的数据和元数据同步。本文记录了如何使用 Docker Compose 部署 MinIO 站点复制集群，配置两个 MinIO 实例，并进行同步测试和故障恢复测试。测试环境基于 20T 磁盘，适用于需要高可用性和灾难恢复的场景。</p><span id="more"></span><h2 id="MinIO-站点复制简介"><a href="#MinIO-站点复制简介" class="headerlink" title="MinIO 站点复制简介"></a>MinIO 站点复制简介</h2><p>MinIO 的站点复制是一种集群级别的双向同步机制，可同步数据（桶、对象）和元数据（用户、策略、配置）。其主要特性包括：</p><ul><li><strong>最终一致性</strong>：对象数据近实时同步。</li><li><strong>严格一致性</strong>：元数据保持完全一致。</li><li><strong>高可用性</strong>：任一集群故障时，另一个集群可继续提供服务。</li></ul><p>本文将部署两个 MinIO 实例（SITE1 和 SITE2），通过 <code>minio-mc</code> 容器配置站点复制，并测试同步和故障恢复。</p><h2 id="环境与配置"><a href="#环境与配置" class="headerlink" title="环境与配置"></a>环境与配置</h2><h3 id="硬件与网络"><a href="#硬件与网络" class="headerlink" title="硬件与网络"></a>硬件与网络</h3><ul><li><strong>服务器</strong>：两台服务器（MinIO1: <code>192.168.199.145</code>，MinIO2: <code>192.168.199.147</code>）。</li><li><strong>磁盘</strong>：每台服务器挂载 20T 磁盘。</li><li><strong>网络</strong>：1Gbps 带宽，RTT &lt; 20ms。</li><li><strong>操作系统</strong>：Linux（支持 Docker）。</li></ul><h3 id="Docker-Compose-配置"><a href="#Docker-Compose-配置" class="headerlink" title="Docker Compose 配置"></a>Docker Compose 配置</h3><p>以下是 MinIO 和 <code>minio-mc</code> 服务的 Docker Compose 配置：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">minio:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&quot;$&#123;MINIO_IMAGE&#125;&quot;</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">4096M</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span> </span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">minio</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;$&#123;MINIO_PORT&#125;:9000&quot;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;$&#123;MINIO_CONSOLE_PORT&#125;:9001&quot;</span></span><br><span class="line">    <span class="attr">command:</span> <span class="string">server</span> <span class="string">/data</span> <span class="string">--console-address</span> <span class="string">&quot;:9001&quot;</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">MINIO_ROOT_USER:</span> <span class="string">&quot;$&#123;MINIO_ROOT_USER&#125;&quot;</span></span><br><span class="line">      <span class="attr">MINIO_ROOT_PASSWORD:</span> <span class="string">&quot;$&#123;MINIO_ROOT_PASSWORD&#125;&quot;</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;curl&quot;</span>, <span class="string">&quot;-f&quot;</span>, <span class="string">&quot;http://localhost:9000/minio/health/live&quot;</span>]</span><br><span class="line">      <span class="attr">interval:</span> <span class="string">30s</span></span><br><span class="line">      <span class="attr">timeout:</span> <span class="string">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">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/etc/localtime:/etc/localtime:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./data/minio/data:/data</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">minio-mc:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">minio/mc:latest</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">minio-mc</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span> </span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">SITE1_URL:</span> <span class="string">&quot;$&#123;SITE1_URL&#125;&quot;</span></span><br><span class="line">      <span class="attr">SITE2_URL:</span> <span class="string">&quot;$&#123;SITE2_URL&#125;&quot;</span></span><br><span class="line">      <span class="attr">MINIO_ROOT_USER:</span> <span class="string">&quot;$&#123;MINIO_ROOT_USER&#125;&quot;</span></span><br><span class="line">      <span class="attr">MINIO_ROOT_PASSWORD:</span> <span class="string">&quot;$&#123;MINIO_ROOT_PASSWORD&#125;&quot;</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./site-replication.sh:/site-replication.sh</span></span><br><span class="line">    <span class="attr">entrypoint:</span> [<span class="string">&quot;/bin/bash&quot;</span>, <span class="string">&quot;/site-replication.sh&quot;</span>]</span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD-SHELL&quot;</span>, <span class="string">&quot;mc --version &gt;/dev/null 2&gt;&amp;1&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">start_period:</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">restart:</span> <span class="string">always</span></span><br><span class="line"></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line">  <span class="attr">middleware:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">bridge</span></span><br></pre></td></tr></table></figure><h3 id="环境变量"><a href="#环境变量" class="headerlink" title="环境变量"></a>环境变量</h3><p>环境变量存储在 <code>.env</code> 文件中：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># MinIO</span></span><br><span class="line">MINIO_PORT=9000</span><br><span class="line">MINIO_CONSOLE_PORT=9001</span><br><span class="line">MINIO_ROOT_USER=<span class="string">&quot;admin&quot;</span></span><br><span class="line">MINIO_ROOT_PASSWORD=<span class="string">&quot;Admin@123.com&quot;</span></span><br><span class="line">MINIO_IMAGE=<span class="string">&quot;minio/minio:RELEASE.2025-04-22T22-12-26Z&quot;</span></span><br><span class="line">SITE1_URL=<span class="string">&quot;http://192.168.145:9000&quot;</span></span><br><span class="line">SITE2_URL=<span class="string">&quot;http://192.168.147:9000&quot;</span></span><br></pre></td></tr></table></figure><h3 id="站点复制脚本"><a href="#站点复制脚本" class="headerlink" title="站点复制脚本"></a>站点复制脚本</h3><p><code>site-replication.sh</code> 用于配置站点复制：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 严格模式：错误、未定义变量、管道失败时退出</span></span><br><span class="line"><span class="built_in">set</span> -euo pipefail</span><br><span class="line"></span><br><span class="line"><span class="comment"># 颜色定义</span></span><br><span class="line">RED=<span class="string">&#x27;\033[0;31m&#x27;</span></span><br><span class="line">GREEN=<span class="string">&#x27;\033[0;32m&#x27;</span></span><br><span class="line">CYAN=<span class="string">&#x27;\033[1;36m&#x27;</span></span><br><span class="line">YELLOW=<span class="string">&#x27;\033[1;33m&#x27;</span></span><br><span class="line">BLUE=<span class="string">&#x27;\033[0;34m&#x27;</span></span><br><span class="line">MAGENTA=<span class="string">&#x27;\033[0;35m&#x27;</span></span><br><span class="line">RESET=<span class="string">&#x27;\033[0m&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 更丰富的图标集</span></span><br><span class="line">ICON_INFO=<span class="string">&quot;🌐&quot;</span></span><br><span class="line">ICON_SUCCESS=<span class="string">&quot;✨&quot;</span></span><br><span class="line">ICON_WARNING=<span class="string">&quot;⚠️&quot;</span></span><br><span class="line">ICON_ERROR=<span class="string">&quot;💥&quot;</span></span><br><span class="line">ICON_DEBUG=<span class="string">&quot;🐞&quot;</span></span><br><span class="line">ICON_WAIT=<span class="string">&quot;⏳&quot;</span></span><br><span class="line">ICON_CLEAN=<span class="string">&quot;🧹&quot;</span></span><br><span class="line">ICON_CONFIG=<span class="string">&quot;⚙️&quot;</span></span><br><span class="line">ICON_NETWORK=<span class="string">&quot;📡&quot;</span></span><br><span class="line">ICON_START=<span class="string">&quot;🚀&quot;</span></span><br><span class="line">ICON_READY=<span class="string">&quot;✅&quot;</span></span><br><span class="line">ICON_FINISH=<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="function"><span class="title">log</span></span>() &#123;</span><br><span class="line">  <span class="built_in">local</span> level=<span class="variable">$1</span> message=<span class="variable">$2</span></span><br><span class="line">  <span class="built_in">local</span> color icon timestamp</span><br><span class="line">  timestamp=$(<span class="built_in">date</span> -u <span class="string">&#x27;+%H:%M:%S&#x27;</span>)</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">case</span> <span class="variable">$level</span> <span class="keyword">in</span></span><br><span class="line">    INFO)    color=<span class="string">&quot;<span class="variable">$GREEN</span>&quot;</span>  icon=<span class="string">&quot;<span class="variable">$ICON_INFO</span>&quot;</span> ;;</span><br><span class="line">    SUCCESS) color=<span class="string">&quot;<span class="variable">$GREEN</span>&quot;</span>  icon=<span class="string">&quot;<span class="variable">$ICON_SUCCESS</span>&quot;</span> ;;</span><br><span class="line">    WARN)    color=<span class="string">&quot;<span class="variable">$YELLOW</span>&quot;</span> icon=<span class="string">&quot;<span class="variable">$ICON_WARNING</span>&quot;</span> ;;</span><br><span class="line">    ERROR)   color=<span class="string">&quot;<span class="variable">$RED</span>&quot;</span>    icon=<span class="string">&quot;<span class="variable">$ICON_ERROR</span>&quot;</span> ;;</span><br><span class="line">    DEBUG)   color=<span class="string">&quot;<span class="variable">$BLUE</span>&quot;</span>   icon=<span class="string">&quot;<span class="variable">$ICON_DEBUG</span>&quot;</span> ;;</span><br><span class="line">    WAIT)    color=<span class="string">&quot;<span class="variable">$MAGENTA</span>&quot;</span> icon=<span class="string">&quot;<span class="variable">$ICON_WAIT</span>&quot;</span> ;;</span><br><span class="line">    *)       color=<span class="string">&quot;<span class="variable">$CYAN</span>&quot;</span>   icon=<span class="string">&quot;<span class="variable">$ICON_INFO</span>&quot;</span> ;;</span><br><span class="line">  <span class="keyword">esac</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># 直接输出消息，避免嵌套格式化问题</span></span><br><span class="line">  <span class="built_in">printf</span> <span class="string">&quot;<span class="variable">$&#123;color&#125;</span>%s %-7s\t%s<span class="variable">$&#123;RESET&#125;</span></span></span><br><span class="line"><span class="string">&quot;</span> <span class="string">&quot;<span class="variable">$timestamp</span> <span class="variable">$icon</span>&quot;</span> <span class="string">&quot;[<span class="variable">$level</span>]&quot;</span> <span class="string">&quot;<span class="variable">$message</span>&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 简洁标题样式（改为 === 标题 === 形式）</span></span><br><span class="line"><span class="function"><span class="title">header</span></span>() &#123;</span><br><span class="line">  <span class="keyword">if</span> [ <span class="string">&quot;<span class="variable">$2</span>&quot;</span> = <span class="string">&quot;MinIO 站点复制初始化&quot;</span> ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">printf</span> <span class="string">&quot;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"><span class="variable">$&#123;MAGENTA&#125;</span>███╗   ███╗██╗███╗   ██╗██╗ ██████╗     ███╗   ███╗ ██████╗</span></span><br><span class="line"><span class="string">████╗ ████║██║████╗  ██║██║██╔═══██╗    ████╗ ████║██╔════╝</span></span><br><span class="line"><span class="string">██╔████╔██║██║██╔██╗ ██║██║██║   ██║    ██╔████╔██║██║     </span></span><br><span class="line"><span class="string">██║╚██╔╝██║██║██║╚██╗██║██║██║   ██║    ██║╚██╔╝██║██║     </span></span><br><span class="line"><span class="string">██║ ╚═╝ ██║██║██║ ╚████║██║╚██████╔╝    ██║ ╚═╝ ██║╚██████╗</span></span><br><span class="line"><span class="string">╚═╝     ╚═╝╚═╝╚═╝  ╚═══╝╚═╝ ╚═════╝     ╚═╝     ╚═╝ ╚═════╝</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">&gt;&gt; %s %s<span class="variable">$&#123;RESET&#125;</span></span></span><br><span class="line"><span class="string">&quot;</span> <span class="string">&quot;<span class="variable">$1</span>&quot;</span> <span class="string">&quot;<span class="variable">$2</span>&quot;</span></span><br><span class="line">    <span class="built_in">printf</span> <span class="string">&quot;</span></span><br><span class="line"><span class="string">&quot;</span></span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    <span class="built_in">printf</span> <span class="string">&quot;</span></span><br><span class="line"><span class="string"><span class="variable">$&#123;CYAN&#125;</span>[ TASK %d ] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━</span></span><br><span class="line"><span class="string">&gt;&gt; %s %s<span class="variable">$&#123;RESET&#125;</span></span></span><br><span class="line"><span class="string">&quot;</span> <span class="string">&quot;<span class="variable">$task_number</span>&quot;</span> <span class="string">&quot;<span class="variable">$1</span>&quot;</span> <span class="string">&quot;<span class="variable">$2</span>&quot;</span></span><br><span class="line">    <span class="built_in">printf</span> <span class="string">&quot;</span></span><br><span class="line"><span class="string">&quot;</span></span><br><span class="line">    task_number=$((task_number + <span class="number">1</span>))</span><br><span class="line">  <span class="keyword">fi</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 初始化任务计数器</span></span><br><span class="line">task_number=1</span><br><span class="line"></span><br><span class="line"><span class="comment"># 等待服务就绪（合并为一个任务）</span></span><br><span class="line"><span class="function"><span class="title">wait_for_services</span></span>() &#123;</span><br><span class="line">  <span class="built_in">local</span> retries=15 delay=2 attempt=1</span><br><span class="line">  <span class="built_in">local</span> spinner=(<span class="string">&quot;⣾&quot;</span> <span class="string">&quot;⣽&quot;</span> <span class="string">&quot;⣻&quot;</span> <span class="string">&quot;⢿&quot;</span> <span class="string">&quot;⡿&quot;</span> <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">local</span> all_ready=0</span><br><span class="line"></span><br><span class="line">  header <span class="string">&quot;<span class="variable">$ICON_WAIT</span>&quot;</span> <span class="string">&quot;等待 MinIO 服务就绪&quot;</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> site <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;!SITES[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">    <span class="built_in">local</span> <span class="built_in">alias</span>=<span class="string">&quot;HEALTHCHECK_<span class="variable">$site</span>&quot;</span></span><br><span class="line">    <span class="built_in">local</span> url=<span class="string">&quot;<span class="variable">$&#123;SITES[$site]&#125;</span>&quot;</span></span><br><span class="line">    <span class="built_in">local</span> attempt=1</span><br><span class="line">    <span class="built_in">local</span> all_ready=0</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="built_in">log</span> INFO <span class="string">&quot;检查服务: <span class="variable">$url</span>&quot;</span></span><br><span class="line">    <span class="keyword">while</span> [ <span class="variable">$attempt</span> -le <span class="variable">$retries</span> ]; <span class="keyword">do</span></span><br><span class="line">      <span class="keyword">if</span> /usr/bin/mc <span class="built_in">alias</span> <span class="built_in">set</span> <span class="string">&quot;<span class="variable">$alias</span>&quot;</span> <span class="string">&quot;<span class="variable">$url</span>&quot;</span> <span class="string">&quot;<span class="variable">$MINIO_ACCESS_KEY</span>&quot;</span> <span class="string">&quot;<span class="variable">$MINIO_SECRET_KEY</span>&quot;</span> &gt;/dev/null 2&gt;&amp;1 &amp;&amp; \</span><br><span class="line">         /usr/bin/mc <span class="built_in">ls</span> <span class="string">&quot;<span class="variable">$alias</span>&quot;</span> &gt;/dev/null 2&gt;&amp;1; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">log</span> SUCCESS <span class="string">&quot;服务已就绪: <span class="variable">$url</span>&quot;</span></span><br><span class="line">        all_ready=1</span><br><span class="line">        <span class="keyword">if</span> [ <span class="string">&quot;<span class="variable">$site</span>&quot;</span> = <span class="string">&quot;SITE1&quot;</span> ]; <span class="keyword">then</span></span><br><span class="line">          <span class="built_in">printf</span> <span class="string">&quot;<span class="variable">$&#123;CYAN&#125;</span>%s<span class="variable">$&#123;RESET&#125;</span></span></span><br><span class="line"><span class="string">&quot;</span> <span class="string">&quot;<span class="subst">$(for i in $(seq 1 61)</span>; do printf &quot;</span>-<span class="string">&quot;; done)&quot;</span></span><br><span class="line">        <span class="keyword">fi</span></span><br><span class="line">        <span class="built_in">break</span></span><br><span class="line">      <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line">      <span class="built_in">printf</span> <span class="string">&quot;\r%-80s&quot;</span> <span class="string">&quot; &quot;</span></span><br><span class="line">      <span class="built_in">printf</span> <span class="string">&quot;\r<span class="variable">$&#123;YELLOW&#125;</span>%s 尝试 %2d/%-2d 检查服务 %s 中...<span class="variable">$&#123;RESET&#125;</span>&quot;</span> \</span><br><span class="line">        <span class="string">&quot;<span class="variable">$&#123;spinner[$((attempt % <span class="variable">$&#123;#spinner[@]&#125;</span>))]&#125;</span>&quot;</span> \</span><br><span class="line">        <span class="variable">$attempt</span> <span class="variable">$retries</span> <span class="string">&quot;<span class="variable">$url</span>&quot;</span></span><br><span class="line">      <span class="built_in">sleep</span> <span class="variable">$delay</span></span><br><span class="line">      ((attempt++))</span><br><span class="line">      delay=$((delay * <span class="number">2</span> &gt; <span class="number">8</span> ? <span class="number">8</span> : delay * <span class="number">2</span>))</span><br><span class="line">    <span class="keyword">done</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> [ <span class="variable">$all_ready</span> -eq 0 ]; <span class="keyword">then</span></span><br><span class="line">      <span class="built_in">log</span> ERROR <span class="string">&quot;服务 <span class="variable">$url</span> 在 <span class="variable">$retries</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 class="keyword">done</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置别名（优化颜色格式）</span></span><br><span class="line"><span class="function"><span class="title">configure_aliases</span></span>() &#123;</span><br><span class="line">  header <span class="string">&quot;<span class="variable">$ICON_CONFIG</span>&quot;</span> <span class="string">&quot;配置 MinIO 站点别名&quot;</span></span><br><span class="line">  <span class="keyword">for</span> site <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;!SITES[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">    <span class="built_in">local</span> url=<span class="string">&quot;<span class="variable">$&#123;SITES[$site]&#125;</span>&quot;</span></span><br><span class="line">    /usr/bin/mc <span class="built_in">alias</span> remove <span class="string">&quot;<span class="variable">$site</span>&quot;</span> 2&gt;/dev/null || <span class="literal">true</span></span><br><span class="line">    <span class="keyword">if</span> /usr/bin/mc <span class="built_in">alias</span> <span class="built_in">set</span> <span class="string">&quot;<span class="variable">$site</span>&quot;</span> <span class="string">&quot;<span class="variable">$url</span>&quot;</span> <span class="string">&quot;<span class="variable">$MINIO_ACCESS_KEY</span>&quot;</span> <span class="string">&quot;<span class="variable">$MINIO_SECRET_KEY</span>&quot;</span> &gt;/dev/null 2&gt;&amp;1; <span class="keyword">then</span></span><br><span class="line">      <span class="built_in">log</span> SUCCESS <span class="string">&quot;别名配置成功: <span class="variable">$&#123;site&#125;</span> → <span class="variable">$&#123;url&#125;</span>&quot;</span></span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      <span class="built_in">log</span> ERROR <span class="string">&quot;无法配置别名: <span class="variable">$site</span> → <span class="variable">$url</span>&quot;</span></span><br><span class="line">      <span class="built_in">return</span> 1</span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">  <span class="keyword">done</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 检查复制配置状态</span></span><br><span class="line"><span class="function"><span class="title">check_replication_status</span></span>() &#123;</span><br><span class="line">  /usr/bin/mc admin replicate info SITE1 2&gt;&amp;1 | grep -q <span class="string">&quot;SiteReplication enabled&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 清除原复制配置</span></span><br><span class="line"><span class="function"><span class="title">cleanup_old_replication</span></span>() &#123;</span><br><span class="line">  header <span class="string">&quot;<span class="variable">$ICON_CLEAN</span>&quot;</span> <span class="string">&quot;清理原有复制配置&quot;</span></span><br><span class="line">  <span class="keyword">for</span> site <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;!SITES[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">    <span class="built_in">log</span> INFO <span class="string">&quot;正在清理 <span class="variable">$site</span> 的复制配置...&quot;</span></span><br><span class="line">    <span class="keyword">if</span> /usr/bin/mc admin replicate <span class="built_in">rm</span> --all <span class="string">&quot;<span class="variable">$site</span>&quot;</span> --force 2&gt;/dev/null; <span class="keyword">then</span></span><br><span class="line">      <span class="built_in">log</span> SUCCESS <span class="string">&quot;成功清理 <span class="variable">$site</span> 的配置&quot;</span></span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      <span class="built_in">log</span> WARN <span class="string">&quot;<span class="variable">$site</span> 无配置可清理或清理失败&quot;</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">  <span class="keyword">done</span></span><br><span class="line">  <span class="built_in">sleep</span> 2</span><br><span class="line">  <span class="keyword">if</span> check_replication_status; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">log</span> ERROR <span class="string">&quot;复制配置仍存在，请手动检查&quot;</span></span><br><span class="line">    <span class="built_in">return</span> 1</span><br><span class="line">  <span class="keyword">fi</span></span><br><span class="line">  <span class="built_in">log</span> SUCCESS <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">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 可靠的bucket删除函数</span></span><br><span class="line"><span class="function"><span class="title">delete_all_buckets</span></span>() &#123;</span><br><span class="line">  <span class="built_in">local</span> site=<span class="variable">$1</span></span><br><span class="line">  <span class="built_in">log</span> WARN <span class="string">&quot;即将清空 <span class="variable">$&#123;site&#125;</span> 的所有bucket...&quot;</span></span><br><span class="line">  <span class="built_in">local</span> buckets</span><br><span class="line">  buckets=$(/usr/bin/mc <span class="built_in">ls</span> <span class="string">&quot;<span class="variable">$site</span>&quot;</span> --json | jq -r .key | <span class="built_in">tr</span> -d <span class="string">&#x27;/&#x27;</span> | grep -v <span class="string">&#x27;^$&#x27;</span>)</span><br><span class="line">  <span class="keyword">if</span> [ -z <span class="string">&quot;<span class="variable">$buckets</span>&quot;</span> ]; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">log</span> INFO <span class="string">&quot;没有 bucket 需要删除&quot;</span></span><br><span class="line">    <span class="built_in">return</span> 0</span><br><span class="line">  <span class="keyword">fi</span></span><br><span class="line">  <span class="built_in">echo</span> <span class="string">&quot;<span class="variable">$buckets</span>&quot;</span> | <span class="keyword">while</span> <span class="built_in">read</span> -r bucket; <span class="keyword">do</span></span><br><span class="line">    <span class="built_in">log</span> INFO <span class="string">&quot;正在删除 <span class="variable">$&#123;site&#125;</span>/<span class="variable">$&#123;bucket&#125;</span>...&quot;</span></span><br><span class="line">    <span class="keyword">if</span> /usr/bin/mc rb --force <span class="string">&quot;<span class="variable">$&#123;site&#125;</span>/<span class="variable">$&#123;bucket&#125;</span>&quot;</span> &gt;/dev/null 2&gt;&amp;1; <span class="keyword">then</span></span><br><span class="line">      <span class="built_in">log</span> SUCCESS <span class="string">&quot;删除成功: <span class="variable">$&#123;site&#125;</span>/<span class="variable">$&#123;bucket&#125;</span>&quot;</span></span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      <span class="built_in">log</span> ERROR <span class="string">&quot;删除失败: <span class="variable">$&#123;site&#125;</span>/<span class="variable">$&#123;bucket&#125;</span>&quot;</span></span><br><span class="line">      <span class="built_in">return</span> 1</span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">  <span class="keyword">done</span></span><br><span class="line">  <span class="keyword">if</span> /usr/bin/mc <span class="built_in">ls</span> <span class="string">&quot;<span class="variable">$site</span>&quot;</span> | grep -q .; <span class="keyword">then</span></span><br><span class="line">    <span class="built_in">log</span> ERROR <span class="string">&quot;<span class="variable">$&#123;site&#125;</span> 中仍有bucket存在&quot;</span></span><br><span class="line">    <span class="built_in">return</span> 1</span><br><span class="line">  <span class="keyword">fi</span></span><br><span class="line">  <span class="built_in">log</span> SUCCESS <span class="string">&quot;<span class="variable">$&#123;site&#125;</span> 已完全清空&quot;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置复制配置</span></span><br><span class="line"><span class="function"><span class="title">setup_replication</span></span>() &#123;</span><br><span class="line">  header <span class="string">&quot;<span class="variable">$ICON_NETWORK</span>&quot;</span> <span class="string">&quot;设置站点复制&quot;</span></span><br><span class="line">  <span class="built_in">local</span> retries=5 delay=2 attempt=1</span><br><span class="line">  <span class="built_in">local</span> site_list=(<span class="string">&quot;<span class="variable">$&#123;!SITES[@]&#125;</span>&quot;</span>)</span><br><span class="line">  <span class="keyword">while</span> [ <span class="variable">$attempt</span> -le <span class="variable">$retries</span> ]; <span class="keyword">do</span></span><br><span class="line">    <span class="built_in">log</span> WAIT <span class="string">&quot;尝试配置复制 (<span class="variable">$&#123;attempt&#125;</span>/<span class="variable">$&#123;retries&#125;</span>)...&quot;</span></span><br><span class="line">    output=$(/usr/bin/mc admin replicate add <span class="string">&quot;<span class="variable">$&#123;site_list[@]&#125;</span>&quot;</span> 2&gt;&amp;1)</span><br><span class="line">    <span class="keyword">if</span> [ $? -eq 0 ]; <span class="keyword">then</span></span><br><span class="line">      <span class="built_in">log</span> SUCCESS <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">      <span class="built_in">return</span> 0</span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">    <span class="keyword">if</span> [[ <span class="variable">$output</span> == *<span class="string">&quot;only one cluster may have data&quot;</span>* ]]; <span class="keyword">then</span></span><br><span class="line">      <span class="built_in">log</span> WARN <span class="string">&quot;检测到 SITE2 中已有数据，违反复制要求&quot;</span></span><br><span class="line">      <span class="keyword">if</span> ! delete_all_buckets <span class="string">&quot;SITE2&quot;</span>; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">log</span> ERROR <span class="string">&quot;清空 SITE2 失败，无法继续&quot;</span></span><br><span class="line">        <span class="built_in">return</span> 1</span><br><span class="line">      <span class="keyword">fi</span></span><br><span class="line">      <span class="built_in">log</span> INFO <span class="string">&quot;等待 <span class="variable">$&#123;delay&#125;</span> 秒让系统完成清理...&quot;</span></span><br><span class="line">      <span class="built_in">sleep</span> <span class="variable">$delay</span></span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      <span class="built_in">log</span> ERROR <span class="string">&quot;复制配置失败: <span class="subst">$(echo <span class="string">&quot;<span class="variable">$output</span>&quot;</span> | head -n1)</span>&quot;</span></span><br><span class="line">      <span class="built_in">log</span> DEBUG <span class="string">&quot;完整错误: <span class="variable">$output</span>&quot;</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">    ((attempt++))</span><br><span class="line">    delay=$((delay * <span class="number">2</span> &gt; <span class="number">8</span> ? <span class="number">8</span> : delay * <span class="number">2</span>))</span><br><span class="line">  <span class="keyword">done</span></span><br><span class="line">  <span class="built_in">log</span> ERROR <span class="string">&quot;经过 <span class="variable">$&#123;retries&#125;</span> 次尝试后仍无法配置复制&quot;</span></span><br><span class="line">  <span class="built_in">return</span> 1</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 优化状态验证表格</span></span><br><span class="line"><span class="function"><span class="title">verify_status</span></span>() &#123;</span><br><span class="line">  header <span class="string">&quot;<span class="variable">$ICON_NETWORK</span>&quot;</span> <span class="string">&quot;复制状态验证&quot;</span></span><br><span class="line">  <span class="keyword">for</span> site <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;!SITES[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">    <span class="built_in">printf</span> <span class="string">&quot;<span class="variable">$&#123;GREEN&#125;</span>%s [SUCCESS]   查询成功: %s → %s<span class="variable">$&#123;RESET&#125;</span></span></span><br><span class="line"><span class="string">&quot;</span> <span class="string">&quot;<span class="variable">$ICON_SUCCESS</span>&quot;</span> <span class="string">&quot;<span class="variable">$site</span>&quot;</span> <span class="string">&quot;<span class="variable">$&#123;SITES[$site]&#125;</span>&quot;</span></span><br><span class="line">    <span class="built_in">printf</span> <span class="string">&quot;<span class="variable">$&#123;CYAN&#125;</span>%s<span class="variable">$&#123;RESET&#125;</span></span></span><br><span class="line"><span class="string">&quot;</span> <span class="string">&quot;<span class="subst">$(for i in $(seq 1 160)</span>; do printf &quot;</span>-<span class="string">&quot;; done)&quot;</span></span><br><span class="line">    status_output=$(/usr/bin/mc admin replicate info <span class="string">&quot;<span class="variable">$site</span>&quot;</span> 2&gt;&amp;1)</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">echo</span> <span class="string">&quot;<span class="variable">$status_output</span>&quot;</span> | grep -q <span class="string">&quot;SiteReplication enabled&quot;</span>; <span class="keyword">then</span></span><br><span class="line">      <span class="built_in">printf</span> <span class="string">&quot;<span class="variable">$&#123;GREEN&#125;</span>%s<span class="variable">$&#123;RESET&#125;</span></span></span><br><span class="line"><span class="string">&quot;</span> <span class="string">&quot;<span class="variable">$status_output</span>&quot;</span></span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">      <span class="built_in">printf</span> <span class="string">&quot;<span class="variable">$&#123;RED&#125;</span>%s<span class="variable">$&#123;RESET&#125;</span></span></span><br><span class="line"><span class="string">&quot;</span> <span class="string">&quot;<span class="variable">$status_output</span>&quot;</span></span><br><span class="line">    <span class="keyword">fi</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="keyword">done</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 主流程控制</span></span><br><span class="line"><span class="function"><span class="title">main</span></span>() &#123;</span><br><span class="line">  : <span class="string">&quot;<span class="variable">$&#123;SITE1_URL:?需要 SITE1_URL 环境变量&#125;</span>&quot;</span></span><br><span class="line">  : <span class="string">&quot;<span class="variable">$&#123;SITE2_URL:?需要 SITE2_URL 环境变量&#125;</span>&quot;</span></span><br><span class="line">  : <span class="string">&quot;<span class="variable">$&#123;MINIO_ACCESS_KEY:?需要 MINIO_ACCESS_KEY 环境变量&#125;</span>&quot;</span></span><br><span class="line">  : <span class="string">&quot;<span class="variable">$&#123;MINIO_SECRET_KEY:?需要 MINIO_SECRET_KEY 环境变量&#125;</span>&quot;</span></span><br><span class="line">  <span class="built_in">declare</span> -A SITES=([<span class="string">&quot;SITE1&quot;</span>]=<span class="string">&quot;<span class="variable">$SITE1_URL</span>&quot;</span> [<span class="string">&quot;SITE2&quot;</span>]=<span class="string">&quot;<span class="variable">$SITE2_URL</span>&quot;</span>)</span><br><span class="line">  header <span class="string">&quot;<span class="variable">$ICON_START</span>&quot;</span> <span class="string">&quot;MinIO 站点复制初始化&quot;</span></span><br><span class="line">  wait_for_services</span><br><span class="line">  configure_aliases || <span class="built_in">exit</span> 1</span><br><span class="line">  cleanup_old_replication || <span class="built_in">exit</span> 1</span><br><span class="line">  setup_replication || <span class="built_in">exit</span> 1</span><br><span class="line">  verify_status</span><br><span class="line">  header <span class="string">&quot;<span class="variable">$ICON_FINISH</span>&quot;</span> <span class="string">&quot;MinIO 站点复制已就绪&quot;</span></span><br><span class="line">  <span class="built_in">log</span> SUCCESS <span class="string">&quot;所有配置已完成，服务运行中...&quot;</span></span><br><span class="line">  <span class="built_in">log</span> INFO <span class="string">&quot;按 Ctrl+C 停止服务&quot;</span></span><br><span class="line">  <span class="built_in">exec</span> <span class="built_in">tail</span> -f /dev/null</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">trap</span> <span class="string">&#x27;log INFO &quot;收到终止信号，正在关闭...&quot;; exit 0&#x27;</span> SIGTERM SIGINT</span><br><span class="line">main</span><br></pre></td></tr></table></figure><h2 id="部署步骤"><a href="#部署步骤" class="headerlink" title="部署步骤"></a>部署步骤</h2><h3 id="准备环境"><a href="#准备环境" class="headerlink" title="准备环境"></a>准备环境</h3><ol><li>创建目录：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /data/opt/installmiddleware/data/minio/data</span><br></pre></td></tr></table></figure></li><li>设置磁盘权限：<br>确保 20T 磁盘挂载到 <code>/data</code>，并赋予权限：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">chown</span> -R 1000:1000 ./data/minio/data</span><br></pre></td></tr></table></figure></li><li>保存配置：<ul><li>保存 <code>docker-compose.yml</code> 和 <code>.env</code> 文件。</li><li>保存 <code>site-replication.sh</code>，设置可执行权限：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">chmod</span> +x site-replication.sh</span><br></pre></td></tr></table></figure></li></ul></li></ol><h3 id="启动服务"><a href="#启动服务" class="headerlink" title="启动服务"></a>启动服务</h3><p>在 MinIO1 和 MinIO2 服务器上分别部署 MinIO 实例：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cd</span> /data/opt/installmiddleware</span><br><span class="line">docker-compose up -d</span><br></pre></td></tr></table></figure><h3 id="配置站点复制"><a href="#配置站点复制" class="headerlink" title="配置站点复制"></a>配置站点复制</h3><ul><li><code>minio-mc</code> 容器自动运行 <code>site-replication.sh</code>，配置站点复制。</li><li>检查日志：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker logs --<span class="built_in">tail</span> 100 minio-mc</span><br></pre></td></tr></table></figure>预期输出：<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Configuring aliases for SITE1 and SITE2...</span><br><span class="line">Adding site replication between SITE1 and SITE2...</span><br><span class="line">Site replication configured successfully!</span><br></pre></td></tr></table></figure></li></ul><h2 id="同步测试"><a href="#同步测试" class="headerlink" title="同步测试"></a>同步测试</h2><h3 id="测试目标"><a href="#测试目标" class="headerlink" title="测试目标"></a>测试目标</h3><p>验证 MinIO1 创建的桶和上传的对象是否自动同步到 MinIO2。</p><h3 id="测试步骤"><a href="#测试步骤" class="headerlink" title="测试步骤"></a>测试步骤</h3><ol><li>在 MinIO1 创建桶：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker <span class="built_in">exec</span> -it minio-mc bash</span><br><span class="line">mc mb SITE1/test-bucket</span><br></pre></td></tr></table></figure></li><li>上传测试文件：<ul><li>创建文件：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Hello, MinIO!&quot;</span> &gt; test.txt</span><br></pre></td></tr></table></figure></li><li>上传到 MinIO1：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">mc <span class="built_in">cp</span> test.txt SITE1/test-bucket</span><br></pre></td></tr></table></figure></li></ul></li><li>验证 MinIO2 同步：<ul><li>检查桶：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">mc <span class="built_in">ls</span> SITE2</span><br></pre></td></tr></table></figure>预期输出：<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">[2025-05-13 16:40:00 CST]     0B test-bucket/</span><br></pre></td></tr></table></figure></li><li>检查文件：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">mc <span class="built_in">ls</span> SITE2/test-bucket</span><br></pre></td></tr></table></figure>预期输出：<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">[2025-05-13 16:40:10 CST]    14B test.txt</span><br></pre></td></tr></table></figure></li></ul></li><li>访问 MinIO2 控制台：<ul><li>打开 <code>http://192.168.199.147:9000</code>，登录（<code>admin</code>&#x2F;<code>Admin@123.com</code>）。</li><li>确认 <code>test-bucket</code> 和 <code>test.txt</code> 存在。</li></ul></li></ol><h3 id="测试结果"><a href="#测试结果" class="headerlink" title="测试结果"></a>测试结果</h3><p>桶和文件成功同步，说明站点复制正常，同步延迟通常在毫秒级（RTT &lt; 20ms）。</p><h2 id="故障恢复测试"><a href="#故障恢复测试" class="headerlink" title="故障恢复测试"></a>故障恢复测试</h2><h3 id="测试目标-1"><a href="#测试目标-1" class="headerlink" title="测试目标"></a>测试目标</h3><p>模拟 MinIO1 故障，验证 MinIO2 的服务可用性，并测试 MinIO1 恢复后的同步。</p><h3 id="测试步骤-1"><a href="#测试步骤-1" class="headerlink" title="测试步骤"></a>测试步骤</h3><ol><li>停止 MinIO1：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker-compose stop minio</span><br></pre></td></tr></table></figure></li><li>检查站点复制状态：<ul><li>在 <code>minio-mc</code> 容器中：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">mc admin replicate status SITE2</span><br></pre></td></tr></table></figure>预期输出（基于实际测试）：<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Bucket replication status:</span><br><span class="line">●  0/1 Buckets in sync</span><br><span class="line">Bucket          | SITE1           | SITE2          </span><br><span class="line">test            |                 | ✗  in-sync     </span><br><span class="line">...</span><br><span class="line">Object replication status:</span><br><span class="line">Link:          ● offline 5 seconds (total downtime: 4 minutes 30 seconds)</span><br><span class="line">Errors:        0 in last 1 minute; 1 in last 1hr</span><br></pre></td></tr></table></figure></li></ul></li><li>验证 MinIO2 服务：<ul><li>上传新文件：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&quot;MinIO2 test&quot;</span> &gt; test2.txt</span><br><span class="line">mc <span class="built_in">cp</span> test2.txt SITE2/test-bucket</span><br></pre></td></tr></table></figure></li><li>检查：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">mc <span class="built_in">ls</span> SITE2/test-bucket</span><br></pre></td></tr></table></figure>预期输出：<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">[2025-05-13 16:45:00 CST]    14B test.txt</span><br><span class="line">[2025-05-13 16:45:10 CST]    12B test2.txt</span><br></pre></td></tr></table></figure></li></ul></li><li>恢复 MinIO1：<ul><li>启动：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker-compose start minio</span><br></pre></td></tr></table></figure></li><li>验证健康：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">curl -f http://192.168.199.145:9000/minio/health/live</span><br></pre></td></tr></table></figure></li></ul></li><li>重新同步：<ul><li>触发增量同步：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">mc admin replicate resync start SITE2 SITE1</span><br></pre></td></tr></table></figure></li><li>检查状态：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">mc admin replicate status SITE2</span><br></pre></td></tr></table></figure>预期输出：<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Site Replication Status:</span><br><span class="line">- Site: SITE1 (http://192.168.199.145:9000) - Online</span><br><span class="line">- Site: SITE2 (http://192.168.199.147:9000) - Online</span><br><span class="line">Replication Status: Active</span><br></pre></td></tr></table></figure></li></ul></li><li>验证 MinIO1 同步：<ul><li>检查：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">mc <span class="built_in">ls</span> SITE1/test-bucket</span><br></pre></td></tr></table></figure>预期输出：<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">[2025-05-13 16:45:00 CST]    14B test.txt</span><br><span class="line">[2025-05-13 16:45:10 CST]    12B test2.txt</span><br></pre></td></tr></table></figure></li></ul></li></ol><h3 id="测试结果-1"><a href="#测试结果-1" class="headerlink" title="测试结果"></a>测试结果</h3><ul><li>MinIO1 故障期间，MinIO2 正常提供服务。</li><li>MinIO1 恢复后，增量数据（<code>test2.txt</code>）同步成功，站点复制恢复正常。</li></ul><h2 id="注意事项与优化建议"><a href="#注意事项与优化建议" class="headerlink" title="注意事项与优化建议"></a>注意事项与优化建议</h2><h3 id="磁盘与虚拟化"><a href="#磁盘与虚拟化" class="headerlink" title="磁盘与虚拟化"></a>磁盘与虚拟化</h3><ul><li>20T 磁盘（虚拟化后 18T）可能受虚拟化影响，建议直通磁盘：<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">volumes:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">/dev/sdb:/data</span></span><br></pre></td></tr></table></figure></li><li>定期检查磁盘健康：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">smartctl -a /dev/sdb</span><br></pre></td></tr></table></figure></li></ul><h3 id="网络"><a href="#网络" class="headerlink" title="网络"></a>网络</h3><ul><li>确保 RTT &lt; 20ms，带宽 ≥ 1Gbps。</li><li>检查防火墙：<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ufw allow from 192.168.199.0/24 to any port 9000</span><br></pre></td></tr></table></figure></li></ul><h3 id="安全性"><a href="#安全性" class="headerlink" title="安全性"></a>安全性</h3><ul><li>替换默认凭据（<code>admin</code>&#x2F;<code>Admin@123.com</code>）。</li><li>启用 TLS：<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">environment:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">MINIO_SERVER_URL=https://192.168.199.145:9000</span></span><br></pre></td></tr></table></figure></li></ul><h3 id="监控"><a href="#监控" class="headerlink" title="监控"></a>监控</h3><ul><li>启用 Prometheus：<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">environment:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">MINIO_PROMETHEUS_AUTH_TYPE=public</span></span><br></pre></td></tr></table></figure></li><li>使用 Grafana 监控节点状态（<code>minio_node_up</code>）和复制延迟（<code>minio_replication_last_hour_latency_millis</code>）。</li></ul><h3 id="预算"><a href="#预算" class="headerlink" title="预算"></a>预算</h3><ul><li>站点复制需要两台服务器（约 14000-25000 元）。若预算有限，可考虑单向主从复制（约 7000-13000 元）。</li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过 Docker Compose 和 <code>site-replication.sh</code>，我们部署了 MinIO 站点复制集群，实现了 MinIO1 和 MinIO2 的数据和元数据同步。同步测试验证了桶和对象的自动同步，故障恢复测试确认了 MinIO2 的高可用性和 MinIO1 恢复后的增量同步。该方案结合 20T 磁盘的存储容量，适用于高可用性场景。</p><p>如需进一步优化（如 webhook 通知、Flask API 集成），请参考 MinIO 文档：<span class="exturl" data-url="aHR0cHM6Ly9taW4uaW8vZG9jcy9taW5pby9saW51eC9vcGVyYXRpb25zL2luc3RhbGwtZGVwbG95LW1hbmFnZS9tdWx0aS1zaXRlLXJlcGxpY2F0aW9uLmh0bWw=">Site Replication<i class="fa fa-external-link-alt"></i></span>。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt; MinIO 是一个高性能的分布式对象存储系统，其站点复制（Site Replication）功能支持跨集群的数据和元数据同步。本文记录了如何使用 Docker Compose 部署 MinIO 站点复制集群，配置两个 MinIO 实例，并进行同步测试和故障恢复测试。测试环境基于 20T 磁盘，适用于需要高可用性和灾难恢复的场景。&lt;/p&gt;</summary>
    
    
    
    <category term="Development" scheme="https://freemankevin.uk/categories/Development/"/>
    
    
    <category term="Docker" scheme="https://freemankevin.uk/tags/Docker/"/>
    
    <category term="MinIO" scheme="https://freemankevin.uk/tags/MinIO/"/>
    
    <category term="SITE Replication" scheme="https://freemankevin.uk/tags/SITE-Replication/"/>
    
    <category term="High Availability" scheme="https://freemankevin.uk/tags/High-Availability/"/>
    
    <category term="Error Recovery" scheme="https://freemankevin.uk/tags/Error-Recovery/"/>
    
  </entry>
  
  <entry>
    <title>如何在 Docker 环境中部署 VLLM</title>
    <link href="https://freemankevin.uk/2025/05/12/docker-vllm/"/>
    <id>https://freemankevin.uk/2025/05/12/docker-vllm/</id>
    <published>2025-05-12T09:14:25.000Z</published>
    <updated>2026-05-21T06:03:03.314Z</updated>
    
    <content type="html"><![CDATA[<p> 本指南将详细介绍如何在 Windows 和 Linux 系统上使用 Docker 部署 vLLM 大模型服务，并提供跨平台测试方案。</p><span id="more"></span><h2 id="系统要求"><a href="#系统要求" class="headerlink" title="系统要求"></a>系统要求</h2><h3 id="硬件要求"><a href="#硬件要求" class="headerlink" title="硬件要求"></a>硬件要求</h3><ul><li>NVIDIA GPU (建议 RTX 3060 或更高)</li><li>显存要求:<ul><li>Qwen&#x2F;Qwen3-0.6B: 至少 8GB （本地测试）</li><li>Qwen&#x2F;QwQ-32B: 至少 64GB（生产使用）</li></ul></li><li>内存: 16GB 或更高</li></ul><h3 id="软件要求"><a href="#软件要求" class="headerlink" title="软件要求"></a>软件要求</h3><ul><li>操作系统:<ul><li>Windows 10&#x2F;11 (专业版&#x2F;企业版)</li><li>Linux (Ubuntu 20.04+&#x2F;CentOS 7+)</li></ul></li><li>Docker Engine 20.10+</li><li>NVIDIA 驱动 535+</li><li>NVIDIA Container Toolkit</li></ul><h2 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h2><h3 id="1-安装必要组件"><a href="#1-安装必要组件" class="headerlink" title="1. 安装必要组件"></a>1. 安装必要组件</h3><p><strong>Windows 环境:</strong></p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 安装 WSL2 (Windows 子系统)</span></span><br><span class="line">wsl <span class="literal">--install</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 Docker Desktop</span></span><br><span class="line"><span class="comment"># 从 https://www.docker.com/products/docker-desktop 下载安装</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 NVIDIA 驱动和 CUDA</span></span><br><span class="line"><span class="comment"># 从 https://developer.nvidia.com/cuda-downloads 下载</span></span><br></pre></td></tr></table></figure><p><strong>Linux 环境:</strong></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 安装 Docker</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 docker-ce docker-ce-cli containerd.io</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 NVIDIA Container Toolkit</span></span><br><span class="line">distribution=$(. /etc/os-release;<span class="built_in">echo</span> $ID<span class="variable">$VERSION_ID</span>) \</span><br><span class="line">   &amp;&amp; curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | <span class="built_in">sudo</span> apt-key add - \</span><br><span class="line">   &amp;&amp; curl -s -L https://nvidia.github.io/nvidia-docker/<span class="variable">$distribution</span>/nvidia-docker.list | <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/apt/sources.list.d/nvidia-docker.list</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 nvidia-docker2</span><br><span class="line"><span class="built_in">sudo</span> systemctl restart docker</span><br></pre></td></tr></table></figure><h3 id="2-验证环境"><a href="#2-验证环境" class="headerlink" title="2. 验证环境"></a>2. 验证环境</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 验证 Docker 安装</span></span><br><span class="line">docker --version</span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证 NVIDIA 支持</span></span><br><span class="line">docker run --<span class="built_in">rm</span> --gpus all nvidia/cuda:11.0.3-base-ubuntu20.04 nvidia-smi</span><br></pre></td></tr></table></figure><h2 id="Docker-部署"><a href="#Docker-部署" class="headerlink" title="Docker 部署"></a>Docker 部署</h2><h3 id="1-创建-docker-compose-yml-文件"><a href="#1-创建-docker-compose-yml-文件" class="headerlink" title="1. 创建 docker-compose.yml 文件"></a>1. 创建 docker-compose.yml 文件</h3><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment"># version: &#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">vllm:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">vllm/vllm-openai:latest</span></span><br><span class="line">    <span class="attr">runtime:</span> <span class="string">nvidia</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">vllm</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">deploy:</span></span><br><span class="line">      <span class="attr">resources:</span></span><br><span class="line">        <span class="attr">reservations:</span></span><br><span class="line">          <span class="attr">devices:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="attr">driver:</span> <span class="string">nvidia</span></span><br><span class="line">              <span class="attr">capabilities:</span> [<span class="string">gpu</span>]</span><br><span class="line">              <span class="attr">count:</span> <span class="string">all</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">$HOME/.cache/huggingface:/root/.cache/huggingface</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;28000:8000&quot;</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">HF_HOME=/root/.cache/huggingface</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True</span></span><br><span class="line">    <span class="attr">command:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">--model</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">Qwen/Qwen3-0.6B</span> <span class="comment"># 或 Qwen/QwQ-32B</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">--gpu-memory-utilization</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;0.8&quot;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">--trust-remote-code</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">--max-num-seqs</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;256&quot;</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD-SHELL&quot;</span>, <span class="string">&quot;curl -f http://localhost:8000/health || exit 1&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">60s</span></span><br></pre></td></tr></table></figure><p><strong>Windows 用户注意</strong>:</p><ul><li>将 <code>$HOME/.cache/huggingface</code> 替换为 <code>C:/Users/Devops/.cache/huggingface</code></li><li>确保路径使用正斜杠 <code>/</code> 而非反斜杠 <code>\</code></li></ul><h3 id="2-启动服务"><a href="#2-启动服务" class="headerlink" title="2. 启动服务"></a>2. 启动服务</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 下载 vLLM 镜像</span></span><br><span class="line">docker pull vllm/vllm-openai:latest</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><h3 id="3-验证服务"><a href="#3-验证服务" class="headerlink" title="3. 验证服务"></a>3. 验证服务</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 检查容器状态</span></span><br><span class="line">docker ps</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看日志</span></span><br><span class="line">docker logs vllm</span><br><span class="line"></span><br><span class="line"><span class="comment"># 健康检查</span></span><br><span class="line">curl http://localhost:28000/health</span><br></pre></td></tr></table></figure><h2 id="模型下载与管理"><a href="#模型下载与管理" class="headerlink" title="模型下载与管理"></a>模型下载与管理</h2><h3 id="1-手动下载模型-可选"><a href="#1-手动下载模型-可选" class="headerlink" title="1. 手动下载模型 (可选)"></a>1. 手动下载模型 (可选)</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 安装 huggingface_hub</span></span><br><span class="line">pip install huggingface_hub</span><br><span class="line"></span><br><span class="line"><span class="comment"># 下载模型 (可在宿主机执行)</span></span><br><span class="line">huggingface-cli download Qwen/Qwen3-0.6B </span><br><span class="line"></span><br><span class="line"><span class="comment"># 模型默认存放在用户家目录下，比如:</span></span><br><span class="line"><span class="comment"># C:/Users/Devops/.cache/huggingface/hub/models--Qwen--Qwen3-0.6B</span></span><br></pre></td></tr></table></figure><h3 id="2-使用-vLLM-自动下载"><a href="#2-使用-vLLM-自动下载" class="headerlink" title="2. 使用 vLLM 自动下载"></a>2. 使用 vLLM 自动下载</h3><p>vLLM 会在首次启动时自动下载模型，但建议提前下载以避免超时。</p><h2 id="服务测试"><a href="#服务测试" class="headerlink" title="服务测试"></a>服务测试</h2><h3 id="1-使用-curl-测试"><a href="#1-使用-curl-测试" class="headerlink" title="1. 使用 curl 测试"></a>1. 使用 curl 测试</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">curl http://localhost:28000/v1/completions \</span><br><span class="line">  -H <span class="string">&quot;Content-Type: application/json&quot;</span> \</span><br><span class="line">  -d <span class="string">&#x27;&#123;</span></span><br><span class="line"><span class="string">      &quot;model&quot;: &quot;Qwen/Qwen3-0.6B&quot;,</span></span><br><span class="line"><span class="string">      &quot;prompt&quot;: &quot;你好，介绍一下你自己&quot;,</span></span><br><span class="line"><span class="string">      &quot;max_tokens&quot;: 100</span></span><br><span class="line"><span class="string">  &#125;&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="2-使用-HTML-测试界面"><a href="#2-使用-HTML-测试界面" class="headerlink" title="2. 使用 HTML 测试界面"></a>2. 使用 HTML 测试界面</h3><p>创建 <code>vllm-test.html</code> 文件：</p><figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">h2</span>&gt;</span>vLLM 测试界面<span class="tag">&lt;/<span class="name">h2</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">textarea</span> <span class="attr">id</span>=<span class="string">&quot;input&quot;</span> <span class="attr">rows</span>=<span class="string">&quot;4&quot;</span> <span class="attr">cols</span>=<span class="string">&quot;50&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;输入提示词...&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">textarea</span>&gt;</span><span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">button</span> <span class="attr">onclick</span>=<span class="string">&quot;generate()&quot;</span>&gt;</span>生成<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">pre</span> <span class="attr">id</span>=<span class="string">&quot;output&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">pre</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">generate</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> input = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;input&quot;</span>).<span class="property">value</span>;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">try</span> &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">&quot;http://localhost:28000/v1/completions&quot;</span>, &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="attr">method</span>: <span class="string">&quot;POST&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">          <span class="attr">headers</span>: &#123; <span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;application/json&quot;</span> &#125;,</span></span><br><span class="line"><span class="language-javascript">          <span class="attr">body</span>: <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">model</span>: <span class="string">&quot;Qwen/Qwen3-0.6B&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">prompt</span>: input,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">max_tokens</span>: <span class="number">100</span></span></span><br><span class="line"><span class="language-javascript">          &#125;)</span></span><br><span class="line"><span class="language-javascript">        &#125;);</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">const</span> result = <span class="keyword">await</span> response.<span class="title function_">json</span>();</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;output&quot;</span>).<span class="property">textContent</span> = result.<span class="property">choices</span>[<span class="number">0</span>].<span class="property">text</span>;</span></span><br><span class="line"><span class="language-javascript">      &#125; <span class="keyword">catch</span> (error) &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&quot;output&quot;</span>).<span class="property">textContent</span> = <span class="string">&quot;错误: &quot;</span> + error.<span class="property">message</span>;</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">  </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="跨平台测试方案"><a href="#跨平台测试方案" class="headerlink" title="跨平台测试方案"></a>跨平台测试方案</h2><h3 id="Windows-环境测试"><a href="#Windows-环境测试" class="headerlink" title="Windows 环境测试"></a>Windows 环境测试</h3><ol><li><p><strong>浏览器安全限制</strong>:</p><ul><li>Chrome&#x2F;Firefox 默认阻止跨域请求</li><li>解决方案:<ul><li>使用 <code>file:///</code> 协议直接打开 HTML 文件</li><li>或使用以下命令启动 Chrome 禁用安全限制:<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">chrome.exe <span class="literal">--user-data-dir</span>=<span class="string">&quot;C:/Temp&quot;</span> <span class="literal">--disable-web-security</span></span><br></pre></td></tr></table></figure></li></ul></li></ul></li><li><p><strong>替代方案</strong>:</p><ul><li>使用 Postman 或 Insomnia 测试 API</li><li>使用 Python 脚本测试:<figure class="highlight python"><table><tr><td class="code"><pre><span class="line"><span class="keyword">from</span> openai <span class="keyword">import</span> OpenAI</span><br><span class="line"></span><br><span class="line">client = OpenAI(base_url=<span class="string">&quot;http://localhost:28000/v1&quot;</span>, api_key=<span class="string">&quot;token-abc123&quot;</span>)</span><br><span class="line"></span><br><span class="line">completion = client.completions.create(</span><br><span class="line">    model=<span class="string">&quot;Qwen/Qwen3-0.6B&quot;</span>,</span><br><span class="line">    prompt=<span class="string">&quot;你好，介绍一下你自己&quot;</span>,</span><br><span class="line">    max_tokens=<span class="number">100</span></span><br><span class="line">)</span><br><span class="line"><span class="built_in">print</span>(completion.choices[<span class="number">0</span>].text)</span><br></pre></td></tr></table></figure></li></ul></li></ol><h3 id="Linux-环境测试"><a href="#Linux-环境测试" class="headerlink" title="Linux 环境测试"></a>Linux 环境测试</h3><ol><li><p><strong>浏览器测试</strong>:</p><ul><li>可直接使用 Firefox 打开 HTML 文件</li><li>或部署简单 HTTP 服务器:<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">python3 -m http.server 8000</span><br></pre></td></tr></table></figure>然后访问 <code>http://localhost:8000/vllm-test.html</code></li></ul></li><li><p><strong>命令行测试</strong>:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 使用 httpie 工具</span></span><br><span class="line">http POST http://localhost:28000/v1/completions \</span><br><span class="line">  model=<span class="string">&quot;Qwen/Qwen3-0.6B&quot;</span> \</span><br><span class="line">  prompt=<span class="string">&quot;你好&quot;</span> \</span><br><span class="line">  max_tokens:=50</span><br></pre></td></tr></table></figure></li></ol><h2 id="常见问题解决"><a href="#常见问题解决" class="headerlink" title="常见问题解决"></a>常见问题解决</h2><h3 id="1-模型下载失败"><a href="#1-模型下载失败" class="headerlink" title="1. 模型下载失败"></a>1. 模型下载失败</h3><p><strong>症状</strong>: 容器日志显示下载超时或失败</p><p><strong>解决方案</strong>:</p><ul><li>手动下载模型到缓存目录</li><li>设置 HTTP 代理:<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">environment:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">HF_HUB_ENABLE_HF_TRANSFER=1</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">http_proxy=http://your-proxy:port</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">https_proxy=http://your-proxy:port</span></span><br></pre></td></tr></table></figure></li></ul><h3 id="2-GPU-内存不足"><a href="#2-GPU-内存不足" class="headerlink" title="2. GPU 内存不足"></a>2. GPU 内存不足</h3><p><strong>症状</strong>: CUDA out of memory 错误</p><p><strong>解决方案</strong>:</p><ul><li>降低 <code>--gpu-memory-utilization</code> 值 (如 0.5)</li><li>使用更小模型 (如 Qwen3-0.6B 替代 QwQ-32B)</li><li>添加 <code>--enforce-eager</code> 参数减少内存占用</li></ul><h3 id="3-跨域问题-CORS"><a href="#3-跨域问题-CORS" class="headerlink" title="3. 跨域问题 (CORS)"></a>3. 跨域问题 (CORS)</h3><p><strong>症状</strong>: HTML 测试界面无法访问 API</p><p><strong>解决方案</strong>:</p><ul><li>启动 vLLM 时添加 CORS 参数:<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">command:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">--model</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">Qwen/Qwen3-0.6B</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">--cors-allow-origins</span> <span class="string">&quot;*&quot;</span></span><br></pre></td></tr></table></figure></li><li>或使用 Nginx 反向代理配置 CORS</li></ul><h3 id="4-Windows-路径问题"><a href="#4-Windows-路径问题" class="headerlink" title="4. Windows 路径问题"></a>4. Windows 路径问题</h3><p><strong>症状</strong>: 卷挂载失败</p><p><strong>解决方案</strong>:</p><ul><li>使用绝对路径并确保 Docker Desktop 已启用 “Shared Drives”</li><li>示例:<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">volumes:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">C:/Users/Devops/.cache/huggingface:/root/.cache/huggingface</span></span><br></pre></td></tr></table></figure></li></ul><h2 id="性能优化建议"><a href="#性能优化建议" class="headerlink" title="性能优化建议"></a>性能优化建议</h2><ol><li><p><strong>量化</strong>:</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">command:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">--model</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">Qwen/Qwen3-0.6B</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">--quantization</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">awq</span>  <span class="comment"># 或 gptq</span></span><br></pre></td></tr></table></figure></li><li><p><strong>批处理优化</strong>:</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">command:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">--max-num-batched-tokens</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">&quot;4096&quot;</span></span><br></pre></td></tr></table></figure></li><li><p><strong>并行推理</strong>:</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">command:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">--tensor-parallel-size</span></span><br><span class="line">  <span class="bullet">-</span> <span class="string">&quot;2&quot;</span>  <span class="comment"># 使用2个GPU</span></span><br></pre></td></tr></table></figure></li></ol>]]></content>
    
    
    <summary type="html">&lt;p&gt; 本指南将详细介绍如何在 Windows 和 Linux 系统上使用 Docker 部署 vLLM 大模型服务，并提供跨平台测试方案。&lt;/p&gt;</summary>
    
    
    
    <category term="Development" scheme="https://freemankevin.uk/categories/Development/"/>
    
    
    <category term="Docker" scheme="https://freemankevin.uk/tags/Docker/"/>
    
    <category term="VLLM" scheme="https://freemankevin.uk/tags/VLLM/"/>
    
    <category term="OPenAI" scheme="https://freemankevin.uk/tags/OPenAI/"/>
    
    <category term="LLM" scheme="https://freemankevin.uk/tags/LLM/"/>
    
  </entry>
  
  <entry>
    <title>使用 Cloudflare Tunnel 安全暴露本地服务到公网</title>
    <link href="https://freemankevin.uk/2025/04/23/Cloudflare-Tunnel/"/>
    <id>https://freemankevin.uk/2025/04/23/Cloudflare-Tunnel/</id>
    <published>2025-04-23T07:14:25.000Z</published>
    <updated>2026-05-21T06:03:03.314Z</updated>
    
    <content type="html"><![CDATA[<p> Cloudflare Tunnel 是一种强大的反向隧道服务，允许用户将本地服务器或内部网络资源安全暴露到公网，而无需开放防火墙端口或拥有公网 IP 地址。本文将详细介绍 Cloudflare Tunnel 的工作原理、功能特点、使用场景，并结合实际操作步骤，展示如何通过 Cloudflare Tunnel 将本地服务映射到公网域名。</p><span id="more"></span><h2 id="什么是-Cloudflare-Tunnel？"><a href="#什么是-Cloudflare-Tunnel？" class="headerlink" title="什么是 Cloudflare Tunnel？"></a>什么是 Cloudflare Tunnel？</h2><p>Cloudflare Tunnel 是 Cloudflare 提供的一项服务，通过运行轻量级客户端 <code>cloudflared</code>，在本地设备与 Cloudflare 全球网络之间建立安全的出站连接（outbound-only）。外部用户可以通过 Cloudflare 的网络访问你的本地服务，而无需直接暴露服务器的 IP 或端口。</p><h3 id="工作原理"><a href="#工作原理" class="headerlink" title="工作原理"></a>工作原理</h3><ol><li><strong>安装客户端</strong>：在本地服务器或设备上安装 <code>cloudflared</code>，这是 Cloudflare 提供的隧道守护进程。</li><li><strong>创建隧道</strong>：使用 <code>cloudflared</code> 创建一个隧道，与 Cloudflare 边缘网络建立连接，无需公网 IP。</li><li><strong>路由流量</strong>：在 Cloudflare 仪表盘中配置域名或子域名，外部请求通过 Cloudflare 转发到本地服务。</li><li><strong>安全性保障</strong>：所有流量经过 Cloudflare 的加密，支持 HTTPS，并可结合 Cloudflare Access 添加身份验证。</li></ol><h3 id="主要特点"><a href="#主要特点" class="headerlink" title="主要特点"></a>主要特点</h3><ul><li><strong>无需端口转发</strong>：无需配置路由器或开放防火墙端口，适合家庭网络或受限环境。</li><li><strong>免费基础服务</strong>：基本功能（如创建隧道、绑定域名）免费，适合个人用户或小型项目。</li><li><strong>安全性增强</strong>：提供 DDoS 防护、SSL&#x2F;TLS 加密，流量通过 Cloudflare 全球网络。</li><li><strong>灵活性</strong>：支持多种协议（如 HTTP、SSH、RDP），可暴露网页服务、远程桌面或游戏服务器。</li></ul><h3 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h3><ul><li><strong>远程访问本地服务</strong>：如在家运行 NAS，想通过公网访问文件管理界面。</li><li><strong>开发测试</strong>：快速将本地开发环境暴露到公网，测试 webhook 或第三方回调。</li><li><strong>替代 VPN</strong>：相比传统 VPN，Cloudflare Tunnel 配置简单，适合快速部署。</li></ul><h3 id="对比-ngrok"><a href="#对比-ngrok" class="headerlink" title="对比 ngrok"></a>对比 ngrok</h3><p>与类似的反向隧道工具 ngrok 相比，Cloudflare Tunnel 有以下优势：</p><ul><li><strong>成本</strong>：ngrok 免费版有严格的时长（2小时断开）和连接限制，而 Cloudflare Tunnel 免费版更宽松。</li><li><strong>域名</strong>：ngrok 免费版提供随机域名，Cloudflare 支持自定义域名。</li><li><strong>安全性</strong>：Cloudflare 提供额外的 DDoS 防护和全球 CDN 加速。</li></ul><h2 id="实践：使用-Cloudflare-Tunnel-暴露本地服务"><a href="#实践：使用-Cloudflare-Tunnel-暴露本地服务" class="headerlink" title="实践：使用 Cloudflare Tunnel 暴露本地服务"></a>实践：使用 Cloudflare Tunnel 暴露本地服务</h2><p>下面，我们将通过实际操作，展示如何使用 Cloudflare Tunnel 将本地运行的网页服务（<code>http://localhost:19000</code>）映射到公网域名 <code>share.freemankevin.uk</code>。</p><h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><ol><li>注册 Cloudflare 账号：登录 Cloudflare 仪表盘，添加你的域名并确保 DNS 托管在 Cloudflare。</li><li>安装 <code>cloudflared</code>：<ul><li>在 Windows 上，下载 <span class="exturl" data-url="aHR0cHM6Ly9kZXZlbG9wZXJzLmNsb3VkZmxhcmUuY29tL2Nsb3VkZmxhcmUtb25lL2Nvbm5lY3Rpb25zL2Nvbm5lY3QtYXBwcy9pbnN0YWxsLWFuZC1zZXR1cC9pbnN0YWxsYXRpb24v">cloudflared.exe<i class="fa fa-external-link-alt"></i></span>（官方下载地址）。</li><li>将 <code>cloudflared.exe</code> 放置在合适目录（如 <code>C:\cloudflared\</code>）。</li></ul></li></ol><h3 id="安装-Cloudflare-Tunnel-服务"><a href="#安装-Cloudflare-Tunnel-服务" class="headerlink" title="安装 Cloudflare Tunnel 服务"></a>安装 Cloudflare Tunnel 服务</h3><p>运行以下命令以安装 <code>cloudflared</code> 服务并绑定 Cloudflare 账户：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">cloudflared.exe service install eyJhIjoiMjc0YzhmYzViSa2kih1k3MzVhNjBjNWQ1MTkzOWQyMDEiLCJ0IjoiMDEwNDI5MmEtNzEwYS00NTBkLWI3OGYtOTNjZTExYjhmYTZlIiwicyI6Ik56Um1ZVGcyT0dRdE9XUm1OaTAwWkRJM0xUbGxZemN0TWpKbFlUWmhabiJzTlRRMiJ9</span><br></pre></td></tr></table></figure><div class="note warning"><p><code>eyJh...</code> 是 Cloudflare 提供的认证令牌，请替换为你自己的令牌（从 Cloudflare 仪表盘获取）。</p></div><p>成功后，<code>cloudflared</code> 将作为系统服务运行。</p><h3 id="创建隧道"><a href="#创建隧道" class="headerlink" title="创建隧道"></a>创建隧道</h3><p>创建名为 <code>share</code> 的隧道：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">cloudflared tunnel create share</span><br></pre></td></tr></table></figure><p>输出类似以下内容：</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">Tunnel credentials written to C:\Users\Devops\.cloudflared\ab9d567c-00c0-46f3-83b7-680ei8b2f3f6.json. cloudflared chose this file based on where your origin certificate was found. Keep this file secret. To revoke these credentials, delete the tunnel.</span><br><span class="line"></span><br><span class="line">Created tunnel share with id ab9d567c-00c0-46f3-83b7-680ei8b2f3f6</span><br></pre></td></tr></table></figure><p>这会生成一个隧道 ID（<code>ab9d567c-00c0-46f3-83b7-680ei8b2f3f6</code>）和凭证文件（<code>ab9d567c-00c0-46f3-83b7-680ei8b2f3f6.json</code>）。请妥善保存凭证文件，避免泄露。</p><h3 id="配置隧道"><a href="#配置隧道" class="headerlink" title="配置隧道"></a>配置隧道</h3><p>创建配置文件 <code>config.yml</code>，内容如下：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">tunnel:</span> <span class="string">share</span></span><br><span class="line"><span class="attr">credentials-file:</span> <span class="string">C:\Users\Devops\.cloudflared\ab9d567c-00c0-46f3-83b7-680ei8b2f3f6.json</span></span><br><span class="line"><span class="attr">ingress:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">hostname:</span> <span class="string">share.freemankevin.uk</span></span><br><span class="line">    <span class="attr">service:</span> <span class="string">http://localhost:19000</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">service:</span> <span class="string">http_status:404</span></span><br></pre></td></tr></table></figure><ul><li><code>tunnel</code>：指定隧道名称（<code>share</code>）。</li><li><code>credentials-file</code>：指定凭证文件路径。</li><li><code>ingress</code>：定义路由规则，将 <code>share.freemankevin.uk</code> 的请求转发到本地 <code>http://localhost:19000</code>，其他请求返回 404。</li></ul><p>将 <code>config.yml</code> 保存到 <code>C:\Users\Devops\.cloudflared\</code> 目录。</p><h3 id="配置-DNS-记录"><a href="#配置-DNS-记录" class="headerlink" title="配置 DNS 记录"></a>配置 DNS 记录</h3><p>在 Cloudflare 仪表盘中，添加 CNAME 记录：</p><table><thead><tr><th>类型</th><th>名称</th><th>目标</th></tr></thead><tbody><tr><td>CNAME</td><td>share</td><td>ab9d567c-00c0-46f3-83b7-680ei8b2f3f6.cfargotunnel.com</td></tr></tbody></table><p>或者，使用以下命令自动配置 DNS：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">cloudflared tunnel route dns share share.freemankevin.uk</span><br></pre></td></tr></table></figure><h3 id="运行隧道"><a href="#运行隧道" class="headerlink" title="运行隧道"></a>运行隧道</h3><p>运行以下命令启动隧道：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">cloudflared tunnel <span class="literal">--config</span> C:\Users\Devops\.cloudflared\config.yml <span class="literal">--origin-ca-pool</span> C:\Users\Devops\.cloudflared\ca<span class="literal">-certificates</span>.pem <span class="literal">--logfile</span> C:\Users\Devops\.cloudflared\cloudflared.log run share</span><br></pre></td></tr></table></figure><p>参数说明：</p><ul><li><code>--config</code>：指定配置文件路径。</li><li><code>--origin-ca-pool</code>：指定 CA 证书路径（可选，通常用于企业环境）。</li><li><code>--logfile</code>：指定日志文件路径，便于调试。</li></ul><p>启动后，<code>share.freemankevin.uk</code> 将可通过公网访问，并指向本地 <code>http://localhost:19000</code> 的服务。</p><h3 id="测试访问"><a href="#测试访问" class="headerlink" title="测试访问"></a>测试访问</h3><p>在浏览器中访问 <code>https://share.freemankevin.uk</code>，确认是否能正常访问本地服务。如果无法访问，检查以下内容：</p><ol><li>确保本地服务（<code>http://localhost:19000</code>）正在运行。</li><li>检查 Cloudflare 仪表盘中的 DNS 记录是否正确。</li><li>查看 <code>cloudflared</code> 日志（<code>C:\Users\Devops\.cloudflared\cloudflared.log</code>）以排查错误。</li></ol><h3 id="添加系统服务"><a href="#添加系统服务" class="headerlink" title="添加系统服务"></a>添加系统服务</h3><p>为了方便启动和管理隧道，我们可以将上面的隧道共享服务添加到系统服务中：</p><h4 id="添加服务"><a href="#添加服务" class="headerlink" title="添加服务"></a>添加服务</h4><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 以管理员身份打开 PowerShell</span></span><br><span class="line"><span class="comment"># 创建系统服务</span></span><br><span class="line"><span class="built_in">sc</span> create CloudflaredTunnel binPath= <span class="string">&quot;C:\Program Files (x86)\cloudflared\cloudflared.exe tunnel --config C:\Users\Devops\.cloudflared\config.yml run share&quot;</span> <span class="built_in">start</span>= auto DisplayName= <span class="string">&quot;Cloudflare Tunnel Service&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">sc</span> description CloudflaredTunnel <span class="string">&quot;Cloudflare Tunnel for secure remote access&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">sc</span> failure CloudflaredTunnel reset= <span class="number">30</span> actions= restart/<span class="number">5000</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动服务</span></span><br><span class="line"><span class="built_in">sc</span> <span class="built_in">start</span> CloudflaredTunnel</span><br></pre></td></tr></table></figure><p>添加后，<code>cloudflared</code> 将作为系统服务运行，无需手动启动。</p><h4 id="卸载服务"><a href="#卸载服务" class="headerlink" title="卸载服务"></a>卸载服务</h4><p>如果不再需要该服务，可以卸载：</p><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line"><span class="built_in">sc</span> delete CloudflaredTunnel</span><br></pre></td></tr></table></figure><h2 id="免费版限制"><a href="#免费版限制" class="headerlink" title="免费版限制"></a>免费版限制</h2><ul><li><strong>带宽</strong>：Cloudflare Tunnel 免费版没有明确的带宽限制，但可能对滥用行为进行限制。</li><li><strong>功能</strong>：高级功能（如负载均衡、Zero Trust 策略）需要付费计划。</li><li><strong>域名</strong>：需使用 Cloudflare 托管的域名（可免费注册或迁移现有域名）。</li></ul><h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><h3 id="隧道无法连接？"><a href="#隧道无法连接？" class="headerlink" title="隧道无法连接？"></a>隧道无法连接？</h3><ul><li>检查 <code>cloudflared</code> 是否正常运行，查看日志文件。</li><li>确保网络允许 <code>cloudflared</code> 的出站连接（端口 443）。</li></ul><h3 id="DNS-配置失败？"><a href="#DNS-配置失败？" class="headerlink" title="DNS 配置失败？"></a>DNS 配置失败？</h3><ul><li>确认域名已正确托管在 Cloudflare。</li><li>检查 CNAME 记录是否指向正确的隧道地址。</li></ul><h3 id="如何停止隧道？"><a href="#如何停止隧道？" class="headerlink" title="如何停止隧道？"></a>如何停止隧道？</h3><ul><li>按 <code>Ctrl+C</code> 停止 <code>cloudflared</code> 进程。</li><li>或删除隧道：<code>cloudflared tunnel delete share</code>。</li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Cloudflare Tunnel 是一个简单、安全且免费的工具，适合将本地服务暴露到公网。通过以上步骤，你可以轻松将本地网页服务映射到自定义域名，并享受 Cloudflare 提供的加密和 DDoS 防护。相比 ngrok，Cloudflare Tunnel 在成本、灵活性和安全性上更具优势，非常适合个人开发者、家庭用户或小型项目。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt; Cloudflare Tunnel 是一种强大的反向隧道服务，允许用户将本地服务器或内部网络资源安全暴露到公网，而无需开放防火墙端口或拥有公网 IP 地址。本文将详细介绍 Cloudflare Tunnel 的工作原理、功能特点、使用场景，并结合实际操作步骤，展示如何通过 Cloudflare Tunnel 将本地服务映射到公网域名。&lt;/p&gt;</summary>
    
    
    
    <category term="Development" scheme="https://freemankevin.uk/categories/Development/"/>
    
    
    <category term="Cloudflare" scheme="https://freemankevin.uk/tags/Cloudflare/"/>
    
    <category term="Intranet penetration" scheme="https://freemankevin.uk/tags/Intranet-penetration/"/>
    
    <category term="DevOps" scheme="https://freemankevin.uk/tags/DevOps/"/>
    
  </entry>
  
  <entry>
    <title>在 Docker 环境中部署 Nexus 仓库</title>
    <link href="https://freemankevin.uk/2025/04/22/docker-nexus/"/>
    <id>https://freemankevin.uk/2025/04/22/docker-nexus/</id>
    <published>2025-04-22T07:14:25.000Z</published>
    <updated>2026-05-21T06:03:03.314Z</updated>
    
    <content type="html"><![CDATA[<p> Nexus是一个功能强大的仓库管理工具，用于托管Maven工件、Docker镜像等。本文将详细介绍如何在Docker环境中部署Nexus仓库管理器，并集成PostgreSQL数据库、快照清理服务和数据库备份服务。</p><span id="more"></span><h2 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h2><h3 id="目录结构创建"><a href="#目录结构创建" class="headerlink" title="目录结构创建"></a>目录结构创建</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 创建Nexus数据目录</span></span><br><span class="line"><span class="built_in">mkdir</span> -p ./nexus/sonatype-work</span><br><span class="line"><span class="built_in">chmod</span> -R 755 ./nexus/sonatype-work</span><br><span class="line"><span class="built_in">chown</span> -R 200:200 ./nexus/sonatype-work</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建Nexus密钥目录</span></span><br><span class="line"><span class="built_in">mkdir</span> -p ./nexus/secret</span><br><span class="line"><span class="built_in">cat</span> &gt; ./nexus/secret/nexus-secrets.json &lt;&lt;<span class="string">EOF</span></span><br><span class="line"><span class="string">&#123;</span></span><br><span class="line"><span class="string">  &quot;active&quot;: &quot;nexus-key&quot;,</span></span><br><span class="line"><span class="string">  &quot;keys&quot;: [</span></span><br><span class="line"><span class="string">    &#123;</span></span><br><span class="line"><span class="string">      &quot;id&quot;: &quot;nexus-key&quot;,</span></span><br><span class="line"><span class="string">      &quot;key&quot;: &quot;$(openssl rand -base64 32)&quot;</span></span><br><span class="line"><span class="string">    &#125;</span></span><br><span class="line"><span class="string">  ]</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置权限</span></span><br><span class="line"><span class="built_in">chmod</span> 600 ./nexus/secret/nexus-secrets.json</span><br><span class="line"><span class="built_in">chown</span> 200:200 ./nexus/secret/nexus-secrets.json</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建PostgreSQL目录</span></span><br><span class="line"><span class="built_in">mkdir</span> -p ./postgres/data ./postgres/dbbackups</span><br><span class="line"><span class="built_in">chmod</span> -R 755 ./postgres/data ./postgres/dbbackups</span><br><span class="line"><span class="built_in">chown</span> -R 101:103 ./postgres/data ./postgres/dbbackups</span><br></pre></td></tr></table></figure><h3 id="环境变量配置"><a href="#环境变量配置" class="headerlink" title="环境变量配置"></a>环境变量配置</h3><p>创建<code>.env</code>文件：</p><figure class="highlight ini"><table><tr><td class="code"><pre><span class="line"><span class="comment"># Nexus配置</span></span><br><span class="line"><span class="attr">NEXUS_PORT</span>=<span class="number">8081</span></span><br><span class="line"><span class="attr">NEXUS_IMAGE</span>=sonatype/nexus3:<span class="number">3.79</span>.<span class="number">0</span></span><br><span class="line"><span class="attr">NEXUS_PASS</span>=Admin@gmail.<span class="number">123</span>.com</span><br><span class="line"><span class="attr">HEALTHCHECK_PORT</span>=<span class="number">8000</span></span><br><span class="line"><span class="attr">NEXUS_URL</span>=http://<span class="number">192.168</span>.<span class="number">1.100</span>:<span class="number">8081</span></span><br><span class="line"><span class="attr">NEXUS_USER</span>=admin</span><br><span class="line"><span class="attr">REPOSITORY_NAME</span>=maven-snapshots</span><br><span class="line"></span><br><span class="line"><span class="comment"># PostgreSQL配置</span></span><br><span class="line"><span class="attr">POSTGRES_PORT</span>=<span class="number">5432</span></span><br><span class="line"><span class="attr">POSTGRES_USER</span>=nexus</span><br><span class="line"><span class="attr">POSTGRES_PASS</span>=Nexus@gmail.<span class="number">123</span>.com</span><br><span class="line"><span class="attr">POSTGRES_DB</span>=nexus</span><br><span class="line"><span class="attr">POSTGRES_IMAGE</span>=kartoza/postgis:<span class="number">17</span>-<span class="number">3.5</span></span><br><span class="line"><span class="attr">POSTGRES_BACKUP_IMAGE</span>=kartoza/pg-backup:<span class="number">17</span>-<span class="number">3.5</span></span><br></pre></td></tr></table></figure><h2 id="Docker-Compose配置"><a href="#Docker-Compose配置" class="headerlink" title="Docker Compose配置"></a>Docker Compose配置</h2><p>创建<code>docker-compose.yaml</code>文件：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="comment">#version: &#x27;3&#x27;</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">nexus:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&quot;$&#123;NEXUS_IMAGE&#125;&quot;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">nexus</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">8192M</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;$&#123;NEXUS_PORT&#125;:8081&quot;</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">TZ:</span> <span class="string">Asia/Shanghai</span></span><br><span class="line">      <span class="attr">INSTALL4J_ADD_VM_PARAMS:</span> <span class="string">&quot;-Xms2g -Xmx2g -XX:MaxDirectMemorySize=2g -Djava.util.prefs.userRoot=/opt/sonatype/sonatype-work -Dnexus.datastore.enabled=true -Dnexus.datastore.nexus.jdbcUrl=jdbc:postgresql://postgres:5432/nexus?gssEncMode=disable -Dnexus.datastore.nexus.username=nexus -Dnexus.datastore.nexus.password=Nexus@gmail.123.com -Dnexus.datastore.nexus.advanced=maximumPoolSize=50 -Dkaraf.data=/opt/sonatype/sonatype-work -Dkaraf.etc=/opt/sonatype/sonatype-work/etc&quot;</span></span><br><span class="line">      <span class="attr">NEXUS_SECURITY_RANDOMPASSWORD:</span> <span class="string">&quot;false&quot;</span></span><br><span class="line">      <span class="attr">NEXUS_SECRETS_KEY_FILE:</span> <span class="string">/opt/sonatype/sonatype-work/etc/nexus-secrets.json</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</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:8081/service/rest/v1/status&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">120s</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/etc/localtime:/etc/localtime:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./nexus/secret/nexus-secrets.json:/opt/sonatype/sonatype-work/etc/nexus-secrets.json:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./nexus/sonatype-work:/opt/sonatype/sonatype-work</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">nexus-cleanup:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">ghcr.io/freemankevin/clean-snapshots/nexus-cleanup:sha-afbc846</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">nexus-cleanup</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">NEXUS_URL:</span> <span class="string">&quot;$&#123;NEXUS_URL&#125;&quot;</span></span><br><span class="line">      <span class="attr">NEXUS_USER:</span> <span class="string">&quot;$&#123;NEXUS_USER:-admin&#125;&quot;</span></span><br><span class="line">      <span class="attr">NEXUS_PASS:</span> <span class="string">&quot;$&#123;NEXUS_PASS&#125;&quot;</span></span><br><span class="line">      <span class="attr">REPOSITORY_NAME:</span> <span class="string">&quot;$&#123;REPOSITORY_NAME:-maven-snapshots&#125;&quot;</span></span><br><span class="line">      <span class="attr">RETAIN_COUNT:</span> <span class="string">&quot;3&quot;</span></span><br><span class="line">      <span class="attr">DRY_RUN:</span> <span class="string">&quot;false&quot;</span></span><br><span class="line">      <span class="attr">LOG_LEVEL:</span> <span class="string">&quot;INFO&quot;</span></span><br><span class="line">      <span class="attr">SCHEDULE_TIME:</span> <span class="string">&quot;03:00&quot;</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/etc/localtime:/etc/localtime:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./nexus/nexus-cleanup-logs:/var/log</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;$&#123;HEALTHCHECK_PORT&#125;:8000&quot;</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">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:8000/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">depends_on:</span></span><br><span class="line">      <span class="attr">nexus:</span></span><br><span class="line">        <span class="attr">condition:</span> <span class="string">service_healthy</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  <span class="attr">postgres:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&quot;$&#123;POSTGRES_IMAGE&#125;&quot;</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">postgres</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">8192M</span>  </span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;$&#123;POSTGRES_PORT&#125;:5432&quot;</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">TZ:</span> <span class="string">Asia/Shanghai</span></span><br><span class="line">      <span class="attr">POSTGRES_DB:</span> <span class="string">&quot;$&#123;POSTGRES_DB&#125;&quot;</span></span><br><span class="line">      <span class="attr">POSTGRES_USER:</span> <span class="string">&quot;$&#123;POSTGRES_USER&#125;&quot;</span></span><br><span class="line">      <span class="attr">POSTGRES_PASS:</span> <span class="string">&quot;$&#123;POSTGRES_PASS&#125;&quot;</span></span><br><span class="line">      <span class="attr">POSTGRES_INITDB_ARGS:</span> <span class="string">&quot;--encoding=UTF8&quot;</span></span><br><span class="line">      <span class="attr">ALLOW_IP_RANGE:</span> <span class="string">&quot;0.0.0.0/0&quot;</span></span><br><span class="line">      <span class="attr">POSTGRES_MULTIPLE_EXTENSIONS:</span> <span class="string">&quot;postgis,hstore,postgis_topology,postgis_raster,pgrouting,pg_trgm&quot;</span></span><br><span class="line">      <span class="attr">RUN_AS_ROOT:</span> <span class="string">&#x27;true&#x27;</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</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-SHELL&quot;</span>, <span class="string">&quot;PGPASSWORD=$&#123;POSTGRES_PASS&#125; pg_isready -h localhost -U $&#123;POSTGRES_USER&#125;&quot;</span>]</span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/etc/localtime:/etc/localtime:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./postgres/data:/var/lib/postgresql</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./postgres/dbbackups:/backups</span></span><br><span class="line">      <span class="comment">#- ./init-postgres.sql:/docker-entrypoint-initdb.d/init.sql</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">postgres-backup:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">&quot;$&#123;POSTGRES_BACKUP_IMAGE&#125;&quot;</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">4096M</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">postgres-backup</span></span><br><span class="line">    <span class="attr">hostname:</span> <span class="string">postgres-backups</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">middleware</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">TZ:</span> <span class="string">Asia/Shanghai</span></span><br><span class="line">      <span class="attr">DUMPPREFIX:</span> <span class="string">PG_db</span></span><br><span class="line">      <span class="attr">POSTGRES_USER:</span> <span class="string">&quot;$&#123;POSTGRES_USER&#125;&quot;</span></span><br><span class="line">      <span class="attr">POSTGRES_PASS:</span> <span class="string">&quot;$&#123;POSTGRES_PASS&#125;&quot;</span></span><br><span class="line">      <span class="attr">POSTGRES_PORT:</span> <span class="string">&quot;5432&quot;</span></span><br><span class="line">      <span class="attr">POSTGRES_HOST:</span> <span class="string">&quot;postgres&quot;</span></span><br><span class="line">      <span class="attr">CRON_SCHEDULE:</span> <span class="string">&quot;0 2 * * *&quot;</span></span><br><span class="line">      <span class="attr">REMOVE_BEFORE:</span> <span class="string">&quot;15&quot;</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/etc/localtime:/etc/localtime:ro</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./postgres/dbbackups:/backups</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="attr">postgres:</span></span><br><span class="line">        <span class="attr">condition:</span> <span class="string">service_healthy</span></span><br><span class="line"></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line">  <span class="attr">middleware:</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">bridge</span></span><br></pre></td></tr></table></figure><h2 id="服务部署"><a href="#服务部署" class="headerlink" title="服务部署"></a>服务部署</h2><h3 id="加载Docker镜像（离线环境）"><a href="#加载Docker镜像（离线环境）" class="headerlink" title="加载Docker镜像（离线环境）"></a>加载Docker镜像（离线环境）</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker load -i images/nexus_3.79.0_amd64.tar.gz</span><br><span class="line">docker load -i images/nexus-cleanup.tar.gz</span><br><span class="line">docker load -i images/pg-v17-3.5.tar.gz</span><br><span class="line">docker load -i images/pg-backup-v17-3.5.tar.gz</span><br></pre></td></tr></table></figure><h3 id="启动服务"><a href="#启动服务" class="headerlink" title="启动服务"></a>启动服务</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker-compose up -d</span><br></pre></td></tr></table></figure><p>验证服务状态：</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker-compose ps</span><br></pre></td></tr></table></figure><h2 id="密码重置"><a href="#密码重置" class="headerlink" title="密码重置"></a>密码重置</h2><p>如果需要重置管理员密码：</p><ol><li>进入PostgreSQL容器：</li></ol><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker <span class="built_in">exec</span> -it postgres bash</span><br></pre></td></tr></table></figure><ol start="2"><li>执行SQL：</li></ol><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="comment">--- 将默认admin 密码改为 admin123</span></span><br><span class="line"><span class="keyword">UPDATE</span> security_user </span><br><span class="line"><span class="keyword">SET</span> password<span class="operator">=</span><span class="string">&#x27;$shiro1$SHA-512$1024$NE+wqQq/TmjZMvfI7ENh/g==$V4yPw8T64UQ6GfJfxYq2hLsVrBY8D1v+bktfOxGdt4b/9BthpWPNUy/CBk6V9iA0nHpzYzJFWO8v/tZFtES8CA==&#x27;</span>, </span><br><span class="line">status<span class="operator">=</span><span class="string">&#x27;active&#x27;</span> </span><br><span class="line"><span class="keyword">WHERE</span> id<span class="operator">=</span><span class="string">&#x27;admin&#x27;</span>;</span><br></pre></td></tr></table></figure><ol start="3"><li>重启服务：</li></ol><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker-compose restart nexus</span><br></pre></td></tr></table></figure><h2 id="监控与验证"><a href="#监控与验证" class="headerlink" title="监控与验证"></a>监控与验证</h2><h3 id="服务健康检查"><a href="#服务健康检查" class="headerlink" title="服务健康检查"></a>服务健康检查</h3><ul><li>Nexus: <code>curl http://localhost:18080/service/rest/v1/status</code></li><li>Cleanup: <code>curl http://localhost:8000/health</code></li><li>PostgreSQL: <code>docker exec postgres pg_isready -U nexus</code></li></ul><h3 id="日志检查"><a href="#日志检查" class="headerlink" title="日志检查"></a>日志检查</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">docker logs nexus</span><br><span class="line"><span class="built_in">tail</span> -f ./nexus/nexus-cleanup-logs/cleanup.log</span><br></pre></td></tr></table></figure><h2 id="性能优化建议"><a href="#性能优化建议" class="headerlink" title="性能优化建议"></a>性能优化建议</h2><ol><li><p><strong>JVM调优</strong>：</p><figure class="highlight ini"><table><tr><td class="code"><pre><span class="line">-Xms4g -Xmx4g -XX:<span class="attr">MaxDirectMemorySize</span>=<span class="number">4</span>g</span><br></pre></td></tr></table></figure></li><li><p><strong>PostgreSQL配置</strong>：</p><figure class="highlight ini"><table><tr><td class="code"><pre><span class="line"><span class="attr">max_connections</span> = <span class="number">200</span></span><br><span class="line"><span class="attr">work_mem</span> = <span class="number">16</span>MB</span><br></pre></td></tr></table></figure></li><li><p><strong>清理策略</strong>：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">RETAIN_COUNT:</span> <span class="string">&quot;5&quot;</span></span><br><span class="line"><span class="attr">SCHEDULE_TIME:</span> <span class="string">&quot;02:00&quot;</span></span><br></pre></td></tr></table></figure></li></ol><h2 id="常见问题排查"><a href="#常见问题排查" class="headerlink" title="常见问题排查"></a>常见问题排查</h2><table><thead><tr><th>问题</th><th>解决方案</th></tr></thead><tbody><tr><td>Nexus启动失败</td><td>检查JVM内存设置</td></tr><tr><td>PostgreSQL连接错误</td><td>验证.env文件凭据</td></tr><tr><td>清理服务不工作</td><td>检查NEXUS_URL配置</td></tr></tbody></table><h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><p>本文详细介绍了Nexus在Docker环境中的完整部署方案，包含数据库集成、自动清理和备份功能。该方案适合生产环境使用，可根据实际需求进行调整优化。</p><p><strong>相关资源</strong>：</p><ul><li><span class="exturl" data-url="aHR0cHM6Ly9oZWxwLnNvbmF0eXBlLmNvbS9yZXBvbWFuYWdlcjM=">Nexus官方文档<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly93d3cucG9zdGdyZXNxbC5vcmcvZG9jcy9jdXJyZW50L3J1bnRpbWUtY29uZmlnLmh0bWw=">PostgreSQL最佳实践<i class="fa fa-external-link-alt"></i></span></li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt; Nexus是一个功能强大的仓库管理工具，用于托管Maven工件、Docker镜像等。本文将详细介绍如何在Docker环境中部署Nexus仓库管理器，并集成PostgreSQL数据库、快照清理服务和数据库备份服务。&lt;/p&gt;</summary>
    
    
    
    <category term="Development" scheme="https://freemankevin.uk/categories/Development/"/>
    
    
    <category term="Docker" scheme="https://freemankevin.uk/tags/Docker/"/>
    
    <category term="PostgreSQL" scheme="https://freemankevin.uk/tags/PostgreSQL/"/>
    
    <category term="Nexus" scheme="https://freemankevin.uk/tags/Nexus/"/>
    
    <category term="Maven" scheme="https://freemankevin.uk/tags/Maven/"/>
    
  </entry>
  
  <entry>
    <title>Vim 常用配置说明文档</title>
    <link href="https://freemankevin.uk/2025/03/05/vim/"/>
    <id>https://freemankevin.uk/2025/03/05/vim/</id>
    <published>2025-03-05T06:30:00.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p> 当前文档为 Vim 编辑器的常用配置说明，适用于 Linux 和 Mac 环境。配置项旨在提升代码编辑体验，包括语法高亮、文件类型检测、粘贴优化等功能。配置文件通常位于 <code>~/.vimrc</code>（Linux&#x2F;Mac），如果文件不存在，可通过 <code>vim ~/.vimrc</code> 创建。</p><span id="more"></span><h2 id="配置内容"><a href="#配置内容" class="headerlink" title="配置内容"></a>配置内容</h2><p>以下是推荐的 Vim 配置项及其说明：</p><figure class="highlight vim"><table><tr><td class="code"><pre><span class="line"><span class="comment">&quot; 启用语法高亮</span></span><br><span class="line"><span class="keyword">syntax</span> <span class="keyword">on</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 启用文件类型检测</span></span><br><span class="line"><span class="keyword">filetype</span> <span class="keyword">on</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 启用文件类型插件和自动缩进（基于文件类型）</span></span><br><span class="line"><span class="keyword">filetype</span> plugin <span class="built_in">indent</span> <span class="keyword">on</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 设置默认颜色方案</span></span><br><span class="line"><span class="keyword">colorscheme</span> default</span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 禁用自动缩进</span></span><br><span class="line"><span class="keyword">set</span> noautoindent</span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 禁用智能缩进</span></span><br><span class="line"><span class="keyword">set</span> nosmartindent</span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 禁用在插入注释时自动添加注释字符</span></span><br><span class="line"><span class="keyword">set</span> formatoptions-=r</span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 禁用在按 &#x27;o&#x27; 或 &#x27;O&#x27; 时自动添加注释</span></span><br><span class="line"><span class="keyword">set</span> formatoptions-=<span class="keyword">o</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 禁用自动换行，保持原始行长</span></span><br><span class="line"><span class="keyword">set</span> textwidth=<span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 启用粘贴模式，防止自动格式化（建议临时使用）</span></span><br><span class="line"><span class="keyword">set</span> paste</span><br></pre></td></tr></table></figure><h3 id="配置项详细说明"><a href="#配置项详细说明" class="headerlink" title="配置项详细说明"></a>配置项详细说明</h3><ol><li><p><strong><code>syntax on</code></strong></p><ul><li><strong>功能</strong>: 启用语法高亮，根据文件类型显示不同颜色。</li><li><strong>适用场景</strong>: 提高代码可读性，适用于编程语言（如 Python、YAML）。</li><li><strong>注意</strong>: 需终端支持颜色输出（Linux&#x2F;Mac 通常支持）。</li></ul></li><li><p><strong><code>filetype on</code></strong></p><ul><li><strong>功能</strong>: 启用文件类型检测，基于文件扩展名或内容自动识别类型。</li><li><strong>适用场景</strong>: 确保 Vim 正确加载特定文件类型的设置。</li><li><strong>注意</strong>: 与 <code>filetype plugin indent on</code> 配合使用。</li></ul></li><li><p><strong><code>filetype plugin indent on</code></strong></p><ul><li><strong>功能</strong>: 启用文件类型插件和基于类型的自动缩进。</li><li><strong>适用场景</strong>: 为不同语言提供定制化缩进规则（如 Python 使用 4 空格）。</li><li><strong>注意</strong>: 如果禁用缩进（见下文），可能需调整此项。</li></ul></li><li><p><strong><code>colorscheme default</code></strong></p><ul><li><strong>功能</strong>: 设置默认颜色方案，控制语法高亮的颜色。</li><li><strong>适用场景</strong>: 提供基础视觉效果，可替换为其他方案（如 <code>colorscheme desert</code>）。</li><li><strong>注意</strong>: 需安装对应颜色方案文件（通常默认已包含）。</li></ul></li><li><p><strong><code>set noautoindent</code></strong></p><ul><li><strong>功能</strong>: 禁用自动缩进，防止新行继承上一行的缩进。</li><li><strong>适用场景</strong>: 粘贴代码时保持原格式，避免意外缩进。</li></ul></li><li><p><strong><code>set nosmartindent</code></strong></p><ul><li><strong>功能</strong>: 禁用智能缩进，防止根据语法自动调整缩进。</li><li><strong>适用场景</strong>: 与 <code>noautoindent</code> 配合，适合粘贴大段文本。</li></ul></li><li><p><strong><code>set formatoptions-=r</code></strong></p><ul><li><strong>功能</strong>: 禁用在插入模式下输入注释时自动添加注释字符。</li><li><strong>适用场景</strong>: 防止在多行注释中意外添加多余 <code>*</code> 或 <code>#</code>。</li></ul></li><li><p><strong><code>set formatoptions-=o</code></strong></p><ul><li><strong>功能</strong>: 禁用在按 <code>o</code> 或 <code>O</code>（新行）时自动添加注释。</li><li><strong>适用场景</strong>: 保持手动控制注释格式。</li></ul></li><li><p><strong><code>set textwidth=0</code></strong></p><ul><li><strong>功能</strong>: 禁用自动换行，保持原始行长。</li><li><strong>适用场景</strong>: 粘贴长行代码或文档时避免截断。</li></ul></li><li><p><strong><code>set paste</code></strong></p><ul><li><strong>功能</strong>: 启用粘贴模式，禁用自动格式化和缩进。</li><li><strong>适用场景</strong>: 粘贴外部代码时保持原样。</li><li><strong>注意</strong>: 建议临时启用（<code>:set paste</code>），粘贴后关闭（<code>:set nopaste</code>），否则可能影响正常编辑。</li></ul></li></ol><h2 id="冲突分析"><a href="#冲突分析" class="headerlink" title="冲突分析"></a>冲突分析</h2><p>以下是配置项中可能发生的冲突及解决方法：</p><ol><li><p><strong><code>noautoindent</code>、<code>nosmartindent</code> 与 <code>filetype plugin indent on</code> 的冲突</strong></p><ul><li><strong>问题</strong>: <code>filetype plugin indent on</code> 启用基于文件类型的自动缩进，而 <code>noautoindent</code> 和 <code>nosmartindent</code> 试图禁用所有自动缩进，导致行为不一致。</li><li><strong>影响</strong>: 可能导致缩进规则失效或混乱，尤其在打开新文件时。</li><li><strong>解决</strong>: 如果目标是禁用缩进（例如为粘贴优化），建议移除 <code>filetype plugin indent on</code> 或仅保留 <code>filetype on</code> 和 <code>syntax on</code>。</li></ul></li><li><p><strong><code>set paste</code> 的全局影响</strong></p><ul><li><strong>问题</strong>: <code>set paste</code> 是一个全局设置，会禁用缩进、自动补全等插件功能，长期启用可能干扰正常编辑。</li><li><strong>影响</strong>: 影响 <code>filetype plugin indent on</code> 的效果，甚至可能与自定义键盘映射冲突。</li><li><strong>解决</strong>: 改为临时使用，添加快捷键切换：<figure class="highlight vim"><table><tr><td class="code"><pre><span class="line"><span class="keyword">nnoremap</span> <span class="symbol">&lt;F2&gt;</span> :<span class="keyword">set</span> paste!<span class="symbol">&lt;CR&gt;</span></span><br></pre></td></tr></table></figure>粘贴时按 <code>F2</code> 启用，粘贴后再次按 <code>F2</code> 关闭。</li></ul></li><li><p><strong><code>cindent</code>（未包含但可能相关）的潜在冲突</strong></p><ul><li><strong>问题</strong>: 如果添加 <code>set cindent</code>（启用 C 风格缩进），会与 <code>noautoindent</code> 和 <code>nosmartindent</code> 冲突，因为 <code>cindent</code> 尝试应用缩进规则。</li><li><strong>影响</strong>: 缩进行为不可预测，可能导致代码格式混乱。</li><li><strong>解决</strong>: 避免同时使用 <code>cindent</code> 和 <code>noautoindent</code>&#x2F;<code>nosmartindent</code>。如果需要 C 风格缩进，移除前两者。</li></ul></li></ol><h2 id="优化配置建议"><a href="#优化配置建议" class="headerlink" title="优化配置建议"></a>优化配置建议</h2><p>根据上述分析，优化后的 <code>~/.vimrc</code> 配置如下，兼顾语法高亮和粘贴优化：</p><figure class="highlight vim"><table><tr><td class="code"><pre><span class="line"><span class="comment">&quot; 启用语法高亮和文件类型检测</span></span><br><span class="line"><span class="keyword">syntax</span> <span class="keyword">on</span></span><br><span class="line"><span class="keyword">filetype</span> <span class="keyword">on</span></span><br><span class="line"><span class="comment">&quot; 禁用基于文件类型的自动缩进插件（避免与粘贴冲突）</span></span><br><span class="line"><span class="comment">&quot; filetype plugin indent on</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 设置默认颜色方案</span></span><br><span class="line"><span class="keyword">colorscheme</span> default</span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 禁用自动缩进和智能缩进（适合粘贴）</span></span><br><span class="line"><span class="keyword">set</span> noautoindent</span><br><span class="line"><span class="keyword">set</span> nosmartindent</span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 禁用自动注释格式</span></span><br><span class="line"><span class="keyword">set</span> formatoptions-=r</span><br><span class="line"><span class="keyword">set</span> formatoptions-=<span class="keyword">o</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 禁用自动换行</span></span><br><span class="line"><span class="keyword">set</span> textwidth=<span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&quot; 粘贴模式建议临时启用，添加快捷键切换</span></span><br><span class="line"><span class="comment">&quot; set paste</span></span><br><span class="line"><span class="keyword">nnoremap</span> <span class="symbol">&lt;F2&gt;</span> :<span class="keyword">set</span> paste!<span class="symbol">&lt;CR&gt;</span></span><br></pre></td></tr></table></figure><h3 id="使用说明"><a href="#使用说明" class="headerlink" title="使用说明"></a>使用说明</h3><ul><li><strong>保存配置</strong>: 将上述内容写入 <code>~/.vimrc</code>，运行 <code>source ~/.vimrc</code> 应用。</li><li><strong>测试</strong>: 打开文件（<code>vim test.yaml</code>），按 <code>F2</code> 进入粘贴模式，粘贴内容，检查格式。</li><li><strong>自定义</strong>: 根据需求调整颜色方案或添加其他插件。</li></ul><h2 id="兼容性注意"><a href="#兼容性注意" class="headerlink" title="兼容性注意"></a>兼容性注意</h2><ul><li><strong>Linux&#x2F;Mac</strong>: 配置适用于大多数终端（需支持 ANSI 颜色）。若无颜色，检查 <code>TERM</code> 变量（<code>echo $TERM</code> 应为 <code>xterm</code> 或 <code>xterm-256color</code>）。</li><li><strong>插件</strong>: 若使用插件（如 NERDTree），可能需额外配置，避免与 <code>paste</code> 冲突。</li><li><strong>更新</strong>: 定期更新 Vim（<code>sudo apt update &amp;&amp; sudo apt install vim</code> 或 <code>brew install vim</code>）以获取最新功能。</li></ul><hr><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>此配置优化了语法高亮和粘贴体验，消除了 <code>noautoindent</code>&#x2F;<code>nosmartindent</code> 与 <code>filetype plugin indent on</code> 的冲突，并建议临时管理 <code>paste</code> 模式。安装后测试效果，若有特定需求（如支持特定语言），可进一步扩展配置。如需更多帮助，请提供使用反馈！</p>]]></content>
    
    
    <summary type="html">&lt;p&gt; 当前文档为 Vim 编辑器的常用配置说明，适用于 Linux 和 Mac 环境。配置项旨在提升代码编辑体验，包括语法高亮、文件类型检测、粘贴优化等功能。配置文件通常位于 &lt;code&gt;~/.vimrc&lt;/code&gt;（Linux&amp;#x2F;Mac），如果文件不存在，可通过 &lt;code&gt;vim ~/.vimrc&lt;/code&gt; 创建。&lt;/p&gt;</summary>
    
    
    
    <category term="Linux" scheme="https://freemankevin.uk/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://freemankevin.uk/tags/Linux/"/>
    
    <category term="VIM" scheme="https://freemankevin.uk/tags/VIM/"/>
    
  </entry>
  
  <entry>
    <title>二进制方式部署Kubernetes 集群</title>
    <link href="https://freemankevin.uk/2025/02/08/k8s-binary/"/>
    <id>https://freemankevin.uk/2025/02/08/k8s-binary/</id>
    <published>2025-02-08T08:23:25.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p> 本文详细介绍如何使用二进制方式在 Debian 系统上搭建一个生产级别的高可用 Kubernetes 集群。</p><span id="more"></span><hr><h1 id="部署规划"><a href="#部署规划" class="headerlink" title="部署规划"></a>部署规划</h1><h2 id="服务器清单"><a href="#服务器清单" class="headerlink" title="服务器清单"></a>服务器清单</h2><table><thead><tr><th>角色</th><th>主机名</th><th>IP地址</th><th>配置</th><th>系统</th></tr></thead><tbody><tr><td>LB-1</td><td>lb1.k8s.com</td><td>192.168.171.134</td><td>2C4G</td><td>Debian 12</td></tr><tr><td>LB-2</td><td>lb2.k8s.com</td><td>192.168.171.135</td><td>2C4G</td><td>Debian 12</td></tr><tr><td>VIP</td><td>-</td><td>192.168.171.133</td><td>-</td><td>-</td></tr><tr><td>ETCD-1</td><td>etcd1.k8s.com</td><td>192.168.171.136</td><td>4C8G</td><td>Debian 12</td></tr><tr><td>ETCD-2</td><td>etcd2.k8s.com</td><td>192.168.171.137</td><td>4C8G</td><td>Debian 12</td></tr><tr><td>ETCD-3</td><td>etcd3.k8s.com</td><td>192.168.171.138</td><td>4C8G</td><td>Debian 12</td></tr><tr><td>Master-1</td><td>master1.k8s.com</td><td>192.168.171.136</td><td>4C8G</td><td>Debian 12</td></tr><tr><td>Master-2</td><td>master2.k8s.com</td><td>192.168.171.137</td><td>4C8G</td><td>Debian 12</td></tr><tr><td>Master-3</td><td>master3.k8s.com</td><td>192.168.171.138</td><td>4C8G</td><td>Debian 12</td></tr><tr><td>Worker-1</td><td>worker1.k8s.com</td><td>192.168.171.139</td><td>8C16G</td><td>Debian 12</td></tr><tr><td>Harbor</td><td>harbor.k8s.com</td><td>192.168.171.50</td><td>4C8G</td><td>Debian 12</td></tr><tr><td>NFS</td><td>nfs.k8s.com</td><td>192.168.171.140</td><td>4C8G</td><td>Debian 12</td></tr></tbody></table><h2 id="网络规划"><a href="#网络规划" class="headerlink" title="网络规划"></a>网络规划</h2><ul><li>节点网段: 192.168.171.0&#x2F;24</li><li>Pod 网段: 10.244.0.0&#x2F;16</li><li>Service 网段: 10.96.0.0&#x2F;12</li><li>DNS 服务: CoreDNS</li></ul><h2 id="组件版本"><a href="#组件版本" class="headerlink" title="组件版本"></a>组件版本</h2><ul><li>Kubernetes: v1.27.8</li><li>Etcd: v3.5.9</li><li>Docker: 24.0.7</li><li>Containerd: 1.7.6</li><li>Calico: v3.26.1</li><li>CoreDNS: v1.10.1</li><li>Harbor: v2.9.1</li></ul><hr><h1 id="系统初始化"><a href="#系统初始化" class="headerlink" title="系统初始化"></a>系统初始化</h1><h2 id="添加软件源"><a href="#添加软件源" class="headerlink" title="添加软件源"></a>添加软件源</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">备份原始源文件</span></span><br><span class="line">cp /etc/apt/sources.list /etc/apt/sources.list.bak</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">清理并配置新的软件源</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">删除注释行和空行</span></span><br><span class="line">sed -i &#x27;/^#/d; /^$/d&#x27; /etc/apt/sources.list</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">注释掉原始行</span></span><br><span class="line">sed -i &#x27;s/^deb cdrom:\[Debian GNU\/Linux.*$/#&amp;/&#x27; /etc/apt/sources.list</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">删除旧的安全源</span></span><br><span class="line">sed -i &#x27;/^deb http:\/\/security.debian.org\/debian-security/d&#x27; /etc/apt/sources.list</span><br><span class="line">sed -i &#x27;/^deb-src http:\/\/security.debian.org\/debian-security/d&#x27; /etc/apt/sources.list</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加清华源</span></span><br><span class="line">cat &gt; /etc/apt/sources.list &lt;&lt; EOF</span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free</span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free</span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-backports main contrib non-free</span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">源码镜像（可选）</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">deb-src http://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">deb-src http://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">deb-src http://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-backports main contrib non-free</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">deb-src http://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free</span></span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><h2 id="系统更新"><a href="#系统更新" class="headerlink" title="系统更新"></a>系统更新</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">更新软件包索引</span></span><br><span class="line">apt update </span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">升级所有已安装的软件包</span></span><br><span class="line">apt upgrade -y </span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安装重要的系统更新（如果有的话）</span></span><br><span class="line">apt dist-upgrade -y</span><br></pre></td></tr></table></figure><h2 id="基础工具安装"><a href="#基础工具安装" class="headerlink" title="基础工具安装"></a>基础工具安装</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安装基础工具包</span></span><br><span class="line">apt update</span><br><span class="line">apt install -y \</span><br><span class="line">    # 系统工具</span><br><span class="line">    apt-transport-https \</span><br><span class="line">    ca-certificates \</span><br><span class="line">    vim \</span><br><span class="line">    net-tools \</span><br><span class="line">    sudo \</span><br><span class="line">    telnet \</span><br><span class="line">    ufw \</span><br><span class="line">    iotop \</span><br><span class="line">    rsync \</span><br><span class="line">    unzip \</span><br><span class="line">    iputils-ping \</span><br><span class="line">    gawk \</span><br><span class="line">    sed \</span><br><span class="line">    cron \</span><br><span class="line">    gnupg \</span><br><span class="line">    locales \</span><br><span class="line">    curl \</span><br><span class="line">    wget \</span><br><span class="line">    tree \</span><br><span class="line">    htop \</span><br><span class="line">    nmon \</span><br><span class="line">    lsof \</span><br><span class="line">    # 网络工具</span><br><span class="line">    nfs-common \</span><br><span class="line">    sshpass \</span><br><span class="line">    software-properties-common \</span><br><span class="line">    # 系统监控</span><br><span class="line">    sysstat \</span><br><span class="line">    # 文本处理</span><br><span class="line">    jq \</span><br><span class="line">    # 版本控制</span><br><span class="line">    git</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">清理不需要的包</span></span><br><span class="line">apt autoremove -y</span><br></pre></td></tr></table></figure><h2 id="系统语言配置"><a href="#系统语言配置" class="headerlink" title="系统语言配置"></a>系统语言配置</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成英文语言环境</span></span><br><span class="line">locale-gen en_US.UTF-8</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置系统默认语言</span></span><br><span class="line">cat &gt; /etc/default/locale &lt;&lt; EOF</span><br><span class="line">LC_ALL=en_US.utf8</span><br><span class="line">LANG=en_US.utf8</span><br><span class="line">LANGUAGE=en_US.utf8</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置语言生成</span></span><br><span class="line">sed -i &#x27;s/^zh_CN.UTF-8 UTF-8/#zh_CN.UTF-8 UTF-8/&#x27; /etc/locale.gen</span><br><span class="line">sed -i &#x27;s/#en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/&#x27; /etc/locale.gen</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重新生成语言文件</span></span><br><span class="line">locale-gen</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置环境变量</span></span><br><span class="line">echo &quot;export LANG=en_US.utf8&quot; &gt;&gt; /etc/profile</span><br><span class="line">echo &quot;export LANGUAGE=en_US.utf8&quot; &gt;&gt; /etc/profile</span><br><span class="line">source /etc/profile</span><br></pre></td></tr></table></figure><h2 id="SSH远程访问配置"><a href="#SSH远程访问配置" class="headerlink" title="SSH远程访问配置"></a>SSH远程访问配置</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置SSH允许root登录</span></span><br><span class="line">sed -ri &#x27;s/#PermitRootLogin prohibit-password/PermitRootLogin yes/&#x27; /etc/ssh/sshd_config</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">加强SSH安全配置</span></span><br><span class="line">cat &gt;&gt; /etc/ssh/sshd_config &lt;&lt; EOF</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">SSH认证配置</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">同时启用密码和密钥认证，便于初始化后的管理</span></span><br><span class="line">PasswordAuthentication yes</span><br><span class="line">PubkeyAuthentication yes</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">设置SSH协议版本</span></span><br><span class="line">Protocol 2</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">限制最大认证尝试次数</span></span><br><span class="line">MaxAuthTries 3</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">禁用空密码</span></span><br><span class="line">PermitEmptyPasswords no</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">设置登录超时时间（秒）</span></span><br><span class="line">LoginGraceTime 60</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启用严格模式</span></span><br><span class="line">StrictModes yes</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安全加固建议（等系统完全配置好后可以考虑启用）：</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">1. 禁用密码认证，只使用密钥认证</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">PasswordAuthentication no</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">2. 限制允许登录的用户</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">AllowUsers your-user-name</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">3. 更改默认端口</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Port 2222</span></span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重启SSH服务</span></span><br><span class="line">systemctl restart ssh</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证配置</span></span><br><span class="line">egrep &#x27;^PermitRootLogin&#x27; /etc/ssh/sshd_config</span><br></pre></td></tr></table></figure><h2 id="Shell环境优化"><a href="#Shell环境优化" class="headerlink" title="Shell环境优化"></a>Shell环境优化</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置.bashrc</span></span><br><span class="line">cat &gt;&gt; ~/.bashrc &lt;&lt; EOF</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置命令别名</span></span><br><span class="line">alias ll=&#x27;ls -l&#x27;</span><br><span class="line">alias la=&#x27;ls -A&#x27;</span><br><span class="line">alias l=&#x27;ls -CF&#x27;</span><br><span class="line">alias vi=&#x27;vim&#x27;</span><br><span class="line">alias cls=&#x27;clear&#x27;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置命令历史记录</span></span><br><span class="line">HISTSIZE=5000</span><br><span class="line">HISTFILESIZE=10000</span><br><span class="line">HISTTIMEFORMAT=&quot;%F %T &quot;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置PS1提示符</span></span><br><span class="line">PS1=&#x27;\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ &#x27;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启用颜色支持</span></span><br><span class="line">export LS_OPTIONS=&#x27;--color=auto&#x27;</span><br><span class="line">eval &quot;$(dircolors)&quot;</span><br><span class="line">alias ls=&#x27;ls $LS_OPTIONS&#x27;</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">应用新配置</span></span><br><span class="line">source ~/.bashrc</span><br></pre></td></tr></table></figure><h2 id="网络配置（可选）"><a href="#网络配置（可选）" class="headerlink" title="网络配置（可选）"></a>网络配置（可选）</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置静态IP</span></span><br><span class="line">cat &gt; /etc/network/interfaces &lt;&lt; EOF</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">This file describes the network interfaces available on your system</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">and how to activate them. For more information, see interfaces(5).</span></span><br><span class="line"></span><br><span class="line">source /etc/network/interfaces.d/*</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">The loopback network interface</span></span><br><span class="line">auto lo</span><br><span class="line">iface lo inet loopback</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">The primary network interface</span></span><br><span class="line">auto ens32</span><br><span class="line">iface ens32 inet static</span><br><span class="line">    address 192.168.171.136</span><br><span class="line">    netmask 255.255.255.0</span><br><span class="line">    gateway 192.168.171.2</span><br><span class="line">    # DNS配置</span><br><span class="line">    dns-nameservers 8.8.8.8 8.8.4.4</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><h2 id="系统优化"><a href="#系统优化" class="headerlink" title="系统优化"></a>系统优化</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">关闭swap</span></span><br><span class="line">swapoff -a</span><br><span class="line">sed -i &#x27;/swap/d&#x27; /etc/fstab</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置系统限制</span></span><br><span class="line">cat &gt; /etc/security/limits.conf &lt;&lt; EOF</span><br><span class="line">* soft nofile 65535</span><br><span class="line">* hard nofile 65535</span><br><span class="line">* soft nproc 65535</span><br><span class="line">* hard nproc 65535</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">优化内核参数</span></span><br><span class="line">cat &gt; /etc/sysctl.d/99-sysctl.conf &lt;&lt; EOF</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">系统级别的最大文件句柄数</span></span><br><span class="line">fs.file-max = 2097152</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">TCP连接参数优化</span></span><br><span class="line">net.ipv4.tcp_max_syn_backlog = 8192</span><br><span class="line">net.core.somaxconn = 32768</span><br><span class="line">net.ipv4.tcp_timestamps = 1</span><br><span class="line">net.ipv4.tcp_fin_timeout = 30</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">内存参数优化</span></span><br><span class="line">vm.swappiness = 0</span><br><span class="line">vm.overcommit_memory = 1</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">应用内核参数</span></span><br><span class="line">sysctl -p</span><br></pre></td></tr></table></figure><h2 id="系统服务优化"><a href="#系统服务优化" class="headerlink" title="系统服务优化"></a>系统服务优化</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">禁用不需要的服务</span></span><br><span class="line">systemctl stop rpcbind</span><br><span class="line">systemctl disable rpcbind</span><br><span class="line">apt autoremove rpcbind -y</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置防火墙（UFW）</span></span><br><span class="line">ufw default deny incoming</span><br><span class="line">ufw default allow outgoing</span><br><span class="line">ufw allow ssh</span><br><span class="line">ufw allow 80/tcp</span><br><span class="line">ufw allow 443/tcp</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">根据需要添加其他端口</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启用防火墙</span></span><br><span class="line">ufw --force enable</span><br></pre></td></tr></table></figure><h2 id="完成初始化"><a href="#完成初始化" class="headerlink" title="完成初始化"></a>完成初始化</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">同步文件系统</span></span><br><span class="line">sync</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重启系统使所有更改生效</span></span><br><span class="line">reboot</span><br></pre></td></tr></table></figure><h2 id="自动化部署"><a href="#自动化部署" class="headerlink" title="自动化部署"></a>自动化部署</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建一个初始化脚本</span></span><br><span class="line">cat &gt; init-debian.sh &lt;&lt; &#x27;EOF&#x27;</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Debian系统初始化脚本</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">使用方法: ./init-debian.sh</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查是否为root用户</span></span><br><span class="line">if [ &quot;$(id -u)&quot; != &quot;0&quot; ]; then</span><br><span class="line">   echo &quot;此脚本必须以root权限运行&quot; </span><br><span class="line">   exit 1</span><br><span class="line">fi</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">这里放入上述所有配置步骤</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">...</span></span><br><span class="line"></span><br><span class="line">echo &quot;系统初始化完成，请重启服务器&quot;</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加执行权限</span></span><br><span class="line">chmod +x init-debian.sh</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">运行脚本</span></span><br><span class="line">./init-debian.sh</span><br></pre></td></tr></table></figure><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li>在执行初始化操作前，建议先备份重要数据</li><li>修改网络配置时需要特别小心，错误的配置可能导致无法远程访问</li><li>防火墙规则要根据实际需求配置</li><li>建议保存一份配置文件的备份</li><li>初始化完成后要及时修改root密码和SSH配置</li></ol><h2 id="故障排除"><a href="#故障排除" class="headerlink" title="故障排除"></a>故障排除</h2><p>如果在初始化过程中遇到问题，可以检查以下几点：</p><ol><li>查看系统日志：<code>journalctl -xe</code></li><li>检查服务状态：<code>systemctl status &lt;服务名&gt;</code></li><li>检查网络连接：<code>ping -c 4 8.8.8.8</code></li><li>验证软件源可用性：<code>apt update</code></li></ol><hr><h1 id="高可用负载均衡部署"><a href="#高可用负载均衡部署" class="headerlink" title="高可用负载均衡部署"></a>高可用负载均衡部署</h1><h2 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">更新系统并安装基础工具</span></span><br><span class="line">apt-get update</span><br><span class="line">apt-get install -y \</span><br><span class="line">    psmisc \</span><br><span class="line">    curl \</span><br><span class="line">    wget \</span><br><span class="line">    net-tools \</span><br><span class="line">    ipvsadm \</span><br><span class="line">    ipset</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查网络配置</span></span><br><span class="line">ip a</span><br></pre></td></tr></table></figure><h2 id="Keepalived-部署"><a href="#Keepalived-部署" class="headerlink" title="Keepalived 部署"></a>Keepalived 部署</h2><h3 id="安装-Keepalived"><a href="#安装-Keepalived" class="headerlink" title="安装 Keepalived"></a>安装 Keepalived</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在所有负载均衡节点上安装</span></span><br><span class="line">apt install -y keepalived</span><br></pre></td></tr></table></figure><h3 id="配置健康检查脚本"><a href="#配置健康检查脚本" class="headerlink" title="配置健康检查脚本"></a>配置健康检查脚本</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建健康检查脚本</span></span><br><span class="line">cat &gt; /etc/keepalived/check_apiserver.sh &lt;&lt; EOF</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line"></span><br><span class="line">API_URL=&quot;https://192.168.171.133:6443/healthz&quot;</span><br><span class="line">TIMEOUT=3</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查API服务器健康状态</span></span><br><span class="line">if curl -k -s --connect-timeout $&#123;TIMEOUT&#125; $&#123;API_URL&#125; | grep -q &quot;ok&quot;; then</span><br><span class="line">    exit 0</span><br><span class="line">else</span><br><span class="line">    exit 1</span><br><span class="line">fi</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加执行权限</span></span><br><span class="line">chmod +x /etc/keepalived/check_apiserver.sh</span><br></pre></td></tr></table></figure><h3 id="主节点配置"><a href="#主节点配置" class="headerlink" title="主节点配置"></a>主节点配置</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置主节点的keepalived</span></span><br><span class="line">cat &gt; /etc/keepalived/keepalived.conf &lt;&lt; EOF</span><br><span class="line">! Configuration File for keepalived</span><br><span class="line">global_defs &#123;</span><br><span class="line">    router_id LVS_DEVEL</span><br><span class="line">    script_user root</span><br><span class="line">    enable_script_security</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">HAProxy进程检查</span></span><br><span class="line">vrrp_script check_haproxy &#123;</span><br><span class="line">    script &quot;/usr/bin/killall -0 haproxy&quot;</span><br><span class="line">    interval 2</span><br><span class="line">    weight 2</span><br><span class="line">    fall 2</span><br><span class="line">    rise 1</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">API服务器健康检查</span></span><br><span class="line">vrrp_script check_apiserver &#123;</span><br><span class="line">    script &quot;/etc/keepalived/check_apiserver.sh&quot;</span><br><span class="line">    interval 3</span><br><span class="line">    weight -2</span><br><span class="line">    fall 10</span><br><span class="line">    rise 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">    state MASTER</span><br><span class="line">    interface ens192                # 根据实际网卡名修改</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_pass K8SHA_KA_AUTH    # 建议修改密码</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.171.133             # VIP地址</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    # 使用单播模式（推荐）</span><br><span class="line">    unicast_src_ip 192.168.171.134  # 本机IP（LB-1）</span><br><span class="line">    unicast_peer &#123;</span><br><span class="line">        192.168.171.135             # 对端IP（LB-2）</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    # 配置追踪脚本</span><br><span class="line">    track_script &#123;</span><br><span class="line">        check_apiserver</span><br><span class="line">        check_haproxy</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><h3 id="备节点配置"><a href="#备节点配置" class="headerlink" title="备节点配置"></a>备节点配置</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置备节点的keepalived</span></span><br><span class="line">cat &gt; /etc/keepalived/keepalived.conf &lt;&lt; EOF</span><br><span class="line">! Configuration File for keepalived</span><br><span class="line">global_defs &#123;</span><br><span class="line">    router_id LVS_DEVEL</span><br><span class="line">    script_user root</span><br><span class="line">    enable_script_security</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">vrrp_script check_haproxy &#123;</span><br><span class="line">    script &quot;/usr/bin/killall -0 haproxy&quot;</span><br><span class="line">    interval 2</span><br><span class="line">    weight 2</span><br><span class="line">    fall 2</span><br><span class="line">    rise 1</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">vrrp_script check_apiserver &#123;</span><br><span class="line">    script &quot;/etc/keepalived/check_apiserver.sh&quot;</span><br><span class="line">    interval 3</span><br><span class="line">    weight -2</span><br><span class="line">    fall 10</span><br><span class="line">    rise 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">    state BACKUP</span><br><span class="line">    interface ens192                # 根据实际网卡名修改</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_pass K8SHA_KA_AUTH    # 与主节点保持一致</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.171.133             # VIP地址</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    unicast_src_ip 192.168.171.135  # 本机IP（LB-2）</span><br><span class="line">    unicast_peer &#123;</span><br><span class="line">        192.168.171.134             # 对端IP（LB-1）</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    track_script &#123;</span><br><span class="line">        check_apiserver</span><br><span class="line">        check_haproxy</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><h3 id="启动服务"><a href="#启动服务" class="headerlink" title="启动服务"></a>启动服务</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查配置文件语法</span></span><br><span class="line">keepalived -t -f /etc/keepalived/keepalived.conf</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动并设置开机自启</span></span><br><span class="line">systemctl start keepalived</span><br><span class="line">systemctl enable keepalived</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查服务状态</span></span><br><span class="line">systemctl status keepalived</span><br></pre></td></tr></table></figure><h2 id="HAProxy-部署"><a href="#HAProxy-部署" class="headerlink" title="HAProxy 部署"></a>HAProxy 部署</h2><h3 id="安装-HAProxy"><a href="#安装-HAProxy" class="headerlink" title="安装 HAProxy"></a>安装 HAProxy</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在所有负载均衡节点上安装</span></span><br><span class="line">apt install -y haproxy</span><br></pre></td></tr></table></figure><h3 id="配置-HAProxy"><a href="#配置-HAProxy" class="headerlink" title="配置 HAProxy"></a>配置 HAProxy</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">备份原配置</span></span><br><span class="line">cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建新配置</span></span><br><span class="line">cat &gt; /etc/haproxy/haproxy.cfg &lt;&lt; EOF</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">---------------------------------------------------------------------</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Global settings</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">---------------------------------------------------------------------</span></span><br><span class="line">global</span><br><span class="line">    log /dev/log local0</span><br><span class="line">    log /dev/log local1 notice</span><br><span class="line">    daemon</span><br><span class="line">    maxconn 100000</span><br><span class="line">    user haproxy</span><br><span class="line">    group haproxy</span><br><span class="line">    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">---------------------------------------------------------------------</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Default settings</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">---------------------------------------------------------------------</span></span><br><span class="line">defaults</span><br><span class="line">    log     global</span><br><span class="line">    mode    tcp</span><br><span class="line">    option  dontlognull</span><br><span class="line">    timeout connect 5000ms</span><br><span class="line">    timeout client  50000ms</span><br><span class="line">    timeout server  50000ms</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">---------------------------------------------------------------------</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Statistics settings</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">---------------------------------------------------------------------</span></span><br><span class="line">listen stats</span><br><span class="line">    bind *:9090</span><br><span class="line">    mode http</span><br><span class="line">    stats enable</span><br><span class="line">    stats uri /stats</span><br><span class="line">    stats refresh 30s</span><br><span class="line">    stats auth admin:Admin@123.com    # 访问统计页面的用户名和密码</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">---------------------------------------------------------------------</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Frontend configuration <span class="keyword">for</span> API server</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">---------------------------------------------------------------------</span></span><br><span class="line">frontend k8s-apiserver</span><br><span class="line">    bind *:6443</span><br><span class="line">    mode tcp</span><br><span class="line">    option tcplog</span><br><span class="line">    default_backend k8s-apiserver</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">---------------------------------------------------------------------</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Backend configuration <span class="keyword">for</span> API server</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">---------------------------------------------------------------------</span></span><br><span class="line">backend k8s-apiserver</span><br><span class="line">    mode tcp</span><br><span class="line">    option tcp-check</span><br><span class="line">    balance roundrobin</span><br><span class="line">    default-server inter 10s downinter 5s rise 2 fall 2 slowstart 60s maxconn 250 maxqueue 256 weight 100</span><br><span class="line">    server master1 192.168.171.136:6443 check</span><br><span class="line">    server master2 192.168.171.137:6443 check</span><br><span class="line">    server master3 192.168.171.138:6443 check</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><h3 id="启动服务-1"><a href="#启动服务-1" class="headerlink" title="启动服务"></a>启动服务</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查配置文件语法</span></span><br><span class="line">haproxy -f /etc/haproxy/haproxy.cfg -c</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动并设置开机自启</span></span><br><span class="line">systemctl start haproxy</span><br><span class="line">systemctl enable haproxy</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查服务状态</span></span><br><span class="line">systemctl status haproxy</span><br></pre></td></tr></table></figure><h2 id="验证部署"><a href="#验证部署" class="headerlink" title="验证部署"></a>验证部署</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查VIP是否生效</span></span><br><span class="line">ip a | grep 192.168.1.110</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查HAProxy统计页面</span></span><br><span class="line">curl -u admin:Admin@123.com http://localhost:9090/stats</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">测试API服务器访问</span></span><br><span class="line">curl -k https://192.168.171.133:6443/healthz</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">测试故障转移</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">1. 在主节点上停止HAProxy</span></span><br><span class="line">systemctl stop haproxy</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">2. 观察VIP是否漂移到备节点</span></span><br><span class="line">ip a</span><br></pre></td></tr></table></figure><h2 id="故障排除-1"><a href="#故障排除-1" class="headerlink" title="故障排除"></a>故障排除</h2><ol><li>Keepalived 故障排查：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查日志</span></span><br><span class="line">journalctl -u keepalived -f</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查配置</span></span><br><span class="line">keepalived -t -f /etc/keepalived/keepalived.conf</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查网络接口</span></span><br><span class="line">ip a</span><br></pre></td></tr></table></figure><ol start="2"><li>HAProxy 故障排查：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查日志</span></span><br><span class="line">journalctl -u haproxy -f</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查配置</span></span><br><span class="line">haproxy -f /etc/haproxy/haproxy.cfg -c</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查端口监听</span></span><br><span class="line">netstat -ntlp | grep haproxy</span><br></pre></td></tr></table></figure><h2 id="注意事项-1"><a href="#注意事项-1" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li><p>网络配置：</p><ul><li>确保防火墙允许VRRP协议（端口112）</li><li>允许HAProxy监听端口（6443, 9090）</li><li>检查网卡名称是否正确</li></ul></li><li><p>安全建议：</p><ul><li>修改Keepalived认证密码</li><li>更改HAProxy统计页面的访问凭据</li><li>限制HAProxy统计页面的访问IP</li></ul></li><li><p>维护建议：</p><ul><li>定期检查服务状态</li><li>监控日志信息</li><li>定期测试故障转移功能</li></ul></li><li><p>性能优化：</p><ul><li>根据实际负载调整HAProxy的连接数限制</li><li>适当调整超时时间</li><li>监控系统资源使用情况</li></ul></li></ol><hr><h1 id="ETCD-集群部署"><a href="#ETCD-集群部署" class="headerlink" title="ETCD 集群部署"></a>ETCD 集群部署</h1><h2 id="环境准备-1"><a href="#环境准备-1" class="headerlink" title="环境准备"></a>环境准备</h2><h3 id="主机配置"><a href="#主机配置" class="headerlink" title="主机配置"></a>主机配置</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">修改主机名</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在 etcd1 上执行</span></span><br><span class="line">hostnamectl set-hostname etcd1</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在 etcd2 上执行</span></span><br><span class="line">hostnamectl set-hostname etcd2</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在 etcd3 上执行</span></span><br><span class="line">hostnamectl set-hostname etcd3</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置 hosts 解析</span></span><br><span class="line">cat &gt;&gt; /etc/hosts &lt;&lt; EOF</span><br><span class="line">192.168.171.136 etcd1</span><br><span class="line">192.168.171.137 etcd2</span><br><span class="line">192.168.171.138 etcd3</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><h3 id="配置免密登录"><a href="#配置免密登录" class="headerlink" title="配置免密登录"></a>配置免密登录</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在 etcd1 上执行</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成密钥对</span></span><br><span class="line">ssh-keygen -t rsa -b 2048 -N &quot;&quot; -f ~/.ssh/id_rsa</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">分发公钥</span></span><br><span class="line">for host in etcd1 etcd2 etcd3; do</span><br><span class="line">    sshpass -p &#x27;your_password&#x27; ssh-copy-id -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa.pub &quot;root@$host&quot;</span><br><span class="line">done</span><br></pre></td></tr></table></figure><h3 id="配置环境变量"><a href="#配置环境变量" class="headerlink" title="配置环境变量"></a>配置环境变量</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在所有节点上执行</span></span><br><span class="line">cat &gt;&gt; /etc/profile &lt;&lt; EOF</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">ETCD API 版本</span></span><br><span class="line">export ETCDCTL_API=3</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">source /etc/profile</span><br></pre></td></tr></table></figure><h2 id="组件安装"><a href="#组件安装" class="headerlink" title="组件安装"></a>组件安装</h2><h3 id="安装-CFSSL-工具"><a href="#安装-CFSSL-工具" class="headerlink" title="安装 CFSSL 工具"></a>安装 CFSSL 工具</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在所有节点上执行</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安装 CFSSL（下载地址：https://github.com/cloudflare/cfssl/releases）</span></span><br><span class="line">cp cfssl_1.6.3_linux_amd64 /usr/local/bin/cfssl</span><br><span class="line">cp cfssljson_1.6.3_linux_amd64 /usr/local/bin/cfssljson</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加执行权限</span></span><br><span class="line">chmod +x /usr/local/bin/cfssl /usr/local/bin/cfssljson</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证安装</span></span><br><span class="line">cfssl version</span><br><span class="line">cfssljson -version</span><br></pre></td></tr></table></figure><h3 id="安装-ETCD"><a href="#安装-ETCD" class="headerlink" title="安装 ETCD"></a>安装 ETCD</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在所有节点上执行</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">设置环境变量</span></span><br><span class="line">export ETCD_VER=v3.5.9</span><br><span class="line">export DOWNLOAD_URL=&quot;https://github.com/etcd-io/etcd/releases/download&quot;</span><br><span class="line">export INSTALL_DIR=&quot;/usr/local/bin&quot;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">下载 ETCD 二进制文件</span></span><br><span class="line">wget $&#123;DOWNLOAD_URL&#125;/$&#123;ETCD_VER&#125;/etcd-$&#123;ETCD_VER&#125;-linux-amd64.tar.gz</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证下载文件完整性</span></span><br><span class="line">wget $&#123;DOWNLOAD_URL&#125;/$&#123;ETCD_VER&#125;/etcd-$&#123;ETCD_VER&#125;-linux-amd64.tar.gz.asc</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">如果需要验证签名</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">gpg --verify etcd-<span class="variable">$&#123;ETCD_VER&#125;</span>-linux-amd64.tar.gz.asc</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">解压安装包</span></span><br><span class="line">tar -xzf etcd-$&#123;ETCD_VER&#125;-linux-amd64.tar.gz -C /tmp/</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">复制二进制文件到安装目录</span></span><br><span class="line">cp /tmp/etcd-$&#123;ETCD_VER&#125;-linux-amd64/etcd* $&#123;INSTALL_DIR&#125;/</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">清理临时文件</span></span><br><span class="line">rm -rf /tmp/etcd-$&#123;ETCD_VER&#125;-linux-amd64* etcd-$&#123;ETCD_VER&#125;-linux-amd64.tar.gz*</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建数据目录</span></span><br><span class="line">mkdir -p /data/etcd</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证安装</span></span><br><span class="line"><span class="meta prompt_">$</span><span class="language-bash">&#123;INSTALL_DIR&#125;/etcd --version</span></span><br><span class="line"><span class="meta prompt_">$</span><span class="language-bash">&#123;INSTALL_DIR&#125;/etcdctl version</span></span><br></pre></td></tr></table></figure><h2 id="配置-TLS-证书"><a href="#配置-TLS-证书" class="headerlink" title="配置 TLS 证书"></a>配置 TLS 证书</h2><h3 id="创建证书配置"><a href="#创建证书配置" class="headerlink" title="创建证书配置"></a>创建证书配置</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在 etcd1 上执行</span></span><br><span class="line">mkdir -p /etc/etcd/ssl</span><br><span class="line">cd /etc/etcd/ssl</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建 CA 配置文件</span></span><br><span class="line">cat &gt; ca-config.json &lt;&lt; EOF</span><br><span class="line">&#123;</span><br><span class="line">    &quot;signing&quot;: &#123;</span><br><span class="line">        &quot;default&quot;: &#123;</span><br><span class="line">            &quot;expiry&quot;: &quot;876000h&quot;</span><br><span class="line">        &#125;,</span><br><span class="line">        &quot;profiles&quot;: &#123;</span><br><span class="line">            &quot;server&quot;: &#123;</span><br><span class="line">                &quot;expiry&quot;: &quot;876000h&quot;,</span><br><span class="line">                &quot;usages&quot;: [</span><br><span class="line">                    &quot;signing&quot;,</span><br><span class="line">                    &quot;key encipherment&quot;,</span><br><span class="line">                    &quot;server auth&quot;,</span><br><span class="line">                    &quot;client auth&quot;</span><br><span class="line">                ]</span><br><span class="line">            &#125;,</span><br><span class="line">            &quot;client&quot;: &#123;</span><br><span class="line">                &quot;expiry&quot;: &quot;876000h&quot;,</span><br><span class="line">                &quot;usages&quot;: [</span><br><span class="line">                    &quot;signing&quot;,</span><br><span class="line">                    &quot;key encipherment&quot;,</span><br><span class="line">                    &quot;client auth&quot;</span><br><span class="line">                ]</span><br><span class="line">            &#125;,</span><br><span class="line">            &quot;peer&quot;: &#123;</span><br><span class="line">                &quot;expiry&quot;: &quot;876000h&quot;,</span><br><span class="line">                &quot;usages&quot;: [</span><br><span class="line">                    &quot;signing&quot;,</span><br><span class="line">                    &quot;key encipherment&quot;,</span><br><span class="line">                    &quot;server auth&quot;,</span><br><span class="line">                    &quot;client auth&quot;</span><br><span class="line">                ]</span><br><span class="line">            &#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><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建 CA 证书请求文件</span></span><br><span class="line">cat &gt; etcd-ca-csr.json &lt;&lt; EOF</span><br><span class="line">&#123;</span><br><span class="line">    &quot;key&quot;: &#123;</span><br><span class="line">        &quot;algo&quot;: &quot;rsa&quot;,</span><br><span class="line">        &quot;size&quot;: 4096</span><br><span class="line">    &#125;,</span><br><span class="line">    &quot;names&quot;: [</span><br><span class="line">        &#123;</span><br><span class="line">            &quot;C&quot;: &quot;CN&quot;,</span><br><span class="line">            &quot;L&quot;: &quot;Beijing&quot;,</span><br><span class="line">            &quot;ST&quot;: &quot;Beijing&quot;,</span><br><span class="line">            &quot;O&quot;: &quot;k8s&quot;,</span><br><span class="line">            &quot;OU&quot;: &quot;System&quot;</span><br><span class="line">        &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建客户端证书请求文件</span></span><br><span class="line">cat &gt; client-csr.json &lt;&lt; EOF</span><br><span class="line">&#123;</span><br><span class="line">    &quot;CN&quot;: &quot;client&quot;,</span><br><span class="line">    &quot;key&quot;: &#123;</span><br><span class="line">        &quot;algo&quot;: &quot;rsa&quot;,</span><br><span class="line">        &quot;size&quot;: 2048</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建服务端证书请求文件</span></span><br><span class="line">cat &gt; etcd-server-csr.json &lt;&lt; EOF</span><br><span class="line">&#123;</span><br><span class="line">    &quot;CN&quot;: &quot;etcd-server&quot;,</span><br><span class="line">    &quot;hosts&quot;: [</span><br><span class="line">        &quot;192.168.171.136&quot;,</span><br><span class="line">        &quot;192.168.171.137&quot;,</span><br><span class="line">        &quot;192.168.171.138&quot;,</span><br><span class="line">        &quot;127.0.0.1&quot;</span><br><span class="line">    ],</span><br><span class="line">    &quot;key&quot;: &#123;</span><br><span class="line">        &quot;algo&quot;: &quot;rsa&quot;,</span><br><span class="line">        &quot;size&quot;: 2048</span><br><span class="line">    &#125;,</span><br><span class="line">    &quot;names&quot;: [</span><br><span class="line">        &#123;</span><br><span class="line">            &quot;C&quot;: &quot;CN&quot;,</span><br><span class="line">            &quot;L&quot;: &quot;Beijing&quot;,</span><br><span class="line">            &quot;O&quot;: &quot;etcd-cluster&quot;,</span><br><span class="line">            &quot;OU&quot;: &quot;System&quot;,</span><br><span class="line">            &quot;ST&quot;: &quot;Beijing&quot;</span><br><span class="line">        &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建对等证书请求文件</span></span><br><span class="line">cat &gt; etcd-peer-csr.json &lt;&lt; EOF</span><br><span class="line">&#123;</span><br><span class="line">    &quot;CN&quot;: &quot;etcd-peer&quot;,</span><br><span class="line">    &quot;hosts&quot;: [</span><br><span class="line">        &quot;192.168.171.136&quot;,</span><br><span class="line">        &quot;192.168.171.137&quot;,</span><br><span class="line">        &quot;192.168.171.138&quot;,</span><br><span class="line">        &quot;127.0.0.1&quot;</span><br><span class="line">    ],</span><br><span class="line">    &quot;key&quot;: &#123;</span><br><span class="line">        &quot;algo&quot;: &quot;rsa&quot;,</span><br><span class="line">        &quot;size&quot;: 2048</span><br><span class="line">    &#125;,</span><br><span class="line">    &quot;names&quot;: [</span><br><span class="line">        &#123;</span><br><span class="line">            &quot;C&quot;: &quot;CN&quot;,</span><br><span class="line">            &quot;L&quot;: &quot;Beijing&quot;,</span><br><span class="line">            &quot;O&quot;: &quot;etcd-cluster&quot;,</span><br><span class="line">            &quot;OU&quot;: &quot;System&quot;,</span><br><span class="line">            &quot;ST&quot;: &quot;Beijing&quot;</span><br><span class="line">        &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><h3 id="生成证书"><a href="#生成证书" class="headerlink" title="生成证书"></a>生成证书</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在 etcd1 上执行</span></span><br><span class="line">cd /etc/etcd/ssl</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成 CA 证书</span></span><br><span class="line">cfssl gencert -initca etcd-ca-csr.json | cfssljson -bare etcd-ca</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成客户端证书</span></span><br><span class="line">cfssl gencert \</span><br><span class="line">    -ca=etcd-ca.pem \</span><br><span class="line">    -ca-key=etcd-ca-key.pem \</span><br><span class="line">    -config=ca-config.json \</span><br><span class="line">    -profile=client client-csr.json | cfssljson -bare client</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成服务端证书</span></span><br><span class="line">cfssl gencert \</span><br><span class="line">    -ca=etcd-ca.pem \</span><br><span class="line">    -ca-key=etcd-ca-key.pem \</span><br><span class="line">    -config=ca-config.json \</span><br><span class="line">    -profile=server etcd-server-csr.json | cfssljson -bare etcd-server</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成对等证书</span></span><br><span class="line">cfssl gencert \</span><br><span class="line">    -ca=etcd-ca.pem \</span><br><span class="line">    -ca-key=etcd-ca-key.pem \</span><br><span class="line">    -config=ca-config.json \</span><br><span class="line">    -profile=peer etcd-peer-csr.json | cfssljson -bare etcd-peer</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">分发证书到其他节点</span></span><br><span class="line">for host in etcd2 etcd3; do</span><br><span class="line">    ssh $host &quot;mkdir -p /etc/etcd/ssl&quot;</span><br><span class="line">    scp /etc/etcd/ssl/* $host:/etc/etcd/ssl/</span><br><span class="line">done</span><br></pre></td></tr></table></figure><h2 id="配置-ETCD-服务"><a href="#配置-ETCD-服务" class="headerlink" title="配置 ETCD 服务"></a>配置 ETCD 服务</h2><h3 id="创建服务配置文件"><a href="#创建服务配置文件" class="headerlink" title="创建服务配置文件"></a>创建服务配置文件</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在 etcd1 上执行</span></span><br><span class="line">cat &gt; /lib/systemd/system/etcd.service &lt;&lt; EOF</span><br><span class="line">[Unit]</span><br><span class="line">Description=Etcd Server</span><br><span class="line">After=network.target</span><br><span class="line">After=network-online.target</span><br><span class="line">Wants=network-online.target</span><br><span class="line">Before=kube-apiserver.service</span><br><span class="line">Documentation=https://github.com/coreos</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">Type=notify</span><br><span class="line">WorkingDirectory=/data/etcd/</span><br><span class="line">ExecStart=/usr/local/bin/etcd \\</span><br><span class="line">  --name=etcd1 \\</span><br><span class="line">  --cert-file=/etc/etcd/ssl/etcd-server.pem \\</span><br><span class="line">  --key-file=/etc/etcd/ssl/etcd-server-key.pem \\</span><br><span class="line">  --peer-cert-file=/etc/etcd/ssl/etcd-peer.pem \\</span><br><span class="line">  --peer-key-file=/etc/etcd/ssl/etcd-peer-key.pem \\</span><br><span class="line">  --trusted-ca-file=/etc/etcd/ssl/etcd-ca.pem \\</span><br><span class="line">  --peer-trusted-ca-file=/etc/etcd/ssl/etcd-ca.pem \\</span><br><span class="line">  --initial-advertise-peer-urls=https://192.168.171.136:2380 \\</span><br><span class="line">  --listen-peer-urls=https://192.168.171.136:2380 \\</span><br><span class="line">  --listen-client-urls=https://192.168.171.136:2379 \\</span><br><span class="line">  --advertise-client-urls=https://192.168.171.136:2379 \\</span><br><span class="line">  --initial-cluster-token=etcd-cluster-0 \\</span><br><span class="line">  --initial-cluster=etcd1=https://192.168.171.136:2380,etcd2=https://192.168.171.137:2380,etcd3=https://192.168.171.138:2380 \\</span><br><span class="line">  --initial-cluster-state=new \\</span><br><span class="line">  --data-dir=/data/etcd \\</span><br><span class="line">  --snapshot-count=50000 \\</span><br><span class="line">  --auto-compaction-retention=1 \\</span><br><span class="line">  --max-request-bytes=10485760 \\</span><br><span class="line">  --quota-backend-bytes=8589934592</span><br><span class="line">Restart=always</span><br><span class="line">RestartSec=15</span><br><span class="line">LimitNOFILE=65536</span><br><span class="line">OOMScoreAdjust=-999</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">分发到其他节点并修改配置</span></span><br><span class="line">for host in etcd2 etcd3; do</span><br><span class="line">    scp /lib/systemd/system/etcd.service $host:/lib/systemd/system/</span><br><span class="line">    ssh $host &quot;sed -i &#x27;s/etcd1/$host/g; s/192.168.171.136/192.168.171.$(expr 136 + $(echo $host | cut -c5))/g&#x27; /lib/systemd/system/etcd.service&quot;</span><br><span class="line">done</span><br></pre></td></tr></table></figure><h3 id="启动服务-2"><a href="#启动服务-2" class="headerlink" title="启动服务"></a>启动服务</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在所有节点上执行</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建数据目录</span></span><br><span class="line">mkdir -p /data/etcd</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重载服务配置</span></span><br><span class="line">systemctl daemon-reload</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动并设置开机自启</span></span><br><span class="line">systemctl enable --now etcd</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看服务状态</span></span><br><span class="line">systemctl status etcd</span><br></pre></td></tr></table></figure><h2 id="集群验证"><a href="#集群验证" class="headerlink" title="集群验证"></a>集群验证</h2><h3 id="配置命令别名"><a href="#配置命令别名" class="headerlink" title="配置命令别名"></a>配置命令别名</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在所有节点上执行</span></span><br><span class="line">cat &gt;&gt; ~/.bashrc &lt;&lt; EOF</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">ETCD 集群操作别名</span></span><br><span class="line">alias etcdctl=&#x27;etcdctl \\</span><br><span class="line">    --endpoints=192.168.171.136:2379,192.168.171.137:2379,192.168.171.138:2379 \\</span><br><span class="line">    --cacert=/etc/etcd/ssl/etcd-ca.pem \\</span><br><span class="line">    --cert=/etc/etcd/ssl/etcd-server.pem \\</span><br><span class="line">    --key=/etc/etcd/ssl/etcd-server-key.pem&#x27;</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">source ~/.bashrc</span><br></pre></td></tr></table></figure><h3 id="检查集群状态"><a href="#检查集群状态" class="headerlink" title="检查集群状态"></a>检查集群状态</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看集群成员</span></span><br><span class="line">etcdctl member list -w table</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看集群健康状态</span></span><br><span class="line">etcdctl endpoint health -w table</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">写入测试数据</span></span><br><span class="line">etcdctl put test &quot;hello etcd&quot;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">读取测试数据</span></span><br><span class="line">etcdctl get test</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">删除测试数据</span></span><br><span class="line">etcdctl del test</span><br></pre></td></tr></table></figure><h2 id="集群备份"><a href="#集群备份" class="headerlink" title="集群备份"></a>集群备份</h2><h3 id="配置自动备份"><a href="#配置自动备份" class="headerlink" title="配置自动备份"></a>配置自动备份</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建备份目录</span></span><br><span class="line">mkdir -p /data/etcd-backups</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建备份脚本</span></span><br><span class="line">cat &gt; /data/etcd-backups/etcd-backup.sh &lt;&lt; EOF</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">备份配置</span></span><br><span class="line">BACKUP_DIR=&quot;/data/etcd-backups&quot;</span><br><span class="line">DATE=\$(date +%Y%m%d%H%M%S)</span><br><span class="line">LOG_FILE=&quot;\$&#123;BACKUP_DIR&#125;/backup-\$&#123;DATE&#125;.log&quot;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">备份命令</span></span><br><span class="line">/usr/local/bin/etcdctl \\</span><br><span class="line">    --endpoints=192.168.171.136:2379 \\</span><br><span class="line">    --cacert=/etc/etcd/ssl/etcd-ca.pem \\</span><br><span class="line">    --cert=/etc/etcd/ssl/etcd-server.pem \\</span><br><span class="line">    --key=/etc/etcd/ssl/etcd-server-key.pem \\</span><br><span class="line">    snapshot save \$&#123;BACKUP_DIR&#125;/backup-\$&#123;DATE&#125;.db &gt; \$&#123;LOG_FILE&#125; 2&gt;&amp;1</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">清理旧备份</span></span><br><span class="line">find \$&#123;BACKUP_DIR&#125; -name &quot;backup-*.db&quot; -mtime +7 -delete</span><br><span class="line">find \$&#123;BACKUP_DIR&#125; -name &quot;backup-*.log&quot; -mtime +7 -delete</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加执行权限</span></span><br><span class="line">chmod +x /data/etcd-backups/etcd-backup.sh</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加定时任务</span></span><br><span class="line">echo &quot;0 2 * * * /data/etcd-backups/etcd-backup.sh&quot; &gt;&gt; /var/spool/cron/crontabs/root</span><br></pre></td></tr></table></figure><h2 id="故障排除-2"><a href="#故障排除-2" class="headerlink" title="故障排除"></a>故障排除</h2><h3 id="常见问题排查"><a href="#常见问题排查" class="headerlink" title="常见问题排查"></a>常见问题排查</h3><ol><li>证书问题：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查证书有效期</span></span><br><span class="line">openssl x509 -in /etc/etcd/ssl/etcd-server.pem -text -noout | grep -A2 Validity</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查证书权限</span></span><br><span class="line">ls -l /etc/etcd/ssl/</span><br></pre></td></tr></table></figure><ol start="2"><li>网络问题：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查端口监听</span></span><br><span class="line">netstat -ntlp | grep etcd</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查端口连通性</span></span><br><span class="line">for port in 2379 2380; do</span><br><span class="line">    for host in 192.168.171.136 192.168.171.137 192.168.171.138; do</span><br><span class="line">        echo &quot;Testing $host:$port...&quot;</span><br><span class="line">        nc -zv $host $port</span><br><span class="line">    done</span><br><span class="line">done</span><br></pre></td></tr></table></figure><ol start="3"><li>日志排查：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看实时日志</span></span><br><span class="line">journalctl -u etcd -f</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看错误日志</span></span><br><span class="line">journalctl -u etcd -p err</span><br></pre></td></tr></table></figure><h2 id="性能优化"><a href="#性能优化" class="headerlink" title="性能优化"></a>性能优化</h2><ol><li>系统参数优化：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">调整系统限制</span></span><br><span class="line">cat &gt;&gt; /etc/security/limits.conf &lt;&lt; EOF</span><br><span class="line">* soft nofile 65536</span><br><span class="line">* hard nofile 65536</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">调整内核参数</span></span><br><span class="line">cat &gt;&gt; /etc/sysctl.conf &lt;&lt; EOF</span><br><span class="line">net.ipv4.ip_local_port_range = 1024 65000</span><br><span class="line">net.core.somaxconn = 32768</span><br><span class="line">net.core.netdev_max_backlog = 16384</span><br><span class="line">net.ipv4.tcp_max_syn_backlog = 8096</span><br><span class="line">net.ipv4.tcp_tw_reuse = 1</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">sysctl -p</span><br></pre></td></tr></table></figure><ol start="2"><li>ETCD 参数优化：</li></ol><ul><li>适当调整 <code>--snapshot-count</code></li><li>根据实际情况调整 <code>--quota-backend-bytes</code></li><li>配置合适的 <code>--auto-compaction-retention</code></li></ul><h2 id="注意事项-2"><a href="#注意事项-2" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li><p>安全建议：</p><ul><li>定期更新证书</li><li>限制访问权限</li><li>配置防火墙规则</li></ul></li><li><p>维护建议：</p><ul><li>定期备份数据</li><li>监控集群状态</li><li>及时清理历史数据</li></ul></li><li><p>性能建议：</p><ul><li>使用 SSD 存储</li><li>独立的磁盘空间</li><li>足够的内存配置</li></ul></li><li><p>高可用建议：</p><ul><li>节点跨机架部署</li><li>配置监控告警</li><li>定期进行故障演练</li></ul></li></ol><hr><h1 id="Harbor-私有镜像仓库部署"><a href="#Harbor-私有镜像仓库部署" class="headerlink" title="Harbor 私有镜像仓库部署"></a>Harbor 私有镜像仓库部署</h1><h2 id="环境准备-2"><a href="#环境准备-2" class="headerlink" title="环境准备"></a>环境准备</h2><h3 id="DNS-配置"><a href="#DNS-配置" class="headerlink" title="DNS 配置"></a>DNS 配置</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置本地解析</span></span><br><span class="line">cat &gt;&gt; /etc/hosts &lt;&lt; EOF</span><br><span class="line">192.168.171.50 harbor.k8s.com</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">修改主机名</span></span><br><span class="line">hostnamectl set-hostname harbor.k8s.com</span><br></pre></td></tr></table></figure><h3 id="存储配置"><a href="#存储配置" class="headerlink" title="存储配置"></a>存储配置</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安装 LVM 工具</span></span><br><span class="line">apt-get update</span><br><span class="line">apt-get install -y lvm2</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建物理卷</span></span><br><span class="line">pvcreate /dev/sdb1</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建卷组</span></span><br><span class="line">vgcreate data_vg /dev/sdb1</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建逻辑卷</span></span><br><span class="line">lvcreate -l +100%FREE -n data_lv data_vg</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">格式化逻辑卷</span></span><br><span class="line">mkfs.ext4 /dev/data_vg/data_lv</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">清理旧配置</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">sed -i <span class="string">&#x27;/\/data/d&#x27;</span> /etc/fstab</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置挂载</span></span><br><span class="line">echo &quot;/dev/data_vg/data_lv /data ext4 defaults 0 0&quot; &gt;&gt; /etc/fstab</span><br><span class="line">mkdir -p /data</span><br><span class="line">mount -a</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证挂载</span></span><br><span class="line">df -h /data</span><br></pre></td></tr></table></figure><h2 id="Docker-环境配置"><a href="#Docker-环境配置" class="headerlink" title="Docker 环境配置"></a>Docker 环境配置</h2><h3 id="安装-Docker"><a href="#安装-Docker" class="headerlink" title="安装 Docker"></a>安装 Docker</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安装依赖包</span></span><br><span class="line">apt-get update</span><br><span class="line">apt-get install -y \</span><br><span class="line">    apt-transport-https \</span><br><span class="line">    ca-certificates \</span><br><span class="line">    curl \</span><br><span class="line">    gnupg \</span><br><span class="line">    lsb-release</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加 Docker 官方 GPG 密钥</span></span><br><span class="line">curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加 Docker 软件源</span></span><br><span class="line">echo &quot;deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable&quot; | tee /etc/apt/sources.list.d/docker.list &gt; /dev/null</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安装 Docker</span></span><br><span class="line">apt-get update</span><br><span class="line">apt-get install -y docker-ce docker-ce-cli containerd.io</span><br></pre></td></tr></table></figure><h3 id="配置-Docker"><a href="#配置-Docker" class="headerlink" title="配置 Docker"></a>配置 Docker</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建 Docker 配置目录</span></span><br><span class="line">mkdir -p /etc/docker</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置 Docker daemon</span></span><br><span class="line">cat &gt; /etc/docker/daemon.json &lt;&lt; &#x27;EOF&#x27;</span><br><span class="line">&#123;</span><br><span class="line">  &quot;registry-mirrors&quot;: [&quot;https://ustc-edu-cn.mirror.aliyuncs.com&quot;],</span><br><span class="line">  &quot;debug&quot;: false,</span><br><span class="line">  &quot;ip-forward&quot;: true,</span><br><span class="line">  &quot;ipv6&quot;: false,</span><br><span class="line">  &quot;live-restore&quot;: true,</span><br><span class="line">  &quot;log-driver&quot;: &quot;json-file&quot;,</span><br><span class="line">  &quot;log-level&quot;: &quot;warn&quot;,</span><br><span class="line">  &quot;log-opts&quot;: &#123;</span><br><span class="line">    &quot;max-size&quot;: &quot;100m&quot;,</span><br><span class="line">    &quot;max-file&quot;: &quot;2&quot;</span><br><span class="line">  &#125;,</span><br><span class="line">  &quot;selinux-enabled&quot;: false,</span><br><span class="line">  &quot;experimental&quot;: true,</span><br><span class="line">  &quot;storage-driver&quot;: &quot;overlay2&quot;,</span><br><span class="line">  &quot;metrics-addr&quot;: &quot;0.0.0.0:9323&quot;,</span><br><span class="line">  &quot;data-root&quot;: &quot;/data/docker&quot;,</span><br><span class="line">  &quot;default-ulimits&quot;: &#123;</span><br><span class="line">    &quot;nofile&quot;: &#123;</span><br><span class="line">      &quot;Name&quot;: &quot;nofile&quot;,</span><br><span class="line">      &quot;Hard&quot;: 65536,</span><br><span class="line">      &quot;Soft&quot;: 65536</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  &quot;exec-opts&quot;: [&quot;native.cgroupdriver=systemd&quot;]</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重启 Docker 服务</span></span><br><span class="line">systemctl daemon-reload</span><br><span class="line">systemctl restart docker</span><br><span class="line">systemctl enable docker</span><br></pre></td></tr></table></figure><h3 id="安装-Docker-Compose"><a href="#安装-Docker-Compose" class="headerlink" title="安装 Docker Compose"></a>安装 Docker Compose</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">下载 Docker Compose</span></span><br><span class="line">COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep &#x27;tag_name&#x27; | cut -d\&quot; -f4)</span><br><span class="line">curl -L &quot;https://github.com/docker/compose/releases/download/$&#123;COMPOSE_VERSION&#125;/docker-compose-$(uname -s)-$(uname -m)&quot; -o /usr/local/bin/docker-compose</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加执行权限</span></span><br><span class="line">chmod +x /usr/local/bin/docker-compose</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证安装</span></span><br><span class="line">docker-compose version</span><br></pre></td></tr></table></figure><h2 id="Harbor-部署"><a href="#Harbor-部署" class="headerlink" title="Harbor 部署"></a>Harbor 部署</h2><h3 id="下载-Harbor"><a href="#下载-Harbor" class="headerlink" title="下载 Harbor"></a>下载 Harbor</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">设置 Harbor 版本</span></span><br><span class="line">export HARBOR_VERSION=&quot;v2.9.1&quot;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">下载 Harbor 安装包</span></span><br><span class="line">wget https://github.com/goharbor/harbor/releases/download/$&#123;HARBOR_VERSION&#125;/harbor-offline-installer-$&#123;HARBOR_VERSION&#125;.tgz</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">解压安装包</span></span><br><span class="line">tar xzvf harbor-offline-installer-$&#123;HARBOR_VERSION&#125;.tgz -C /data</span><br></pre></td></tr></table></figure><h3 id="配置-Harbor"><a href="#配置-Harbor" class="headerlink" title="配置 Harbor"></a>配置 Harbor</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建配置文件</span></span><br><span class="line">cp /data/harbor/harbor.yml.tmpl /data/harbor/harbor.yml</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">修改配置文件</span></span><br><span class="line">cat &gt; /data/harbor/harbor.yml &lt;&lt; EOF</span><br><span class="line">hostname: harbor.k8s.com</span><br><span class="line">https:</span><br><span class="line">  certificate: /data/harbor/ssl/harbor.k8s.com.crt</span><br><span class="line">  private_key: /data/harbor/ssl/harbor.k8s.com.key</span><br><span class="line">harbor_admin_password: Harbor@123.com</span><br><span class="line">data_volume: /data/harbor/harbor-data</span><br><span class="line">log:</span><br><span class="line">  location: /data/harbor/harbor-logs</span><br><span class="line">  level: info</span><br><span class="line">  local:</span><br><span class="line">    rotate_count: 50</span><br><span class="line">    rotate_size: 200M</span><br><span class="line">database:</span><br><span class="line">  password: root123</span><br><span class="line">  max_idle_conns: 100</span><br><span class="line">  max_open_conns: 900</span><br><span class="line">storage_service:</span><br><span class="line">  ca_bundle: /etc/ssl/certs/ca-certificates.crt</span><br><span class="line">  redirect:</span><br><span class="line">    disabled: false</span><br><span class="line">  cache:</span><br><span class="line">    enabled: true</span><br><span class="line">    expire_hours: 24</span><br><span class="line">trivy:</span><br><span class="line">  enabled: true</span><br><span class="line">  ignore_unfixed: false</span><br><span class="line">  skip_update: false</span><br><span class="line">  offline_scan: false</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><h3 id="配置-TLS-证书-1"><a href="#配置-TLS-证书-1" class="headerlink" title="配置 TLS 证书"></a>配置 TLS 证书</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建证书目录</span></span><br><span class="line">mkdir -p /data/harbor/ssl</span><br><span class="line">cd /data/harbor/ssl</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成 CA 私钥和证书</span></span><br><span class="line">openssl genrsa -out ca.key 4096</span><br><span class="line">openssl req -x509 -new -nodes -sha512 -days 3650 \</span><br><span class="line">    -subj &quot;/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=harbor.k8s.com&quot; \</span><br><span class="line">    -key ca.key \</span><br><span class="line">    -out ca.crt</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成服务器私钥</span></span><br><span class="line">openssl genrsa -out harbor.k8s.com.key 4096</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成证书签名请求</span></span><br><span class="line">openssl req -sha512 -new \</span><br><span class="line">    -subj &quot;/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=harbor.k8s.com&quot; \</span><br><span class="line">    -key harbor.k8s.com.key \</span><br><span class="line">    -out harbor.k8s.com.csr</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置证书扩展信息</span></span><br><span class="line">cat &gt; v3.ext &lt;&lt; EOF</span><br><span class="line">authorityKeyIdentifier=keyid,issuer</span><br><span class="line">basicConstraints=CA:FALSE</span><br><span class="line">keyUsage=digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment</span><br><span class="line">extendedKeyUsage=serverAuth</span><br><span class="line">subjectAltName=@alt_names</span><br><span class="line"></span><br><span class="line">[alt_names]</span><br><span class="line">DNS.1=harbor.k8s.com</span><br><span class="line">DNS.2=harbor</span><br><span class="line">IP.1=192.168.171.50</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成服务器证书</span></span><br><span class="line">openssl x509 -req -sha512 -days 3650 \</span><br><span class="line">    -extfile v3.ext \</span><br><span class="line">    -CA ca.crt -CAkey ca.key -CAcreateserial \</span><br><span class="line">    -in harbor.k8s.com.csr \</span><br><span class="line">    -out harbor.k8s.com.crt</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成客户端证书</span></span><br><span class="line">openssl x509 -inform PEM -in harbor.k8s.com.crt -out harbor.k8s.com.cert</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置 Docker 证书</span></span><br><span class="line">mkdir -p /etc/docker/certs.d/harbor.k8s.com/</span><br><span class="line">cp ca.crt /etc/docker/certs.d/harbor.k8s.com/</span><br><span class="line">cp harbor.k8s.com.cert /etc/docker/certs.d/harbor.k8s.com/</span><br><span class="line">cp harbor.k8s.com.key /etc/docker/certs.d/harbor.k8s.com/</span><br></pre></td></tr></table></figure><h3 id="安装-Harbor"><a href="#安装-Harbor" class="headerlink" title="安装 Harbor"></a>安装 Harbor</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">cd /data/harbor</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安装 Harbor</span></span><br><span class="line">./prepare --with-trivy</span><br><span class="line">./install.sh --with-trivy</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证安装</span></span><br><span class="line">docker ps</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">测试登录</span></span><br><span class="line">docker login -u admin -p &#x27;Harbor@123.com&#x27; harbor.k8s.com</span><br></pre></td></tr></table></figure><h2 id="客户端配置"><a href="#客户端配置" class="headerlink" title="客户端配置"></a>客户端配置</h2><h3 id="配置-Docker-客户端"><a href="#配置-Docker-客户端" class="headerlink" title="配置 Docker 客户端"></a>配置 Docker 客户端</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">复制证书到客户端</span></span><br><span class="line">mkdir -p /etc/docker/certs.d/harbor.k8s.com/</span><br><span class="line">scp harbor-server:/etc/docker/certs.d/harbor.k8s.com/* /etc/docker/certs.d/harbor.k8s.com/</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重启 Docker 服务</span></span><br><span class="line">systemctl restart docker</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">测试登录</span></span><br><span class="line">docker login harbor.k8s.com</span><br></pre></td></tr></table></figure><h2 id="维护管理"><a href="#维护管理" class="headerlink" title="维护管理"></a>维护管理</h2><h3 id="备份配置"><a href="#备份配置" class="headerlink" title="备份配置"></a>备份配置</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建备份脚本</span></span><br><span class="line">cat &gt; /data/harbor/backup.sh &lt;&lt; &#x27;EOF&#x27;</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line"></span><br><span class="line">BACKUP_DIR=&quot;/data/harbor/backups&quot;</span><br><span class="line">DATE=$(date +%Y%m%d_%H%M%S)</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建备份目录</span></span><br><span class="line">mkdir -p $&#123;BACKUP_DIR&#125;/$&#123;DATE&#125;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">停止服务</span></span><br><span class="line">cd /data/harbor</span><br><span class="line">docker-compose down</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">备份数据</span></span><br><span class="line">tar czf $&#123;BACKUP_DIR&#125;/$&#123;DATE&#125;/harbor_data.tar.gz /data/harbor/harbor-data</span><br><span class="line">tar czf $&#123;BACKUP_DIR&#125;/$&#123;DATE&#125;/harbor_config.tar.gz /data/harbor/harbor.yml /data/harbor/ssl</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动服务</span></span><br><span class="line">docker-compose up -d</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">清理旧备份</span></span><br><span class="line">find $&#123;BACKUP_DIR&#125; -type d -mtime +7 -exec rm -rf &#123;&#125; \;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">记录备份日志</span></span><br><span class="line">echo &quot;Backup completed at $(date &#x27;+%Y-%m-%d %H:%M:%S&#x27;)&quot; &gt;&gt; /data/harbor/harbor-logs/backup.log</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加执行权限</span></span><br><span class="line">chmod +x /data/harbor/backup.sh</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建日志目录</span></span><br><span class="line">mkdir -p /data/harbor/harbor-logs</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加到 root 用户的定时任务</span></span><br><span class="line">(crontab -l 2&gt;/dev/null; echo &quot;0 2 * * * /data/harbor/backup.sh &gt; /dev/null 2&gt;&amp;1&quot;) | crontab -</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证定时任务</span></span><br><span class="line">crontab -l</span><br></pre></td></tr></table></figure><h3 id="监控配置"><a href="#监控配置" class="headerlink" title="监控配置"></a>监控配置</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建监控脚本</span></span><br><span class="line">cat &gt; /data/harbor/monitor.sh &lt;&lt; &#x27;EOF&#x27;</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查 Harbor 服务状态</span></span><br><span class="line">check_harbor() &#123;</span><br><span class="line">    local containers=$(docker ps --format &#x27;&#123;&#123;.Names&#125;&#125;&#x27; | grep &#x27;^harbor-&#x27;)</span><br><span class="line">    if [ $(echo &quot;$containers&quot; | wc -l) -lt 7 ]; then</span><br><span class="line">        echo &quot;Warning: Some Harbor containers are not running&quot;</span><br><span class="line">        return 1</span><br><span class="line">    fi</span><br><span class="line">    return 0</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查存储空间</span></span><br><span class="line">check_storage() &#123;</span><br><span class="line">    local usage=$(df -h /data | awk &#x27;NR==2 &#123;print $5&#125;&#x27; | sed &#x27;s/%//&#x27;)</span><br><span class="line">    if [ $usage -gt 80 ]; then</span><br><span class="line">        echo &quot;Warning: Storage usage is above 80%&quot;</span><br><span class="line">        return 1</span><br><span class="line">    fi</span><br><span class="line">    return 0</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">主检查逻辑</span></span><br><span class="line">main() &#123;</span><br><span class="line">    check_harbor || echo &quot;Harbor service check failed&quot;</span><br><span class="line">    check_storage || echo &quot;Storage check failed&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">main</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">chmod +x /data/harbor/monitor.sh</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加到 crontab</span></span><br><span class="line">echo &quot;*/5 * * * * /data/harbor/monitor.sh &gt;&gt; /data/harbor/harbor-logs/monitor.log 2&gt;&amp;1&quot; &gt;&gt; /var/spool/cron/crontabs/root</span><br></pre></td></tr></table></figure><h2 id="故障排除-3"><a href="#故障排除-3" class="headerlink" title="故障排除"></a>故障排除</h2><h3 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h3><ol><li>证书问题：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查证书有效期</span></span><br><span class="line">openssl x509 -in /data/harbor/ssl/harbor.k8s.com.crt -text -noout | grep -A2 Validity</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查证书配置</span></span><br><span class="line">ls -l /etc/docker/certs.d/harbor.k8s.com/</span><br></pre></td></tr></table></figure><ol start="2"><li>存储问题：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查存储空间</span></span><br><span class="line">df -h /data</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查 Docker 存储</span></span><br><span class="line">docker system df</span><br></pre></td></tr></table></figure><ol start="3"><li>服务问题：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查服务状态</span></span><br><span class="line">cd /data/harbor</span><br><span class="line">docker-compose ps</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看服务日志</span></span><br><span class="line">docker-compose logs</span><br></pre></td></tr></table></figure><h2 id="性能优化-1"><a href="#性能优化-1" class="headerlink" title="性能优化"></a>性能优化</h2><ol><li>系统优化：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">调整系统限制</span></span><br><span class="line">cat &gt;&gt; /etc/security/limits.conf &lt;&lt; EOF</span><br><span class="line">* soft nofile 65535</span><br><span class="line">* hard nofile 65535</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">调整内核参数</span></span><br><span class="line">cat &gt;&gt; /etc/sysctl.conf &lt;&lt; EOF</span><br><span class="line">net.ipv4.ip_local_port_range = 1024 65000</span><br><span class="line">net.core.somaxconn = 32768</span><br><span class="line">fs.file-max = 1000000</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">sysctl -p</span><br></pre></td></tr></table></figure><ol start="2"><li>Docker 优化：</li></ol><ul><li>配置合适的日志轮转策略</li><li>使用高性能存储</li><li>定期清理未使用的镜像和容器</li></ul><h2 id="注意事项-3"><a href="#注意事项-3" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li><p>安全建议：</p><ul><li>及时更新系统和组件</li><li>定期轮换密码和证书</li><li>限制访问权限</li><li>配置防火墙规则</li></ul></li><li><p>维护建议：</p><ul><li>定期备份数据</li><li>监控系统资源</li><li>及时清理垃圾数据</li><li>保持日志分析</li></ul></li><li><p>高可用建议：</p><ul><li>配置负载均衡</li><li>实现数据备份</li><li>监控告警配置</li><li>故障恢复演练</li></ul></li></ol><hr><h1 id="Kubernetes-集群环境部署"><a href="#Kubernetes-集群环境部署" class="headerlink" title="Kubernetes 集群环境部署"></a>Kubernetes 集群环境部署</h1><h2 id="环境准备-3"><a href="#环境准备-3" class="headerlink" title="环境准备"></a>环境准备</h2><h3 id="主机配置-1"><a href="#主机配置-1" class="headerlink" title="主机配置"></a>主机配置</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置主机名</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Master 节点</span></span><br><span class="line">hostnamectl set-hostname master1.k8s.com</span><br><span class="line">hostnamectl set-hostname master2.k8s.com</span><br><span class="line">hostnamectl set-hostname master3.k8s.com</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Worker 节点</span></span><br><span class="line">hostnamectl set-hostname worker1.k8s.com</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置 DNS 解析</span></span><br><span class="line">cat &gt;&gt; /etc/hosts &lt;&lt; EOF</span><br><span class="line">192.168.171.136 etcd1</span><br><span class="line">192.168.171.50  harbor harbor.k8s.com</span><br><span class="line">192.168.171.136 master1 master1.k8s.com</span><br><span class="line">192.168.171.137 master2 master2.k8s.com</span><br><span class="line">192.168.171.138 master3 master3.k8s.com</span><br><span class="line">192.168.171.139 worker1 worker1.k8s.com</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置免密登录</span></span><br><span class="line">ssh-keygen -t rsa -b 2048 -N &quot;&quot; -f ~/.ssh/id_rsa</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">分发公钥</span></span><br><span class="line">for host in harbor etcd1 master&#123;1..3&#125; worker1; do</span><br><span class="line">    sshpass -p &#x27;your_password&#x27; ssh-copy-id -o StrictHostKeyChecking=no root@$&#123;host&#125;</span><br><span class="line">done</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">分发hosts文件</span></span><br><span class="line">for host in master&#123;2..3&#125; worker1; do</span><br><span class="line">    scp /etc/hosts $&#123;host&#125;:/etc/</span><br><span class="line">done</span><br></pre></td></tr></table></figure><h3 id="系统配置"><a href="#系统配置" class="headerlink" title="系统配置"></a>系统配置</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在所有节点上执行</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">关闭 swap</span></span><br><span class="line">swapoff -a</span><br><span class="line">sed -i &#x27;/swap/d&#x27; /etc/fstab</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">加载内核模块</span></span><br><span class="line">cat &gt; /etc/modules-load.d/k8s.conf &lt;&lt; EOF</span><br><span class="line">overlay</span><br><span class="line">br_netfilter</span><br><span class="line">ip_vs</span><br><span class="line">ip_vs_rr</span><br><span class="line">ip_vs_wrr</span><br><span class="line">ip_vs_sh</span><br><span class="line">nf_conntrack</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">加载模块</span></span><br><span class="line">modprobe overlay</span><br><span class="line">modprobe br_netfilter</span><br><span class="line">modprobe ip_vs</span><br><span class="line">modprobe ip_vs_rr</span><br><span class="line">modprobe ip_vs_wrr</span><br><span class="line">modprobe ip_vs_sh</span><br><span class="line">modprobe nf_conntrack</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">更新内核设置</span></span><br><span class="line">cat &gt; /etc/sysctl.d/k8s.conf &lt;&lt; EOF</span><br><span class="line">net.bridge.bridge-nf-call-iptables  = 1</span><br><span class="line">net.bridge.bridge-nf-call-ip6tables = 1</span><br><span class="line">net.ipv4.ip_forward                 = 1</span><br><span class="line">vm.swappiness                       = 0</span><br><span class="line">fs.file-max                         = 1000000</span><br><span class="line">net.ipv4.ip_local_port_range       = 1024 65000</span><br><span class="line">net.ipv4.tcp_tw_reuse              = 1</span><br><span class="line">net.ipv4.tcp_fin_timeout           = 30</span><br><span class="line">net.core.somaxconn                 = 32768</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">sysctl --system</span><br></pre></td></tr></table></figure><h2 id="组件安装-1"><a href="#组件安装-1" class="headerlink" title="组件安装"></a>组件安装</h2><h3 id="容器运行时"><a href="#容器运行时" class="headerlink" title="容器运行时"></a>容器运行时</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安装 containerd</span></span><br><span class="line">export CONTAINERD_VERSION=&quot;1.7.6&quot;</span><br><span class="line">wget https://github.com/containerd/containerd/releases/download/v$&#123;CONTAINERD_VERSION&#125;/containerd-$&#123;CONTAINERD_VERSION&#125;-linux-amd64.tar.gz</span><br><span class="line">tar Cxzvf /usr/local containerd-$&#123;CONTAINERD_VERSION&#125;-linux-amd64.tar.gz</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置 containerd 服务</span></span><br><span class="line">wget https://raw.githubusercontent.com/containerd/containerd/main/containerd.service -O /usr/local/lib/systemd/system/containerd.service</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成默认配置</span></span><br><span class="line">mkdir -p /etc/containerd</span><br><span class="line">containerd config default &gt; /etc/containerd/config.toml</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">修改配置</span></span><br><span class="line">sed -i &#x27;s|/var/lib/containerd|/data/containerd|g&#x27; /etc/containerd/config.toml</span><br><span class="line">sed -i &#x27;s|k8s.gcr.io/pause:3.6|registry.aliyuncs.com/google_containers/pause:3.9|g&#x27; /etc/containerd/config.toml</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加镜像仓库配置</span></span><br><span class="line">cat &gt;&gt; /etc/containerd/config.toml &lt;&lt; EOF</span><br><span class="line">      [plugins.&quot;io.containerd.grpc.v1.cri&quot;.registry.mirrors.&quot;docker.io&quot;]</span><br><span class="line">        endpoint = [&quot;https://docker.mirrors.ustc.edu.cn&quot;,&quot;http://hub-mirror.c.163.com&quot;]</span><br><span class="line">      [plugins.&quot;io.containerd.grpc.v1.cri&quot;.registry.mirrors.&quot;gcr.io&quot;]</span><br><span class="line">        endpoint = [&quot;https://gcr.mirrors.ustc.edu.cn&quot;]</span><br><span class="line">      [plugins.&quot;io.containerd.grpc.v1.cri&quot;.registry.mirrors.&quot;k8s.gcr.io&quot;]</span><br><span class="line">        endpoint = [&quot;https://gcr.mirrors.ustc.edu.cn/google-containers/&quot;]</span><br><span class="line">      [plugins.&quot;io.containerd.grpc.v1.cri&quot;.registry.mirrors.&quot;quay.io&quot;]</span><br><span class="line">        endpoint = [&quot;https://quay.mirrors.ustc.edu.cn&quot;]</span><br><span class="line">      [plugins.&quot;io.containerd.grpc.v1.cri&quot;.registry.mirrors.&quot;harbor.k8s.com&quot;]</span><br><span class="line">        endpoint = [&quot;https://harbor.k8s.com&quot;]</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动服务</span></span><br><span class="line">systemctl daemon-reload</span><br><span class="line">systemctl enable --now containerd</span><br></pre></td></tr></table></figure><h3 id="安装-CNI-插件"><a href="#安装-CNI-插件" class="headerlink" title="安装 CNI 插件"></a>安装 CNI 插件</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">下载并安装 CNI 插件</span></span><br><span class="line">CNI_VERSION=&quot;v1.2.0&quot;</span><br><span class="line">wget https://github.com/containernetworking/plugins/releases/download/$&#123;CNI_VERSION&#125;/cni-plugins-linux-amd64-$&#123;CNI_VERSION&#125;.tgz</span><br><span class="line">mkdir -p /opt/cni/bin</span><br><span class="line">tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-$&#123;CNI_VERSION&#125;.tgz</span><br></pre></td></tr></table></figure><h3 id="安装-nerdctl"><a href="#安装-nerdctl" class="headerlink" title="安装 nerdctl"></a>安装 nerdctl</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">下载并安装 nerdctl</span></span><br><span class="line">NERDCTL_VERSION=&quot;1.6.2&quot;</span><br><span class="line">wget https://github.com/containerd/nerdctl/releases/download/v$&#123;NERDCTL_VERSION&#125;/nerdctl-full-$&#123;NERDCTL_VERSION&#125;-linux-amd64.tar.gz</span><br><span class="line">tar Cxzvf /usr/local nerdctl-full-$&#123;NERDCTL_VERSION&#125;-linux-amd64.tar.gz</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置别名</span></span><br><span class="line">cat &gt;&gt; /etc/profile &lt;&lt; EOF</span><br><span class="line">alias docker=&#x27;nerdctl --namespace k8s.io&#x27;</span><br><span class="line">alias docker-compose=&#x27;nerdctl compose&#x27;</span><br><span class="line">alias crictl=&#x27;crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock&#x27;</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">source /etc/profile</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置 nerdctl</span></span><br><span class="line">mkdir -p /etc/nerdctl</span><br><span class="line">cat &gt; /etc/nerdctl/nerdctl.toml &lt;&lt; EOF</span><br><span class="line">namespace = &quot;k8s.io&quot;</span><br><span class="line">insecure_registry = true</span><br><span class="line">cni_path = &quot;/opt/cni/bin/&quot;</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><h3 id="安装-Kubernetes-组件"><a href="#安装-Kubernetes-组件" class="headerlink" title="安装 Kubernetes 组件"></a>安装 Kubernetes 组件</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加 Kubernetes 软件源</span></span><br><span class="line">curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -</span><br><span class="line">cat &gt; /etc/apt/sources.list.d/kubernetes.list &lt;&lt; EOF</span><br><span class="line">deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安装指定版本</span></span><br><span class="line">export KUBE_VERSION=&quot;1.27.8&quot;</span><br><span class="line">apt update</span><br><span class="line">apt install -y kubelet=$&#123;KUBE_VERSION&#125;-00 kubeadm=$&#123;KUBE_VERSION&#125;-00 kubectl=$&#123;KUBE_VERSION&#125;-00</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">锁定版本</span></span><br><span class="line">apt-mark hold kubelet kubeadm kubectl</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启用自动补全</span></span><br><span class="line">apt install -y bash-completion</span><br><span class="line">echo &#x27;source &lt;(kubectl completion bash)&#x27; &gt;&gt; ~/.bashrc</span><br><span class="line">source ~/.bashrc</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">预拉取镜像</span></span><br><span class="line">kubeadm config images pull --kubernetes-version=v$&#123;KUBE_VERSION&#125; \</span><br><span class="line">    --image-repository=&#x27;registry.aliyuncs.com/google_containers&#x27;</span><br></pre></td></tr></table></figure><h2 id="证书配置"><a href="#证书配置" class="headerlink" title="证书配置"></a>证书配置</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建证书目录</span></span><br><span class="line">mkdir -p /etc/kubernetes/pki/etcd</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">复制 ETCD 证书</span></span><br><span class="line">scp etcd1:/etc/etcd/ssl/etcd-ca.pem /etc/kubernetes/pki/etcd/</span><br><span class="line">scp etcd1:/etc/etcd/ssl/client.pem /etc/kubernetes/pki/apiserver-etcd-client.pem</span><br><span class="line">scp etcd1:/etc/etcd/ssl/client-key.pem /etc/kubernetes/pki/apiserver-etcd-client-key.pem</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">复制 Harbor 证书</span></span><br><span class="line">mkdir -p /etc/tls/harbor/</span><br><span class="line">scp -r harbor:/etc/docker/certs.d/harbor.k8s.com /etc/tls/harbor/</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">更新系统证书</span></span><br><span class="line">cp /etc/tls/harbor/harbor.k8s.com/ca.crt /usr/local/share/ca-certificates/</span><br><span class="line">cp /etc/tls/harbor/harbor.k8s.com/harbor.k8s.com.cert /usr/local/share/ca-certificates/</span><br><span class="line">update-ca-certificates</span><br></pre></td></tr></table></figure><h2 id="系统优化-1"><a href="#系统优化-1" class="headerlink" title="系统优化"></a>系统优化</h2><h3 id="性能调优"><a href="#性能调优" class="headerlink" title="性能调优"></a>性能调优</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">调整系统限制</span></span><br><span class="line">cat &gt;&gt; /etc/security/limits.conf &lt;&lt; EOF</span><br><span class="line">* soft nofile 65536</span><br><span class="line">* hard nofile 65536</span><br><span class="line">* soft nproc 65536</span><br><span class="line">* hard nproc 65536</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">调整内核参数</span></span><br><span class="line">cat &gt;&gt; /etc/sysctl.conf &lt;&lt; EOF</span><br><span class="line">net.ipv4.tcp_max_syn_backlog = 8192</span><br><span class="line">net.core.somaxconn = 32768</span><br><span class="line">net.ipv4.tcp_timestamps = 1</span><br><span class="line">net.ipv4.tcp_fin_timeout = 30</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">sysctl -p</span><br></pre></td></tr></table></figure><h3 id="安全加固"><a href="#安全加固" class="headerlink" title="安全加固"></a>安全加固</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">禁用不必要的服务</span></span><br><span class="line">systemctl stop apparmor</span><br><span class="line">systemctl disable apparmor</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置防火墙规则</span></span><br><span class="line">ufw allow 6443/tcp  # Kubernetes API</span><br><span class="line">ufw allow 2379/tcp  # etcd client API</span><br><span class="line">ufw allow 2380/tcp  # etcd peer API</span><br><span class="line">ufw allow 10250/tcp # Kubelet API</span><br><span class="line">ufw allow 10251/tcp # kube-scheduler</span><br><span class="line">ufw allow 10252/tcp # kube-controller-manager</span><br></pre></td></tr></table></figure><h2 id="验证部署-1"><a href="#验证部署-1" class="headerlink" title="验证部署"></a>验证部署</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证模块加载</span></span><br><span class="line">lsmod | grep -e br_netfilter -e overlay -e ip_vs</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证端口</span></span><br><span class="line">netstat -ntlp | grep -e containerd -e kubelet</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证镜像</span></span><br><span class="line">crictl images</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证 Kubernetes 组件</span></span><br><span class="line">systemctl status kubelet</span><br><span class="line">kubectl version --client</span><br><span class="line">kubeadm version</span><br></pre></td></tr></table></figure><h2 id="注意事项-4"><a href="#注意事项-4" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li><p>网络要求：</p><ul><li>节点间网络互通</li><li>可访问外网（用于下载组件）</li><li>防火墙开放必要端口</li></ul></li><li><p>安全建议：</p><ul><li>及时更新系统和组件</li><li>使用最新的稳定版本</li><li>配置适当的安全策略</li></ul></li><li><p>维护建议：</p><ul><li>定期检查系统资源</li><li>监控关键组件状态</li><li>保持日志分析和审计</li></ul></li></ol><hr><h1 id="Kubernetes-集群部署"><a href="#Kubernetes-集群部署" class="headerlink" title="Kubernetes 集群部署"></a>Kubernetes 集群部署</h1><h2 id="初始化配置"><a href="#初始化配置" class="headerlink" title="初始化配置"></a>初始化配置</h2><h3 id="创建集群配置文件"><a href="#创建集群配置文件" class="headerlink" title="创建集群配置文件"></a>创建集群配置文件</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在 master1 节点上执行</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">生成默认配置</span></span><br><span class="line">kubeadm config print init-defaults &gt; kubeadm-init.yaml</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">修改配置文件</span></span><br><span class="line">cat &gt; kubeadm-init.yaml &lt;&lt; EOF</span><br><span class="line">apiVersion: kubeadm.k8s.io/v1beta3</span><br><span class="line">kind: InitConfiguration</span><br><span class="line">localAPIEndpoint:</span><br><span class="line">  advertiseAddress: 192.168.171.136</span><br><span class="line">  bindPort: 6443</span><br><span class="line">nodeRegistration:</span><br><span class="line">  criSocket: unix:///var/run/containerd/containerd.sock</span><br><span class="line">  taints:</span><br><span class="line">    - effect: NoSchedule</span><br><span class="line">      key: node-role.kubernetes.io/control-plane</span><br><span class="line">---</span><br><span class="line">apiVersion: kubeadm.k8s.io/v1beta3</span><br><span class="line">kind: ClusterConfiguration</span><br><span class="line">certificatesDir: /etc/kubernetes/pki</span><br><span class="line">clusterName: kubernetes</span><br><span class="line">controllerManager: &#123;&#125;</span><br><span class="line">dns:</span><br><span class="line">  type: CoreDNS</span><br><span class="line">etcd:</span><br><span class="line">  external:</span><br><span class="line">    endpoints:</span><br><span class="line">      - https://192.168.171.136:2379</span><br><span class="line">      - https://192.168.171.137:2379</span><br><span class="line">      - https://192.168.171.138:2379</span><br><span class="line">    caFile: /etc/kubernetes/pki/etcd/etcd-ca.pem</span><br><span class="line">    certFile: /etc/kubernetes/pki/apiserver-etcd-client.pem</span><br><span class="line">    keyFile: /etc/kubernetes/pki/apiserver-etcd-client-key.pem</span><br><span class="line">kubernetesVersion: 1.27.8</span><br><span class="line">imageRepository: registry.aliyuncs.com/google_containers</span><br><span class="line">networking:</span><br><span class="line">  serviceSubnet: 10.96.0.0/12</span><br><span class="line">  podSubnet: 10.244.0.0/16</span><br><span class="line">---</span><br><span class="line">apiVersion: kubeproxy.config.k8s.io/v1alpha1</span><br><span class="line">kind: KubeProxyConfiguration</span><br><span class="line">mode: ipvs</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><h2 id="集群初始化"><a href="#集群初始化" class="headerlink" title="集群初始化"></a>集群初始化</h2><h3 id="初始化主节点"><a href="#初始化主节点" class="headerlink" title="初始化主节点"></a>初始化主节点</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在 master1 节点上执行</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">初始化集群</span></span><br><span class="line">kubeadm init --config=kubeadm-init.yaml --upload-certs</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置 kubectl</span></span><br><span class="line">mkdir -p $HOME/.kube</span><br><span class="line">cp -i /etc/kubernetes/admin.conf $HOME/.kube/config</span><br><span class="line">chown $(id -u):$(id -g) $HOME/.kube/config</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置环境变量</span></span><br><span class="line">echo &quot;export KUBECONFIG=/etc/kubernetes/admin.conf&quot; &gt;&gt; /etc/profile</span><br><span class="line">source /etc/profile</span><br></pre></td></tr></table></figure><h3 id="添加节点"><a href="#添加节点" class="headerlink" title="添加节点"></a>添加节点</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在其他 master 节点上执行</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">加入控制平面节点</span></span><br><span class="line">kubeadm join 192.168.171.136:6443 --token &lt;token&gt; \</span><br><span class="line">    --discovery-token-ca-cert-hash sha256:&lt;hash&gt; \</span><br><span class="line">    --control-plane --certificate-key &lt;key&gt; \</span><br><span class="line">    --cri-socket=unix:///var/run/containerd/containerd.sock</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在 worker 节点上执行</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">加入工作节点</span></span><br><span class="line">kubeadm join 192.168.171.136:6443 --token &lt;token&gt; \</span><br><span class="line">    --discovery-token-ca-cert-hash sha256:&lt;hash&gt; \</span><br><span class="line">    --cri-socket=unix:///var/run/containerd/containerd.sock</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置环境变量</span></span><br><span class="line">echo &quot;export KUBECONFIG=/etc/kubernetes/admin.conf&quot; &gt;&gt; /etc/profile</span><br><span class="line">source /etc/profile</span><br></pre></td></tr></table></figure><h3 id="节点标签管理"><a href="#节点标签管理" class="headerlink" title="节点标签管理"></a>节点标签管理</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加 worker 标签</span></span><br><span class="line">kubectl label nodes worker1.k8s.com node-role.kubernetes.io/worker=</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加污点</span></span><br><span class="line">kubectl taint nodes master1.k8s.com node-role.kubernetes.io/control-plane=:NoSchedule</span><br><span class="line">kubectl taint nodes master2.k8s.com node-role.kubernetes.io/control-plane=:NoSchedule</span><br><span class="line">kubectl taint nodes master3.k8s.com node-role.kubernetes.io/control-plane=:NoSchedule</span><br></pre></td></tr></table></figure><h2 id="网络配置"><a href="#网络配置" class="headerlink" title="网络配置"></a>网络配置</h2><h3 id="安装-Calico"><a href="#安装-Calico" class="headerlink" title="安装 Calico"></a>安装 Calico</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加 Helm 仓库</span></span><br><span class="line">helm repo add projectcalico https://docs.tigera.io/calico/charts</span><br><span class="line">helm repo update</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建配置文件</span></span><br><span class="line">cat &gt; calico-values.yaml &lt;&lt; EOF</span><br><span class="line">installation:</span><br><span class="line">  cni:</span><br><span class="line">    type: Calico</span><br><span class="line">  ipPools:</span><br><span class="line">  - cidr: 10.244.0.0/16</span><br><span class="line">    encapsulation: IPIP</span><br><span class="line">    natOutgoing: true</span><br><span class="line">    nodeSelector: all()</span><br><span class="line">  registry: docker.io</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安装 Calico</span></span><br><span class="line">helm install calico projectcalico/tigera-operator -f calico-values.yaml</span><br></pre></td></tr></table></figure><h3 id="CoreDNS-配置"><a href="#CoreDNS-配置" class="headerlink" title="CoreDNS 配置"></a>CoreDNS 配置</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置 CoreDNS</span></span><br><span class="line">kubectl -n kube-system get cm coredns -o yaml &gt; coredns-cm.yaml</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">修改配置</span></span><br><span class="line">cat &gt; coredns-cm.yaml &lt;&lt; EOF</span><br><span class="line">apiVersion: v1</span><br><span class="line">data:</span><br><span class="line">  Corefile: |</span><br><span class="line">    .:53 &#123;</span><br><span class="line">        errors</span><br><span class="line">        health &#123;</span><br><span class="line">           lameduck 5s</span><br><span class="line">        &#125;</span><br><span class="line">        hosts &#123;</span><br><span class="line">          192.168.171.50 harbor.k8s.com</span><br><span class="line">          fallthrough</span><br><span class="line">        &#125;</span><br><span class="line">        ready</span><br><span class="line">        kubernetes cluster.local in-addr.arpa ip6.arpa &#123;</span><br><span class="line">           pods insecure</span><br><span class="line">           fallthrough in-addr.arpa ip6.arpa</span><br><span class="line">           ttl 30</span><br><span class="line">        &#125;</span><br><span class="line">        prometheus :9153</span><br><span class="line">        forward . /etc/resolv.conf &#123;</span><br><span class="line">           max_concurrent 1000</span><br><span class="line">        &#125;</span><br><span class="line">        cache 30</span><br><span class="line">        loop</span><br><span class="line">        reload</span><br><span class="line">        loadbalance</span><br><span class="line">    &#125;</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">应用配置</span></span><br><span class="line">kubectl apply -f coredns-cm.yaml</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重启 CoreDNS</span></span><br><span class="line">kubectl -n kube-system delete pod -l k8s-app=kube-dns</span><br></pre></td></tr></table></figure><h2 id="组件配置"><a href="#组件配置" class="headerlink" title="组件配置"></a>组件配置</h2><h3 id="暴露组件端口"><a href="#暴露组件端口" class="headerlink" title="暴露组件端口"></a>暴露组件端口</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在所有 master 节点上执行</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">修改 kube-scheduler 配置</span></span><br><span class="line">sed -i &#x27;s/- --bind-address=127.0.0.1/- --bind-address=0.0.0.0/&#x27; /etc/kubernetes/manifests/kube-scheduler.yaml</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">修改 kube-controller-manager 配置</span></span><br><span class="line">sed -i &#x27;s/- --bind-address=127.0.0.1/- --bind-address=0.0.0.0/&#x27; /etc/kubernetes/manifests/kube-controller-manager.yaml</span><br></pre></td></tr></table></figure><h2 id="集群验证-1"><a href="#集群验证-1" class="headerlink" title="集群验证"></a>集群验证</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证集群状态</span></span><br><span class="line">kubectl get nodes</span><br><span class="line">kubectl get pods -A</span><br><span class="line">kubectl cluster-info</span><br><span class="line">kubectl get componentstatuses</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证网络</span></span><br><span class="line">kubectl run test-nginx --image=nginx</span><br><span class="line">kubectl expose pod test-nginx --port=80 --type=NodePort</span><br><span class="line">curl http://&lt;node-ip&gt;:&lt;node-port&gt;</span><br></pre></td></tr></table></figure><h2 id="维护操作"><a href="#维护操作" class="headerlink" title="维护操作"></a>维护操作</h2><h3 id="证书更新"><a href="#证书更新" class="headerlink" title="证书更新"></a>证书更新</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看证书过期时间</span></span><br><span class="line">kubeadm certs check-expiration</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">更新证书</span></span><br><span class="line">kubeadm certs renew all</span><br></pre></td></tr></table></figure><h3 id="集群升级"><a href="#集群升级" class="headerlink" title="集群升级"></a>集群升级</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">升级 kubeadm</span></span><br><span class="line">apt-mark unhold kubeadm</span><br><span class="line">apt-get update</span><br><span class="line">apt-get install -y kubeadm=&lt;version&gt;</span><br><span class="line">apt-mark hold kubeadm</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">升级控制平面</span></span><br><span class="line">kubeadm upgrade plan</span><br><span class="line">kubeadm upgrade apply v&lt;version&gt;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">升级 kubelet 和 kubectl</span></span><br><span class="line">apt-mark unhold kubelet kubectl</span><br><span class="line">apt-get install -y kubelet=&lt;version&gt; kubectl=&lt;version&gt;</span><br><span class="line">apt-mark hold kubelet kubectl</span><br><span class="line">systemctl restart kubelet</span><br></pre></td></tr></table></figure><h2 id="故障处理"><a href="#故障处理" class="headerlink" title="故障处理"></a>故障处理</h2><h3 id="重置节点"><a href="#重置节点" class="headerlink" title="重置节点"></a>重置节点</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">清理节点</span></span><br><span class="line">kubeadm reset</span><br><span class="line">iptables -F &amp;&amp; iptables -X</span><br><span class="line">iptables -t nat -F &amp;&amp; iptables -t nat -X</span><br><span class="line">iptables -t mangle -F &amp;&amp; iptables -t mangle -X</span><br><span class="line">ipvsadm --clear</span><br><span class="line">rm -rf /etc/kubernetes/ /var/lib/kubelet/ /var/lib/etcd/</span><br></pre></td></tr></table></figure><h3 id="常见问题排查-1"><a href="#常见问题排查-1" class="headerlink" title="常见问题排查"></a>常见问题排查</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看组件日志</span></span><br><span class="line">journalctl -xeu kubelet</span><br><span class="line">kubectl logs -n kube-system &lt;pod-name&gt;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查网络</span></span><br><span class="line">kubectl exec -it &lt;pod-name&gt; -- ping &lt;service-name&gt;</span><br><span class="line">kubectl get endpoints &lt;service-name&gt;</span><br></pre></td></tr></table></figure><h2 id="注意事项-5"><a href="#注意事项-5" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li><p>高可用配置：</p><ul><li>至少部署三个 master 节点</li><li>使用负载均衡器</li><li>配置外部 etcd 集群</li></ul></li><li><p>安全建议：</p><ul><li>及时更新组件版本</li><li>配置网络策略</li><li>使用 RBAC 控制访问</li><li>定期备份 etcd 数据</li></ul></li><li><p>性能优化：</p><ul><li>合理配置资源限制</li><li>优化网络配置</li><li>监控系统性能</li></ul></li><li><p>运维建议：</p><ul><li>实施监控告警</li><li>定期进行备份</li><li>制定故障恢复预案</li><li>保持文档更新</li></ul></li></ol><hr><h1 id="NFS-StorageClass-部署"><a href="#NFS-StorageClass-部署" class="headerlink" title="NFS StorageClass 部署"></a>NFS StorageClass 部署</h1><h2 id="存储服务器配置"><a href="#存储服务器配置" class="headerlink" title="存储服务器配置"></a>存储服务器配置</h2><h3 id="安装-NFS-服务"><a href="#安装-NFS-服务" class="headerlink" title="安装 NFS 服务"></a>安装 NFS 服务</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">安装 NFS 服务器</span></span><br><span class="line">apt-get update</span><br><span class="line">apt-get install -y nfs-kernel-server</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建共享目录</span></span><br><span class="line">mkdir -p /data/ifs/kubernetes</span><br><span class="line">chown -R nobody:nogroup /data/ifs/kubernetes</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置共享权限</span></span><br><span class="line">cat &gt;&gt; /etc/exports &lt;&lt; EOF</span><br><span class="line">/data/ifs/kubernetes 192.168.171.0/24(no_root_squash,rw,sync,no_subtree_check)</span><br><span class="line">EOF</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动服务</span></span><br><span class="line">systemctl enable --now nfs-kernel-server</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证配置</span></span><br><span class="line">exportfs -av</span><br></pre></td></tr></table></figure><h3 id="配置防火墙"><a href="#配置防火墙" class="headerlink" title="配置防火墙"></a>配置防火墙</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">允许 NFS 相关端口</span></span><br><span class="line">ufw allow 2049/tcp  # NFS</span><br><span class="line">ufw allow 111/tcp   # portmapper</span><br><span class="line">ufw allow 111/udp</span><br><span class="line">ufw allow 32765:32768/tcp  # NFS 动态端口</span><br><span class="line">ufw allow 32765:32768/udp</span><br></pre></td></tr></table></figure><h2 id="客户端配置-1"><a href="#客户端配置-1" class="headerlink" title="客户端配置"></a>客户端配置</h2><h3 id="安装-NFS-客户端"><a href="#安装-NFS-客户端" class="headerlink" title="安装 NFS 客户端"></a>安装 NFS 客户端</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在所有 Kubernetes 节点上执行</span></span><br><span class="line">apt-get update</span><br><span class="line">apt-get install -y nfs-common</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置 NFS 服务器解析</span></span><br><span class="line">echo &quot;192.168.171.140 nfs.k8s.com&quot; &gt;&gt; /etc/hosts</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">验证 NFS 挂载</span></span><br><span class="line">showmount -e nfs.k8s.com</span><br></pre></td></tr></table></figure><h2 id="StorageClass-部署"><a href="#StorageClass-部署" class="headerlink" title="StorageClass 部署"></a>StorageClass 部署</h2><h3 id="安装-NFS-Provisioner"><a href="#安装-NFS-Provisioner" class="headerlink" title="安装 NFS Provisioner"></a>安装 NFS Provisioner</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建命名空间</span></span><br><span class="line">kubectl create namespace nfs-provisioner</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建 ServiceAccount</span></span><br><span class="line">cat &gt; rbac.yaml &lt;&lt; EOF</span><br><span class="line">apiVersion: v1</span><br><span class="line">kind: ServiceAccount</span><br><span class="line">metadata:</span><br><span class="line">  name: nfs-client-provisioner</span><br><span class="line">  namespace: nfs-provisioner</span><br><span class="line">---</span><br><span class="line">kind: ClusterRole</span><br><span class="line">apiVersion: rbac.authorization.k8s.io/v1</span><br><span class="line">metadata:</span><br><span class="line">  name: nfs-client-provisioner-runner</span><br><span class="line">rules:</span><br><span class="line">  - apiGroups: [&quot;&quot;]</span><br><span class="line">    resources: [&quot;nodes&quot;]</span><br><span class="line">    verbs: [&quot;get&quot;, &quot;list&quot;, &quot;watch&quot;]</span><br><span class="line">  - apiGroups: [&quot;&quot;]</span><br><span class="line">    resources: [&quot;persistentvolumes&quot;]</span><br><span class="line">    verbs: [&quot;get&quot;, &quot;list&quot;, &quot;watch&quot;, &quot;create&quot;, &quot;delete&quot;]</span><br><span class="line">  - apiGroups: [&quot;&quot;]</span><br><span class="line">    resources: [&quot;persistentvolumeclaims&quot;]</span><br><span class="line">    verbs: [&quot;get&quot;, &quot;list&quot;, &quot;watch&quot;, &quot;update&quot;]</span><br><span class="line">  - apiGroups: [&quot;storage.k8s.io&quot;]</span><br><span class="line">    resources: [&quot;storageclasses&quot;]</span><br><span class="line">    verbs: [&quot;get&quot;, &quot;list&quot;, &quot;watch&quot;]</span><br><span class="line">  - apiGroups: [&quot;&quot;]</span><br><span class="line">    resources: [&quot;events&quot;]</span><br><span class="line">    verbs: [&quot;create&quot;, &quot;update&quot;, &quot;patch&quot;]</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">kubectl apply -f rbac.yaml</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建 Deployment</span></span><br><span class="line">cat &gt; deployment.yaml &lt;&lt; EOF</span><br><span class="line">apiVersion: apps/v1</span><br><span class="line">kind: Deployment</span><br><span class="line">metadata:</span><br><span class="line">  name: nfs-client-provisioner</span><br><span class="line">  namespace: nfs-provisioner</span><br><span class="line">spec:</span><br><span class="line">  replicas: 1</span><br><span class="line">  strategy:</span><br><span class="line">    type: Recreate</span><br><span class="line">  selector:</span><br><span class="line">    matchLabels:</span><br><span class="line">      app: nfs-client-provisioner</span><br><span class="line">  template:</span><br><span class="line">    metadata:</span><br><span class="line">      labels:</span><br><span class="line">        app: nfs-client-provisioner</span><br><span class="line">    spec:</span><br><span class="line">      serviceAccountName: nfs-client-provisioner</span><br><span class="line">      containers:</span><br><span class="line">        - name: nfs-client-provisioner</span><br><span class="line">          image: registry.aliyuncs.com/google_containers/sig-storage/nfs-subdir-external-provisioner:v4.0.2</span><br><span class="line">          volumeMounts:</span><br><span class="line">            - name: nfs-client-root</span><br><span class="line">              mountPath: /persistentvolumes</span><br><span class="line">          env:</span><br><span class="line">            - name: PROVISIONER_NAME</span><br><span class="line">              value: k8s-sigs.io/nfs-subdir-external-provisioner</span><br><span class="line">            - name: NFS_SERVER</span><br><span class="line">              value: nfs.k8s.com</span><br><span class="line">            - name: NFS_PATH</span><br><span class="line">              value: /data/ifs/kubernetes</span><br><span class="line">      volumes:</span><br><span class="line">        - name: nfs-client-root</span><br><span class="line">          nfs:</span><br><span class="line">            server: nfs.k8s.com</span><br><span class="line">            path: /data/ifs/kubernetes</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">kubectl apply -f deployment.yaml</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建 StorageClass</span></span><br><span class="line">cat &gt; storageclass.yaml &lt;&lt; EOF</span><br><span class="line">apiVersion: storage.k8s.io/v1</span><br><span class="line">kind: StorageClass</span><br><span class="line">metadata:</span><br><span class="line">  name: nfs-client</span><br><span class="line">  annotations:</span><br><span class="line">    storageclass.kubernetes.io/is-default-class: &quot;true&quot;</span><br><span class="line">provisioner: k8s-sigs.io/nfs-subdir-external-provisioner</span><br><span class="line">parameters:</span><br><span class="line">  archiveOnDelete: &quot;false&quot;</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">kubectl apply -f storageclass.yaml</span><br></pre></td></tr></table></figure><h3 id="验证部署-2"><a href="#验证部署-2" class="headerlink" title="验证部署"></a>验证部署</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建测试 PVC</span></span><br><span class="line">cat &gt; test-claim.yaml &lt;&lt; EOF</span><br><span class="line">apiVersion: v1</span><br><span class="line">kind: PersistentVolumeClaim</span><br><span class="line">metadata:</span><br><span class="line">  name: test-claim</span><br><span class="line">spec:</span><br><span class="line">  accessModes:</span><br><span class="line">    - ReadWriteMany</span><br><span class="line">  resources:</span><br><span class="line">    requests:</span><br><span class="line">      storage: 1Mi</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">kubectl apply -f test-claim.yaml</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建测试 Pod</span></span><br><span class="line">cat &gt; test-pod.yaml &lt;&lt; EOF</span><br><span class="line">apiVersion: v1</span><br><span class="line">kind: Pod</span><br><span class="line">metadata:</span><br><span class="line">  name: test-pod</span><br><span class="line">spec:</span><br><span class="line">  containers:</span><br><span class="line">    - name: test-pod</span><br><span class="line">      image: busybox</span><br><span class="line">      command:</span><br><span class="line">        - &quot;/bin/sh&quot;</span><br><span class="line">      args:</span><br><span class="line">        - &quot;-c&quot;</span><br><span class="line">        - &quot;touch /mnt/SUCCESS &amp;&amp; exit 0 || exit 1&quot;</span><br><span class="line">      volumeMounts:</span><br><span class="line">        - name: nfs-pvc</span><br><span class="line">          mountPath: &quot;/mnt&quot;</span><br><span class="line">  restartPolicy: &quot;Never&quot;</span><br><span class="line">  volumes:</span><br><span class="line">    - name: nfs-pvc</span><br><span class="line">      persistentVolumeClaim:</span><br><span class="line">        claimName: test-claim</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">kubectl apply -f test-pod.yaml</span><br></pre></td></tr></table></figure><h2 id="监控配置-1"><a href="#监控配置-1" class="headerlink" title="监控配置"></a>监控配置</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建监控脚本</span></span><br><span class="line">cat &gt; /usr/local/bin/monitor-nfs.sh &lt;&lt; &#x27;EOF&#x27;</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查 NFS 服务状态</span></span><br><span class="line">check_nfs_service() &#123;</span><br><span class="line">    if ! systemctl is-active --quiet nfs-kernel-server; then</span><br><span class="line">        echo &quot;NFS service is not running&quot;</span><br><span class="line">        return 1</span><br><span class="line">    fi</span><br><span class="line">    return 0</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查存储空间</span></span><br><span class="line">check_storage() &#123;</span><br><span class="line">    local usage=$(df -h /data/ifs/kubernetes | awk &#x27;NR==2 &#123;print $5&#125;&#x27; | sed &#x27;s/%//&#x27;)</span><br><span class="line">    if [ $usage -gt 80 ]; then</span><br><span class="line">        echo &quot;Storage usage is above 80%&quot;</span><br><span class="line">        return 1</span><br><span class="line">    fi</span><br><span class="line">    return 0</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">检查 NFS 挂载点</span></span><br><span class="line">check_mounts() &#123;</span><br><span class="line">    if ! mountpoint -q /data/ifs/kubernetes; then</span><br><span class="line">        echo &quot;NFS directory is not mounted&quot;</span><br><span class="line">        return 1</span><br><span class="line">    fi</span><br><span class="line">    return 0</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">主检查逻辑</span></span><br><span class="line">main() &#123;</span><br><span class="line">    check_nfs_service || echo &quot;NFS service check failed&quot;</span><br><span class="line">    check_storage || echo &quot;Storage check failed&quot;</span><br><span class="line">    check_mounts || echo &quot;Mount check failed&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">main</span><br><span class="line">EOF</span><br><span class="line"></span><br><span class="line">chmod +x /usr/local/bin/monitor-nfs.sh</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加到 crontab</span></span><br><span class="line">(crontab -l 2&gt;/dev/null; echo &quot;*/5 * * * * /usr/local/bin/monitor-nfs.sh &gt;&gt; /var/log/nfs-monitor.log 2&gt;&amp;1&quot;) | crontab -</span><br></pre></td></tr></table></figure><h2 id="注意事项-6"><a href="#注意事项-6" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li><p>性能优化：</p><ul><li>使用 SSD 存储</li><li>调整 NFS 缓存参数</li><li>配置合适的网络带宽</li></ul></li><li><p>安全建议：</p><ul><li>限制 NFS 访问IP</li><li>配置防火墙规则</li><li>定期更新系统</li></ul></li><li><p>维护建议：</p><ul><li>定期备份数据</li><li>监控存储使用量</li><li>及时清理无用数据</li></ul></li><li><p>高可用建议：</p><ul><li>配置 NFS 服务器集群</li><li>使用网络存储备份</li><li>配置自动故障转移</li></ul></li></ol>]]></content>
    
    
    <summary type="html">&lt;p&gt; 本文详细介绍如何使用二进制方式在 Debian 系统上搭建一个生产级别的高可用 Kubernetes 集群。&lt;/p&gt;</summary>
    
    
    
    <category term="Kubernetes" scheme="https://freemankevin.uk/categories/Kubernetes/"/>
    
    
    <category term="Debian" scheme="https://freemankevin.uk/tags/Debian/"/>
    
    <category term="Harbor" scheme="https://freemankevin.uk/tags/Harbor/"/>
    
    <category term="Kubernetes" scheme="https://freemankevin.uk/tags/Kubernetes/"/>
    
    <category term="ETCD" scheme="https://freemankevin.uk/tags/ETCD/"/>
    
    <category term="NFS" scheme="https://freemankevin.uk/tags/NFS/"/>
    
  </entry>
  
  <entry>
    <title>Maven 私有仓库使用规范</title>
    <link href="https://freemankevin.uk/2025/02/07/maven-nexus/"/>
    <id>https://freemankevin.uk/2025/02/07/maven-nexus/</id>
    <published>2025-02-07T08:17:25.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p> Maven私有仓库(Nexus)是企业进行依赖管理的重要基础设施。然而在实际使用中,团队常常因配置混乱导致跨团队协作困难,依赖问题频发。比如本地构建或打包时出现异常,公有云仓库与私有仓库混用导致缓存失效,这些都增加了不必要的沟通与排查成本。为此,我们需要统一规范配置,明确依赖管理流程,包括拉取依赖、上传私有包等标准操作方式。通过规范化管理,不仅可以方便项目交接和新人上手,还能充分发挥私有仓库的缓存加速作用,提升团队整体开发效率。本文将详细介绍Maven私有仓库的最佳实践,帮助团队建立起高效的依赖管理体系。</p><span id="more"></span><h2 id="修改Maven配置"><a href="#修改Maven配置" class="headerlink" title="修改Maven配置"></a>修改Maven配置</h2><h3 id="修改settings配置"><a href="#修改settings配置" class="headerlink" title="修改settings配置"></a>修改settings配置</h3><p>私有仓库Nexus信息示例:</p><ul><li>Nexus服务地址: <code>http://nexus.your-company.com:8081/</code></li><li>开发者账号: <code>developer/your-password</code></li><li>Maven公共仓库地址: <code>http://nexus.your-company.com:8081/repository/maven-public/</code></li><li>Maven私有包-稳定版本-上传地址: <code>http://nexus.your-company.com:8081/repository/maven-releases/</code></li><li>Maven私有包-开发版本-上传地址: <code>http://nexus.your-company.com:8081/repository/maven-snapshots/</code></li></ul><p>需要修改settings.xml配置文件,使其完全通过企业内网Nexus访问依赖,而不是直接访问公网仓库。这样可以:</p><ol><li>首次使用时,Nexus会从公网拉取并缓存依赖</li><li>后续使用时直接从Nexus获取缓存的依赖,加快构建速度</li><li>统一管理团队使用的依赖版本</li></ol><p>settings.xml示例配置:</p><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">settings</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">mirrors</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">mirror</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">id</span>&gt;</span>nexus<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>*<span class="tag">&lt;/<span class="name">mirrorOf</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">url</span>&gt;</span>http://nexus.your-company.com:8081/repository/maven-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">servers</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">server</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">id</span>&gt;</span>maven-releases<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">username</span>&gt;</span>$&#123;NEXUS_USERNAME&#125;<span class="tag">&lt;/<span class="name">username</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">password</span>&gt;</span>$&#123;NEXUS_PASSWORD&#125;<span class="tag">&lt;/<span class="name">password</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">server</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">server</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">id</span>&gt;</span>maven-snapshots<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">username</span>&gt;</span>$&#123;NEXUS_USERNAME&#125;<span class="tag">&lt;/<span class="name">username</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">password</span>&gt;</span>$&#123;NEXUS_PASSWORD&#125;<span class="tag">&lt;/<span class="name">password</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">server</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">servers</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><h4 id="公网包支持"><a href="#公网包支持" class="headerlink" title="公网包支持"></a>公网包支持</h4><p>如果在使用内网Maven公共仓库时无法拉取某些公网依赖包:</p><ol><li>可以联系Nexus管理员添加所需的公网仓库源</li><li>默认应该已配置了主流公共仓库(如Maven中央仓库、阿里云Maven仓库等)</li><li>如需添加其他冷门仓库源,请提供仓库地址给管理员统一配置</li></ol><h4 id="内网私有包支持"><a href="#内网私有包支持" class="headerlink" title="内网私有包支持"></a>内网私有包支持</h4><p>如果无法拉取内网私有包:</p><ol><li>优先联系包的开发团队,确认是否已上传到私有仓库</li><li>如未上传,请开发团队先完成上传</li></ol><p>上传私有包到releases仓库:</p><ol><li>通过Nexus Web UI上传</li><li>选择 <code>hosted</code> 类型的仓库才能上传成功</li></ol><h4 id="批量上传包到私库"><a href="#批量上传包到私库" class="headerlink" title="批量上传包到私库"></a>批量上传包到私库</h4><p>对于需要批量上传的场景:</p><ol><li>可以使用maven-deploy插件上传:</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">mvn deploy:deploy-file \</span><br><span class="line">    -Durl=http://nexus.your-company.com:8081/repository/maven-snapshots \</span><br><span class="line">    -DrepositoryId=snapshots \</span><br><span class="line">    -Dfile=your-artifact.jar \</span><br><span class="line">    -DgroupId=com.company \</span><br><span class="line">    -DartifactId=project \</span><br><span class="line">    -Dversion=1.0-SNAPSHOT \</span><br><span class="line">    -Dpackaging=jar</span><br></pre></td></tr></table></figure><ol start="2"><li>也可以使用批量上传工具,如阿里云云效的 <code>migrate-local-repo-tool.jar</code></li></ol><h3 id="修改父POM配置"><a href="#修改父POM配置" class="headerlink" title="修改父POM配置"></a>修改父POM配置</h3><p>在项目顶级pom.xml中配置仓库信息:</p><figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">project</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">repositories</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">repository</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">id</span>&gt;</span>maven-public<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">name</span>&gt;</span>maven-public<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">url</span>&gt;</span>http://nexus.your-company.com:8081/repository/maven-public/<span class="tag">&lt;/<span class="name">url</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">releases</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">enabled</span>&gt;</span>true<span class="tag">&lt;/<span class="name">enabled</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">releases</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">snapshots</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">enabled</span>&gt;</span>true<span class="tag">&lt;/<span class="name">enabled</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">snapshots</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">repository</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">repositories</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">distributionManagement</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">repository</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">id</span>&gt;</span>maven-releases<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">name</span>&gt;</span>maven-releases<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">url</span>&gt;</span>http://nexus.your-company.com:8081/repository/maven-releases/<span class="tag">&lt;/<span class="name">url</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">repository</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">snapshotRepository</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">id</span>&gt;</span>maven-snapshots<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">name</span>&gt;</span>maven-snapshots<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">url</span>&gt;</span>http://nexus.your-company.com:8081/repository/maven-snapshots/<span class="tag">&lt;/<span class="name">url</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">snapshotRepository</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">distributionManagement</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="Nexus仓库说明"><a href="#Nexus仓库说明" class="headerlink" title="Nexus仓库说明"></a>Nexus仓库说明</h3><p>Nexus作为仓库管理工具的主要功能:</p><pre><code class="highlight mermaid">graph LR    A[用户] --&gt; |mvn install / package| B[maven]    B --&gt; C[nexus]    C --&gt; |查找依赖| D&#123;判断&#125;    D -- 存在 --&gt; E[直接返回给用户]    D -- 不存在 --&gt; F[找公网]    F --&gt; G[公共仓库]    G --&gt; H[maven中央仓库]    G -.-&gt; C    C -.-&gt; A</code></pre><h4 id="Maven公共仓库"><a href="#Maven公共仓库" class="headerlink" title="Maven公共仓库"></a>Maven公共仓库</h4><ul><li>用途:存储公共依赖包</li><li>特点:自动从公网仓库同步和缓存</li><li>应用:主要用于依赖解析和下载</li></ul><h4 id="Maven-Releases仓库"><a href="#Maven-Releases仓库" class="headerlink" title="Maven Releases仓库"></a>Maven Releases仓库</h4><ul><li>用途:存储稳定版本构件</li><li>特点:不可变性,版本唯一</li><li>应用:正式发布版本管理</li></ul><h4 id="Maven-Snapshots仓库"><a href="#Maven-Snapshots仓库" class="headerlink" title="Maven Snapshots仓库"></a>Maven Snapshots仓库</h4><ul><li>用途:存储开发版本构件</li><li>特点:可覆盖更新,版本号带-SNAPSHOT后缀</li><li>应用:开发阶段使用</li></ul><h4 id="使用建议"><a href="#使用建议" class="headerlink" title="使用建议"></a>使用建议</h4><ol><li>严格遵循版本命名规范</li><li>合理配置权限管理</li><li>正确配置pom.xml和settings.xml</li><li>确保网络环境正常访问</li></ol>]]></content>
    
    
    <summary type="html">&lt;p&gt; Maven私有仓库(Nexus)是企业进行依赖管理的重要基础设施。然而在实际使用中,团队常常因配置混乱导致跨团队协作困难,依赖问题频发。比如本地构建或打包时出现异常,公有云仓库与私有仓库混用导致缓存失效,这些都增加了不必要的沟通与排查成本。为此,我们需要统一规范配置,明确依赖管理流程,包括拉取依赖、上传私有包等标准操作方式。通过规范化管理,不仅可以方便项目交接和新人上手,还能充分发挥私有仓库的缓存加速作用,提升团队整体开发效率。本文将详细介绍Maven私有仓库的最佳实践,帮助团队建立起高效的依赖管理体系。&lt;/p&gt;</summary>
    
    
    
    <category term="Development" scheme="https://freemankevin.uk/categories/Development/"/>
    
    
    <category term="Nexus" scheme="https://freemankevin.uk/tags/Nexus/"/>
    
    <category term="Maven" scheme="https://freemankevin.uk/tags/Maven/"/>
    
    <category term="Aliyun" scheme="https://freemankevin.uk/tags/Aliyun/"/>
    
  </entry>
  
  <entry>
    <title>GitLab 配置优化与 CICD 集成指南</title>
    <link href="https://freemankevin.uk/2025/01/21/gitlab-cicd/"/>
    <id>https://freemankevin.uk/2025/01/21/gitlab-cicd/</id>
    <published>2025-01-21T09:32:25.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p> 本文档旨在提供 GitLab 配置优化、集成最佳实践、安全加固、备份与恢复策略以及监控方法，帮助团队在使用 GitLab 进行源代码管理和持续集成&#x2F;持续交付（CICD）时提升性能、安全性及稳定性。</p><span id="more"></span><h2 id="GitLab-添加内网信任"><a href="#GitLab-添加内网信任" class="headerlink" title="GitLab 添加内网信任"></a>GitLab 添加内网信任</h2><h3 id="目的"><a href="#目的" class="headerlink" title="目的"></a>目的</h3><p>为 GitLab 配置内网信任，允许 GitLab 访问内网服务。</p><h3 id="操作步骤"><a href="#操作步骤" class="headerlink" title="操作步骤"></a>操作步骤</h3><ol><li>进入 GitLab 管理员界面。</li><li>进入设置页面，选择 <strong>网络</strong>。</li><li>进入 <strong>出站请求</strong>，勾选以下选项：<ul><li>允许来自 <strong>webhooks</strong> 和集成对本地网络的请求</li><li>允许系统钩子向本地网络发送请求</li></ul></li><li>在空白框中粘贴需要调用的内网IP、域名。</li><li>登录 GitLab 服务器，编辑 <strong>&#x2F;etc&#x2F;hosts</strong> 文件，添加自定义域名映射。</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">192.168.x.x traefik.k8scluster.com</span><br><span class="line">192.168.x.x harbor.dockerregistry.com</span><br><span class="line">192.168.x.x argocd.k8scluster.com</span><br><span class="line">192.168.x.x grpc.argocd.k8scluster.com</span><br></pre></td></tr></table></figure><h2 id="GitLab-集成-ArgoCD"><a href="#GitLab-集成-ArgoCD" class="headerlink" title="GitLab 集成 ArgoCD"></a>GitLab 集成 ArgoCD</h2><h3 id="目的-1"><a href="#目的-1" class="headerlink" title="目的"></a>目的</h3><p>通过 GitLab 与 ArgoCD 集成，实现流水线中对 ArgoCD 应用的自动化操作，同时隐藏 ArgoCD 真实服务器信息。</p><h3 id="操作步骤-1"><a href="#操作步骤-1" class="headerlink" title="操作步骤"></a>操作步骤</h3><ol><li>进入项目组页面，选择 <strong>设置</strong> -&gt; <strong>CI&#x2F;CD</strong> -&gt; <strong>变量</strong>。</li><li>添加以下变量：<ul><li><strong>ARGOCD_USERNAME</strong>: 自定义值，勾选 Masked</li><li><strong>ARGOCD_SERVER</strong>: 自定义值，勾选 Masked</li><li><strong>ARGOCD_PASSWORD</strong>: 自定义值，勾选 Masked</li></ul></li></ol><h2 id="GitLab-集成-Minio"><a href="#GitLab-集成-Minio" class="headerlink" title="GitLab 集成 Minio"></a>GitLab 集成 Minio</h2><h3 id="目的-2"><a href="#目的-2" class="headerlink" title="目的"></a>目的</h3><p>将构建的制品存储到 Minio，减轻 GitLab 服务器的负担。</p><h3 id="操作步骤-2"><a href="#操作步骤-2" class="headerlink" title="操作步骤"></a>操作步骤</h3><ol><li><p>修改 GitLab 配置文件：</p> <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo vim /etc/gitlab/gitlab.rb</span><br><span class="line">gitlab_rails[&#x27;artifacts_enabled&#x27;] = true</span><br><span class="line">gitlab_rails[&#x27;artifacts_object_store_enabled&#x27;] = true</span><br><span class="line">gitlab_rails[&#x27;artifacts_object_store_remote_directory&#x27;] = &#x27;gitlab-artifacts&#x27;</span><br><span class="line">gitlab_rails[&#x27;artifacts_object_store_connection&#x27;] = &#123;</span><br><span class="line">&#x27;provider&#x27; =&gt; &#x27;AWS&#x27;,</span><br><span class="line">&#x27;region&#x27; =&gt; &#x27;us-east-1&#x27;,</span><br><span class="line">&#x27;aws_access_key_id&#x27; =&gt; &#x27;your_access_key&#x27;,</span><br><span class="line">&#x27;aws_secret_access_key&#x27; =&gt; &#x27;your_secret_key&#x27;,</span><br><span class="line">&#x27;endpoint&#x27; =&gt; &#x27;http://&lt;minio_server&gt;:9000&#x27;,</span><br><span class="line">&#x27;path_style&#x27; =&gt; true</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>重载配置：</p></li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo gitlab-ctl reconfigure</span><br></pre></td></tr></table></figure><h2 id="GitLab-集成-Harbor"><a href="#GitLab-集成-Harbor" class="headerlink" title="GitLab 集成 Harbor"></a>GitLab 集成 Harbor</h2><h3 id="目的-3"><a href="#目的-3" class="headerlink" title="目的"></a>目的</h3><p>将构建的 Docker 镜像直接推送到 Harbor，无需重复配置。</p><h3 id="操作步骤-3"><a href="#操作步骤-3" class="headerlink" title="操作步骤"></a>操作步骤</h3><ol><li>进入 <strong>管理界面</strong> 或 <strong>项目组管理界面</strong>，选择 <strong>设置</strong> -&gt; <strong>集成</strong>。</li><li>添加 Harbor 集成，输入以下信息：<ul><li><strong>域名</strong>：Harbor 地址</li><li><strong>项目名称</strong>：目标项目</li><li><strong>用户</strong>：使用机器人名称</li><li><strong>用户密码</strong>：Harbor 认证密码</li></ul></li></ol><h2 id="GitLab-文件大小限制调整"><a href="#GitLab-文件大小限制调整" class="headerlink" title="GitLab 文件大小限制调整"></a>GitLab 文件大小限制调整</h2><h3 id="目的-4"><a href="#目的-4" class="headerlink" title="目的"></a>目的</h3><p>调整 GitLab 上传文件的大小限制，以适应大文件的上传需求。</p><h3 id="操作步骤-4"><a href="#操作步骤-4" class="headerlink" title="操作步骤"></a>操作步骤</h3><ol><li><p>进入 <strong>管理员界面</strong> 或 <strong>项目组页面</strong>，选择 <strong>设置</strong> -&gt; <strong>CI&#x2F;CD</strong> -&gt; <strong>流水线通用设置</strong>，调整 <strong>最大工件大小</strong>。</p></li><li><p>如果以上设置无效，修改 GitLab 服务器配置文件：</p> <figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo vim /etc/gitlab/gitlab.rb</span><br><span class="line">nginx[&#x27;client_max_body_size&#x27;] = &#x27;200m&#x27;</span><br></pre></td></tr></table></figure></li><li><p>重载配置：</p></li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo gitlab-ctl reconfigure</span><br></pre></td></tr></table></figure><h2 id="GitLab-集成-CICD"><a href="#GitLab-集成-CICD" class="headerlink" title="GitLab 集成 CICD"></a>GitLab 集成 CICD</h2><h3 id="目的-5"><a href="#目的-5" class="headerlink" title="目的"></a>目的</h3><p>配置 GitLab CI&#x2F;CD，使机器人能够自动化更新代码。</p><h3 id="操作步骤-5"><a href="#操作步骤-5" class="headerlink" title="操作步骤"></a>操作步骤</h3><ol><li>进入项目页面，选择 <strong>设置</strong> -&gt; <strong>访问令牌</strong>，创建一个长期有效的开发者身份令牌。</li><li>进入 <strong>CI&#x2F;CD</strong> -&gt; <strong>变量</strong>，添加以下变量：<ul><li><strong>GITLAB_CI_TOKEN</strong>: 自定义值，勾选 Masked</li></ul></li></ol><h2 id="GitLab-性能优化"><a href="#GitLab-性能优化" class="headerlink" title="GitLab 性能优化"></a>GitLab 性能优化</h2><h3 id="目的-6"><a href="#目的-6" class="headerlink" title="目的"></a>目的</h3><p>优化 GitLab 性能，提高并发处理能力，减少响应时间。</p><h3 id="操作步骤-6"><a href="#操作步骤-6" class="headerlink" title="操作步骤"></a>操作步骤</h3><ol><li><strong>优化数据库</strong>：调整 PostgreSQL 配置，增加 <code>shared_buffers</code> 和 <code>work_mem</code> 设置：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo vim /etc/gitlab/postgresql.conf</span><br><span class="line">shared_buffers = 1GB</span><br><span class="line">work_mem = 64MB</span><br></pre></td></tr></table></figure><ol start="2"><li><strong>启用 Redis 缓存</strong>：配置 GitLab 使用 Redis 缓存：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo vim /etc/gitlab/gitlab.rb</span><br><span class="line">gitlab_rails[&#x27;redis_host&#x27;] = &#x27;localhost&#x27;</span><br><span class="line">gitlab_rails[&#x27;redis_port&#x27;] = 6379</span><br></pre></td></tr></table></figure><ol start="3"><li><p><strong>使用 SSD 存储</strong>：为 GitLab 配置 SSD 存储，提高 I&#x2F;O 性能。</p></li><li><p><strong>优化 Nginx 配置</strong>：调整 Nginx 设置，提高吞吐量：</p></li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo vim /etc/gitlab/nginx/gitlab-http.conf</span><br><span class="line">worker_processes auto;</span><br><span class="line">worker_connections 4096;</span><br></pre></td></tr></table></figure><ol start="5"><li><strong>分离 GitLab 服务</strong>：将 GitLab 服务分离到不同服务器，减轻单台服务器负担。</li></ol><h2 id="GitLab-安全加固"><a href="#GitLab-安全加固" class="headerlink" title="GitLab 安全加固"></a>GitLab 安全加固</h2><h3 id="目的-7"><a href="#目的-7" class="headerlink" title="目的"></a>目的</h3><p>加强 GitLab 的安全性，防止潜在的安全漏洞。</p><h3 id="操作步骤-7"><a href="#操作步骤-7" class="headerlink" title="操作步骤"></a>操作步骤</h3><ol><li><strong>启用 HTTPS</strong>：为 GitLab 配置 SSL，确保数据传输加密：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo vim /etc/gitlab/gitlab.rb</span><br><span class="line">external_url &#x27;https://gitlab.example.com&#x27;</span><br><span class="line">nginx[&#x27;ssl_certificate&#x27;] = &quot;/etc/ssl/certs/gitlab.crt&quot;</span><br><span class="line">nginx[&#x27;ssl_certificate_key&#x27;] = &quot;/etc/ssl/private/gitlab.key&quot;</span><br></pre></td></tr></table></figure><ol start="2"><li><p><strong>启用双因素认证（2FA）</strong>：在 GitLab 设置页面启用 2FA。</p></li><li><p><strong>使用 LDAP 或 OAuth 实现企业认证</strong>：</p></li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo vim /etc/gitlab/gitlab.rb</span><br><span class="line">gitlab_rails[&#x27;ldap_enabled&#x27;] = true</span><br><span class="line">gitlab_rails[&#x27;ldap_servers&#x27;] = YAML.load &lt;&lt;-EOS</span><br><span class="line">main:</span><br><span class="line">  label: &#x27;LDAP&#x27;</span><br><span class="line">  host: &#x27;_your_ldap_server_&#x27;</span><br><span class="line">  port: 389</span><br><span class="line">  uid: &#x27;sAMAccountName&#x27;</span><br><span class="line">  bind_dn: &#x27;CN=bind_user,CN=Users,DC=example,DC=com&#x27;</span><br><span class="line">  password: &#x27;_your_password_&#x27;</span><br><span class="line">EOS</span><br></pre></td></tr></table></figure><h2 id="GitLab-备份与恢复"><a href="#GitLab-备份与恢复" class="headerlink" title="GitLab 备份与恢复"></a>GitLab 备份与恢复</h2><h3 id="目的-8"><a href="#目的-8" class="headerlink" title="目的"></a>目的</h3><p>配置自动备份，以确保 GitLab 数据的安全性。</p><h3 id="操作步骤-8"><a href="#操作步骤-8" class="headerlink" title="操作步骤"></a>操作步骤</h3><ol><li><strong>配置自动备份</strong>：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo vim /etc/gitlab/gitlab.rb</span><br><span class="line">gitlab_rails[&#x27;backup_path&#x27;] = &#x27;/var/opt/gitlab/backups&#x27;</span><br><span class="line">gitlab_rails[&#x27;backup_keep_time&#x27;] = 604800  # 保留7天备份</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置 crontab 定期备份</span></span><br><span class="line">crontab -e</span><br><span class="line">0 2 * * * gitlab-rake gitlab:backup:create</span><br></pre></td></tr></table></figure><ol start="2"><li><strong>恢复备份</strong>：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo gitlab-rake gitlab:backup:restore BACKUP=timestamp_of_backup</span><br></pre></td></tr></table></figure><ol start="3"><li><strong>备份恢复测试</strong>：定期进行恢复测试，确保备份数据可用。</li></ol><h2 id="GitLab-日志与监控"><a href="#GitLab-日志与监控" class="headerlink" title="GitLab 日志与监控"></a>GitLab 日志与监控</h2><h3 id="目的-9"><a href="#目的-9" class="headerlink" title="目的"></a>目的</h3><p>通过日志管理和监控 GitLab 服务，及时发现和解决问题。</p><h3 id="操作步骤-9"><a href="#操作步骤-9" class="headerlink" title="操作步骤"></a>操作步骤</h3><ol><li><strong>配置日志收集</strong>：使用 <code>logrotate</code> 管理 GitLab 日志文件：</li></ol><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo vim /etc/logrotate.d/gitlab</span><br><span class="line">/var/log/gitlab/*.log &#123;</span><br><span class="line">    daily</span><br><span class="line">    rotate 7</span><br><span class="line">    compress</span><br><span class="line">    missingok</span><br><span class="line">    notifempty</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="2"><li><p><strong>使用 Prometheus 和 Grafana 监控 GitLab</strong>：通过 Prometheus 集成监控 GitLab 性能，使用 Grafana 展示数据。</p></li><li><p><strong>设置邮件通知</strong>：配置 GitLab 邮件通知，及时了解系统状态。</p></li></ol><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>本文档涵盖了 GitLab 的常见配置优化、集成 CICD、备份恢复、安全加固和监控等方面。通过这些操作，您可以有效提升 GitLab 的性能、安全性和可靠性。如果您有任何问题或进一步的需求，欢迎留言讨论。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt; 本文档旨在提供 GitLab 配置优化、集成最佳实践、安全加固、备份与恢复策略以及监控方法，帮助团队在使用 GitLab 进行源代码管理和持续集成&amp;#x2F;持续交付（CICD）时提升性能、安全性及稳定性。&lt;/p&gt;</summary>
    
    
    
    <category term="Development" scheme="https://freemankevin.uk/categories/Development/"/>
    
    
    <category term="Development" scheme="https://freemankevin.uk/tags/Development/"/>
    
    <category term="GitLab" scheme="https://freemankevin.uk/tags/GitLab/"/>
    
    <category term="CICD" scheme="https://freemankevin.uk/tags/CICD/"/>
    
  </entry>
  
  <entry>
    <title>如何在 Docker 环境中部署 GitLab Runner</title>
    <link href="https://freemankevin.uk/2025/01/21/docker-runner/"/>
    <id>https://freemankevin.uk/2025/01/21/docker-runner/</id>
    <published>2025-01-21T09:14:25.000Z</published>
    <updated>2026-05-21T06:03:03.314Z</updated>
    
    <content type="html"><![CDATA[<p> 在本篇文章中，我们将介绍如何在 Docker 环境中部署 GitLab Runner，以便使用 GitLab CI&#x2F;CD 实现自动化构建与部署。我们将通过 Docker Compose 配置并管理 GitLab Runner 容器，详细讲解配置文件和注册过程。</p><span id="more"></span><h2 id="部署-GitLab-Runner"><a href="#部署-GitLab-Runner" class="headerlink" title="部署 GitLab Runner"></a>部署 GitLab Runner</h2><p>GitLab Runner 是 GitLab CI&#x2F;CD 的一个组成部分，用于执行 CI&#x2F;CD 作业。本文将介绍如何在 Docker 环境中部署 GitLab Runner，并配置其与 GitLab 服务器的连接。我们将使用 Docker Compose 来管理 GitLab Runner 容器的启动和配置。</p><h3 id="创建-Docker-Compose-配置文件"><a href="#创建-Docker-Compose-配置文件" class="headerlink" title="创建 Docker Compose 配置文件"></a>创建 Docker Compose 配置文件</h3><p>首先，我们需要为 GitLab Runner 创建一个 <code>docker-compose.yml</code> 配置文件。在该文件中，我们定义了 GitLab Runner 容器的基本配置信息，包括使用的镜像、挂载的卷以及容器的特权模式。</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">gitlab-runner-npm:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">gitlab/gitlab-runner:latest</span>  <span class="comment"># 使用 GitLab Runner 的最新版本镜像</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">gitlab-runner-npm</span>  <span class="comment"># 容器名称</span></span><br><span class="line">    <span class="attr">privileged:</span> <span class="literal">true</span>  <span class="comment"># 启用特权模式，允许容器执行 Docker 操作</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span>  <span class="comment"># 容器崩溃时自动重启</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./gitlab-runner/:/etc/gitlab-runner</span>  <span class="comment"># 将本地的 GitLab Runner 配置文件挂载到容器中</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">~/.docker:/root/.docker</span>  <span class="comment"># 将本地 Docker 配置挂载到容器中，确保 Runner 可以使用 Docker 客户端</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/var/run/docker.sock:/var/run/docker.sock</span>  <span class="comment"># 共享 Docker 套接字，允许 Runner 执行 Docker 命令</span></span><br><span class="line">      <span class="comment">#- ./cache:/cache  # 可选的缓存挂载，用于加速构建过程</span></span><br></pre></td></tr></table></figure><p>在这个 <code>docker-compose.yml</code> 文件中，我们挂载了几个目录和文件以确保容器能够正确工作：</p><ul><li><code>./gitlab-runner/</code>：用于存储 GitLab Runner 配置。</li><li><code>~/.docker</code>：将主机上的 Docker 配置挂载到容器中。</li><li><code>/var/run/docker.sock</code>：容器通过这个挂载与宿主机的 Docker 守护进程进行通信，允许 Runner 执行 Docker 命令。</li></ul><h3 id="注册-GitLab-Runner"><a href="#注册-GitLab-Runner" class="headerlink" title="注册 GitLab Runner"></a>注册 GitLab Runner</h3><p>GitLab Runner 需要在注册后才能与 GitLab 服务进行通信。以下是注册 GitLab Runner 的脚本，它通过 Docker 执行 <code>gitlab-runner register</code> 命令。</p><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line"></span><br><span class="line">REGISTRATION_TOKEN=&quot;YOUR_REGISTRATION_TOKEN&quot;  # GitLab 注册令牌，替换为实际值</span><br><span class="line">RUNNER_NAME=&quot;gitlab-runner-npm-group&quot;  # Runner 的名称</span><br><span class="line"></span><br><span class="line">docker exec -it &quot;$&#123;RUNNER_NAME&#125;&quot; gitlab-runner register \</span><br><span class="line">  --non-interactive \</span><br><span class="line">  --url &quot;http://gitlab.example.com/&quot; \  # GitLab 服务器地址，替换为实际地址</span><br><span class="line">  --registration-token &quot;$&#123;REGISTRATION_TOKEN&#125;&quot; \</span><br><span class="line">  --executor &quot;docker&quot; \  # 使用 Docker 执行器</span><br><span class="line">  --docker-image &quot;docker:19.03.12&quot; \  # Docker 镜像，选择适合的版本</span><br><span class="line">  --description &quot;Docker Runner&quot; \  # Runner 描述</span><br><span class="line">  --tag-list &quot;docker-npm&quot; \  # Runner 标签，帮助过滤任务</span><br><span class="line">  --locked=true \  # 锁定 Runner，防止其他 GitLab 实例注册</span><br><span class="line">  --docker-privileged=true \  # 启用 Docker 特权模式</span><br><span class="line">  --run-untagged=false \  # 不运行未打标签的作业</span><br><span class="line">  --docker-tlsverify=false \  # 禁用 Docker TLS 验证</span><br><span class="line">  --docker-disable-entrypoint-overwrite=false \  # 不禁用容器入口点覆盖</span><br><span class="line">  --docker-oom-kill-disable=false \  # 启用 OOM 杀死</span><br><span class="line">  --docker-disable-cache=false \  # 启用 Docker 缓存</span><br><span class="line">  --docker-shm-size=0 \  # 设置共享内存大小</span><br><span class="line">  --cache-type=&quot;s3&quot; \  # 配置 S3 缓存</span><br><span class="line">  --cache-path=&quot;runner&quot; \  # 缓存路径</span><br><span class="line">  --cache-shared=true \  # 启用共享缓存</span><br><span class="line">  --cache-s3-server-address=&quot;s3.example.com:9000&quot; \  # S3 服务器地址，替换为实际值</span><br><span class="line">  --cache-s3-access-key=&quot;YOUR_S3_ACCESS_KEY&quot; \  # S3 访问密钥</span><br><span class="line">  --cache-s3-secret-key=&quot;YOUR_S3_SECRET_KEY&quot; \  # S3 秘密访问密钥</span><br><span class="line">  --cache-s3-bucket-name=&quot;runner-cache&quot; \  # S3 存储桶名称</span><br><span class="line">  --cache-s3-insecure=true  # 启用不安全连接</span><br></pre></td></tr></table></figure><h3 id="GitLab-Runner-配置"><a href="#GitLab-Runner-配置" class="headerlink" title="GitLab Runner 配置"></a>GitLab Runner 配置</h3><p>在容器中，我们可以编辑 GitLab Runner 的配置文件 <code>config.toml</code>，以设置并优化 Runner 的行为。以下是 <code>config.toml</code> 文件的示例，其中包含了多个重要的配置项：</p><figure class="highlight toml"><table><tr><td class="code"><pre><span class="line"><span class="attr">concurrent</span> = <span class="number">1</span>  <span class="comment"># 限制同时运行的作业数</span></span><br><span class="line"><span class="attr">check_interval</span> = <span class="number">0</span>  <span class="comment"># 检查任务队列的间隔时间</span></span><br><span class="line"></span><br><span class="line"><span class="section">[session_server]</span></span><br><span class="line">  <span class="attr">session_timeout</span> = <span class="number">1800</span>  <span class="comment"># 会话超时设置（单位：秒）</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 class="comment"># Runner 名称</span></span><br><span class="line">  <span class="attr">url</span> = <span class="string">&quot;http://gitlab.example.com/&quot;</span>  <span class="comment"># GitLab 实例的 URL</span></span><br><span class="line">  <span class="attr">token</span> = <span class="string">&quot;YOUR_REGISTRATION_TOKEN&quot;</span>  <span class="comment"># 注册令牌，替换为实际值</span></span><br><span class="line">  <span class="attr">executor</span> = <span class="string">&quot;docker&quot;</span>  <span class="comment"># 使用 Docker 执行作业</span></span><br><span class="line"></span><br><span class="line">  <span class="section">[runners.custom_build_dir]</span></span><br><span class="line">  <span class="comment">#[runners.cache]  # 缓存配置，通常用于加速构建过程</span></span><br><span class="line">  <span class="comment">#  Type = &quot;local&quot;</span></span><br><span class="line">  <span class="comment">#  Path = &quot;/cache&quot;</span></span><br><span class="line">  <span class="comment">#  Shared = true</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 class="comment"># 使用 S3 作为缓存类型</span></span><br><span class="line">    <span class="attr">Path</span> = <span class="string">&quot;runner&quot;</span>  <span class="comment"># 缓存路径</span></span><br><span class="line">    <span class="attr">Shared</span> = <span class="literal">true</span>  <span class="comment"># 启用共享缓存</span></span><br><span class="line">    <span class="section">[runners.cache.s3]</span></span><br><span class="line">      <span class="attr">ServerAddress</span> = <span class="string">&quot;s3.example.com:9000&quot;</span>  <span class="comment"># S3 服务器地址，替换为实际地址</span></span><br><span class="line">      <span class="attr">AccessKey</span> = <span class="string">&quot;YOUR_S3_ACCESS_KEY&quot;</span>  <span class="comment"># S3 访问密钥</span></span><br><span class="line">      <span class="attr">SecretKey</span> = <span class="string">&quot;YOUR_S3_SECRET_KEY&quot;</span>  <span class="comment"># S3 秘密访问密钥</span></span><br><span class="line">      <span class="attr">BucketName</span> = <span class="string">&quot;runner-cache&quot;</span>  <span class="comment"># S3 存储桶名称</span></span><br><span class="line">      <span class="attr">Insecure</span> = <span class="literal">true</span>  <span class="comment"># 启用不安全连接</span></span><br><span class="line"></span><br><span class="line">  <span class="section">[runners.docker]</span></span><br><span class="line">    <span class="attr">tls_verify</span> = <span class="literal">false</span>  <span class="comment"># 禁用 Docker TLS 验证</span></span><br><span class="line">    <span class="attr">image</span> = <span class="string">&quot;docker:19.03.12&quot;</span>  <span class="comment"># Docker 镜像版本</span></span><br><span class="line">    <span class="attr">privileged</span> = <span class="literal">true</span>  <span class="comment"># 启用特权模式</span></span><br><span class="line">    <span class="attr">disable_entrypoint_overwrite</span> = <span class="literal">false</span>  <span class="comment"># 启用容器入口点覆盖</span></span><br><span class="line">    <span class="attr">oom_kill_disable</span> = <span class="literal">false</span>  <span class="comment"># 启用 OOM 杀死</span></span><br><span class="line">    <span class="attr">disable_cache</span> = <span class="literal">false</span>  <span class="comment"># 启用缓存</span></span><br><span class="line">    <span class="attr">volumes</span> = [<span class="string">&quot;/cache&quot;</span>]  <span class="comment"># 挂载的目录</span></span><br><span class="line">    <span class="attr">shm_size</span> = <span class="number">536870912</span>  <span class="comment"># 设置共享内存大小</span></span><br><span class="line">    <span class="attr">memory</span> = <span class="string">&quot;24000m&quot;</span>  <span class="comment"># 分配内存</span></span><br><span class="line">    <span class="attr">memory_swap</span> = <span class="string">&quot;26g&quot;</span>  <span class="comment"># 设置交换内存</span></span><br><span class="line">    <span class="attr">cpus</span> = <span class="string">&quot;12&quot;</span>  <span class="comment"># 分配 CPU 核数</span></span><br><span class="line">    <span class="attr">allowed_images</span> = [  <span class="comment"># 限制 Runner 使用的镜像列表</span></span><br><span class="line">      <span class="string">&quot;harbor.dockerregistry.com/kubernetes/maven:3.6.3-openjdk-8-slim&quot;</span>,</span><br><span class="line">      <span class="string">&quot;harbor.dockerregistry.com/kubernetes/kaniko-project/executor:v1.14.0-debug&quot;</span>,</span><br><span class="line">      <span class="string">&quot;harbor.dockerregistry.com/kubernetes/argocli-git:v2.7.14&quot;</span>,</span><br><span class="line">      <span class="string">&quot;harbor.dockerregistry.com/kubernetes/nodejs:*&quot;</span></span><br><span class="line">    ]</span><br></pre></td></tr></table></figure><h4 id="重要配置说明："><a href="#重要配置说明：" class="headerlink" title="重要配置说明："></a>重要配置说明：</h4><ul><li><strong><code>privileged</code></strong>：启用特权模式，允许容器执行 Docker 操作。这是必需的，因为 GitLab Runner 需要能够在容器中执行构建任务。</li><li><strong><code>executor</code></strong>：指定运行作业的执行器，通常为 <code>docker</code>，可以在容器中运行任务。</li><li><strong><code>volumes</code></strong>：挂载卷，允许容器访问宿主机的文件系统。例如，挂载 Docker 套接字和共享缓存目录。</li><li><strong><code>memory</code> 和 <code>cpus</code></strong>：为 Runner 分配内存和 CPU 资源，根据需要调整这些参数以优化构建性能。</li></ul><h3 id="启动-GitLab-Runner"><a href="#启动-GitLab-Runner" class="headerlink" title="启动 GitLab Runner"></a>启动 GitLab Runner</h3><p>完成以上配置后，我们可以通过以下命令启动 GitLab Runner 容器：</p><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">docker-compose up -d  # 在后台启动服务</span><br></pre></td></tr></table></figure><p>这将启动 GitLab Runner，并且它会自动与 GitLab 实例注册。您可以登录 GitLab 查看 Runner 是否成功注册并开始处理作业。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt; 在本篇文章中，我们将介绍如何在 Docker 环境中部署 GitLab Runner，以便使用 GitLab CI&amp;#x2F;CD 实现自动化构建与部署。我们将通过 Docker Compose 配置并管理 GitLab Runner 容器，详细讲解配置文件和注册过程。&lt;/p&gt;</summary>
    
    
    
    <category term="Development" scheme="https://freemankevin.uk/categories/Development/"/>
    
    
    <category term="Docker" scheme="https://freemankevin.uk/tags/Docker/"/>
    
    <category term="GitLab Runner" scheme="https://freemankevin.uk/tags/GitLab-Runner/"/>
    
    <category term="GitLab" scheme="https://freemankevin.uk/tags/GitLab/"/>
    
  </entry>
  
  <entry>
    <title>如何在Kubernetes 环境中安装 Grafana 部署指南</title>
    <link href="https://freemankevin.uk/2025/01/21/k8s-grafana/"/>
    <id>https://freemankevin.uk/2025/01/21/k8s-grafana/</id>
    <published>2025-01-21T08:53:25.000Z</published>
    <updated>2026-05-21T06:03:03.318Z</updated>
    
    <content type="html"><![CDATA[<p> 本文介绍如何通过 Helm 部署 Grafana 并配置反向代理，以便在 Kubernetes 集群中使用 Grafana，支持 HTTPS 加密和基本认证。</p><span id="more"></span><h2 id="下载-Helm-Chart"><a href="#下载-Helm-Chart" class="headerlink" title="下载 Helm Chart"></a>下载 Helm Chart</h2><p>首先创建目录并下载 Grafana 的 Helm Chart。</p><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">mkdir -p grafana </span><br><span class="line">cd grafana</span><br><span class="line">helm repo add grafana https://grafana.github.io/helm-charts</span><br><span class="line">helm repo update</span><br><span class="line">helm search repo grafana/grafana -l</span><br><span class="line">helm search repo grafana/grafana --versions</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">如果需要下载指定版本</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">helm pull grafana/grafana --version 7.2.3</span> </span><br><span class="line">tar xf grafana-7.2.3.tgz</span><br><span class="line">cp -rvf grafana/values.yaml&#123;,.bak&#125;</span><br></pre></td></tr></table></figure><h2 id="创建自定义-values-yaml"><a href="#创建自定义-values-yaml" class="headerlink" title="创建自定义 values.yaml"></a>创建自定义 <code>values.yaml</code></h2><p>Grafana 的 <code>values.yaml</code> 文件用于配置 Helm Chart 部署的参数。以下是常用的配置项：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">image:</span></span><br><span class="line">  <span class="attr">registry:</span> <span class="string">docker.io</span></span><br><span class="line">  <span class="attr">repository:</span> <span class="string">grafana/grafana</span></span><br><span class="line">  <span class="attr">tag:</span> <span class="string">&quot;10.2.3&quot;</span>  <span class="comment"># 修改为固定版本的镜像标签</span></span><br><span class="line">  </span><br><span class="line"><span class="attr">ingress:</span></span><br><span class="line">  <span class="attr">enabled:</span> <span class="literal">true</span>  <span class="comment"># 启用 Ingress</span></span><br><span class="line">  <span class="attr">annotations:</span>  <span class="comment"># 添加注释</span></span><br><span class="line">    <span class="attr">kubernetes.io/ingress.class:</span> <span class="string">&quot;nginx&quot;</span></span><br><span class="line">    <span class="attr">nginx.ingress.kubernetes.io/rewrite-target:</span> <span class="string">/$1</span></span><br><span class="line">    <span class="attr">nginx.ingress.kubernetes.io/use-regex:</span> <span class="string">&quot;true&quot;</span></span><br><span class="line">  <span class="attr">hosts:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">grafana.k8scluster.com</span>  <span class="comment"># 使用域名访问 Grafana</span></span><br><span class="line">  </span><br><span class="line"><span class="attr">persistence:</span></span><br><span class="line">  <span class="attr">type:</span> <span class="string">pvc</span> </span><br><span class="line">  <span class="attr">enabled:</span> <span class="literal">true</span>  <span class="comment"># 启用 PVC 持久化存储</span></span><br><span class="line">  <span class="attr">storageClassName:</span> <span class="string">default</span>  <span class="comment"># 使用默认存储类</span></span><br><span class="line">  <span class="attr">accessModes:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">ReadWriteOnce</span></span><br><span class="line">  <span class="attr">size:</span> <span class="string">1Gi</span>  <span class="comment"># 设置 PVC 大小为 1Gi</span></span><br><span class="line"></span><br><span class="line"><span class="attr">extraVolumeMounts:</span>  <span class="comment"># 配置额外的挂载路径</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">grafana-data</span></span><br><span class="line">    <span class="attr">mountPath:</span> <span class="string">/var/lib/grafana/plugins</span></span><br><span class="line">    <span class="attr">subPath:</span> <span class="string">plugins</span></span><br><span class="line">    <span class="attr">readOnly:</span> <span class="literal">false</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">grafana-data</span></span><br><span class="line">    <span class="attr">mountPath:</span> <span class="string">/var/lib/grafana/dashboards</span></span><br><span class="line">    <span class="attr">subPath:</span> <span class="string">dashboards</span></span><br><span class="line">    <span class="attr">readOnly:</span> <span class="literal">false</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">grafana-data</span></span><br><span class="line">    <span class="attr">mountPath:</span> <span class="string">/etc/grafana/provisioning</span></span><br><span class="line">    <span class="attr">subPath:</span> <span class="string">provisioning</span></span><br><span class="line">    <span class="attr">readOnly:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="attr">extraVolumes:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">grafana-data</span></span><br><span class="line">    <span class="attr">persistentVolumeClaim:</span></span><br><span class="line">      <span class="attr">claimName:</span> <span class="string">grafana-data-pvc</span>  <span class="comment"># 使用指定的 PVC</span></span><br></pre></td></tr></table></figure><h3 id="配置解释"><a href="#配置解释" class="headerlink" title="配置解释"></a>配置解释</h3><ul><li><p><strong>镜像配置 (<code>image</code>)</strong>：选择正确的 Grafana 镜像版本。这里的 <code>tag</code> 参数设置为具体版本，如 <code>10.2.3</code>。</p></li><li><p><strong>Ingress 配置 (<code>ingress</code>)</strong>：</p><ul><li>启用 Ingress 以便通过域名访问 Grafana。</li><li><code>nginx.ingress.kubernetes.io/rewrite-target</code>：将请求路径重写为适合 Grafana 的路径。</li><li><code>path</code> 和 <code>pathType</code> 配置了访问路径，并使用正则匹配来灵活处理请求。</li><li><code>hosts</code> 配置为本地域名，确保 Grafana 可以通过指定域名访问。</li></ul></li><li><p><strong>持久化配置 (<code>persistence</code>)</strong>：</p><ul><li>使用 PVC 进行持久化存储，以便在 Grafana Pod 重启时不会丢失数据。</li><li>配置存储大小为 <code>1Gi</code>，并选择合适的存储类 <code>default</code>。</li></ul></li><li><p><strong>额外的挂载配置 (<code>extraVolumeMounts</code>)</strong>：</p><ul><li>将 Grafana 的插件、仪表盘和配置文件夹挂载到指定路径，确保 Grafana 启动时能够使用这些资源。</li></ul></li></ul><h2 id="使用-Helm-安装-Grafana"><a href="#使用-Helm-安装-Grafana" class="headerlink" title="使用 Helm 安装 Grafana"></a>使用 Helm 安装 Grafana</h2><p>使用以下命令来安装 Grafana 并指定自定义的 <code>values.yaml</code> 配置文件：</p><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">helm install grafana -f grafana/values.yaml ./grafana --namespace grafana --create-namespace</span><br></pre></td></tr></table></figure><h3 id="安装完成后输出"><a href="#安装完成后输出" class="headerlink" title="安装完成后输出"></a>安装完成后输出</h3><p>安装完成后，您可以通过以下命令获取 Grafana 的默认管理员密码：</p><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">kubectl get secret --namespace grafana grafana -o jsonpath=&quot;&#123;.data.admin-password&#125;&quot; | base64 --decode ; echo</span><br></pre></td></tr></table></figure><p>Grafana 控制台可以通过以下 DNS 地址访问：</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">http://grafana.k8scluster.com</span><br></pre></td></tr></table></figure><p>登录时，使用管理员账户 <code>admin</code> 和密码。</p><h2 id="更新-Helm-部署"><a href="#更新-Helm-部署" class="headerlink" title="更新 Helm 部署"></a>更新 Helm 部署</h2><p>若需要对已部署的 Grafana 进行更新（例如修改配置），可以使用以下命令：</p><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">helm upgrade grafana -f grafana/values.yaml ./grafana --namespace grafana</span><br></pre></td></tr></table></figure><h3 id="更新后输出"><a href="#更新后输出" class="headerlink" title="更新后输出"></a>更新后输出</h3><p>更新后同样可以通过以下命令获取更新后的管理员密码：</p><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">kubectl get secret --namespace grafana grafana -o jsonpath=&quot;&#123;.data.admin-password&#125;&quot; | base64 --decode ; echo</span><br></pre></td></tr></table></figure><h2 id="登录-Grafana-控制台"><a href="#登录-Grafana-控制台" class="headerlink" title="登录 Grafana 控制台"></a>登录 Grafana 控制台</h2><p>Grafana 控制台可以通过浏览器访问以下地址：</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">http://grafana.k8scluster.com:30886/grafana</span><br></pre></td></tr></table></figure><p>登录时，使用之前获取的管理员密码进行登录。</p><h2 id="导出-Prometheus-和-Alertmanager"><a href="#导出-Prometheus-和-Alertmanager" class="headerlink" title="导出 Prometheus 和 Alertmanager"></a>导出 Prometheus 和 Alertmanager</h2><h3 id="创建-Prometheus-和-Alertmanager-的-Ingress"><a href="#创建-Prometheus-和-Alertmanager-的-Ingress" class="headerlink" title="创建 Prometheus 和 Alertmanager 的 Ingress"></a>创建 Prometheus 和 Alertmanager 的 Ingress</h3><p>为 Prometheus 和 Alertmanager 创建一个 Ingress 资源，使其通过域名访问。</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">kind:</span> <span class="string">Ingress</span></span><br><span class="line"><span class="attr">apiVersion:</span> <span class="string">networking.k8s.io/v1</span></span><br><span class="line"><span class="attr">metadata:</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">prometheus-ingress</span></span><br><span class="line">  <span class="attr">namespace:</span> <span class="string">kubesphere-monitoring-system</span></span><br><span class="line">  <span class="attr">annotations:</span></span><br><span class="line">    <span class="attr">nginx.ingress.kubernetes.io/auth-realm:</span> <span class="string">Authentication</span> <span class="string">Required</span></span><br><span class="line">    <span class="attr">nginx.ingress.kubernetes.io/auth-secret:</span> <span class="string">prometheus-basic-auth</span></span><br><span class="line">    <span class="attr">nginx.ingress.kubernetes.io/auth-type:</span> <span class="string">basic</span></span><br><span class="line">    <span class="attr">nginx.ingress.kubernetes.io/proxy-body-size:</span> <span class="string">2048m</span></span><br><span class="line">    <span class="attr">nginx.ingress.kubernetes.io/proxy-connect-timeout:</span> <span class="string">&#x27;1800&#x27;</span></span><br><span class="line">    <span class="attr">nginx.ingress.kubernetes.io/proxy-read-timeout:</span> <span class="string">&#x27;1800&#x27;</span></span><br><span class="line">    <span class="attr">nginx.ingress.kubernetes.io/proxy-send-timeout:</span> <span class="string">&#x27;1800&#x27;</span></span><br><span class="line"><span class="attr">spec:</span></span><br><span class="line">  <span class="attr">ingressClassName:</span> <span class="string">nginx</span></span><br><span class="line">  <span class="attr">rules:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">host:</span> <span class="string">prometheus.k8scluster.com</span></span><br><span class="line">      <span class="attr">http:</span></span><br><span class="line">        <span class="attr">paths:</span></span><br><span class="line">          <span class="bullet">-</span> <span class="attr">path:</span> <span class="string">/</span></span><br><span class="line">            <span class="attr">pathType:</span> <span class="string">Prefix</span></span><br><span class="line">            <span class="attr">backend:</span></span><br><span class="line">              <span class="attr">service:</span></span><br><span class="line">                <span class="attr">name:</span> <span class="string">prometheus-k8s</span></span><br><span class="line">                <span class="attr">port:</span></span><br><span class="line">                  <span class="attr">name:</span> <span class="string">web</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">host:</span> <span class="string">alertmanager.k8scluster.com</span></span><br><span class="line">      <span class="attr">http:</span></span><br><span class="line">        <span class="attr">paths:</span></span><br><span class="line">          <span class="bullet">-</span> <span class="attr">path:</span> <span class="string">/</span></span><br><span class="line">            <span class="attr">pathType:</span> <span class="string">Prefix</span></span><br><span class="line">            <span class="attr">backend:</span></span><br><span class="line">              <span class="attr">service:</span></span><br><span class="line">                <span class="attr">name:</span> <span class="string">alertmanager-main</span></span><br><span class="line">                <span class="attr">port:</span></span><br><span class="line">                  <span class="attr">name:</span> <span class="string">web</span></span><br></pre></td></tr></table></figure><h3 id="创建-HTTP-基本认证"><a href="#创建-HTTP-基本认证" class="headerlink" title="创建 HTTP 基本认证"></a>创建 HTTP 基本认证</h3><p>通过 <code>htpasswd</code> 创建一个基本认证文件，并将其作为 Secret 存储：</p><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">htpasswd -c auth admin  # 设置管理员密码</span><br></pre></td></tr></table></figure><h3 id="创建-Secret"><a href="#创建-Secret" class="headerlink" title="创建 Secret"></a>创建 Secret</h3><p>创建 Kubernetes Secret，用于存储基本认证凭证：</p><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">kubectl create secret generic prometheus-basic-auth --from-file=auth -n monitoring</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt; 本文介绍如何通过 Helm 部署 Grafana 并配置反向代理，以便在 Kubernetes 集群中使用 Grafana，支持 HTTPS 加密和基本认证。&lt;/p&gt;</summary>
    
    
    
    <category term="Kubernetes" scheme="https://freemankevin.uk/categories/Kubernetes/"/>
    
    
    <category term="TLS" scheme="https://freemankevin.uk/tags/TLS/"/>
    
    <category term="KubeSphere" scheme="https://freemankevin.uk/tags/KubeSphere/"/>
    
    <category term="Ingress-NGINX" scheme="https://freemankevin.uk/tags/Ingress-NGINX/"/>
    
  </entry>
  
</feed>
