<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Inventory on Tarragon</title><link>https://tarrragon.github.io/blog/tags/inventory/</link><description>Recent content in Inventory on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 03 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/inventory/index.xml" rel="self" type="application/rss+xml"/><item><title>接手陌生機器的盤點：先讀清楚它在跑什麼</title><link>https://tarrragon.github.io/blog/linux/install/inventory-unknown-machine/</link><pubDate>Fri, 03 Jul 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/install/inventory-unknown-machine/</guid><description>&lt;p>這篇處理的情境跟本系列其他篇相反：機器已經裝好、已經在跑，裝它的人可能已離職、可能只留下一句「都在上面了」。系列主線教你把一台空機器變成能跑活的機器；這篇教你把一台「不知道在跑什麼的機器」變成「盤點清楚、敢動手維護的機器」。對照 infra 樹，這篇是 &lt;a href="https://tarrragon.github.io/blog/infra/00-infra-mindset/first-day-with-cloud-account/" data-link-title="拿到雲端帳號的第一天" data-link-desc="被指派 infra 工作、拿到 AWS 或 GCP 帳號、不確定該先做什麼時讀 — 第一小時安全底線、帳號現況判讀、後續學習路線分流">拿到雲端帳號的第一天&lt;/a> 的 OS 層對等篇——那篇盤點的是雲端帳號裡有什麼資源，這篇盤點的是單一台 Linux 機器裡有什麼狀態。&lt;/p>
&lt;p>核心紀律只有一條：&lt;strong>盤點期間只讀不改&lt;/strong>。這跟 &lt;a href="../../debug/diagnosis-read-authoritative-state/">診斷心法&lt;/a> 的「讀權威狀態」是同一個紀律的不同應用——診斷是出問題後讀狀態找根因，盤點是還沒出問題時讀狀態建立現況清單。改動留到盤點完成、你能回答「這台機器停掉會影響誰」之後。本篇所有指令都是唯讀查詢，照著跑不會改變機器狀態；少數需要 root 權限的會標明。&lt;/p>
&lt;p>盤點的產出是一份清單，建議直接開一個文字檔邊查邊記。這份清單之後會變成把機器收斂進版本控制的依據——terminal 捲動紀錄留不住，清單留得住。&lt;/p>
&lt;h2 id="這台是什麼機器">這台是什麼機器&lt;/h2>
&lt;p>盤點的第一層是機器的身分：發行版、架構、實體還是虛擬、活多久了。這層決定後面每一步用什麼指令——套件管理器、服務管理方式、log 位置全由發行版決定，判讀邏輯見 &lt;a href="../platform-divergence-map/">平台與發行版差異的判讀地圖&lt;/a>。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">cat /etc/os-release &lt;span class="c1"># 發行版與版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">uname -a &lt;span class="c1"># kernel 版本與架構（x86_64 / aarch64）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">systemd-detect-virt &lt;span class="c1"># 虛擬化偵測：kvm / vmware / none（實體機）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">uptime &lt;span class="c1"># 活多久、負載&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">hostnamectl &lt;span class="c1"># 主機名與上面幾項的整合視圖&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>uptime&lt;/code> 的天數是一個重要訊號：跑了四百天的機器代表它從沒被重開驗證過——上面的服務能不能在重開機後自己回來，沒人知道。這會影響你後面對「開機自啟清單」那段的重視程度。&lt;/p>
&lt;h2 id="誰能進來">誰能進來&lt;/h2>
&lt;p>第二層是存取面：有哪些帳號、誰有 sudo、誰的 key 被授權登入。接手的機器上常有前人留下的帳號與 key，這些是你動手維護前必須知道的存取路徑——不知道誰能進來，就無法判斷一個改動是不是「只有你會做」。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 有登入 shell 的帳號（排除 nologin / false 的系統帳號）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">grep -vE &lt;span class="s1">&amp;#39;(nologin|false)$&amp;#39;&lt;/span> /etc/passwd
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 誰有 sudo：主檔 + drop-in 目錄都要看（需要 root）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">sudo cat /etc/sudoers
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">sudo ls /etc/sudoers.d/ &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> sudo cat /etc/sudoers.d/*
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="c1"># 每個真人帳號的 SSH 授權 key&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">cat ~/.ssh/authorized_keys
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">sudo cat /home/*/.ssh/authorized_keys
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1"># 最近誰登入過&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">last -20&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>authorized_keys&lt;/code> 每行結尾的 comment（通常是 &lt;code>user@hostname&lt;/code>）是判斷 key 主人的線索。無法對應到在職人員的 key 記進清單——盤點期間先不刪，但接管後的第一批改動應該包含輪替它們。sudoers 的 &lt;code>NOPASSWD&lt;/code> 條目也記下來：它可能是前人為無人值守任務設的，判斷它還需不需要存在的依據見 &lt;a href="../unattended-remote-work/">讓機器跑無人值守的長任務&lt;/a> 對這個取捨的展開。&lt;/p>
&lt;h2 id="跑什麼服務誰開機自啟">跑什麼服務、誰開機自啟&lt;/h2>
&lt;p>第三層是這台機器的「工作內容」：現在跑著哪些服務、重開機後哪些會自己回來。這兩份清單常常對不上，而對不上的地方就是接手後的地雷。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 現在在跑的服務&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">systemctl list-units --type&lt;span class="o">=&lt;/span>service --state&lt;span class="o">=&lt;/span>running
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 開機會自啟的（不只 service，也含 socket / timer）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">systemctl list-unit-files --state&lt;span class="o">=&lt;/span>enabled
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="c1"># 各使用者層的 user unit（--user 屬於各帳號、root 看不到全部）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">systemctl --user list-units --type&lt;span class="o">=&lt;/span>service --state&lt;span class="o">=&lt;/span>running
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">9&lt;/span>&lt;span class="cl">ls /home/*/.config/systemd/user/ 2&amp;gt;/dev/null&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>兩份清單的差集各有含義。&lt;strong>在跑但沒 enable&lt;/strong> 的服務，重開機就消失——它可能是有人手動 &lt;code>systemctl start&lt;/code> 起來忘了 enable，也可能本來就該臨時。&lt;strong>enable 了但沒在跑&lt;/strong>的服務，代表它啟動失敗過或被手動停掉，&lt;code>systemctl status &amp;lt;unit&amp;gt;&lt;/code> 看它最後的狀態與退出原因。&lt;/p>
&lt;p>systemd 之外還有一塊盲區：直接被人手動跑起來、或掛在終端機多工器 session 裡的長期進程。&lt;code>ps aux&lt;/code> 全列太吵，用兩個角度收斂：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 不是從 systemd 起的長期進程：看父進程鏈&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">ps -eo pid,ppid,user,etime,comm --sort&lt;span class="o">=&lt;/span>-etime &lt;span class="p">|&lt;/span> head -30
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 有沒有掛著的 tmux / zellij / screen session（要逐一以各使用者身分查）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">tmux ls 2&amp;gt;/dev/null&lt;span class="p">;&lt;/span> zellij list-sessions 2&amp;gt;/dev/null&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>etime&lt;/code>（運行時長）長但不在 systemd 清單裡的進程，多半是手動起的。掛在多工器 session 裡的服務是最脆的一種——機器重開就沒了、也沒有任何監控。判斷一個進程「活著」與「由誰提供」的精確方法（&lt;code>pgrep&lt;/code> 的比對陷阱、busctl 查註冊表），見 &lt;a href="../../debug/process-service-state-diagnosis/">程序、服務與狀態怎麼判&lt;/a>。&lt;/p>
&lt;h2 id="排程任務藏在哪">排程任務藏在哪&lt;/h2>
&lt;p>第四層是排程：機器在沒人操作的時段自己做什麼。排程任務散落在多個落點，漏看一個就會在某天凌晨被一個「不知道哪來的」任務嚇到。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># systemd timer（現代發行版的主要排程方式）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">systemctl list-timers --all
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># cron：每個使用者各有一份 + 系統層多個目錄&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">sudo ls /var/spool/cron/ &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> sudo crontab -l -u &amp;lt;user&amp;gt; &lt;span class="c1"># 逐一查每個使用者&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">cat /etc/crontab
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">ls /etc/cron.d/ /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/ 2&amp;gt;/dev/null
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c1"># at 佇列（少用但存在）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">atq 2&amp;gt;/dev/null&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>每條排程記三件事：跑什麼、多常跑、失敗了會怎樣。第三件通常沒有答案——cron 任務失敗預設只寄 local mail、沒人會看。這是接管後值得優先補的洞，補法見下面「有沒有在監控自己」段。&lt;/p></description><content:encoded><![CDATA[<p>這篇處理的情境跟本系列其他篇相反：機器已經裝好、已經在跑，裝它的人可能已離職、可能只留下一句「都在上面了」。系列主線教你把一台空機器變成能跑活的機器；這篇教你把一台「不知道在跑什麼的機器」變成「盤點清楚、敢動手維護的機器」。對照 infra 樹，這篇是 <a href="/blog/infra/00-infra-mindset/first-day-with-cloud-account/" data-link-title="拿到雲端帳號的第一天" data-link-desc="被指派 infra 工作、拿到 AWS 或 GCP 帳號、不確定該先做什麼時讀 — 第一小時安全底線、帳號現況判讀、後續學習路線分流">拿到雲端帳號的第一天</a> 的 OS 層對等篇——那篇盤點的是雲端帳號裡有什麼資源，這篇盤點的是單一台 Linux 機器裡有什麼狀態。</p>
<p>核心紀律只有一條：<strong>盤點期間只讀不改</strong>。這跟 <a href="../../debug/diagnosis-read-authoritative-state/">診斷心法</a> 的「讀權威狀態」是同一個紀律的不同應用——診斷是出問題後讀狀態找根因，盤點是還沒出問題時讀狀態建立現況清單。改動留到盤點完成、你能回答「這台機器停掉會影響誰」之後。本篇所有指令都是唯讀查詢，照著跑不會改變機器狀態；少數需要 root 權限的會標明。</p>
<p>盤點的產出是一份清單，建議直接開一個文字檔邊查邊記。這份清單之後會變成把機器收斂進版本控制的依據——terminal 捲動紀錄留不住，清單留得住。</p>
<h2 id="這台是什麼機器">這台是什麼機器</h2>
<p>盤點的第一層是機器的身分：發行版、架構、實體還是虛擬、活多久了。這層決定後面每一步用什麼指令——套件管理器、服務管理方式、log 位置全由發行版決定，判讀邏輯見 <a href="../platform-divergence-map/">平台與發行版差異的判讀地圖</a>。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">cat /etc/os-release        <span class="c1"># 發行版與版本</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">uname -a                   <span class="c1"># kernel 版本與架構（x86_64 / aarch64）</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">systemd-detect-virt        <span class="c1"># 虛擬化偵測：kvm / vmware / none（實體機）</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">uptime                     <span class="c1"># 活多久、負載</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">hostnamectl                <span class="c1"># 主機名與上面幾項的整合視圖</span></span></span></code></pre></div><p><code>uptime</code> 的天數是一個重要訊號：跑了四百天的機器代表它從沒被重開驗證過——上面的服務能不能在重開機後自己回來，沒人知道。這會影響你後面對「開機自啟清單」那段的重視程度。</p>
<h2 id="誰能進來">誰能進來</h2>
<p>第二層是存取面：有哪些帳號、誰有 sudo、誰的 key 被授權登入。接手的機器上常有前人留下的帳號與 key，這些是你動手維護前必須知道的存取路徑——不知道誰能進來，就無法判斷一個改動是不是「只有你會做」。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 有登入 shell 的帳號（排除 nologin / false 的系統帳號）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">grep -vE <span class="s1">&#39;(nologin|false)$&#39;</span> /etc/passwd
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 誰有 sudo：主檔 + drop-in 目錄都要看（需要 root）</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">sudo cat /etc/sudoers
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">sudo ls /etc/sudoers.d/ <span class="o">&amp;&amp;</span> sudo cat /etc/sudoers.d/*
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"># 每個真人帳號的 SSH 授權 key</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">cat ~/.ssh/authorized_keys
</span></span><span class="line"><span class="ln">10</span><span class="cl">sudo cat /home/*/.ssh/authorized_keys
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># 最近誰登入過</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">last -20</span></span></code></pre></div><p><code>authorized_keys</code> 每行結尾的 comment（通常是 <code>user@hostname</code>）是判斷 key 主人的線索。無法對應到在職人員的 key 記進清單——盤點期間先不刪，但接管後的第一批改動應該包含輪替它們。sudoers 的 <code>NOPASSWD</code> 條目也記下來：它可能是前人為無人值守任務設的，判斷它還需不需要存在的依據見 <a href="../unattended-remote-work/">讓機器跑無人值守的長任務</a> 對這個取捨的展開。</p>
<h2 id="跑什麼服務誰開機自啟">跑什麼服務、誰開機自啟</h2>
<p>第三層是這台機器的「工作內容」：現在跑著哪些服務、重開機後哪些會自己回來。這兩份清單常常對不上，而對不上的地方就是接手後的地雷。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 現在在跑的服務</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">systemctl list-units --type<span class="o">=</span>service --state<span class="o">=</span>running
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># 開機會自啟的（不只 service，也含 socket / timer）</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">systemctl list-unit-files --state<span class="o">=</span>enabled
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># 各使用者層的 user unit（--user 屬於各帳號、root 看不到全部）</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">systemctl --user list-units --type<span class="o">=</span>service --state<span class="o">=</span>running
</span></span><span class="line"><span class="ln">9</span><span class="cl">ls /home/*/.config/systemd/user/ 2&gt;/dev/null</span></span></code></pre></div><p>兩份清單的差集各有含義。<strong>在跑但沒 enable</strong> 的服務，重開機就消失——它可能是有人手動 <code>systemctl start</code> 起來忘了 enable，也可能本來就該臨時。<strong>enable 了但沒在跑</strong>的服務，代表它啟動失敗過或被手動停掉，<code>systemctl status &lt;unit&gt;</code> 看它最後的狀態與退出原因。</p>
<p>systemd 之外還有一塊盲區：直接被人手動跑起來、或掛在終端機多工器 session 裡的長期進程。<code>ps aux</code> 全列太吵，用兩個角度收斂：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 不是從 systemd 起的長期進程：看父進程鏈</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">ps -eo pid,ppid,user,etime,comm --sort<span class="o">=</span>-etime <span class="p">|</span> head -30
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># 有沒有掛著的 tmux / zellij / screen session（要逐一以各使用者身分查）</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">tmux ls 2&gt;/dev/null<span class="p">;</span> zellij list-sessions 2&gt;/dev/null</span></span></code></pre></div><p><code>etime</code>（運行時長）長但不在 systemd 清單裡的進程，多半是手動起的。掛在多工器 session 裡的服務是最脆的一種——機器重開就沒了、也沒有任何監控。判斷一個進程「活著」與「由誰提供」的精確方法（<code>pgrep</code> 的比對陷阱、busctl 查註冊表），見 <a href="../../debug/process-service-state-diagnosis/">程序、服務與狀態怎麼判</a>。</p>
<h2 id="排程任務藏在哪">排程任務藏在哪</h2>
<p>第四層是排程：機器在沒人操作的時段自己做什麼。排程任務散落在多個落點，漏看一個就會在某天凌晨被一個「不知道哪來的」任務嚇到。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># systemd timer（現代發行版的主要排程方式）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">systemctl list-timers --all
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># cron：每個使用者各有一份 + 系統層多個目錄</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">sudo ls /var/spool/cron/ <span class="o">&amp;&amp;</span> sudo crontab -l -u &lt;user&gt;   <span class="c1"># 逐一查每個使用者</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">cat /etc/crontab
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">ls /etc/cron.d/ /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/ 2&gt;/dev/null
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># at 佇列（少用但存在）</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">atq 2&gt;/dev/null</span></span></code></pre></div><p>每條排程記三件事：跑什麼、多常跑、失敗了會怎樣。第三件通常沒有答案——cron 任務失敗預設只寄 local mail、沒人會看。這是接管後值得優先補的洞，補法見下面「有沒有在監控自己」段。</p>
<h2 id="對外開了什麼">對外開了什麼</h2>
<p>第五層是網路面：哪些 port 在聽、對誰開放。listening port 清單是「服務清單」的交叉驗證——一個在聽 port 的進程如果不在你前面盤出的服務清單裡，就是盤點有漏。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 在聽的 TCP / UDP port 與對應進程（-p 需要 root 才看得全）</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">sudo ss -tlnp
</span></span><span class="line"><span class="ln">3</span><span class="cl">sudo ss -ulnp
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"># 防火牆狀態：依發行版可能是其中一種</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">sudo nft list ruleset 2&gt;/dev/null <span class="p">|</span> head -50
</span></span><span class="line"><span class="ln">7</span><span class="cl">sudo iptables -L -n 2&gt;/dev/null <span class="p">|</span> head -30
</span></span><span class="line"><span class="ln">8</span><span class="cl">sudo ufw status 2&gt;/dev/null<span class="p">;</span> sudo firewall-cmd --list-all 2&gt;/dev/null</span></span></code></pre></div><p>判讀時把 listen address 分成三類：<code>127.0.0.1</code> 只服務本機、<code>0.0.0.0</code>（或 <code>*</code>）對所有介面開放、特定 IP 只綁那個介面。對外開放又不認得的 port 優先查——<code>ss -tlnp</code> 輸出的進程名回頭對服務清單。防火牆四個指令會有幾個查無結果，這正常：發行版各用不同框架，有輸出的那個才是這台在用的。</p>
<h2 id="裝了什麼">裝了什麼</h2>
<p>第六層是套件面：哪些是刻意裝的、哪些繞過套件管理器直接放進系統。這份清單是之後重建這台機器的素材——<a href="/blog/linux/dotfile/08-sync-bootstrap/bootstrap-script-packages/" data-link-title="Bootstrap Script 與套件清單管理" data-link-desc="寫 dotfile 的 install script、或整理「這台機器裝了什麼」的套件清單時回來讀">模組八的 bootstrap 套件清單</a> 假設你知道要裝什麼，接手的機器上這份「要裝什麼」得反向盤出來。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># Arch：明確安裝的（排除被依賴帶進來的）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">pacman -Qe
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1"># Debian / Ubuntu</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">apt-mark showmanual
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"># 繞過套件管理器的落點</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">ls /usr/local/bin/ /opt/ 2&gt;/dev/null
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># 語言層的全域安裝</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">pip list --user 2&gt;/dev/null<span class="p">;</span> npm ls -g --depth<span class="o">=</span><span class="m">0</span> 2&gt;/dev/null</span></span></code></pre></div><p><code>/usr/local/bin</code> 與 <code>/opt</code> 是重點：套件管理器查不到來源的執行檔，只能靠檔名、<code>--version</code>、跟 <code>strings</code> 猜用途。這些手放的檔案在重裝時最容易遺失——記進清單時同時記「它被哪個服務或排程用到」，孤兒檔案接管後可以清。</p>
<h2 id="設定與-secret-落在哪">設定與 secret 落在哪</h2>
<p>第七層是設定面：改過哪些系統設定、secret 放在哪裡。這層決定「這台機器能不能被重建」——服務跟套件都能重裝，改過的設定跟 secret 沒盤到就永遠丟了。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># /etc 下最近被改過的檔案（排 mtime、抓人為改動的痕跡）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">sudo find /etc -type f -mtime -365 -newer /etc/hostname 2&gt;/dev/null <span class="p">|</span> head -30
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># systemd unit 的 drop-in 覆寫（前人客製服務行為的常見落點）</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">sudo find /etc/systemd/system -name <span class="s2">&#34;*.conf&#34;</span> -path <span class="s2">&#34;*.d/*&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="c1"># 常見 secret 落點（唯讀列出、內容先不看）</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">ls -la /home/*/.env /home/*/*/.env 2&gt;/dev/null
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">ls /home/*/.ssh/ /root/.ssh/ 2&gt;/dev/null
</span></span><span class="line"><span class="ln">10</span><span class="cl">ls /home/*/.config/rclone /home/*/.aws /home/*/.docker 2&gt;/dev/null</span></span></code></pre></div><p><code>/etc</code> 的 mtime 掃描是啟發式——套件更新也會動 <code>/etc</code>，輸出要人工過濾，但它能把「前人改過設定」的範圍從整棵樹縮到幾十個檔案。家目錄的 dotfile 另外看一件事：<code>ls -la ~ | grep '\-&gt;'</code> 檢查有沒有 symlink 指向某個 repo——有的話代表前人用 <a href="/blog/linux/dotfile/01-dotfile-management/management-strategies/" data-link-title="管理策略與選型" data-link-desc="要選 dotfile 管理工具時回來讀 — bare repo、stow、chezmoi 的適用場景與選型判讀">stow 之類的工具</a> 管理過設定，找到那個 repo 等於找到大半份文件。secret 的判讀與收斂策略（哪些能進 repo、哪些只能佔位）見 <a href="/blog/linux/dotfile/08-sync-bootstrap/sync-strategy-secret/" data-link-title="跨機器同步、Secret 管理與環境重建流程" data-link-desc="多台機器的 dotfile 怎麼同步、哪些東西不該進 repo 時回來讀">同步策略與 secret 管理</a>。</p>
<h2 id="有沒有在監控自己">有沒有在監控自己</h2>
<p>第八層是監控面：這台機器的服務掛掉時，有沒有人會知道。接手的機器常常答案是「沒有」——前人肉眼盯著，前人走了就沒人盯。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 各服務有沒有掛 OnFailure 告警鉤子</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">systemctl show sshd -p OnFailure
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">for</span> u in <span class="k">$(</span>systemctl list-unit-files --state<span class="o">=</span>enabled --type<span class="o">=</span>service --no-legend <span class="p">|</span> awk <span class="s1">&#39;{print $1}&#39;</span><span class="k">)</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$u</span><span class="s2">: </span><span class="k">$(</span>systemctl show <span class="s2">&#34;</span><span class="nv">$u</span><span class="s2">&#34;</span> -p OnFailure --value<span class="k">)</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># 有沒有對外心跳（heartbeat timer、healthcheck 打點）</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">systemctl list-timers <span class="p">|</span> grep -iE <span class="s1">&#39;heart|health|canary&#39;</span></span></span></code></pre></div><p>輸出全空代表這台機器掛了不會通知任何人。盤點階段先記錄現況；接管後從最簡單的 OnFailure + 推播建起——至少把 sshd 掛上，它掛了機器就失聯。整套從零建法見 <a href="../../debug/service-failure-monitoring/">服務掛了怎麼自動知道</a>。</p>
<h2 id="盤點完之後">盤點完之後</h2>
<p>清單在手，用一個問題檢驗盤點品質：<strong>「這台機器現在消失，我能靠這份清單把它重建出來嗎？」</strong> 答不出來的段落回去補。能答之後，接手工作分兩條線走：</p>
<ul>
<li><strong>收斂進版本控制</strong>：把盤出來的套件清單、設定改動、服務定義逐步收進 repo，讓機器狀態從「只存在於這台機器上」變成「可從 repo 重現」。這是 <a href="/blog/linux/dotfile/00-dotfile-mindset/" data-link-title="模組零：Dotfile 心智模型" data-link-desc="換機器、開 VM、重灌系統時需要快速還原開發環境，或想釐清哪些配置該版控、哪些該排除時回來讀">模組零講的心智模型</a> 應用在接手情境——差別在素材從盤點來、不是從零設計。</li>
<li><strong>補監控與補文件</strong>：監控空白的服務掛 OnFailure、無人知道的排程補失敗告警、盤點清單本身放進 repo 當文件。</li>
</ul>
<p>機器在雲端的話，OS 層盤完還有帳號層——這台 instance 是誰開的、掛在哪個 VPC、security group 開了什麼，見 <a href="/blog/infra/takeover/" data-link-title="接手維運：別人建的環境怎麼接管" data-link-desc="接手前人的專案時，怎麼在不搞壞東西的前提下盤點現況、建立維運能力、逐步正規化 — 從無 SSH 的 FTP 環境到有半套 IaC 的雲端環境都適用">infra 的接手維運模組</a>。盤點過程中發現已經在壞的狀態（服務起不來、連線異常），從盤點模式切到除錯模式，入口是 <a href="../../debug/diagnosis-read-authoritative-state/">診斷心法</a>。</p>
]]></content:encoded></item></channel></rss>