<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Linux on WYF 的技术博客</title><link>https://saflyer.cn/tags/linux/</link><description>Recent content in Linux on WYF 的技术博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Wed, 16 Sep 2026 14:59:14 +0800</lastBuildDate><atom:link href="https://saflyer.cn/tags/linux/index.xml" rel="self" type="application/rss+xml"/><item><title>Linux运维 02：一台服务器再搭一套完全隔离的 Jenkins（华为云 EulerOS 实战）</title><link>https://saflyer.cn/posts/jenkins-dual-instance-docker/</link><pubDate>Wed, 16 Sep 2026 14:59:14 +0800</pubDate><guid>https://saflyer.cn/posts/jenkins-dual-instance-docker/</guid><description>&lt;img src="https://saflyer.cn/posts/jenkins-dual-instance-docker/cover.webp" alt="Featured image of post Linux运维 02：一台服务器再搭一套完全隔离的 Jenkins（华为云 EulerOS 实战）" /&gt;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;场景：服务器上已经跑着一套给老项目用的 Jenkins（8080 端口），新项目（myapp）需要一套&lt;strong&gt;完全独立&lt;/strong&gt;的 Jenkins——独立端口、独立 home 目录、独立插件体系，互不影响。&#10;系统：Huawei Cloud EulerOS 2.0 (x86_64)，部署方式：Docker + docker-compose。&#10;本文记录从环境调研到初始化、升级、工具配置的全过程，以及踩到的 4 个坑。&#10;（文中密码、密钥均已脱敏，请替换成自己的。）&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="一先看清楚家底环境调研"&gt;&lt;a href="#%e4%b8%80%e5%85%88%e7%9c%8b%e6%b8%85%e6%a5%9a%e5%ae%b6%e5%ba%95%e7%8e%af%e5%a2%83%e8%b0%83%e7%a0%94" class="header-anchor"&gt;&lt;/a&gt;一、先看清楚家底：环境调研&#10;&lt;/h2&gt;&lt;h3 id="11-系统源里有什么-java一个坏消息"&gt;&lt;a href="#11-%e7%b3%bb%e7%bb%9f%e6%ba%90%e9%87%8c%e6%9c%89%e4%bb%80%e4%b9%88-java%e4%b8%80%e4%b8%aa%e5%9d%8f%e6%b6%88%e6%81%af" class="header-anchor"&gt;&lt;/a&gt;1.1 系统源里有什么 Java？——一个坏消息&#10;&lt;/h3&gt;&lt;p&gt;新项目后端是 Spring Boot 3.x，要求 &lt;strong&gt;Java 17+&lt;/strong&gt;。按惯例先查系统源：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-0-1"&gt;&lt;a class="lnlinks" href="#hl-0-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-2"&gt;&lt;a class="lnlinks" href="#hl-0-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-3"&gt;&lt;a class="lnlinks" href="#hl-0-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-4"&gt;&lt;a class="lnlinks" href="#hl-0-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-5"&gt;&lt;a class="lnlinks" href="#hl-0-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /etc/os-release&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# NAME=&amp;#34;Huawei Cloud EulerOS&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# VERSION=&amp;#34;2.0 (x86_64)&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yum list available 2&amp;gt;/dev/null &lt;span class="p"&gt;|&lt;/span&gt; grep -iE &lt;span class="s1"&gt;&amp;#39;openjdk&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;结果只有：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-1-1"&gt;&lt;a class="lnlinks" href="#hl-1-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-2"&gt;&lt;a class="lnlinks" href="#hl-1-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;java-1.8.0-openjdk 1:1.8.0.432.b06-0.hce2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;java-11-openjdk 1:11.0.30.7-0.hce2&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;结论：HCE 2.0 的 yum/dnf 源里没有 java-21-openjdk，连 java-17 也没有&lt;/strong&gt;，只有 1.8 和 11。直接 &lt;code&gt;yum install java-21-openjdk&lt;/code&gt; 必然报&amp;quot;没有任何匹配&amp;quot;。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;dnf 和 yum 在 HCE 上是同一个源，换命令没用。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;这件事直接影响了后面的技术选型：&lt;strong&gt;所有 Java 都不装在系统上&lt;/strong&gt;——Jenkins 本体用官方镜像（自带 JDK），构建用 JDK 来自 Adoptium 官方 tar.gz 解压包，应用运行用 Docker 镜像。系统层面零 Java 安装。&lt;/p&gt;&#10;&lt;h3 id="12-旧-jenkins-是怎么部署的"&gt;&lt;a href="#12-%e6%97%a7-jenkins-%e6%98%af%e6%80%8e%e4%b9%88%e9%83%a8%e7%bd%b2%e7%9a%84" class="header-anchor"&gt;&lt;/a&gt;1.2 旧 Jenkins 是怎么部署的？&#10;&lt;/h3&gt;&lt;p&gt;服务器上已有一套给 bid 项目用的 Jenkins，先摸清它的部署方式（照抄成熟经验，避开它的资源）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-2-1"&gt;&lt;a class="lnlinks" href="#hl-2-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-2-2"&gt;&lt;a class="lnlinks" href="#hl-2-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-2-3"&gt;&lt;a class="lnlinks" href="#hl-2-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-2-4"&gt;&lt;a class="lnlinks" href="#hl-2-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# jenkins 0.0.0.0:8080-&amp;gt;8080/tcp, 0.0.0.0:50000-&amp;gt;50000/tcp&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat /home/compose/docker-compose.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-3-1"&gt;&lt;a class="lnlinks" href="#hl-3-1"&gt; 1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-2"&gt;&lt;a class="lnlinks" href="#hl-3-2"&gt; 2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-3"&gt;&lt;a class="lnlinks" href="#hl-3-3"&gt; 3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-4"&gt;&lt;a class="lnlinks" href="#hl-3-4"&gt; 4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-5"&gt;&lt;a class="lnlinks" href="#hl-3-5"&gt; 5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-6"&gt;&lt;a class="lnlinks" href="#hl-3-6"&gt; 6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-7"&gt;&lt;a class="lnlinks" href="#hl-3-7"&gt; 7&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-8"&gt;&lt;a class="lnlinks" href="#hl-3-8"&gt; 8&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-9"&gt;&lt;a class="lnlinks" href="#hl-3-9"&gt; 9&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-10"&gt;&lt;a class="lnlinks" href="#hl-3-10"&gt;10&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-11"&gt;&lt;a class="lnlinks" href="#hl-3-11"&gt;11&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-12"&gt;&lt;a class="lnlinks" href="#hl-3-12"&gt;12&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-13"&gt;&lt;a class="lnlinks" href="#hl-3-13"&gt;13&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-14"&gt;&lt;a class="lnlinks" href="#hl-3-14"&gt;14&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-15"&gt;&lt;a class="lnlinks" href="#hl-3-15"&gt;15&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-16"&gt;&lt;a class="lnlinks" href="#hl-3-16"&gt;16&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-17"&gt;&lt;a class="lnlinks" href="#hl-3-17"&gt;17&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-18"&gt;&lt;a class="lnlinks" href="#hl-3-18"&gt;18&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-19"&gt;&lt;a class="lnlinks" href="#hl-3-19"&gt;19&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;jenkins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jenkins/jenkins:lts&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jenkins&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;privileged&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;root&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;TZ=Asia/Shanghai&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;8080:8080&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;50000:50000&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./jenkins_home:/var/jenkins_home&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/root/.m2/repository/:/root/.m2/repository/&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./jdk17/:/usr/local/jdk17/&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;extra_hosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;git.example.com:10.10.10.15&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;关键信息：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;项目&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;旧实例情况&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;对新实例的影响&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;端口&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;8080（Web）+ 50000（Agent）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;新实例必须换端口&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;编排目录&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/home/compose/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;新实例用独立目录&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;版本&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2.541.1 (LTS)，镜像 &lt;code&gt;jenkins/jenkins:lts&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;可复用本地镜像，不用重新拉&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;运行 JDK&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;镜像自带 Temurin 21.0.9&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不用管&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;构建 JDK&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;宿主机 &lt;code&gt;/home/compose/jdk17&lt;/code&gt;（Temurin 17.0.18+8，Adoptium tar.gz 解压）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;可以只读挂载复用&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;docker.sock + privileged&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;任务里能直接操作宿主机 Docker&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;新实例不挂，隔离&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;extra_hosts&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;内网 Git &lt;code&gt;git.example.com&lt;/code&gt; → &lt;code&gt;10.10.10.15&lt;/code&gt;，DNS 不解析&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;新实例必须照配，否则拉不了代码&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;已有任务&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;4 个 bid 项目任务，生产在用&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;一个字都不能动&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;另外确认宿主机资源充足（内存 15G 剩 13G，磁盘剩 76G），跑第二个 Jenkins 没压力。&lt;/p&gt;&#10;&lt;h2 id="二方案设计怎么算完全隔离"&gt;&lt;a href="#%e4%ba%8c%e6%96%b9%e6%a1%88%e8%ae%be%e8%ae%a1%e6%80%8e%e4%b9%88%e7%ae%97%e5%ae%8c%e5%85%a8%e9%9a%94%e7%a6%bb" class="header-anchor"&gt;&lt;/a&gt;二、方案设计：怎么算&amp;quot;完全隔离&amp;quot;&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;维度&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;旧实例&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;新实例（jenkins2）&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;编排目录&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/home/compose/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/home/compose-jenkins2/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;容器名&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;jenkins&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;jenkins2&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Web 端口&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;8080&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;8082&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Agent 端口&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;50000&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;50001&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;home 卷&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;./jenkins_home&lt;/code&gt;（6.4G，197 个插件）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;全新空目录&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;运行用户&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;root（privileged）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;镜像默认 jenkins（uid 1000）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;docker.sock&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;挂载&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;不挂&lt;/strong&gt;（任务不能直接动宿主机 Docker）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;.m2 仓库&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;挂宿主机&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不挂，独立&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;jdk17&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;读写挂载&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;只读挂载复用&lt;/strong&gt;（&lt;code&gt;:ro&lt;/code&gt;）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;选 8082/50001 之前先查端口占用：&lt;code&gt;ss -tln&lt;/code&gt;，确认 8080/50000/8081 都已被占，8082/50001 空闲。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="三创建-jenkins2"&gt;&lt;a href="#%e4%b8%89%e5%88%9b%e5%bb%ba-jenkins2" class="header-anchor"&gt;&lt;/a&gt;三、创建 jenkins2&#10;&lt;/h2&gt;&lt;h3 id="31-第一版-compose先跑起来"&gt;&lt;a href="#31-%e7%ac%ac%e4%b8%80%e7%89%88-compose%e5%85%88%e8%b7%91%e8%b5%b7%e6%9d%a5" class="header-anchor"&gt;&lt;/a&gt;3.1 第一版 compose：先跑起来&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-4-1"&gt;&lt;a class="lnlinks" href="#hl-4-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-2"&gt;&lt;a class="lnlinks" href="#hl-4-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-3"&gt;&lt;a class="lnlinks" href="#hl-4-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p /home/compose-jenkins2/jenkins_home&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chown -R 1000:1000 /home/compose-jenkins2/jenkins_home &lt;span class="c1"&gt;# 容器内 jenkins 用户 uid=1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /home/compose-jenkins2&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-5-1"&gt;&lt;a class="lnlinks" href="#hl-5-1"&gt; 1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-2"&gt;&lt;a class="lnlinks" href="#hl-5-2"&gt; 2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-3"&gt;&lt;a class="lnlinks" href="#hl-5-3"&gt; 3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-4"&gt;&lt;a class="lnlinks" href="#hl-5-4"&gt; 4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-5"&gt;&lt;a class="lnlinks" href="#hl-5-5"&gt; 5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-6"&gt;&lt;a class="lnlinks" href="#hl-5-6"&gt; 6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-7"&gt;&lt;a class="lnlinks" href="#hl-5-7"&gt; 7&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-8"&gt;&lt;a class="lnlinks" href="#hl-5-8"&gt; 8&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-9"&gt;&lt;a class="lnlinks" href="#hl-5-9"&gt; 9&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-10"&gt;&lt;a class="lnlinks" href="#hl-5-10"&gt;10&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-11"&gt;&lt;a class="lnlinks" href="#hl-5-11"&gt;11&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-12"&gt;&lt;a class="lnlinks" href="#hl-5-12"&gt;12&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;jenkins2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jenkins/jenkins:lts&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jenkins2&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;TZ=Asia/Shanghai&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;8082:8080&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;50001:50000&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./jenkins_home:/var/jenkins_home&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-6-1"&gt;&lt;a class="lnlinks" href="#hl-6-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-2"&gt;&lt;a class="lnlinks" href="#hl-6-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose up -d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker logs -f jenkins2&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;注意 &lt;code&gt;chown 1000:1000&lt;/code&gt; 不能省：容器以 jenkins（uid 1000）运行，home 目录属主是 root 会起不来。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h3 id="32-浏览器初始化"&gt;&lt;a href="#32-%e6%b5%8f%e8%a7%88%e5%99%a8%e5%88%9d%e5%a7%8b%e5%8c%96" class="header-anchor"&gt;&lt;/a&gt;3.2 浏览器初始化&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;拿初始密码：&lt;code&gt;docker exec jenkins2 cat /var/jenkins_home/secrets/initialAdminPassword&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;浏览器打开 &lt;code&gt;http://&amp;lt;服务器IP&amp;gt;:8082&lt;/code&gt;，粘贴解锁&lt;/li&gt;&#10;&lt;li&gt;选 &lt;strong&gt;Install suggested plugins&lt;/strong&gt;（推荐套装，含 Pipeline / Git / Credentials 等基础插件）&lt;/li&gt;&#10;&lt;li&gt;创建管理员账号，完成&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;两个提醒：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;云服务器记得在&lt;strong&gt;安全组放行 8082&lt;/strong&gt;。&lt;/li&gt;&#10;&lt;li&gt;如果插件下载慢，可以把更新中心换成清华镜像：&lt;code&gt;https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json&lt;/code&gt;（Manage Jenkins → Plugins → Advanced settings → Update Site）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h3 id="33-坑-1gitexamplecom-域名解析不了"&gt;&lt;a href="#33-%e5%9d%91-1gitexamplecom-%e5%9f%9f%e5%90%8d%e8%a7%a3%e6%9e%90%e4%b8%8d%e4%ba%86" class="header-anchor"&gt;&lt;/a&gt;3.3 坑 1：git.example.com 域名解析不了&#10;&lt;/h3&gt;&lt;p&gt;旧实例 compose 里有 &lt;code&gt;extra_hosts&lt;/code&gt;，第一版没抄这一条——内网 GitLab 域名 &lt;code&gt;git.example.com&lt;/code&gt; 在 DNS 里不存在，不配的话流水线 clone 代码必然失败。补上：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-7-1"&gt;&lt;a class="lnlinks" href="#hl-7-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-7-2"&gt;&lt;a class="lnlinks" href="#hl-7-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;extra_hosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;git.example.com:10.10.10.15&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-8-1"&gt;&lt;a class="lnlinks" href="#hl-8-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-2"&gt;&lt;a class="lnlinks" href="#hl-8-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-3"&gt;&lt;a class="lnlinks" href="#hl-8-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-4"&gt;&lt;a class="lnlinks" href="#hl-8-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-5"&gt;&lt;a class="lnlinks" href="#hl-8-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-6"&gt;&lt;a class="lnlinks" href="#hl-8-6"&gt;6&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose up -d &lt;span class="c1"&gt;# 重建&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 验证：&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; jenkins2 grep git.example.com /etc/hosts&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 10.10.10.15 git.example.com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; jenkins2 curl -sk -o /dev/null -w &lt;span class="s1"&gt;&amp;#39;%{http_code}&amp;#39;&lt;/span&gt; https://git.example.com/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 302（可达）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="四坑-2安全警告横幅--顺便升级到最新-lts"&gt;&lt;a href="#%e5%9b%9b%e5%9d%91-2%e5%ae%89%e5%85%a8%e8%ad%a6%e5%91%8a%e6%a8%aa%e5%b9%85--%e9%a1%ba%e4%be%bf%e5%8d%87%e7%ba%a7%e5%88%b0%e6%9c%80%e6%96%b0-lts" class="header-anchor"&gt;&lt;/a&gt;四、坑 2：安全警告横幅 → 顺便升级到最新 LTS&#10;&lt;/h2&gt;&lt;p&gt;初始化完成后，Manage Jenkins 页面顶部挂着红色横幅：&lt;strong&gt;当前 2.541.1 core 存在多个已知安全漏洞&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;因为新实例还没建任何任务，升级零成本，直接升：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-9-1"&gt;&lt;a class="lnlinks" href="#hl-9-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-9-2"&gt;&lt;a class="lnlinks" href="#hl-9-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-9-3"&gt;&lt;a class="lnlinks" href="#hl-9-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-9-4"&gt;&lt;a class="lnlinks" href="#hl-9-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-9-5"&gt;&lt;a class="lnlinks" href="#hl-9-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /home/compose-jenkins2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose pull &lt;span class="c1"&gt;# 拉最新 lts&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose up -d &lt;span class="c1"&gt;# 重建&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -s -D- http://localhost:8082/login &lt;span class="p"&gt;|&lt;/span&gt; grep X-Jenkins&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# X-Jenkins: 2.568.3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;升级到 &lt;strong&gt;2.568.3&lt;/strong&gt;（当时最新 LTS），红色漏洞横幅消失。&lt;/p&gt;&#10;&lt;p&gt;其余几条横幅的处理：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&amp;ldquo;Pipeline: Groovy Libraries 有 CSRF 问题但无修复版本&amp;rdquo;——没修复版本，只能忽略；&lt;/li&gt;&#10;&lt;li&gt;built-in node 安全提示、CSP 提示——确认自己会用 built-in node 构建后，点 Dismiss 即可。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;旧实例（8080）不要顺手升&lt;/strong&gt;：它跑着 bid 项目的生产构建，升级要另约时间窗口、先备份 jenkins_home。隔离的意义就在这里——两边版本可以不一样，互不影响。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="五装插件只装两个"&gt;&lt;a href="#%e4%ba%94%e8%a3%85%e6%8f%92%e4%bb%b6%e5%8f%aa%e8%a3%85%e4%b8%a4%e4%b8%aa" class="header-anchor"&gt;&lt;/a&gt;五、装插件：只装两个&#10;&lt;/h2&gt;&lt;p&gt;推荐套装已经覆盖了 Pipeline、Git、Credentials，额外只需要：&lt;/p&gt;&#10;&lt;p&gt;Manage Jenkins → Plugins → Available plugins，搜索勾选：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;NodeJS Plugin&lt;/strong&gt;——前端构建用。Jenkins 本体只是调度壳子，JDK/Maven 的工具管理是核心自带的，Node 不是；没有它，流水线脚本里 &lt;code&gt;tools { nodejs 'node22' }&lt;/code&gt; 不认识，&lt;code&gt;pnpm install/build&lt;/code&gt; 直接 command not found。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;SSH Agent Plugin&lt;/strong&gt;——部署用。流水线 Deploy 阶段用 &lt;code&gt;sshagent(['凭据ID']) { ... }&lt;/code&gt; 把私钥临时加载进 ssh-agent，实现免密 scp/ssh。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;点 Install，勾选&amp;quot;安装完成后重启 Jenkins&amp;quot;，等半分钟自动重启（不影响 8080 的旧实例）。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;后续小插曲：SSH Agent 方案后来因凭据问题被弃用（改用容器内密钥文件，见本系列第二篇），但插件装着无害。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="六全局工具配置jdk17--maven39--node22"&gt;&lt;a href="#%e5%85%ad%e5%85%a8%e5%b1%80%e5%b7%a5%e5%85%b7%e9%85%8d%e7%bd%aejdk17--maven39--node22" class="header-anchor"&gt;&lt;/a&gt;六、全局工具配置：jdk17 / maven3.9 / node22&#10;&lt;/h2&gt;&lt;p&gt;Manage Jenkins → Tools，配三个工具。&lt;strong&gt;名字必须和流水线脚本里 &lt;code&gt;tools {}&lt;/code&gt; 引用的一字不差&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;h3 id="61-jdk坑-3没有-adoptium-安装器"&gt;&lt;a href="#61-jdk%e5%9d%91-3%e6%b2%a1%e6%9c%89-adoptium-%e5%ae%89%e8%a3%85%e5%99%a8" class="header-anchor"&gt;&lt;/a&gt;6.1 JDK——坑 3：没有 adoptium 安装器&#10;&lt;/h3&gt;&lt;p&gt;点 JDK 新增，打算让 Jenkins 自动装 Temurin 17，结果发现 Add Installer 下拉里&lt;strong&gt;没有 &amp;ldquo;Install from adoptium.net&amp;rdquo;&lt;/strong&gt;（只有 Extract zip / Batch / Shell 三项，这是部分版本/网络环境下的常见情况）。&lt;/p&gt;&#10;&lt;p&gt;解决办法：不自动装，&lt;strong&gt;复用宿主机现成的 JDK 17&lt;/strong&gt;——当年旧实例手工解压的 Adoptium Temurin 17 就在 &lt;code&gt;/home/compose/jdk17&lt;/code&gt;。给 jenkins2 加只读挂载（compose 第三版，也是最终版）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-10-1"&gt;&lt;a class="lnlinks" href="#hl-10-1"&gt; 1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-2"&gt;&lt;a class="lnlinks" href="#hl-10-2"&gt; 2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-3"&gt;&lt;a class="lnlinks" href="#hl-10-3"&gt; 3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-4"&gt;&lt;a class="lnlinks" href="#hl-10-4"&gt; 4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-5"&gt;&lt;a class="lnlinks" href="#hl-10-5"&gt; 5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-6"&gt;&lt;a class="lnlinks" href="#hl-10-6"&gt; 6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-7"&gt;&lt;a class="lnlinks" href="#hl-10-7"&gt; 7&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-8"&gt;&lt;a class="lnlinks" href="#hl-10-8"&gt; 8&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-9"&gt;&lt;a class="lnlinks" href="#hl-10-9"&gt; 9&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-10"&gt;&lt;a class="lnlinks" href="#hl-10-10"&gt;10&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-11"&gt;&lt;a class="lnlinks" href="#hl-10-11"&gt;11&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-12"&gt;&lt;a class="lnlinks" href="#hl-10-12"&gt;12&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-13"&gt;&lt;a class="lnlinks" href="#hl-10-13"&gt;13&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-14"&gt;&lt;a class="lnlinks" href="#hl-10-14"&gt;14&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-15"&gt;&lt;a class="lnlinks" href="#hl-10-15"&gt;15&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;jenkins2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jenkins/jenkins:lts&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jenkins2&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;TZ=Asia/Shanghai&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;8082:8080&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;50001:50000&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./jenkins_home:/var/jenkins_home&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/home/compose/jdk17:/usr/local/jdk17:ro &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 只读复用宿主机的 JDK17&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;extra_hosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;git.example.com:10.10.10.15&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-11-1"&gt;&lt;a class="lnlinks" href="#hl-11-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-11-2"&gt;&lt;a class="lnlinks" href="#hl-11-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-11-3"&gt;&lt;a class="lnlinks" href="#hl-11-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker-compose up -d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; jenkins2 /usr/local/jdk17/bin/java -version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# openjdk version &amp;#34;17.0.18&amp;#34; Temurin-17.0.18+8&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;Tools 页面配置：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;JDK&lt;/strong&gt;：Name 填 &lt;code&gt;jdk17&lt;/code&gt;；&lt;strong&gt;取消勾选 Install automatically&lt;/strong&gt;；JAVA_HOME 填 &lt;code&gt;/usr/local/jdk17&lt;/code&gt;。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;只读挂载（&lt;code&gt;:ro&lt;/code&gt;）是个好习惯：新实例万一配错也伤不到旧实例在用的 JDK。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h3 id="62-maven"&gt;&lt;a href="#62-maven" class="header-anchor"&gt;&lt;/a&gt;6.2 Maven&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Maven&lt;/strong&gt;：Name 填 &lt;code&gt;maven3.9&lt;/code&gt;；勾选 Install automatically → &lt;strong&gt;Install from Apache&lt;/strong&gt; → 选 3.9.x 最新（实际装到 3.9.16）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;默认走 Apache 中央仓库慢，给容器内的 Maven 配阿里云镜像（宿主机写好，jenkins_home 是绑定挂载，容器内直接生效）：&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;/home/compose-jenkins2/jenkins_home/.m2/settings.xml&lt;/code&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-12-1"&gt;&lt;a class="lnlinks" href="#hl-12-1"&gt; 1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-2"&gt;&lt;a class="lnlinks" href="#hl-12-2"&gt; 2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-3"&gt;&lt;a class="lnlinks" href="#hl-12-3"&gt; 3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-4"&gt;&lt;a class="lnlinks" href="#hl-12-4"&gt; 4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-5"&gt;&lt;a class="lnlinks" href="#hl-12-5"&gt; 5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-6"&gt;&lt;a class="lnlinks" href="#hl-12-6"&gt; 6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-7"&gt;&lt;a class="lnlinks" href="#hl-12-7"&gt; 7&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-8"&gt;&lt;a class="lnlinks" href="#hl-12-8"&gt; 8&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-9"&gt;&lt;a class="lnlinks" href="#hl-12-9"&gt; 9&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-10"&gt;&lt;a class="lnlinks" href="#hl-12-10"&gt;10&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;settings&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;mirrors&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;mirror&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;aliyun&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;mirrorOf&amp;gt;&lt;/span&gt;central&lt;span class="nt"&gt;&amp;lt;/mirrorOf&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;aliyun&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;https://maven.aliyun.com/repository/public&lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/mirror&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/mirrors&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/settings&amp;gt;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="63-nodejs"&gt;&lt;a href="#63-nodejs" class="header-anchor"&gt;&lt;/a&gt;6.3 NodeJS&#10;&lt;/h3&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;NodeJS&lt;/strong&gt;：Name 填 &lt;code&gt;node22&lt;/code&gt;；勾选 Install automatically → &lt;strong&gt;Install from nodejs.org&lt;/strong&gt; → Node.js 22.x LTS。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;如果 nodejs.org 下载不动，可以换 npmmirror 的二进制地址：&#10;&lt;code&gt;https://registry.npmmirror.com/-/binary/node/v22.20.0/node-v22.20.0-linux-x64.tar.gz&lt;/code&gt;&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="七坑-4保存配置时报-http-403"&gt;&lt;a href="#%e4%b8%83%e5%9d%91-4%e4%bf%9d%e5%ad%98%e9%85%8d%e7%bd%ae%e6%97%b6%e6%8a%a5-http-403" class="header-anchor"&gt;&lt;/a&gt;七、坑 4：保存配置时报 HTTP 403&#10;&lt;/h2&gt;&lt;p&gt;在 Tools 页面填好 JDK 的 JAVA_HOME，点 Save，弹错：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-13-1"&gt;&lt;a class="lnlinks" href="#hl-13-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-13-2"&gt;&lt;a class="lnlinks" href="#hl-13-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;An&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="n"&gt;occurred&lt;/span&gt; &lt;span class="n"&gt;during&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="n"&gt;validation&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HTTP&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Please&lt;/span&gt; &lt;span class="n"&gt;reload&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;problem&lt;/span&gt; &lt;span class="n"&gt;persists&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;administrator&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;这不是配置填错了。&lt;/strong&gt; 原因是：当天 jenkins2 容器被反复重建过好几次、还升过一次级（2.541.1 → 2.568.3），而浏览器里还是升级前打开的旧会话页面——后台的表单校验接口需要有效的 CSRF crumb，过期会话提交就被 403 拒绝。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;解决：退出登录 → 重新登录 → 重新进 Tools 填一遍 → Save。&lt;/strong&gt; 保存后最好回进页面确认值真的存进去了。如果重新登录后仍然 403，那才需要查容器日志（&lt;code&gt;docker logs jenkins2&lt;/code&gt;）深挖。&lt;/p&gt;&#10;&lt;h2 id="八建-git-凭据"&gt;&lt;a href="#%e5%85%ab%e5%bb%ba-git-%e5%87%ad%e6%8d%ae" class="header-anchor"&gt;&lt;/a&gt;八、建 Git 凭据&#10;&lt;/h2&gt;&lt;p&gt;流水线要从内网 GitLab 拉代码，先建凭据：&lt;/p&gt;&#10;&lt;p&gt;Manage Jenkins → Credentials → System → Global credentials (unrestricted) → Add Credentials：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Kind：&lt;strong&gt;Username with password&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;Username / Password：git.example.com 的账号密码（账号要有 myapp-safe 组的读权限）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ID 手动填 &lt;code&gt;myapp-git&lt;/code&gt;&lt;/strong&gt;（不填会自动生成 UUID，脚本里没法引用）&lt;/li&gt;&#10;&lt;li&gt;Create&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="九收尾状态"&gt;&lt;a href="#%e4%b9%9d%e6%94%b6%e5%b0%be%e7%8a%b6%e6%80%81" class="header-anchor"&gt;&lt;/a&gt;九、收尾状态&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-14-1"&gt;&lt;a class="lnlinks" href="#hl-14-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-14-2"&gt;&lt;a class="lnlinks" href="#hl-14-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-14-3"&gt;&lt;a class="lnlinks" href="#hl-14-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker ps&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# jenkins 0.0.0.0:8080-&amp;gt;8080/tcp, 0.0.0.0:50000-&amp;gt;50000/tcp ← 旧实例，原封不动&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# jenkins2 0.0.0.0:8082-&amp;gt;8080/tcp, 0.0.0.0:50001-&amp;gt;50000/tcp ← 新实例&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;项目&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;值&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;访问地址&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;http://10.10.10.44:8082&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;版本&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2.568.3 (LTS)&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;编排文件&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/home/compose-jenkins2/docker-compose.yml&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;工具&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;jdk17（JAVA_HOME=/usr/local/jdk17）、maven3.9（3.9.16）、node22（22.x）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;插件（额外）&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;NodeJS Plugin、SSH Agent Plugin&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;凭据&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;myapp-git&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;镜像仓库&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Maven 阿里云、Node npmmirror（备用）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="十经验总结"&gt;&lt;a href="#%e5%8d%81%e7%bb%8f%e9%aa%8c%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;十、经验总结&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;先查系统源再定方案&lt;/strong&gt;：HCE 2.0 源里最高只有 OpenJDK 11，想&amp;quot;一条 yum 装 JDK 17/21&amp;quot;会直接卡死；全程容器化 + 官方 tar.gz 是绕开这个问题的正解。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;隔离 = 端口 + 目录 + 权限三件事&lt;/strong&gt;：换端口、独立编排目录、不挂 docker.sock、不用 root 跑，两个 Jenkins 就是真正的两套系统。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;成熟实例的配置是宝藏&lt;/strong&gt;：旧实例的 &lt;code&gt;extra_hosts&lt;/code&gt;（内网 Git 域名）、宿主机 jdk17，都是可以只读复用的现成资产——但复用一律 &lt;code&gt;:ro&lt;/code&gt;。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;新建实例趁没任务赶紧升级&lt;/strong&gt;，安全横幅不要拖；跑生产的实例升级另约窗口。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Jenkins 的 403 表单错误八成是会话过期&lt;/strong&gt;，重新登录比查日志快。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;工具 Name 和脚本 &lt;code&gt;tools{}&lt;/code&gt; 引用必须一字不差&lt;/strong&gt;（jdk17 / maven3.9 / node22），凭据 ID 要手动指定，不要用自动生成的 UUID。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;&lt;em&gt;下一篇：《从零到上线：用这套 Jenkins 部署前后端项目（MySQL/Redis 容器化）踩坑全记录》——包括 3306 之争、ssh-agent 凭据三连败、403 Forbidden、logo 消失之谜等 8 个实战坑。&lt;/em&gt;&lt;/p&gt;&#10;</description></item><item><title>Linux运维 01：Mac 判断服务器端口连通性方法大全（nc / curl / telnet / nmap）</title><link>https://saflyer.cn/posts/mac-port-check-methods/</link><pubDate>Wed, 16 Sep 2026 10:30:00 +0800</pubDate><guid>https://saflyer.cn/posts/mac-port-check-methods/</guid><description>&lt;img src="https://saflyer.cn/posts/mac-port-check-methods/cover.webp" alt="Featured image of post Linux运维 01：Mac 判断服务器端口连通性方法大全（nc / curl / telnet / nmap）" /&gt;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;环境&lt;/strong&gt;：macOS（Apple Silicon），无需安装任何软件即可完成 90% 的排查&#10;&lt;strong&gt;场景&lt;/strong&gt;：服务器部署了服务，想确认&amp;quot;端口到底通不通&amp;quot;&amp;ldquo;这台机器上还开了哪些端口&amp;rdquo;&#10;&lt;strong&gt;读者定位&lt;/strong&gt;：收藏当手册，用到时按目录查&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="一先建立两个认知不懂这两个必误判"&gt;&lt;a href="#%e4%b8%80%e5%85%88%e5%bb%ba%e7%ab%8b%e4%b8%a4%e4%b8%aa%e8%ae%a4%e7%9f%a5%e4%b8%8d%e6%87%82%e8%bf%99%e4%b8%a4%e4%b8%aa%e5%bf%85%e8%af%af%e5%88%a4" class="header-anchor"&gt;&lt;/a&gt;一、先建立两个认知（不懂这两个，必误判）&#10;&lt;/h2&gt;&lt;h3 id="11-ping-不通--端口不通"&gt;&lt;a href="#11-ping-%e4%b8%8d%e9%80%9a--%e7%ab%af%e5%8f%a3%e4%b8%8d%e9%80%9a" class="header-anchor"&gt;&lt;/a&gt;1.1 ping 不通 ≠ 端口不通&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;ping&lt;/code&gt; 走的是 &lt;strong&gt;ICMP 协议&lt;/strong&gt;，而业务端口走的是 &lt;strong&gt;TCP 协议&lt;/strong&gt;，两者互不相干。&#10;很多服务器和内网防火墙会直接丢弃 ICMP 包，造成&amp;quot;ping 100% 丢包但 80 端口网页开得好好的&amp;quot;。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;结论：不要用 ping 判断服务是否存活，要用 TCP 探测。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h3 id="12-连上没字--不通谁先说话问题"&gt;&lt;a href="#12-%e8%bf%9e%e4%b8%8a%e6%b2%a1%e5%ad%97--%e4%b8%8d%e9%80%9a%e8%b0%81%e5%85%88%e8%af%b4%e8%af%9d%e9%97%ae%e9%a2%98" class="header-anchor"&gt;&lt;/a&gt;1.2 连上没字 ≠ 不通（&amp;ldquo;谁先说话&amp;quot;问题）&#10;&lt;/h3&gt;&lt;p&gt;不同协议的&amp;quot;开场白&amp;quot;方向不一样：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;协议类型&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;代表服务&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;连接建立后&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;服务器先说话&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;SSH(22)、MySQL(3306)、FTP(21)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;立刻推送 banner（版本信息）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;客户端先说话&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP(80/8080&amp;hellip;)、Redis(6379)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;一言不发，等你先发请求&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;所以用 telnet 测 HTTP 端口，连上后一片空白、光标干等——&lt;strong&gt;这不是不通，是正常等待&lt;/strong&gt;。输入 &lt;code&gt;GET / HTTP/1.0&lt;/code&gt; 再按两次回车，响应立刻就出来了。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;真实案例&lt;/strong&gt;：浏览器能打开 &lt;code&gt;http://10.36.35.43:8083/login&lt;/code&gt;，但 &lt;code&gt;telnet 10.36.35.43 8083&lt;/code&gt; &amp;ldquo;没响应&amp;rdquo;。用 nc 验证：TCP 秒连，手动发一行 GET 请求立刻返回 &lt;code&gt;HTTP/1.1 200 OK&lt;/code&gt;——端口一直是通的，只是 HTTP 服务不主动打招呼。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="二判断单个端口是否通"&gt;&lt;a href="#%e4%ba%8c%e5%88%a4%e6%96%ad%e5%8d%95%e4%b8%aa%e7%ab%af%e5%8f%a3%e6%98%af%e5%90%a6%e9%80%9a" class="header-anchor"&gt;&lt;/a&gt;二、判断单个端口是否通&#10;&lt;/h2&gt;&lt;h3 id="方法-1ncmacos-自带首选"&gt;&lt;a href="#%e6%96%b9%e6%b3%95-1ncmacos-%e8%87%aa%e5%b8%a6%e9%a6%96%e9%80%89" class="header-anchor"&gt;&lt;/a&gt;方法 1：nc（macOS 自带，首选）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-0-1"&gt;&lt;a class="lnlinks" href="#hl-0-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-2"&gt;&lt;a class="lnlinks" href="#hl-0-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nc -vz 10.36.35.43 &lt;span class="m"&gt;22&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# -v 显示详情 -z 只探测不传数据 -G 2 可指定超时秒数&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;三种结果，语义完全不同，要能读懂：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;输出&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;含义&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;Connection to ... succeeded!&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;✅ 通，且有服务在监听&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;failed: Connection refused&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;主机可达，但端口没服务监听（服务没起/监听别的端口）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;failed: Operation timed out&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;包被防火墙丢了，或主机不可达（不是&amp;quot;没服务&amp;rdquo;）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="方法-2curlhttp-服务最方便"&gt;&lt;a href="#%e6%96%b9%e6%b3%95-2curlhttp-%e6%9c%8d%e5%8a%a1%e6%9c%80%e6%96%b9%e4%be%bf" class="header-anchor"&gt;&lt;/a&gt;方法 2：curl（HTTP 服务最方便）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-1-1"&gt;&lt;a class="lnlinks" href="#hl-1-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-2"&gt;&lt;a class="lnlinks" href="#hl-1-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sI -m &lt;span class="m"&gt;5&lt;/span&gt; http://10.36.35.43:8080 &lt;span class="c1"&gt;# 看状态行 + Server 头&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -v telnet://10.36.35.43:22 &lt;span class="c1"&gt;# 冷门招：telnet:// 协议能测任意 TCP 端口，还能拿到 SSH banner&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="方法-3bash-内置-devtcp零依赖应急"&gt;&lt;a href="#%e6%96%b9%e6%b3%95-3bash-%e5%86%85%e7%bd%ae-devtcp%e9%9b%b6%e4%be%9d%e8%b5%96%e5%ba%94%e6%80%a5" class="header-anchor"&gt;&lt;/a&gt;方法 3：bash 内置 /dev/tcp（零依赖应急）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-2-1"&gt;&lt;a class="lnlinks" href="#hl-2-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash -c &lt;span class="s1"&gt;&amp;#39;(echo &amp;gt; /dev/tcp/10.36.35.43/22) 2&amp;gt;/dev/null &amp;amp;&amp;amp; echo 通 || echo 不通&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;无需任何外部命令，是 bash 自身的特性。缺点是超时不可控（防火墙丢包场景会等很久），日常还是 nc 好用。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;⚠️ 踩坑（实测）：zsh 下直接跑会得到&amp;quot;假阴性&amp;quot;&lt;/strong&gt;。&lt;code&gt;/dev/tcp&lt;/code&gt; 是 &lt;strong&gt;bash 独有&lt;/strong&gt;的伪设备，zsh 不认识——它把 &lt;code&gt;/dev/tcp/10.36.35.43/22&lt;/code&gt; 当普通文件路径，重定向失败的报错又被 &lt;code&gt;2&amp;gt;/dev/null&lt;/code&gt; 吞掉，于是端口明明是通的也输出&amp;quot;不通&amp;quot;。macOS 从 Catalina 起默认 shell 就是 zsh，所以必须套一层 &lt;code&gt;bash -c '...'&lt;/code&gt;。验证：&lt;code&gt;curl -v telnet://IP:端口&lt;/code&gt; 能拿到 banner 而 /dev/tcp 报不通时，先想想自己当前在哪个 shell 里。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h3 id="方法-4telnet新版-macos-需自行安装"&gt;&lt;a href="#%e6%96%b9%e6%b3%95-4telnet%e6%96%b0%e7%89%88-macos-%e9%9c%80%e8%87%aa%e8%a1%8c%e5%ae%89%e8%a3%85" class="header-anchor"&gt;&lt;/a&gt;方法 4：telnet（新版 macOS 需自行安装）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-3-1"&gt;&lt;a class="lnlinks" href="#hl-3-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-3-2"&gt;&lt;a class="lnlinks" href="#hl-3-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install telnet&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;telnet 10.36.35.43 &lt;span class="m"&gt;22&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;看到 &lt;code&gt;Connected to ...&lt;/code&gt; 就说明 TCP 通了。后面有没有字，取决于 1.1 节说的&amp;quot;谁先说话&amp;quot;。&lt;/p&gt;&#10;&lt;h3 id="方法-5nmap装了的话"&gt;&lt;a href="#%e6%96%b9%e6%b3%95-5nmap%e8%a3%85%e4%ba%86%e7%9a%84%e8%af%9d" class="header-anchor"&gt;&lt;/a&gt;方法 5：nmap（装了的话）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-4-1"&gt;&lt;a class="lnlinks" href="#hl-4-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nmap -Pn -p 22,80,443 10.36.35.43&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;&lt;code&gt;-Pn&lt;/code&gt; 很重要&lt;/strong&gt;：nmap 默认先 ping 探测主机死活，ping 不通直接跳过扫描。内网服务器经常禁 ping（见 1.1），不加 &lt;code&gt;-Pn&lt;/code&gt; 会得出&amp;quot;主机 down&amp;quot;的错误结论。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h3 id="方法-6浏览器"&gt;&lt;a href="#%e6%96%b9%e6%b3%95-6%e6%b5%8f%e8%a7%88%e5%99%a8" class="header-anchor"&gt;&lt;/a&gt;方法 6：浏览器&#10;&lt;/h3&gt;&lt;p&gt;HTTP/HTTPS 服务最直接：&lt;code&gt;http://IP:端口&lt;/code&gt; 能打开页面就是通的。但注意它只对 Web 服务有效。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="三扫描整台服务器哪些端口是开的"&gt;&lt;a href="#%e4%b8%89%e6%89%ab%e6%8f%8f%e6%95%b4%e5%8f%b0%e6%9c%8d%e5%8a%a1%e5%99%a8%e5%93%aa%e4%ba%9b%e7%ab%af%e5%8f%a3%e6%98%af%e5%bc%80%e7%9a%84" class="header-anchor"&gt;&lt;/a&gt;三、扫描整台服务器：哪些端口是开的&#10;&lt;/h2&gt;&lt;h3 id="方法-1nmap标准答案"&gt;&lt;a href="#%e6%96%b9%e6%b3%95-1nmap%e6%a0%87%e5%87%86%e7%ad%94%e6%a1%88" class="header-anchor"&gt;&lt;/a&gt;方法 1：nmap（标准答案）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-5-1"&gt;&lt;a class="lnlinks" href="#hl-5-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-2"&gt;&lt;a class="lnlinks" href="#hl-5-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-3"&gt;&lt;a class="lnlinks" href="#hl-5-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-4"&gt;&lt;a class="lnlinks" href="#hl-5-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-5"&gt;&lt;a class="lnlinks" href="#hl-5-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-6"&gt;&lt;a class="lnlinks" href="#hl-5-6"&gt;6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-7"&gt;&lt;a class="lnlinks" href="#hl-5-7"&gt;7&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install nmap&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nmap -Pn 10.36.35.43 &lt;span class="c1"&gt;# top 1000 常用端口（最常用）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nmap -Pn -F 10.36.35.43 &lt;span class="c1"&gt;# top 100，更快&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nmap -Pn -p- 10.36.35.43 &lt;span class="c1"&gt;# 全端口 1-65535（慢，几分钟）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nmap -Pn -sV 10.36.35.43 &lt;span class="c1"&gt;# 顺带识别服务版本&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nmap -Pn -T4 --open 10.36.35.43 &lt;span class="c1"&gt;# 加速 + 只显示开放的&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="方法-2nc--xargs-并发不装任何东西的应急方案"&gt;&lt;a href="#%e6%96%b9%e6%b3%95-2nc--xargs-%e5%b9%b6%e5%8f%91%e4%b8%8d%e8%a3%85%e4%bb%bb%e4%bd%95%e4%b8%9c%e8%a5%bf%e7%9a%84%e5%ba%94%e6%80%a5%e6%96%b9%e6%a1%88" class="header-anchor"&gt;&lt;/a&gt;方法 2：nc + xargs 并发（不装任何东西的应急方案）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-6-1"&gt;&lt;a class="lnlinks" href="#hl-6-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-2"&gt;&lt;a class="lnlinks" href="#hl-6-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-3"&gt;&lt;a class="lnlinks" href="#hl-6-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-4"&gt;&lt;a class="lnlinks" href="#hl-6-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-5"&gt;&lt;a class="lnlinks" href="#hl-6-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;21 22 23 25 53 80 110 143 443 445 465 587 993 995 1080 1433 1521 2181 \&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;2375 3000 3306 3389 4000 5000 5432 5672 5900 6379 8000 8006 8007 8080 8081 \&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;8086 8090 8443 8848 8888 9000 9001 9042 9090 9092 9200 9300 10000 11211 15672 27017&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; tr &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; xargs -P &lt;span class="m"&gt;20&lt;/span&gt; -I&lt;span class="o"&gt;{}&lt;/span&gt; sh -c &lt;span class="s1"&gt;&amp;#39;nc -z -G 2 10.36.35.43 {} &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&amp;amp; echo &amp;#34;OPEN {}&amp;#34;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;原理：&lt;code&gt;nc -z&lt;/code&gt; 逐端口试探 TCP 握手，&lt;code&gt;xargs -P 20&lt;/code&gt; 并发 20 个，50 个常见端口十几秒扫完。&#10;想扫全端口就换成 &lt;code&gt;seq 1 65535 | xargs -P 50 ...&lt;/code&gt;，慢但可行。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;注意列表覆盖&lt;/strong&gt;：上面的清单是手挑的常见端口，像 8083 这种非典型端口就不会命中——扫不到不代表没开，只代表&amp;quot;不在清单里&amp;quot;。要穷举就上 nmap &lt;code&gt;-p-&lt;/code&gt;。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h3 id="方法-3masscan海量端口需-sudo"&gt;&lt;a href="#%e6%96%b9%e6%b3%95-3masscan%e6%b5%b7%e9%87%8f%e7%ab%af%e5%8f%a3%e9%9c%80-sudo" class="header-anchor"&gt;&lt;/a&gt;方法 3：masscan（海量端口，需 sudo）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-7-1"&gt;&lt;a class="lnlinks" href="#hl-7-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-7-2"&gt;&lt;a class="lnlinks" href="#hl-7-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install masscan&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo masscan -p1-65535 10.36.35.43 --rate&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;异步发包，全端口几十秒扫完。适合大网段，单机用 nmap 足矣。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="四识别端口上跑的是什么服务banner-grabbing"&gt;&lt;a href="#%e5%9b%9b%e8%af%86%e5%88%ab%e7%ab%af%e5%8f%a3%e4%b8%8a%e8%b7%91%e7%9a%84%e6%98%af%e4%bb%80%e4%b9%88%e6%9c%8d%e5%8a%a1banner-grabbing" class="header-anchor"&gt;&lt;/a&gt;四、识别端口上跑的是什么服务（banner grabbing）&#10;&lt;/h2&gt;&lt;p&gt;端口通只是第一步，抓 banner 才知道上面跑的是谁：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-8-1"&gt;&lt;a class="lnlinks" href="#hl-8-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-2"&gt;&lt;a class="lnlinks" href="#hl-8-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-3"&gt;&lt;a class="lnlinks" href="#hl-8-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-4"&gt;&lt;a class="lnlinks" href="#hl-8-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-5"&gt;&lt;a class="lnlinks" href="#hl-8-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-6"&gt;&lt;a class="lnlinks" href="#hl-8-6"&gt;6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-7"&gt;&lt;a class="lnlinks" href="#hl-8-7"&gt;7&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-8"&gt;&lt;a class="lnlinks" href="#hl-8-8"&gt;8&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-9"&gt;&lt;a class="lnlinks" href="#hl-8-9"&gt;9&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# SSH / MySQL：连上就读（服务器先说话）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nc -w &lt;span class="m"&gt;2&lt;/span&gt; 10.36.35.43 &lt;span class="m"&gt;22&lt;/span&gt; &amp;lt; /dev/null &lt;span class="p"&gt;|&lt;/span&gt; head -1 &lt;span class="c1"&gt;# SSH-2.0-OpenSSH_8.8&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nc -w &lt;span class="m"&gt;2&lt;/span&gt; 10.36.35.43 &lt;span class="m"&gt;3306&lt;/span&gt; &amp;lt; /dev/null &lt;span class="p"&gt;|&lt;/span&gt; strings &lt;span class="p"&gt;|&lt;/span&gt; head -1 &lt;span class="c1"&gt;# 5.7.44&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Redis：发 PING 看回应（客户端先说话）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;PING\r\n&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; nc -w &lt;span class="m"&gt;2&lt;/span&gt; 10.36.35.43 &lt;span class="m"&gt;6379&lt;/span&gt; &lt;span class="c1"&gt;# -NOAUTH Authentication required.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# HTTP：HEAD 请求&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sI -m &lt;span class="m"&gt;5&lt;/span&gt; http://10.36.35.43:80 &lt;span class="c1"&gt;# Server: nginx/1.13.12&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;一条命令全搞定的懒人方案：&lt;code&gt;nmap -Pn -sV 目标IP&lt;/code&gt;。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="五实战案例扫描内网服务器-10363543"&gt;&lt;a href="#%e4%ba%94%e5%ae%9e%e6%88%98%e6%a1%88%e4%be%8b%e6%89%ab%e6%8f%8f%e5%86%85%e7%bd%91%e6%9c%8d%e5%8a%a1%e5%99%a8-10363543" class="header-anchor"&gt;&lt;/a&gt;五、实战案例：扫描内网服务器 10.36.35.43&#10;&lt;/h2&gt;&lt;p&gt;用方法三·2 的 nc 并发扫描 + 方法四的 banner 抓取，实测结果：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;端口&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;服务&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;识别详情&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;22&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;SSH&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;OpenSSH 8.8&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;80&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nginx/1.13.12，首页 200&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;443&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;开放但未知&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;TCP 通，不回应 HTTPS 握手&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3306&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;MySQL&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;5.7.44（版本号 banner 直接暴露）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;6379&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Redis&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;有密码（NOAUTH）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;8080/8081&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;根路径 404，未暴露 Server 头&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;8083&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nginx 反代的前端登录页（后补扫发现）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;顺带两个安全观察：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;MySQL 版本号在 banner 里裸奔&lt;/strong&gt;——等于告诉攻击者该打哪些 CVE，3306 应只对需要的网段开放&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;nginx 1.13.12 是 2017 年的版本&lt;/strong&gt;，已知漏洞不少（如 CVE-2017-7529），正式服务建议升级&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="六速查表"&gt;&lt;a href="#%e5%85%ad%e9%80%9f%e6%9f%a5%e8%a1%a8" class="header-anchor"&gt;&lt;/a&gt;六、速查表&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;需求&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;命令&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;测单个端口&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nc -vz IP 端口&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;测 HTTP 服务&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl -sI -m 5 http://IP:端口&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;任意 TCP 端口看 banner&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;curl -v telnet://IP:端口&lt;/code&gt; 或 &lt;code&gt;nc -w 2 IP 端口&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;扫常用端口&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nmap -Pn IP&lt;/code&gt;（无 nmap 时用 nc+xargs 脚本）&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;扫全端口&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nmap -Pn -p- IP&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;识别服务版本&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;nmap -Pn -sV IP&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;ping 不通还想扫&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;nmap 务必加 &lt;code&gt;-Pn&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;合规提醒&lt;/strong&gt;：端口扫描只用于自己的服务器或获得明确授权的目标。对陌生主机扫描在多数公司和云厂商守则里属于攻击行为。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;</description></item><item><title>K8s 从零到实战 00（下）：内核参数与容器运行时（containerd 三关）</title><link>https://saflyer.cn/posts/k8s-00b-kernel-containerd/</link><pubDate>Sun, 13 Sep 2026 10:10:00 +0800</pubDate><guid>https://saflyer.cn/posts/k8s-00b-kernel-containerd/</guid><description>&lt;img src="https://saflyer.cn/posts/k8s-00b-kernel-containerd/cover.webp" alt="Featured image of post K8s 从零到实战 00（下）：内核参数与容器运行时（containerd 三关）" /&gt;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;目标：完成 k8s 安装前的最后两项准备——内核网络参数（k8s 的神经网络）和容器运行时（k8s 的手）。&#10;前置：已完成 &lt;a href="https://saflyer.cn/posts/k8s-00a-vm-system-init/"&gt;阶段 0（上）：虚拟机与系统初始化&lt;/a&gt;。&#10;步骤编号延续上篇（从第 5 步开始）；所有命令在 Rocky 机器上以 root 执行。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="5-加载内核模块并开启-iptables-桥接流量必须"&gt;&lt;a href="#5-%e5%8a%a0%e8%bd%bd%e5%86%85%e6%a0%b8%e6%a8%a1%e5%9d%97%e5%b9%b6%e5%bc%80%e5%90%af-iptables-%e6%a1%a5%e6%8e%a5%e6%b5%81%e9%87%8f%e5%bf%85%e9%a1%bb" class="header-anchor"&gt;&lt;/a&gt;5. 加载内核模块并开启 iptables 桥接流量（必须）&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;为什么必须&lt;/strong&gt;——k8s 的 Service 网络（阶段 3 主角）依赖三样底层能力：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;overlay&lt;/code&gt;：容器镜像分层存储的文件系统，containerd 启动容器必备&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;br_netfilter&lt;/code&gt; + &lt;code&gt;bridge-nf-call-iptables=1&lt;/code&gt;：强制网桥流量经过 iptables。Service 虚拟 IP 靠 iptables 规则转换（kube-proxy 写入），桥内流量若绕过 iptables，Service 全部失灵&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;ip_forward=1&lt;/code&gt;：允许节点转发数据包，跨节点 Pod 通信的前提&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;缺了任何一样，阶段 1 的 &lt;code&gt;kubeadm init&lt;/code&gt; 预检会直接报错拒绝安装。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-0-1"&gt;&lt;a class="lnlinks" href="#hl-0-1"&gt; 1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-2"&gt;&lt;a class="lnlinks" href="#hl-0-2"&gt; 2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-3"&gt;&lt;a class="lnlinks" href="#hl-0-3"&gt; 3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-4"&gt;&lt;a class="lnlinks" href="#hl-0-4"&gt; 4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-5"&gt;&lt;a class="lnlinks" href="#hl-0-5"&gt; 5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-6"&gt;&lt;a class="lnlinks" href="#hl-0-6"&gt; 6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-7"&gt;&lt;a class="lnlinks" href="#hl-0-7"&gt; 7&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-8"&gt;&lt;a class="lnlinks" href="#hl-0-8"&gt; 8&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-9"&gt;&lt;a class="lnlinks" href="#hl-0-9"&gt; 9&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-10"&gt;&lt;a class="lnlinks" href="#hl-0-10"&gt;10&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-11"&gt;&lt;a class="lnlinks" href="#hl-0-11"&gt;11&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-12"&gt;&lt;a class="lnlinks" href="#hl-0-12"&gt;12&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-13"&gt;&lt;a class="lnlinks" href="#hl-0-13"&gt;13&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-14"&gt;&lt;a class="lnlinks" href="#hl-0-14"&gt;14&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-15"&gt;&lt;a class="lnlinks" href="#hl-0-15"&gt;15&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; /etc/modules-load.d/k8s.conf &lt;span class="s"&gt;&amp;lt;&amp;lt;EOF&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;overlay&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;br_netfilter&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;modprobe overlay&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;modprobe br_netfilter&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; /etc/sysctl.d/k8s.conf &lt;span class="s"&gt;&amp;lt;&amp;lt;EOF&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;net.bridge.bridge-nf-call-ip6tables = 1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;net.bridge.bridge-nf-call-iptables = 1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;net.ipv4.ip_forward = 1&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sysctl --system&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;验证&lt;/strong&gt;：&lt;code&gt;lsmod | grep br_netfilter&lt;/code&gt; 应有输出，例如：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-1-1"&gt;&lt;a class="lnlinks" href="#hl-1-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-2"&gt;&lt;a class="lnlinks" href="#hl-1-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;br_netfilter 32768 0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bridge 315392 1 br_netfilter&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;输出读法（四列 = 模块名 / 大小(字节) / 引用计数 / 被谁引用）：&#10;引用计数 &lt;code&gt;0&lt;/code&gt; 不等于没用——&lt;code&gt;br_netfilter&lt;/code&gt; 靠 sysctl 开关起作用，不靠被谁引用；&#10;&lt;code&gt;bridge&lt;/code&gt; 行尾出现 &lt;code&gt;br_netfilter&lt;/code&gt;，说明它是 bridge 网桥驱动的&amp;quot;扩展插件&amp;quot;，&#10;专门给网桥加 netfilter（iptables）钩子。两行都在 = 这对搭档都在岗。&#10;（&lt;code&gt;/etc/modules-load.d/&lt;/code&gt; 管开机自动加载，&lt;code&gt;modprobe&lt;/code&gt; 管立即生效，缺一不可。）&lt;/p&gt;&#10;&lt;h2 id="6-安装容器运行时-containerd"&gt;&lt;a href="#6-%e5%ae%89%e8%a3%85%e5%ae%b9%e5%99%a8%e8%bf%90%e8%a1%8c%e6%97%b6-containerd" class="header-anchor"&gt;&lt;/a&gt;6. 安装容器运行时 containerd&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;k8s 自己不会跑容器&lt;/strong&gt;——它只是调度大脑（决定 Pod 放哪台机器），真正拉镜像、起容器的是&lt;strong&gt;容器运行时&lt;/strong&gt;。kubelet 通过标准接口 CRI 指挥 containerd 干活：&lt;code&gt;kubectl 命令 → apiserver → scheduler → kubelet → containerd → 容器进程&lt;/code&gt;。&#10;Kubernetes 从 1.24 起不再直接支持 Docker（它对 k8s 来说太重），&lt;strong&gt;containerd 是主流选择&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;h3 id="61-安装"&gt;&lt;a href="#61-%e5%ae%89%e8%a3%85" class="header-anchor"&gt;&lt;/a&gt;6.1 安装&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-2-1"&gt;&lt;a class="lnlinks" href="#hl-2-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-2-2"&gt;&lt;a class="lnlinks" href="#hl-2-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-2-3"&gt;&lt;a class="lnlinks" href="#hl-2-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-2-4"&gt;&lt;a class="lnlinks" href="#hl-2-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-2-5"&gt;&lt;a class="lnlinks" href="#hl-2-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-2-6"&gt;&lt;a class="lnlinks" href="#hl-2-6"&gt;6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-2-7"&gt;&lt;a class="lnlinks" href="#hl-2-7"&gt;7&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-2-8"&gt;&lt;a class="lnlinks" href="#hl-2-8"&gt;8&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# download.docker.com 国内不可达，使用阿里云 docker-ce 源（只借用它里面的 containerd 包）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 安装 containerd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dnf -y install containerd.io&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 生成默认配置&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;containerd config default &amp;gt; /etc/containerd/config.toml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;containerd 的官方发布渠道是 Docker 公司的软件源 &lt;code&gt;download.docker.com&lt;/code&gt;（国内不可达）。阿里把它整个镜像了一份，我们&lt;strong&gt;借仓库只取 &lt;code&gt;containerd.io&lt;/code&gt; 这一个包&lt;/strong&gt;，不装 docker-ce 本身——虚拟机里不会有 Docker&lt;/li&gt;&#10;&lt;li&gt;包名是 &lt;code&gt;containerd.io&lt;/code&gt;（不带 .io 的是另一个老包，别搞混）&lt;/li&gt;&#10;&lt;li&gt;containerd 没有开箱即用的配置文件，必须先用 &lt;code&gt;config default&lt;/code&gt; 生成底版再修改&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="62-关键修改-1systemdcgroup--true与-kubelet-统一资源管理"&gt;&lt;a href="#62-%e5%85%b3%e9%94%ae%e4%bf%ae%e6%94%b9-1systemdcgroup--true%e4%b8%8e-kubelet-%e7%bb%9f%e4%b8%80%e8%b5%84%e6%ba%90%e7%ae%a1%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;6.2 关键修改 1：SystemdCgroup = true（与 kubelet 统一资源管理）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-3-1"&gt;&lt;a class="lnlinks" href="#hl-3-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -i &lt;span class="s1"&gt;&amp;#39;s/SystemdCgroup = false/SystemdCgroup = true/&amp;#39;&lt;/span&gt; /etc/containerd/config.toml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;为什么必改&lt;/strong&gt;：cgroup 是 Linux 给进程分配/限制资源（CPU、内存）的机制，k8s 的 requests/limits 全靠它。&#10;cgroup 有两种&amp;quot;管理员&amp;quot;：cgroupfs（传统写法）和 systemd（Rocky 9 等现代发行版由 systemd 统一管理）。&#10;&lt;strong&gt;一台机器只能有一个管理员&lt;/strong&gt;——kubelet 用 systemd，containerd 默认却是 cgroupfs（&lt;code&gt;false&lt;/code&gt;），&#10;两个管理员各记一套账，会导致资源统计错乱、节点不稳定。这行 sed 把 containerd 也划归 systemd 阵营。&lt;/p&gt;&#10;&lt;h3 id="63-关键修改-2certsd-镜像代理国内拉镜像的生存指南"&gt;&lt;a href="#63-%e5%85%b3%e9%94%ae%e4%bf%ae%e6%94%b9-2certsd-%e9%95%9c%e5%83%8f%e4%bb%a3%e7%90%86%e5%9b%bd%e5%86%85%e6%8b%89%e9%95%9c%e5%83%8f%e7%9a%84%e7%94%9f%e5%ad%98%e6%8c%87%e5%8d%97" class="header-anchor"&gt;&lt;/a&gt;6.3 关键修改 2：certs.d 镜像代理（国内拉镜像的生存指南）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-4-1"&gt;&lt;a class="lnlinks" href="#hl-4-1"&gt; 1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-2"&gt;&lt;a class="lnlinks" href="#hl-4-2"&gt; 2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-3"&gt;&lt;a class="lnlinks" href="#hl-4-3"&gt; 3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-4"&gt;&lt;a class="lnlinks" href="#hl-4-4"&gt; 4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-5"&gt;&lt;a class="lnlinks" href="#hl-4-5"&gt; 5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-6"&gt;&lt;a class="lnlinks" href="#hl-4-6"&gt; 6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-7"&gt;&lt;a class="lnlinks" href="#hl-4-7"&gt; 7&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-8"&gt;&lt;a class="lnlinks" href="#hl-4-8"&gt; 8&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-9"&gt;&lt;a class="lnlinks" href="#hl-4-9"&gt; 9&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-10"&gt;&lt;a class="lnlinks" href="#hl-4-10"&gt;10&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-11"&gt;&lt;a class="lnlinks" href="#hl-4-11"&gt;11&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-12"&gt;&lt;a class="lnlinks" href="#hl-4-12"&gt;12&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-13"&gt;&lt;a class="lnlinks" href="#hl-4-13"&gt;13&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-14"&gt;&lt;a class="lnlinks" href="#hl-4-14"&gt;14&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-15"&gt;&lt;a class="lnlinks" href="#hl-4-15"&gt;15&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-16"&gt;&lt;a class="lnlinks" href="#hl-4-16"&gt;16&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-17"&gt;&lt;a class="lnlinks" href="#hl-4-17"&gt;17&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-18"&gt;&lt;a class="lnlinks" href="#hl-4-18"&gt;18&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-4-19"&gt;&lt;a class="lnlinks" href="#hl-4-19"&gt;19&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Docker Hub 国内被墙，给 docker.io 配置镜像代理（daocloud）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# containerd 的 registry 配置采用 certs.d 目录（类似 docker 的 registry-mirrors）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p /etc/containerd/certs.d/docker.io&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; /etc/containerd/certs.d/docker.io/hosts.toml &lt;span class="s"&gt;&amp;lt;&amp;lt;EOF&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;server = &amp;#34;https://docker.io&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;[host.&amp;#34;https://docker.m.daocloud.io&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; capabilities = [&amp;#34;pull&amp;#34;, &amp;#34;resolve&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 同理给 registry.k8s.io 配代理：它的 CDN 是 Google 的，国内同样被墙&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#（kubeadm 装集群时我们改用阿里云源规避；但 ingress-nginx、metrics-server 等&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 第三方组件的镜像也在 registry.k8s.io，阶段 6/8 会用到这个代理）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p /etc/containerd/certs.d/registry.k8s.io&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; /etc/containerd/certs.d/registry.k8s.io/hosts.toml &lt;span class="s"&gt;&amp;lt;&amp;lt;EOF&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;server = &amp;#34;https://registry.k8s.io&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;[host.&amp;#34;https://k8s.m.daocloud.io&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; capabilities = [&amp;#34;pull&amp;#34;, &amp;#34;resolve&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 启用 certs.d 目录（containerd 2.x 默认配置里 config_path 为空，指过去即可）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -i &lt;span class="s2"&gt;&amp;#34;/^\s*config_path = &amp;#39;&amp;#39;\s*&lt;/span&gt;$&lt;span class="s2"&gt;/s/&amp;#39;&amp;#39;/&amp;#39;\/etc\/containerd\/certs.d&amp;#39;/&amp;#34;&lt;/span&gt; /etc/containerd/config.toml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;原理&lt;/strong&gt;：certs.d 是 containerd 的&amp;quot;仓库导航改写本&amp;quot;。它拉镜像时的决策过程是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-5-1"&gt;&lt;a class="lnlinks" href="#hl-5-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-2"&gt;&lt;a class="lnlinks" href="#hl-5-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-3"&gt;&lt;a class="lnlinks" href="#hl-5-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-4"&gt;&lt;a class="lnlinks" href="#hl-5-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-5"&gt;&lt;a class="lnlinks" href="#hl-5-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-6"&gt;&lt;a class="lnlinks" href="#hl-5-6"&gt;6&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;要拉 nginx:1.27&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓ 补全为完整地址 docker.io/library/nginx:1.27&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓ 查导航本：/etc/containerd/certs.d/ 下有没有叫 docker.io 的目录？&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓ 有！读里面的 hosts.toml：docker.io 的请求改走 docker.m.daocloud.io&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;实际从 daocloud 下载，但镜像在本地的&amp;#34;户口本&amp;#34;仍登记为 docker.io/library/nginx:1.27&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;目录结构就是映射关系——要拉哪个仓库的镜像，就用哪个目录下的 &lt;code&gt;hosts.toml&lt;/code&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-6-1"&gt;&lt;a class="lnlinks" href="#hl-6-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-2"&gt;&lt;a class="lnlinks" href="#hl-6-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-3"&gt;&lt;a class="lnlinks" href="#hl-6-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/etc/containerd/certs.d/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── docker.io/hosts.toml ← 拉 nginx 等 Docker Hub 镜像时生效&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── registry.k8s.io/hosts.toml ← 拉 k8s 官方组件镜像时生效&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;code&gt;hosts.toml&lt;/code&gt; 三行的含义：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-7-1"&gt;&lt;a class="lnlinks" href="#hl-7-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-7-2"&gt;&lt;a class="lnlinks" href="#hl-7-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-7-3"&gt;&lt;a class="lnlinks" href="#hl-7-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://docker.io&amp;#34;&lt;/span&gt; &lt;span class="c"&gt;# 这份配置管哪个仓库（&amp;#34;户主&amp;#34;）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://docker.m.daocloud.io&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c"&gt;# 实际去哪拉（&amp;#34;代取点&amp;#34;，可写多个按顺序试）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;capabilities&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;pull&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;resolve&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c"&gt;# 代取点只允许&amp;#34;解析+拉取&amp;#34;，禁止 push（安全）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;最后那条 sed 是总开关：containerd 2.x 默认配置里 &lt;code&gt;config_path = ''&lt;/code&gt;（空 = 根本不看 certs.d 目录），&#10;把它指向该目录，导航本才生效。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;为什么这样设计，而不是别的办法&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;❌ &lt;strong&gt;直接改镜像名&lt;/strong&gt;（把 &lt;code&gt;nginx&lt;/code&gt; 写成 &lt;code&gt;docker.m.daocloud.io/library/nginx&lt;/code&gt;）：镜像名写在全世界的&#10;YAML、Helm Chart、kubeadm 生成的清单里，改不完也改不到；换代理时还要全局替换&lt;/li&gt;&#10;&lt;li&gt;❌ &lt;strong&gt;配 HTTP 代理&lt;/strong&gt;：多一个要维护的中间故障点，且企业环境未必有代理可用&lt;/li&gt;&#10;&lt;li&gt;✅ &lt;strong&gt;certs.d&lt;/strong&gt;：只在一个地方声明映射，全世界照常用官方镜像名，拉取被悄悄改道；&#10;daocloud 挂了改两行 hosts.toml 换一家即可，业务零改动。&#10;本质是&lt;strong&gt;逻辑地址（镜像名）与物理地址（镜像站）解耦&lt;/strong&gt;，对 kubelet/YAML/Helm 完全透明&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;strong&gt;registry.k8s.io 那份的必要性&lt;/strong&gt;：阶段 1 装集群时核心组件可以换阿里云源，&#10;但 ingress-nginx（阶段 6）、metrics-server（阶段 8）等第三方组件的官方清单里&lt;strong&gt;写死了&lt;/strong&gt;&#10;&lt;code&gt;registry.k8s.io&lt;/code&gt; 地址，不便改也没法改。配上这条，届时 &lt;code&gt;kubectl apply&lt;/code&gt; 官方清单直接跑通。&lt;/p&gt;&#10;&lt;h3 id="64-关键修改-3pausesandbox镜像指向阿里云国内搭集群第一坑"&gt;&lt;a href="#64-%e5%85%b3%e9%94%ae%e4%bf%ae%e6%94%b9-3pausesandbox%e9%95%9c%e5%83%8f%e6%8c%87%e5%90%91%e9%98%bf%e9%87%8c%e4%ba%91%e5%9b%bd%e5%86%85%e6%90%ad%e9%9b%86%e7%be%a4%e7%ac%ac%e4%b8%80%e5%9d%91" class="header-anchor"&gt;&lt;/a&gt;6.4 关键修改 3：pause（sandbox）镜像指向阿里云（国内搭集群第一坑）&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-8-1"&gt;&lt;a class="lnlinks" href="#hl-8-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-2"&gt;&lt;a class="lnlinks" href="#hl-8-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-8-3"&gt;&lt;a class="lnlinks" href="#hl-8-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# kubelet 1.34 起改为从 containerd 获取 pause 镜像地址（旧的 --pod-infra-container-image 已失效），&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 而 containerd 默认的 registry.k8s.io/pause 的 CDN 国内被墙，不改会导致所有 Pod 卡在创建阶段&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sed -i &lt;span class="s2"&gt;&amp;#34;/^ \[plugins.&amp;#39;io.containerd.cri.v1.images&amp;#39;\]&lt;/span&gt;$&lt;span class="s2"&gt;/a\ sandbox_image = \&amp;#34;registry.aliyuncs.com/google_containers/pause:3.10.2\&amp;#34;&amp;#34;&lt;/span&gt; /etc/containerd/config.toml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;pause 容器是什么&lt;/strong&gt;：一个 Pod 可以装多个容器，它们共享同一个网络命名空间（同一个 IP）。&#10;这个&amp;quot;共享&amp;quot;需要一个先行者先把网络命名空间创建好、占住位置——就是 pause 容器（沙箱容器）。&#10;每个 Pod 里都有一个看不见的 pause，几乎不占资源，但没它 Pod 无法创建。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;问题链条&lt;/strong&gt;：pause 镜像默认在 &lt;code&gt;registry.k8s.io/pause&lt;/code&gt;（Google CDN，国内被墙）→&#10;老办法是 kubelet 参数 &lt;code&gt;--pod-infra-container-image&lt;/code&gt;，但 &lt;strong&gt;kubelet 1.34 起该参数失效&lt;/strong&gt;，&#10;改为从 containerd 的 &lt;code&gt;sandbox_image&lt;/code&gt; 读取 → 不改的后果是&lt;strong&gt;所有 Pod 永远卡在 ContainerCreating&lt;/strong&gt;。&#10;这条 sed 在该插件节下追加一行，指向阿里云镜像站（&lt;code&gt;a\&lt;/code&gt; = 在匹配行之后追加）。&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;三关总结：&lt;code&gt;SystemdCgroup&lt;/code&gt; 让 containerd 与 kubelet 和平共处；&#10;&lt;code&gt;certs.d&lt;/code&gt; 让 Docker Hub / k8s 官方镜像拉得到；&lt;code&gt;sandbox_image&lt;/code&gt; 让 Pod 能创建。&#10;少任何一个，阶段 1 都会以不同的姿势翻车。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h3 id="65-按需虚拟机直连出网被拦时给-containerd-配代理"&gt;&lt;a href="#65-%e6%8c%89%e9%9c%80%e8%99%9a%e6%8b%9f%e6%9c%ba%e7%9b%b4%e8%bf%9e%e5%87%ba%e7%bd%91%e8%a2%ab%e6%8b%a6%e6%97%b6%e7%bb%99-containerd-%e9%85%8d%e4%bb%a3%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;6.5 （按需）虚拟机直连出网被拦时：给 containerd 配代理&#10;&lt;/h3&gt;&lt;p&gt;containerd 是系统服务，不读你终端里 export 的代理变量，必须用 systemd drop-in 单独配置&#10;（&lt;code&gt;192.168.5.2&lt;/code&gt; 是 Lima 内置的&amp;quot;Mac 本机&amp;quot;地址，长期有效，排查思路见&#10;&lt;a href="https://saflyer.cn/posts/k8s-00a-vm-system-init/"&gt;阶段 0（上）附录 A&lt;/a&gt;）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-9-1"&gt;&lt;a class="lnlinks" href="#hl-9-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-9-2"&gt;&lt;a class="lnlinks" href="#hl-9-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-9-3"&gt;&lt;a class="lnlinks" href="#hl-9-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-9-4"&gt;&lt;a class="lnlinks" href="#hl-9-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-9-5"&gt;&lt;a class="lnlinks" href="#hl-9-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-9-6"&gt;&lt;a class="lnlinks" href="#hl-9-6"&gt;6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-9-7"&gt;&lt;a class="lnlinks" href="#hl-9-7"&gt;7&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p /etc/systemd/system/containerd.service.d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; /etc/systemd/system/containerd.service.d/proxy.conf &lt;span class="s"&gt;&amp;lt;&amp;lt;EOF&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;[Service]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;Environment=&amp;#34;HTTP_PROXY=http://192.168.5.2:7897&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;Environment=&amp;#34;HTTPS_PROXY=http://192.168.5.2:7897&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;Environment=&amp;#34;NO_PROXY=localhost,127.0.0.1,192.168.5.0/24,192.168.64.0/24,192.168.0.0/16,10.96.0.0/12&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;⚠️ 配了这个代理后，将来直连恢复或 Clash 关闭时&lt;strong&gt;必须删掉它并重启 containerd&lt;/strong&gt;&#10;（&lt;code&gt;rm 该文件 &amp;amp;&amp;amp; systemctl daemon-reload &amp;amp;&amp;amp; systemctl restart containerd&lt;/code&gt;），&#10;否则 containerd 拉镜像全部失败。原则：代理配置和代理软件同开同关。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h3 id="66-启动与验证"&gt;&lt;a href="#66-%e5%90%af%e5%8a%a8%e4%b8%8e%e9%aa%8c%e8%af%81" class="header-anchor"&gt;&lt;/a&gt;6.6 启动与验证&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-10-1"&gt;&lt;a class="lnlinks" href="#hl-10-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-2"&gt;&lt;a class="lnlinks" href="#hl-10-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-3"&gt;&lt;a class="lnlinks" href="#hl-10-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-4"&gt;&lt;a class="lnlinks" href="#hl-10-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-10-5"&gt;&lt;a class="lnlinks" href="#hl-10-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 启动并设为开机自启&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl daemon-reload&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now containerd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl restart containerd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl status containerd --no-pager&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;验证&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-11-1"&gt;&lt;a class="lnlinks" href="#hl-11-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ctr version &lt;span class="c1"&gt;# 能看到 Client/Server 版本号即成功&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;💡 &lt;strong&gt;镜像代理说明&lt;/strong&gt;：配置后，所有 &lt;code&gt;nginx&lt;/code&gt;、&lt;code&gt;mysql&lt;/code&gt; 这类来自 Docker Hub 的镜像&#10;会经由 &lt;code&gt;docker.m.daocloud.io&lt;/code&gt; 代理拉取，对 Kubernetes 完全透明（镜像名不用改）。&#10;如果 daocloud 将来失效，换其他可用代理地址改 &lt;code&gt;hosts.toml&lt;/code&gt; 即可。&#10;k8s 官方镜像仓库 &lt;code&gt;registry.k8s.io&lt;/code&gt; 本教程网络实测可达，无需代理；&#10;如果你的网络不行，阶段 1 有阿里云替代方案。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="7-检查清单"&gt;&lt;a href="#7-%e6%a3%80%e6%9f%a5%e6%b8%85%e5%8d%95" class="header-anchor"&gt;&lt;/a&gt;7. 检查清单&#10;&lt;/h2&gt;&lt;p&gt;进入下一阶段前确认：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-12-1"&gt;&lt;a class="lnlinks" href="#hl-12-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-2"&gt;&lt;a class="lnlinks" href="#hl-12-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-3"&gt;&lt;a class="lnlinks" href="#hl-12-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-4"&gt;&lt;a class="lnlinks" href="#hl-12-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-12-5"&gt;&lt;a class="lnlinks" href="#hl-12-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;swapon --show &lt;span class="c1"&gt;# 无输出（swap 已关）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;getenforce &lt;span class="c1"&gt;# Permissive&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl is-active containerd &lt;span class="c1"&gt;# active&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sysctl net.ipv4.ip_forward &lt;span class="c1"&gt;# = 1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lsmod &lt;span class="p"&gt;|&lt;/span&gt; grep br_netfilter &lt;span class="c1"&gt;# 有输出&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="常见问题"&gt;&lt;a href="#%e5%b8%b8%e8%a7%81%e9%97%ae%e9%a2%98" class="header-anchor"&gt;&lt;/a&gt;常见问题&#10;&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Q: 第 6 步装 containerd / 拉镜像时网络不通？&lt;/strong&gt;&#10;containerd 是系统服务，不读终端环境变量。先按上篇附录 A 的分层法确认是不是&amp;quot;虚拟机直连被拦&amp;quot;，&#10;是的话用第 6.5 节的 systemd drop-in 给 containerd 配代理；&#10;将来 Pod 出现 &lt;code&gt;ImagePullBackOff&lt;/code&gt; 也先怀疑这层。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Q: containerd 配置文件里的插件名为什么和网上旧教程不一样？&lt;/strong&gt;&#10;containerd 2.x 使用了新版配置格式（如 &lt;code&gt;io.containerd.cri.v1.images&lt;/code&gt;），&#10;旧教程里的 &lt;code&gt;io.containerd.grpc.v1.cri&lt;/code&gt; 是 1.x 的写法。本教程的 sed 命令两种都兼容。&lt;/p&gt;&#10;&lt;h2 id="附录-b集群装好后如何验证阶段-1-完成后使用"&gt;&lt;a href="#%e9%99%84%e5%bd%95-b%e9%9b%86%e7%be%a4%e8%a3%85%e5%a5%bd%e5%90%8e%e5%a6%82%e4%bd%95%e9%aa%8c%e8%af%81%e9%98%b6%e6%ae%b5-1-%e5%ae%8c%e6%88%90%e5%90%8e%e4%bd%bf%e7%94%a8" class="header-anchor"&gt;&lt;/a&gt;附录 B：集群装好后如何验证（阶段 1 完成后使用）&#10;&lt;/h2&gt;&lt;p&gt;进程活着 ≠ 集群可用，&lt;strong&gt;能跑起一个真 Pod 才是终极证明&lt;/strong&gt;。按三层验证（虚拟机里、root 执行）：&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;第一层：节点状态&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-13-1"&gt;&lt;a class="lnlinks" href="#hl-13-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-13-2"&gt;&lt;a class="lnlinks" href="#hl-13-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get nodes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 期望：STATUS 是 Ready&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第二层：系统组件 Pod 全部 Running&lt;/strong&gt;（最关键）&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-14-1"&gt;&lt;a class="lnlinks" href="#hl-14-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-14-2"&gt;&lt;a class="lnlinks" href="#hl-14-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-14-3"&gt;&lt;a class="lnlinks" href="#hl-14-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-14-4"&gt;&lt;a class="lnlinks" href="#hl-14-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-14-5"&gt;&lt;a class="lnlinks" href="#hl-14-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-14-6"&gt;&lt;a class="lnlinks" href="#hl-14-6"&gt;6&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods -n kube-system&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 期望：etcd、kube-apiserver、kube-scheduler、kube-controller-manager、&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# coredns（2个）、calico-node 全部 Running 且 READY 是 1/1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods -A&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 不能有 Pending / CrashLoopBackOff / ImagePullBackOff&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;第三层：跑一个真容器（终极证明）&lt;/strong&gt;&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-15-1"&gt;&lt;a class="lnlinks" href="#hl-15-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-15-2"&gt;&lt;a class="lnlinks" href="#hl-15-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-15-3"&gt;&lt;a class="lnlinks" href="#hl-15-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-15-4"&gt;&lt;a class="lnlinks" href="#hl-15-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-15-5"&gt;&lt;a class="lnlinks" href="#hl-15-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl run nginx-test --image&lt;span class="o"&gt;=&lt;/span&gt;nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods -w &lt;span class="c1"&gt;# 看到 Running 后 Ctrl+C（这步同时验证了调度、镜像拉取、pause 镜像、CNI）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl get pods -o wide &lt;span class="c1"&gt;# Pod 拿到 IP = Calico 网络正常&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; -it nginx-test -- curl -sI localhost &lt;span class="p"&gt;|&lt;/span&gt; head -1 &lt;span class="c1"&gt;# 期望：HTTP/1.1 200 OK&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl delete pod nginx-test &lt;span class="c1"&gt;# 清理&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;辅助定位&lt;/strong&gt;（上面不正常时查）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-16-1"&gt;&lt;a class="lnlinks" href="#hl-16-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-16-2"&gt;&lt;a class="lnlinks" href="#hl-16-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl is-active kubelet containerd &lt;span class="c1"&gt;# 都应为 active&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;crictl ps &lt;span class="p"&gt;|&lt;/span&gt; head &lt;span class="c1"&gt;# containerd 层面的容器（应有 pause 和业务容器）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;判断标准速记：&lt;code&gt;get nodes&lt;/code&gt; Ready → 集群成立；kube-system 全 Running → 控制面健康；&#10;自建 Pod 到 Running 且能 exec → 端到端真通了（也是本阶段 containerd 三个关键修改的验收）。&#10;若 kubectl 报 &amp;ldquo;connection to localhost:8080 refused&amp;rdquo;，说明 kubeconfig 没配，先做阶段 1 的&#10;&lt;code&gt;mkdir -p $HOME/.kube &amp;amp;&amp;amp; cp /etc/kubernetes/admin.conf $HOME/.kube/config&lt;/code&gt;。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h2 id="动手练习"&gt;&lt;a href="#%e5%8a%a8%e6%89%8b%e7%bb%83%e4%b9%a0" class="header-anchor"&gt;&lt;/a&gt;动手练习&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;查看 containerd 配置文件 &lt;code&gt;/etc/containerd/config.toml&lt;/code&gt;，找到你刚改的 &lt;code&gt;SystemdCgroup&lt;/code&gt; 和 &lt;code&gt;config_path&lt;/code&gt; 两行。&lt;/li&gt;&#10;&lt;li&gt;查看 &lt;code&gt;/etc/containerd/certs.d/docker.io/hosts.toml&lt;/code&gt;，理解镜像代理的配置结构。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="下一步"&gt;&lt;a href="#%e4%b8%8b%e4%b8%80%e6%ad%a5" class="header-anchor"&gt;&lt;/a&gt;下一步&#10;&lt;/h2&gt;&lt;p&gt;➡️ 阶段 1：搭建集群（系列第 1 篇，即将发布——从这里开始正式安装 Kubernetes）&lt;/p&gt;&#10;</description></item><item><title>建站运维 02：服务器防爆破实战——fail2ban 部署全记录</title><link>https://saflyer.cn/posts/fail2ban-anti-bruteforce/</link><pubDate>Fri, 11 Sep 2026 16:25:54 +0800</pubDate><guid>https://saflyer.cn/posts/fail2ban-anti-bruteforce/</guid><description>&lt;img src="https://saflyer.cn/posts/fail2ban-anti-bruteforce/cover.webp" alt="Featured image of post 建站运维 02：服务器防爆破实战——fail2ban 部署全记录" /&gt;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;环境&lt;/strong&gt;：腾讯云轻量服务器 / Rocky Linux 9.4 / 2C4G&#10;&lt;strong&gt;日期&lt;/strong&gt;：2026-09-11&#10;&lt;strong&gt;背景&lt;/strong&gt;：服务器 iptables 里有一串 REJECT 名单（云主机安全组件在拦截恶意 IP），查日志发现&lt;strong&gt;过去 24 小时有 397 次 SSH 密码爆破尝试&lt;/strong&gt;——说明我的服务器一直在被人扫。是时候上 fail2ban 了。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="一fail2ban-是什么"&gt;&lt;a href="#%e4%b8%80fail2ban-%e6%98%af%e4%bb%80%e4%b9%88" class="header-anchor"&gt;&lt;/a&gt;一、fail2ban 是什么&#10;&lt;/h2&gt;&lt;p&gt;一句话：&lt;strong&gt;盯着登录日志，谁试错 N 次就把谁关进小黑屋&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;工作机制分两半：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;Filter（侦察兵）&lt;/strong&gt;：实时监控日志（SSH、nginx 等），用正则抓「登录失败」事件，按 IP 计数&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Action（执法队）&lt;/strong&gt;：某 IP 在 &lt;code&gt;findtime&lt;/code&gt; 窗口内失败达到 &lt;code&gt;maxretry&lt;/code&gt; 次 → 自动往 iptables 写一条 REJECT 规则，封禁 &lt;code&gt;bantime&lt;/code&gt; 时长&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;整个过程全自动，不需要人盯着。&lt;/p&gt;&#10;&lt;h2 id="二安装rocky-9--dnf-系"&gt;&lt;a href="#%e4%ba%8c%e5%ae%89%e8%a3%85rocky-9--dnf-%e7%b3%bb" class="header-anchor"&gt;&lt;/a&gt;二、安装（Rocky 9 / dnf 系）&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-0-1"&gt;&lt;a class="lnlinks" href="#hl-0-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-0-2"&gt;&lt;a class="lnlinks" href="#hl-0-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dnf install -y fail2ban fail2ban-firewalld&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fail2ban-client --version &lt;span class="c1"&gt;# 装到 v1.1.0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="三配置etcfail2banjaillocal"&gt;&lt;a href="#%e4%b8%89%e9%85%8d%e7%bd%aeetcfail2banjaillocal" class="header-anchor"&gt;&lt;/a&gt;三、配置（/etc/fail2ban/jail.local）&#10;&lt;/h2&gt;&lt;p&gt;不要改自带的 &lt;code&gt;jail.conf&lt;/code&gt;（升级会被覆盖），新建 &lt;code&gt;jail.local&lt;/code&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-1-1"&gt;&lt;a class="lnlinks" href="#hl-1-1"&gt; 1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-2"&gt;&lt;a class="lnlinks" href="#hl-1-2"&gt; 2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-3"&gt;&lt;a class="lnlinks" href="#hl-1-3"&gt; 3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-4"&gt;&lt;a class="lnlinks" href="#hl-1-4"&gt; 4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-5"&gt;&lt;a class="lnlinks" href="#hl-1-5"&gt; 5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-6"&gt;&lt;a class="lnlinks" href="#hl-1-6"&gt; 6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-7"&gt;&lt;a class="lnlinks" href="#hl-1-7"&gt; 7&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-8"&gt;&lt;a class="lnlinks" href="#hl-1-8"&gt; 8&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-9"&gt;&lt;a class="lnlinks" href="#hl-1-9"&gt; 9&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-10"&gt;&lt;a class="lnlinks" href="#hl-1-10"&gt;10&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-11"&gt;&lt;a class="lnlinks" href="#hl-1-11"&gt;11&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-12"&gt;&lt;a class="lnlinks" href="#hl-1-12"&gt;12&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-13"&gt;&lt;a class="lnlinks" href="#hl-1-13"&gt;13&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-14"&gt;&lt;a class="lnlinks" href="#hl-1-14"&gt;14&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-15"&gt;&lt;a class="lnlinks" href="#hl-1-15"&gt;15&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-16"&gt;&lt;a class="lnlinks" href="#hl-1-16"&gt;16&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-17"&gt;&lt;a class="lnlinks" href="#hl-1-17"&gt;17&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-1-18"&gt;&lt;a class="lnlinks" href="#hl-1-18"&gt;18&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[DEFAULT]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 本机 IP 永不封禁（防误伤自己）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;ignoreip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;127.0.0.1/8 ::1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;bantime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;24h # 封多久&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;findtime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;10m # 多长的观察窗口&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;maxretry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;5 # 窗口内失败几次就封&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;backend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;systemd # 关键！见下方踩坑&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;banaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;iptables-multiport&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[sshd]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;ssh&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[nginx-http-auth]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[nginx-botsearch]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="踩坑rocky-9-上必须-backend--systemd"&gt;&lt;a href="#%e8%b8%a9%e5%9d%91rocky-9-%e4%b8%8a%e5%bf%85%e9%a1%bb-backend--systemd" class="header-anchor"&gt;&lt;/a&gt;踩坑：Rocky 9 上必须 &lt;code&gt;backend = systemd&lt;/code&gt;&#10;&lt;/h3&gt;&lt;p&gt;传统教程都写监控 &lt;code&gt;/var/log/secure&lt;/code&gt;，但 &lt;strong&gt;Rocky 9 / RHEL 9 的 SSH 日志默认进 systemd journal&lt;/strong&gt;，&lt;code&gt;/var/log/secure&lt;/code&gt; 是空的或不完整。不改 backend 的话 fail2ban 会显示「No file is currently monitored」——看似在跑，其实在梦游。&lt;/p&gt;&#10;&lt;h3 id="启动"&gt;&lt;a href="#%e5%90%af%e5%8a%a8" class="header-anchor"&gt;&lt;/a&gt;启动&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-2-1"&gt;&lt;a class="lnlinks" href="#hl-2-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-2-2"&gt;&lt;a class="lnlinks" href="#hl-2-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now fail2ban&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl restart fail2ban&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="四验证别只看启动成功"&gt;&lt;a href="#%e5%9b%9b%e9%aa%8c%e8%af%81%e5%88%ab%e5%8f%aa%e7%9c%8b%e5%90%af%e5%8a%a8%e6%88%90%e5%8a%9f" class="header-anchor"&gt;&lt;/a&gt;四、验证：别只看「启动成功」&#10;&lt;/h2&gt;&lt;p&gt;服务 active ≠ 在干活。要验证三件事：&lt;/p&gt;&#10;&lt;h3 id="1-日志源有没有盯上"&gt;&lt;a href="#1-%e6%97%a5%e5%bf%97%e6%ba%90%e6%9c%89%e6%b2%a1%e6%9c%89%e7%9b%af%e4%b8%8a" class="header-anchor"&gt;&lt;/a&gt;1. 日志源有没有盯上&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-3-1"&gt;&lt;a class="lnlinks" href="#hl-3-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fail2ban-client status sshd&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;关键看输出里的 &lt;code&gt;Journal matches&lt;/code&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-4-1"&gt;&lt;a class="lnlinks" href="#hl-4-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd + _COMM=sshd-session&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;有这行 = 侦察兵真的在盯 sshd 的 journal。如果显示 &lt;code&gt;No file is currently monitored&lt;/code&gt;，就是上面的 backend 坑。&lt;/p&gt;&#10;&lt;h3 id="2-封禁链路端到端实测重要"&gt;&lt;a href="#2-%e5%b0%81%e7%a6%81%e9%93%be%e8%b7%af%e7%ab%af%e5%88%b0%e7%ab%af%e5%ae%9e%e6%b5%8b%e9%87%8d%e8%a6%81" class="header-anchor"&gt;&lt;/a&gt;2. 封禁链路端到端实测（重要！）&#10;&lt;/h3&gt;&lt;p&gt;光看 status 不够，手动封一个测试 IP 验证整条链路：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-5-1"&gt;&lt;a class="lnlinks" href="#hl-5-1"&gt; 1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-2"&gt;&lt;a class="lnlinks" href="#hl-5-2"&gt; 2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-3"&gt;&lt;a class="lnlinks" href="#hl-5-3"&gt; 3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-4"&gt;&lt;a class="lnlinks" href="#hl-5-4"&gt; 4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-5"&gt;&lt;a class="lnlinks" href="#hl-5-5"&gt; 5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-6"&gt;&lt;a class="lnlinks" href="#hl-5-6"&gt; 6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-7"&gt;&lt;a class="lnlinks" href="#hl-5-7"&gt; 7&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-8"&gt;&lt;a class="lnlinks" href="#hl-5-8"&gt; 8&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-9"&gt;&lt;a class="lnlinks" href="#hl-5-9"&gt; 9&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-10"&gt;&lt;a class="lnlinks" href="#hl-5-10"&gt;10&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-11"&gt;&lt;a class="lnlinks" href="#hl-5-11"&gt;11&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-12"&gt;&lt;a class="lnlinks" href="#hl-5-12"&gt;12&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-13"&gt;&lt;a class="lnlinks" href="#hl-5-13"&gt;13&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-5-14"&gt;&lt;a class="lnlinks" href="#hl-5-14"&gt;14&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 203.0.113.99 是 TEST-NET-3 保留地址，随便用不会误伤真人&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fail2ban-client &lt;span class="nb"&gt;set&lt;/span&gt; sshd banip 203.0.113.99&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 看 fail2ban 认账了&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fail2ban-client status sshd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Currently banned: 1 / Banned IP list: 203.0.113.99&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 关键：确认 iptables 里真的出现了拦截规则&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iptables -L -n &lt;span class="p"&gt;|&lt;/span&gt; grep -A2 f2b-sshd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Chain f2b-sshd (1 references)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# REJECT 0 -- 203.0.113.99 0.0.0.0/0 reject-with icmp-port-unreachable&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 测完放出来&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fail2ban-client &lt;span class="nb"&gt;set&lt;/span&gt; sshd unbanip 203.0.113.99&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;只有 iptables 里亲眼看到 REJECT 规则，才算部署完成。&lt;/p&gt;&#10;&lt;h3 id="3-status-输出字段怎么看"&gt;&lt;a href="#3-status-%e8%be%93%e5%87%ba%e5%ad%97%e6%ae%b5%e6%80%8e%e4%b9%88%e7%9c%8b" class="header-anchor"&gt;&lt;/a&gt;3. status 输出字段怎么看&#10;&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-6-1"&gt;&lt;a class="lnlinks" href="#hl-6-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-2"&gt;&lt;a class="lnlinks" href="#hl-6-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-3"&gt;&lt;a class="lnlinks" href="#hl-6-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-4"&gt;&lt;a class="lnlinks" href="#hl-6-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-5"&gt;&lt;a class="lnlinks" href="#hl-6-5"&gt;5&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-6"&gt;&lt;a class="lnlinks" href="#hl-6-6"&gt;6&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-7"&gt;&lt;a class="lnlinks" href="#hl-6-7"&gt;7&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-8"&gt;&lt;a class="lnlinks" href="#hl-6-8"&gt;8&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-6-9"&gt;&lt;a class="lnlinks" href="#hl-6-9"&gt;9&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Status for the jail: sshd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─ Filter&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├─ Currently failed: 0 ← 当前观察窗内正在试错的 IP 数&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├─ Total failed: 0 ← 启动以来抓到的失败总数（不追溯启动前的）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └─ Journal matches: ... ← 盯的日志源&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└─ Actions&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├─ Currently banned: 0 ← 此刻小黑屋里关着几个&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├─ Total banned: 1 ← 历史累计（含手动测试那个）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └─ Banned IP list: ... ← 当前名单&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="五日常运维"&gt;&lt;a href="#%e4%ba%94%e6%97%a5%e5%b8%b8%e8%bf%90%e7%bb%b4" class="header-anchor"&gt;&lt;/a&gt;五、日常运维&#10;&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt" id="hl-7-1"&gt;&lt;a class="lnlinks" href="#hl-7-1"&gt;1&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-7-2"&gt;&lt;a class="lnlinks" href="#hl-7-2"&gt;2&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-7-3"&gt;&lt;a class="lnlinks" href="#hl-7-3"&gt;3&lt;/a&gt;&#10;&lt;/span&gt;&lt;span class="lnt" id="hl-7-4"&gt;&lt;a class="lnlinks" href="#hl-7-4"&gt;4&lt;/a&gt;&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fail2ban-client status &lt;span class="c1"&gt;# 看有几个 jail 在跑&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fail2ban-client status sshd &lt;span class="c1"&gt;# 看战果（封了几个、是谁）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fail2ban-client &lt;span class="nb"&gt;set&lt;/span&gt; sshd unbanip &amp;lt;IP&amp;gt; &lt;span class="c1"&gt;# 误封了手动放人&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tail -f /var/log/fail2ban.log &lt;span class="c1"&gt;# 看实时动态&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h2 id="六后续加固路线"&gt;&lt;a href="#%e5%85%ad%e5%90%8e%e7%bb%ad%e5%8a%a0%e5%9b%ba%e8%b7%af%e7%ba%bf" class="header-anchor"&gt;&lt;/a&gt;六、后续加固路线&#10;&lt;/h2&gt;&lt;p&gt;fail2ban 只是第一道防线，后面还排着：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;SSH 密钥登录 + 关密码登录&lt;/strong&gt;——做完这个，爆破直接归零（釜底抽薪）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;安全组收敛&lt;/strong&gt;——22 端口只对常用 IP 段开放&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;dnf-automatic 自动安全更新&lt;/strong&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;登录成功告警&lt;/strong&gt;——有人登上服务器立刻通知我&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="七总结"&gt;&lt;a href="#%e4%b8%83%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;七、总结&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;部署成本：10 分钟&lt;/li&gt;&#10;&lt;li&gt;维护成本：零（全自动）&lt;/li&gt;&#10;&lt;li&gt;收益：397 次/天的爆破尝试，从「全靠密码强度硬扛」变成「试错 5 次关 24 小时」&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;公网服务器第一课：&lt;strong&gt;你以为是安静的小站，扫描器眼里是嗷嗷待宰的肉鸡&lt;/strong&gt;。fail2ban 该装就早点装。&lt;/p&gt;&#10;</description></item></channel></rss>