<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Antony 筆記：技術原理與實務經驗 – 維運與自動化</title><link>https://blog.kubeantony.com/archive/ops-automation/</link><description>Recent content in 維運與自動化 on Antony 筆記：技術原理與實務經驗</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><lastBuildDate>Tue, 16 Dec 2025 19:45:08 +0800</lastBuildDate><atom:link href="https://blog.kubeantony.com/archive/ops-automation/index.xml" rel="self" type="application/rss+xml"/><item><title>動手實作 OpenTelemetry</title><link>https://blog.kubeantony.com/archive/ops-automation/%E5%8B%95%E6%89%8B%E5%AF%A6%E4%BD%9C-opentelemetry/</link><pubDate>Tue, 16 Dec 2025 19:45:08 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/%E5%8B%95%E6%89%8B%E5%AF%A6%E4%BD%9C-opentelemetry/</guid><description>
&lt;h2&gt;0. Preface&lt;span class="hx:absolute hx:-mt-20" id="0-preface"&gt;&lt;/span&gt;
&lt;a href="#0-preface" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;本篇文章是翻譯 Getting Started with OpenTelemetry (LFS148) 的第四章節，想看原文可參考以下網址：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://training.linuxfoundation.org/training/getting-started-with-opentelemetry-lfs148/#"target="_blank" rel="noopener"&gt;https://training.linuxfoundation.org/training/getting-started-with-opentelemetry-lfs148/#&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;style&gt;
.indent-title-1{
margin-left: 1em;
}
.indent-title-2{
margin-left: 2em;
}
.indent-title-3{
margin-left: 3em;
}
&lt;/style&gt;</description></item><item><title>為什麼需要 OpenTelemetry</title><link>https://blog.kubeantony.com/archive/ops-automation/%E7%82%BA%E4%BB%80%E9%BA%BC%E9%9C%80%E8%A6%81-opentelemetry/</link><pubDate>Tue, 16 Dec 2025 19:44:46 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/%E7%82%BA%E4%BB%80%E9%BA%BC%E9%9C%80%E8%A6%81-opentelemetry/</guid><description>
&lt;h2&gt;0. Preface&lt;span class="hx:absolute hx:-mt-20" id="0-preface"&gt;&lt;/span&gt;
&lt;a href="#0-preface" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;本篇文章是翻譯 Getting Started with OpenTelemetry (LFS148) 的第二章節，想看原文可參考以下網址：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://training.linuxfoundation.org/training/getting-started-with-opentelemetry-lfs148/#"target="_blank" rel="noopener"&gt;https://training.linuxfoundation.org/training/getting-started-with-opentelemetry-lfs148/#&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;style&gt;
.indent-title-1{
margin-left: 1em;
}
.indent-title-2{
margin-left: 2em;
}
.indent-title-3{
margin-left: 3em;
}
&lt;/style&gt;
&lt;h2&gt;1. 學習目標完成本章後，您將能夠：&lt;span class="hx:absolute hx:-mt-20" id="1-學習目標完成本章後您將能夠"&gt;&lt;/span&gt;
&lt;a href="#1-%e5%ad%b8%e7%bf%92%e7%9b%ae%e6%a8%99%e5%ae%8c%e6%88%90%e6%9c%ac%e7%ab%a0%e5%be%8c%e6%82%a8%e5%b0%87%e8%83%bd%e5%a4%a0" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;定義與&lt;strong&gt;工作負載 (Workload)&lt;/strong&gt; 及資源分析相關的通用術語&lt;/li&gt;
&lt;li&gt;說明為何&lt;strong&gt;可觀測性 (Observability)&lt;/strong&gt; 在&lt;strong&gt;分散式系統&lt;/strong&gt;中至關重要&lt;/li&gt;
&lt;li&gt;探討可觀測性的三大支柱——&lt;strong&gt;日誌 (Logs)&lt;/strong&gt;、&lt;strong&gt;指標 (Metrics)&lt;/strong&gt; 與 &lt;strong&gt;追蹤 (Traces)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;探討現代——且常是&lt;strong&gt;多語言混合 (Polyglot)&lt;/strong&gt;——分散式應用程式所面臨的挑戰&lt;/li&gt;
&lt;li&gt;描述 &lt;strong&gt;OpenTelemetry&lt;/strong&gt; 的特性&lt;/li&gt;
&lt;li&gt;說明 &lt;strong&gt;OpenTelemetry&lt;/strong&gt; 如何試圖解決傳統可觀測性解決方案的不足之處&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. 當前可觀察性的狀態&lt;span class="hx:absolute hx:-mt-20" id="2-當前可觀察性的狀態"&gt;&lt;/span&gt;
&lt;a href="#2-%e7%95%b6%e5%89%8d%e5%8f%af%e8%a7%80%e5%af%9f%e6%80%a7%e7%9a%84%e7%8b%80%e6%85%8b" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;根據維基百科的定義，「&lt;strong&gt;可觀測性 (Observability)&lt;/strong&gt; 是衡量我們能多有效地透過系統的外部輸出，來推斷其內部狀態的一項指標」(2024)。換句話說，可觀測性指的是您透過檢視系統（例如應用程式或服務）所產生的資訊，來理解其內部運作狀況的容易程度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;分散式系統 (Distributed System)&lt;/strong&gt; 是由一組獨立的電腦或&lt;strong&gt;節點 (nodes)&lt;/strong&gt; 所組成的網路，它們協同運作以執行任務，表現得就像是一個單一系統。這類系統廣泛應用於&lt;strong&gt;雲端運算 (Cloud Computing)&lt;/strong&gt; 等領域，其中應用程式的不同部分會在不同的伺服器上運行，藉此共享資源並達成&lt;strong&gt;工作負載平衡 (balance the workload)&lt;/strong&gt;。由於分散式系統的複雜性，要在任何時間點掌握每個&lt;strong&gt;元件 (component)&lt;/strong&gt; 內部的運作情形，往往是一項艱鉅的挑戰。這正是可觀測性變得至關重要的原因。&lt;/p&gt;
&lt;p&gt;為了讓分散式系統具備可觀測性，我們必須以一種能讓我們推導其行為的方式來建立狀態模型。這個模型由三個要素組成：&lt;/p&gt;
&lt;p&gt;首先是 &lt;strong&gt;工作負載 (Workload)&lt;/strong&gt;。這是系統為了達成目標所執行的操作。例如，當使用者發送一個請求時，分散式系統通常會將其拆解為由不同服務處理的較小任務。這通常也被稱為 &lt;strong&gt;交易 (Transactions)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;第二是構成分散式系統結構的 &lt;strong&gt;軟體抽象層 (Software Abstractions)&lt;/strong&gt;。這包含了諸如 &lt;strong&gt;負載平衡器 (Load Balancers)&lt;/strong&gt;、&lt;strong&gt;服務 (Services)&lt;/strong&gt;、&lt;strong&gt;Pods&lt;/strong&gt;、&lt;strong&gt;容器 (Containers)&lt;/strong&gt; 等元件。&lt;/p&gt;
&lt;p&gt;最後是提供 &lt;strong&gt;運算資源 (Computational Resources)&lt;/strong&gt;（如 RAM、CPU、磁碟空間、網路）以執行工作的 &lt;strong&gt;實體機器 (Physical Machines)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/SkOqMbyQZg.png" alt="image" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;根據我們的背景不同，在調查分散式系統的效能或進行故障排除時，我們往往會有特定的 &lt;strong&gt;切入視角 (bias)&lt;/strong&gt;。應用程式開發人員通常專注於與工作負載相關的層面，而 &lt;strong&gt;維運團隊 (Operations Teams)&lt;/strong&gt; 則傾向於關注實體資源。&lt;/p&gt;
&lt;p&gt;為了真正理解一個系統，我們必須結合來自多個角度的洞察，並釐清它們彼此之間的關聯。然而，在我們能進行分析之前，必須先捕捉系統行為的各個面向。這通常是透過結合 &lt;strong&gt;日誌 (Logs)&lt;/strong&gt;、&lt;strong&gt;指標 (Metrics)&lt;/strong&gt; 和 &lt;strong&gt;追蹤 (Traces)&lt;/strong&gt; 來完成的。&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h3&gt;2.1. Logs&lt;span class="hx:absolute hx:-mt-20" id="21-logs"&gt;&lt;/span&gt;
&lt;a href="#21-logs" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/S1LPXW1Xbg.png" alt="image" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;日誌（Logs）是一種僅能追加（append-only）的資料結構，用來記錄系統中發生的事件。&lt;/strong&gt; 一筆日誌紀錄包含標示事件發生時間的時間戳記（timestamp），以及描述事件細節的訊息。然而，要制定一個標準化的日誌格式並非易事。其中一個原因是，不同類型的軟體通常傳達不同的資訊內容。HTTP 網頁伺服器的日誌，肯定與核心（kernel）的日誌截然不同。但即使是相似的軟體，人們對於「好的日誌」應具備的樣貌也常有不同看法。&lt;/p&gt;
&lt;p&gt;除了內容之外，日誌格式也會隨著其使用對象（consumers）而有所不同。最初，純文字格式是為了迎合人類的可讀性而設計。然而，隨著軟體系統變得日益複雜，日誌的量級很快就變得難以管理。為了應對這個問題，我們開始將事件編碼為鍵值對（key/value pairs），使其具備機器可讀性（machine-readable），這通常被稱為結構化日誌（structured logging）。&lt;/p&gt;
&lt;p&gt;此外，貨櫃化（containerized）應用程式的分散式與短暫特性（ephemeral nature），意味著登入個別機器去翻找日誌的做法不再可行。因此，人們開始構建日誌代理程式（logging agents）和通訊協定，將日誌轉發到專用的服務中。這些日誌系統實現了高效的儲存，並具備在集中位置搜尋與過濾日誌的能力。&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h3&gt;2.2. Metrics&lt;span class="hx:absolute hx:-mt-20" id="22-metrics"&gt;&lt;/span&gt;
&lt;a href="#22-metrics" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/rJZsEZ1QZl.png" alt="image" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;服務在執行時捕獲的測量值。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;日誌（Logs）非常擅長提供關於個別事件的詳細資訊。然而，有時我們需要掌握系統當前狀態的宏觀概覽（high-level view）。這正是指標（Metrics）派上用場的地方。&lt;/p&gt;
&lt;p&gt;指標是透過對一組事件應用統計運算後，所推導出的單一數值。換句話說，指標代表的是一種聚合數據。這非常有價值，因為它們精簡的呈現方式，讓我們能夠將系統隨時間變化的情形繪製成圖表。&lt;/p&gt;
&lt;p&gt;因應這些需求，業界開發了用來萃取指標的儀器（instruments）、用來表示與傳輸資料的格式與通訊協定、專門用來儲存資料的時序資料庫（time-series databases），以及讓終端使用者能存取這些資料的前端介面。&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h3&gt;2.3. Traces&lt;span class="hx:absolute hx:-mt-20" id="23-traces"&gt;&lt;/span&gt;
&lt;a href="#23-traces" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/H1ACIb1XWx.png" alt="image" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;隨著分散式系統的規模擴大，傳統日誌系統在對複雜問題進行除錯（debug）時，顯然經常感到力有未逮。原因在於，我們往往必須理解系統中一連串事件的脈絡。&lt;/p&gt;
&lt;p&gt;在單機環境下，堆疊追蹤（stack traces）讓我們能將例外狀況（exception）追溯回特定的程式碼行數。然而在分散式環境中，我們無法享有這種便利。取而代之的是，我們必須進行大量的過濾，才能定位出我們關注的日誌事件。為了理解整體脈絡（context），我們必須識別其他相關聯的事件，例如觸發該日誌紀錄的特定請求或交易，以及該請求在系統中處理時所涉及的服務或微服務之順序。這通常會導致大量的人工操作（例如比對時間戳記），或者需要對應用程式具備深厚的領域知識。為了正視這個問題，Google 開發了 &lt;a
href="https://research.google.com/pubs/pub36356.html?spm=5176.100239.blogcont60165.11.OXME9Z"target="_blank" rel="noopener"&gt;Dapper&lt;/a&gt;，並普及了分散式追蹤（distributed tracing）的概念。&lt;/p&gt;
&lt;p&gt;從本質上來說，分散式追蹤就是「強化版」的日誌記錄（logging on steroids）。其核心概念在於為日誌添加交易脈絡（transactional context）。這使得我們能夠推斷因果關係，並還原請求在系統中的完整路徑（journey）。&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;3. 可觀測性的三大支柱&lt;span class="hx:absolute hx:-mt-20" id="3-可觀測性的三大支柱"&gt;&lt;/span&gt;
&lt;a href="#3-%e5%8f%af%e8%a7%80%e6%b8%ac%e6%80%a7%e7%9a%84%e4%b8%89%e5%a4%a7%e6%94%af%e6%9f%b1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;&lt;strong&gt;遙測（Telemetry）&lt;/strong&gt; 是指從遠端或分散式系統自動收集並傳輸資料的過程，目的是為了監控、測量及追蹤這些系統的效能或狀態。遙測資料提供了關於應用程式各個部分運作情形的即時洞察（real-time insights）。這些數據成為可觀測性工具的基礎，協助開發人員和系統管理員觀察、除錯（troubleshoot）並最佳化系統，而無需手動檢查每一個元件。&lt;/p&gt;
&lt;p&gt;從表面上看，Log（日誌）、Metric（指標）和 Trace（追蹤）在其生命週期和組成元件上有許多相似之處。一切都始於 &lt;strong&gt;Instrumentation（儀器化/埋點）&lt;/strong&gt;，負責捕捉並發送資料。這些資料必須具備由格式定義的特定結構。接著，我們需要一種機制來收集並轉發這些遙測數據。通常會有某種 &lt;strong&gt;Agent（代理程式）&lt;/strong&gt; 來進一步擴充（enrich）、處理和批次打包資料，然後將其攝入（ingest）後端系統。這個過程通常涉及一個資料庫，以有效地儲存、索引和搜尋大量的資料。最後，會有前端分析介面讓終端使用者能存取這些數據。&lt;/p&gt;
&lt;p&gt;然而，在實務上，我們針對每種類型的遙測開發專用系統是有充分理由的：每一種遙測訊號（signal）都帶來了獨特的技術挑戰。這些挑戰主要源於資料本質的不同。&lt;/p&gt;
&lt;p&gt;資料模型、交換格式和傳輸協定的設計，高度取決於你處理的是非結構化或半結構化的文字資訊（Logs）、時間序列中緊湊的數值（Metrics），還是描述事件間因果關係的圖狀結構（Traces）。即使是針對單一種訊號，業界在這些議題上也尚未達成共識。&lt;/p&gt;
&lt;p&gt;此外，我們如何運用並從遙測中獲取洞察的方式也大相徑庭。一個系統可能需要執行全文檢索、檢查單一事件、分析歷史趨勢、視覺化請求流程、診斷效能瓶頸等等。這些需求具體體現在儲存、存取模式、查詢功能等方面的設計與最佳化上。&lt;/p&gt;
&lt;p&gt;當面對這些技術挑戰時，&lt;strong&gt;垂直整合（vertical integration）&lt;/strong&gt; 成為了一種務實的解決方案。在實務中，可觀測性廠商往往將問題範圍縮小到單一訊號，並提供生成資料的 Instrumentation 以及分析遙測的工具，形成一個單一且完全整合的解決方案。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/B1mRwWkQbl.png" alt="image" loading="lazy" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Three Pillars of Observability: Metrics, Traces and Logs&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;正因為針對 Logs（日誌）、Metrics（指標）和 Traces（追蹤）擁有各自專用的系統，我們才普遍將它們稱為可觀測性的「三大支柱」。&lt;/p&gt;
&lt;p&gt;「支柱」這個概念提供了一個極佳的思考框架（mental framework），因為它強調了以下重點：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;遙測資料（telemetry）區分為不同的類別。&lt;/li&gt;
&lt;li&gt;每一根支柱都具備其獨特的優勢，且能獨當一面。&lt;/li&gt;
&lt;li&gt;這些支柱具有互補性，必須結合在一起，才能構成實現可觀測性的穩固基石。&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h3&gt;3.1. 現行可觀測性作法的問題&lt;span class="hx:absolute hx:-mt-20" id="31-現行可觀測性作法的問題"&gt;&lt;/span&gt;
&lt;a href="#31-%e7%8f%be%e8%a1%8c%e5%8f%af%e8%a7%80%e6%b8%ac%e6%80%a7%e4%bd%9c%e6%b3%95%e7%9a%84%e5%95%8f%e9%a1%8c" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;面對市面上充斥著大量的開源與商用可觀測性解決方案，你可能會（很合理地）問自己：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如果針對 Logs、Metrics 和 Traces 的產生、收集、儲存與分析，都已經有許多成熟的解決方案了，那我為什麼要在意（OpenTelemetry）？&lt;/li&gt;
&lt;li&gt;目前的可觀測性現狀到底有什麼問題？&lt;/li&gt;
&lt;li&gt;喔，好極了……這該不會又是一次試圖制定標準的嘗試吧？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;這些都是合理的問題。為了回答這些問題，我們必須點出在建構與使用那些「基於支柱（pillar-based）」的可觀測性系統時，所衍生出的一些缺點。&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;3.2. 孤島式的遙測資料難以運用&lt;span class="hx:absolute hx:-mt-20" id="32-孤島式的遙測資料難以運用"&gt;&lt;/span&gt;
&lt;a href="#32-%e5%ad%a4%e5%b3%b6%e5%bc%8f%e7%9a%84%e9%81%99%e6%b8%ac%e8%b3%87%e6%96%99%e9%9b%a3%e4%bb%a5%e9%81%8b%e7%94%a8" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/BkUTKZJXbg.png" alt="image" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;首先，遙測資料的品質本身存在不足。為了說明這一點，讓我們想像一下我們要調查某個問題的根本原因（root cause）。&lt;/p&gt;
&lt;p&gt;問題的第一個徵兆，通常是來自警報，或是指標儀表板（metrics dashboard）上的異常。為了確認該事件值得調查，我們必須先形成初步的假設。目前我們手上唯一的資訊是，在特定時間點發生了某些事情。因此，第一步通常是使用指標系統，去尋找其他在時間上具備關聯性（temporally correlated）且呈現異常行為的指標。&lt;/p&gt;
&lt;p&gt;在對問題做出有根據的推測後，我們會希望深入挖掘（drill down）並調查問題的根本原因。為了獲取額外資訊，我們通常會切換到日誌系統（logging system）。在這裡，我們撰寫查詢語法並進行大量的過濾，試圖找出與那些可疑指標相關的日誌事件。&lt;/p&gt;
&lt;p&gt;發現感興趣的日誌事件後，我們通常想了解該操作發生當下更廣泛的脈絡（context）。遺憾的是，傳統日誌系統缺乏重建特定交易中事件鏈的機制。傳統日誌系統往往無法捕捉操作的完整脈絡，導致難以將跨越不同服務或元件的事件關聯起來。它們經常缺乏保留關鍵 Metadata（如 Trace ID 或 Span ID）的能力，而這些對於連結相關事件至關重要。這種限制導致了系統行為視角的破碎化，單一操作的「故事」散落在多個日誌中，缺乏清晰的敘事。此外，缺乏標準化的查詢語言或介面，更加深了有效搜尋與分析日誌的難度，因為維運人員必須仰賴客製化腳本或手動過濾，才能發掘出模式與異常。&lt;/p&gt;
&lt;p&gt;如果我們將視角從「構建」可觀測性解決方案的人，切換到「使用」它的人，就會發現一種本質上的脫節。真實世界的問題並不是由 Log、Metrics 或 Tracing 構成的。相反地，我們必須在不同類型的遙測數據之間來回切換，以建立心智模型（mental model）並推斷系統的行為。由於可觀測性工具往往是彼此不相連的資料孤島（silos），要釐清資訊片段之間的關聯，會給維運人員帶來巨大的&lt;strong&gt;認知負擔（cognitive load）&lt;/strong&gt;。&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;3.3. 缺乏 Instrumentation (儀器化) 標準導致資料品質低落&lt;span class="hx:absolute hx:-mt-20" id="33-缺乏-instrumentation-儀器化-標準導致資料品質低落"&gt;&lt;/span&gt;
&lt;a href="#33-%e7%bc%ba%e4%b9%8f-instrumentation-%e5%84%80%e5%99%a8%e5%8c%96-%e6%a8%99%e6%ba%96%e5%b0%8e%e8%87%b4%e8%b3%87%e6%96%99%e5%93%81%e8%b3%aa%e4%bd%8e%e8%90%bd" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;另一個讓根本原因分析（root-cause analysis）變得困難的因素是，遙測資料往往深受「缺乏一致性」所苦。&lt;/p&gt;
&lt;p&gt;這導致在不同服務或元件之間&lt;strong&gt;關聯（correlating）&lt;/strong&gt; 事件變得相當困難，因為缺乏標準化的方式來識別相關聯的事件，例如透過 Trace ID 或 Span ID 來串接。&lt;/p&gt;
&lt;p&gt;此外，目前也沒有直接了當的方法，能將多個針對特定解決方案（solution-specific）的日誌函式庫，整合到一個連貫的系統中。這最終導致我們對系統行為的觀察變得破碎且脫節。&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;3.4. 開源軟體缺乏內建 Instrumentation (儀器化)&lt;span class="hx:absolute hx:-mt-20" id="34-開源軟體缺乏內建-instrumentation-儀器化"&gt;&lt;/span&gt;
&lt;a href="#34-%e9%96%8b%e6%ba%90%e8%bb%9f%e9%ab%94%e7%bc%ba%e4%b9%8f%e5%85%a7%e5%bb%ba-instrumentation-%e5%84%80%e5%99%a8%e5%8c%96" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;讓我們從開源軟體開發者的角度來看待這件事。現今，大多數的應用程式都是建構在開源函式庫、框架和獨立元件之上。由於大量的運作都發生在應用程式開發者所撰寫的商業邏輯之外，因此從這些開源元件收集遙測數據（telemetry）至關重要。最了解軟體運作時哪些資訊至關重要的，莫過於開發者與維護者本身。然而，目前缺乏一種透過&lt;strong&gt;原生儀器化（native instrumentation）&lt;/strong&gt; 來傳遞這些資訊的良好方式。&lt;/p&gt;
&lt;p&gt;其中一個選項是選用特定可觀測性解決方案的儀器化工具。然而，這會為專案增加額外的相依性（dependencies），並強迫使用者將其整合到自己的系統中。雖然同時運行多套日誌與指標系統雖然不切實際（impractical），但在技術上尚屬可行；然而，分散式追蹤（Tracing）卻是完全不可能的，因為它需要所有人達成共識，採用統一的標準，才能讓 &lt;strong&gt;Trace Context 的傳遞（propagation）&lt;/strong&gt; 順利運作。&lt;/p&gt;
&lt;p&gt;電腦科學界解決問題的一個常見策略，就是增加一層&lt;strong&gt;間接層（indirection）&lt;/strong&gt;。與其嵌入特定廠商的儀器化程式碼，開源開發者通常會提供可觀測性的 &lt;strong&gt;Hooks&lt;/strong&gt;。這讓使用者能撰寫&lt;strong&gt;轉接器（adapters）&lt;/strong&gt;，將開源元件連接到自己的可觀測性系統。&lt;/p&gt;
&lt;p&gt;雖然這種方法提供了較大的彈性，但也伴隨著不少問題。例如，每當軟體推出新版本時，使用者都必須留意並更新他們的轉接器。此外，這種間接層也增加了系統開銷（overhead），因為我們必須在不同的遙測格式之間進行轉換。&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;3.5. 結合遙測生成與特定方案將導致供應商綁定 (Vendor Lock-in)&lt;span class="hx:absolute hx:-mt-20" id="35-結合遙測生成與特定方案將導致供應商綁定-vendor-lock-in"&gt;&lt;/span&gt;
&lt;a href="#35-%e7%b5%90%e5%90%88%e9%81%99%e6%b8%ac%e7%94%9f%e6%88%90%e8%88%87%e7%89%b9%e5%ae%9a%e6%96%b9%e6%a1%88%e5%b0%87%e5%b0%8e%e8%87%b4%e4%be%9b%e6%87%89%e5%95%86%e7%b6%81%e5%ae%9a-vendor-lock-in" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;讓我們試著戴上終端使用者的帽子（站在使用者的立場）來看待這件事。一旦決定採用某個解決方案，應用程式的程式碼庫（codebase）中就會遍佈著許多針對該特定解決方案的函式庫呼叫（library calls）。&lt;/p&gt;
&lt;p&gt;若日後想要轉換到另一個可觀測性工具，我們將被迫把現有所有的儀器化程式碼（instrumentation）連根拔除並替換，同時還得遷移我們的分析工具。這種「重新儀器化（re-instrumentation）」所需的巨大前期成本，使得遷移變得困難重重，而這正是&lt;strong&gt;供應商綁定（Vendor Lock-in）&lt;/strong&gt; 的一種形式。&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;3.6. 陷入苦戰的可觀測性廠商 / 高聳的進入門檻&lt;span class="hx:absolute hx:-mt-20" id="36-陷入苦戰的可觀測性廠商--高聳的進入門檻"&gt;&lt;/span&gt;
&lt;a href="#36-%e9%99%b7%e5%85%a5%e8%8b%a6%e6%88%b0%e7%9a%84%e5%8f%af%e8%a7%80%e6%b8%ac%e6%80%a7%e5%bb%a0%e5%95%86--%e9%ab%98%e8%81%b3%e7%9a%84%e9%80%b2%e5%85%a5%e9%96%80%e6%aa%bb" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;這個方程式的最後一個環節，是可觀測性廠商本身。乍看之下，廠商似乎是唯一從現狀中獲利的一方。在過去，高品質的儀器化（instrumentation）是與競爭對手做出&lt;strong&gt;市場區隔（differentiation）&lt;strong&gt;的絕佳方式。此外，由於為大量既有軟體開發整合介面（integrations）非常昂貴，可觀測性市場具有相對較高的&lt;/strong&gt;進入門檻（barrier to entry）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;由於客戶對昂貴的「重新儀器化（re-instrumentation）」望之卻步，既有的老牌廠商面臨較少的競爭與創新壓力。然而，他們也正經歷著巨大的痛點。過去十年間，軟體開發的速度呈現指數級成長。現今 &lt;strong&gt;異質化（heterogeneous）&lt;/strong&gt; 的軟體生態，使得要維護針對每一個函式庫、框架和元件的儀器化支援，變得根本不可能。&lt;/p&gt;
&lt;p&gt;一旦廠商開始難以提供（特定的）儀器化支援，客戶就會開始拒絕採用他們的產品。結果導致各家解決方案都在競爭誰能打造出最好的「N 對 N 格式轉換器」，而不是將這些資源投入到開發更棒的分析工具上。另一個缺點是，轉換那些由外部來源產生的資料，往往會導致遙測資料品質的&lt;strong&gt;劣化（degradation）&lt;/strong&gt;。一旦資料定義不再明確，分析起來就變得更加困難。&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;4. 什麼是 OpenTelemetry&lt;span class="hx:absolute hx:-mt-20" id="4-什麼是-opentelemetry"&gt;&lt;/span&gt;
&lt;a href="#4-%e4%bb%80%e9%ba%bc%e6%98%af-opentelemetry" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;OpenTelemetry (OTel) 是一個開源專案，旨在提供標準化的工具和 API，用於生成、收集和匯出&lt;strong&gt;追蹤 (Traces)&lt;/strong&gt;、&lt;strong&gt;指標 (Metrics)&lt;/strong&gt; 和 &lt;strong&gt;日誌 (Logs)&lt;/strong&gt; 等遙測數據。其目的是讓開發人員能深入掌握應用程式的可觀測性，進而協助監控、故障排除以及最佳化軟體系統。&lt;/p&gt;
&lt;p&gt;OpenTelemetry 的主要目標包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;統一的遙測 (Unified telemetry)：&lt;/strong&gt; 將追蹤、日誌和指標結合至單一框架中，實現所有數據的關聯分析，並建立遙測數據的開放標準。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;供應商中立 (Vendor-neutrality)：&lt;/strong&gt; 可整合不同的後端系統來處理數據（不被特定單一廠商綁定）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨平台 (Cross-platform)：&lt;/strong&gt; 支援多種程式語言（如 Java、Python、Go 等）與平台，使其能靈活適用於各種開發環境。&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h3&gt;4.1. OpenTelemetry 不是什麼？&lt;span class="hx:absolute hx:-mt-20" id="41-opentelemetry-不是什麼"&gt;&lt;/span&gt;
&lt;a href="#41-opentelemetry-%e4%b8%8d%e6%98%af%e4%bb%80%e9%ba%bc" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;通常透過定義某個事物「不是什麼」，會更有助於理解它的本質。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OpenTelemetry 是：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;不是一套多合一 (All-in-One) 的監控或可觀測性工具
OpenTelemetry 不會取代像 Datadog、New Relic 或 Prometheus 這類功能完整的監控或可觀測性平台。相反地，它協助收集並標準化遙測數據（追蹤、指標、日誌），讓您可以將數據發送到這些工具進行視覺化和分析。&lt;/li&gt;
&lt;li&gt;不是數據儲存或儀表板 (Dashboarding) 解決方案
OpenTelemetry 本身不負責儲存或視覺化數據。它專注於收集和匯出遙測數據到負責儲存與呈現的外部系統，例如 Grafana、Jaeger 或 Prometheus。&lt;/li&gt;
&lt;li&gt;不是預先設定好的監控工具
OpenTelemetry 是一套用於收集和匯出數據的工具組 (Toolkit)，但它需要進行設定並與其他系統整合。它不會自動提供開箱即用 (out-of-the-box) 的監控或告警功能。&lt;/li&gt;
&lt;li&gt;不是效能最佳化工具 (Performance Optimizer)
雖然 OpenTelemetry 協助您收集詳細的效能數據，但它不會自動將應用程式效能最佳化。它是一種診斷工具，協助您收集數據洞察，以作為手動調校 (Manual tuning) 的依據。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;總結來說：&lt;/strong&gt;
本質上，OpenTelemetry 是一個針對遙測數據的「整合與標準化工具」，而非監控、日誌記錄或效能管理的多合一解決方案。它透過標準化數據收集流程，來與其他工具&lt;strong&gt;相輔相成 (Complements)&lt;/strong&gt;。&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;4.2. 為什麼 OpenTelemetry 備受看好？&lt;span class="hx:absolute hx:-mt-20" id="42-為什麼-opentelemetry-備受看好"&gt;&lt;/span&gt;
&lt;a href="#42-%e7%82%ba%e4%bb%80%e9%ba%bc-opentelemetry-%e5%82%99%e5%8f%97%e7%9c%8b%e5%a5%bd" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;截至本文撰寫時（2024 年 5 月），OpenTelemetry 是 &lt;strong&gt;CNCF&lt;/strong&gt;（雲端原生運算基金會）中成長速度第二快的專案。OpenTelemetry 之所以獲得如此高度的關注，是因為它有望為我們產生遙測數據的方式帶來&lt;strong&gt;根本性的轉變 (Fundamental shift)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我們必須記住，「可觀測性 (Observability)」還是一個相當年輕的領域。在過去，快速的創新步調以及（廠商間的）&lt;strong&gt;利益衝突 (Conflicts of interest)&lt;/strong&gt;，阻礙了我們為遙測數據制定出一套廣泛採用的標準。然而，憑藉著 OpenTelemetry 目前的時機點與&lt;strong&gt;發展動能 (Momentum)&lt;/strong&gt;，看來確實有極大的機會能推動遙測數據通用面向的標準化。&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;4.3. OpenTelemetry 的優勢&lt;span class="hx:absolute hx:-mt-20" id="43-opentelemetry-的優勢"&gt;&lt;/span&gt;
&lt;a href="#43-opentelemetry-%e7%9a%84%e5%84%aa%e5%8b%a2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;一次儀器化，隨處可用 (Instrument once, use everywhere)
OpenTelemetry 的一個關鍵承諾是，您只需對程式碼進行一次 &lt;strong&gt;儀器化 (Instrument)&lt;/strong&gt;，之後便不再需要重複進行，並能在任何地方使用該儀器化結果。OpenTelemetry 體認到，若要成功，它必須成為許多軟體專案的核心依賴 (Dependency)。因此，它遵循嚴格的流程以提供長期的穩定性保證。一旦某個訊號 (Signal) 被宣告為穩定版本 (Stable)，其承諾是客戶端將永遠不會遇到&lt;strong&gt;破壞性的 API 變更 (Breaking API change)&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;將遙測數據的「生成」與「分析」分離
OpenTelemetry 的另一個核心概念是，將產生遙測數據的機制，與分析數據的系統分開。這種開放且&lt;strong&gt;不依賴特定供應商 (Vendor-agnostic)&lt;/strong&gt; 的儀器化方式，標誌著可觀測性產業的根本變革。供應商不再需要投入大量資源開發專有的儀器化工具並維持其更新，而是必須透過功能豐富且易用性極佳的分析平台來做出市場區隔。OpenTelemetry 促進了競爭，因為使用者不再被開發期間選擇的可觀測性解決方案&lt;strong&gt;綁死 (Lock-in)&lt;/strong&gt;。切換到 OpenTelemetry 後，您可以更換平台，而無需重新對整個系統進行儀器化。&lt;/li&gt;
&lt;li&gt;讓軟體預設即具備可觀測性 (Make software observable by default)
藉由 OpenTelemetry，開源開發者可以在專案中加入原生的儀器化功能，而無需引入會造成使用者負擔的廠商特定程式碼。其概念是讓「可觀測性」在開發階段就成為&lt;strong&gt;一等公民 (First-class citizen)&lt;/strong&gt;。透過軟體出廠時即內建儀器化功能，我們不再需要於事後 (After the fact) 透過複雜的機制來擷取和整合數據。&lt;/li&gt;
&lt;li&gt;改善我們使用遙測數據的方式
最後（但絕對同樣重要），OpenTelemetry 試圖改變我們思考和使用遙測數據的方式。OpenTelemetry 摒棄了將日誌、指標和追蹤視為三個獨立&lt;strong&gt;孤島 (Silos)&lt;/strong&gt; 的做法，而是採用將遙測訊號相互連結的典範。隨著上下文 (Context) 在訊號之間建立起接觸點，遙測數據的整體價值與易用性將大幅提升。例如，想像一下能夠直接從儀表板上顯著的統計數據，跳轉到相關聯的日誌中。互相關聯的遙測數據有助於降低維運複雜系統的人員的&lt;strong&gt;認知負荷 (Cognitive load)&lt;/strong&gt;。能夠利用這些連結數據，將標誌著新一代可觀測性工具的誕生。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;5. 本章總結&lt;span class="hx:absolute hx:-mt-20" id="5-本章總結"&gt;&lt;/span&gt;
&lt;a href="#5-%e6%9c%ac%e7%ab%a0%e7%b8%bd%e7%b5%90" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;在本章中，我們涵蓋了 &lt;strong&gt;工作負載與資源分析（Workload and resource analysis）&lt;/strong&gt; 的核心概念，為您在監控與優化現代應用程式時所需的術語打下基礎。我們強調了 &lt;strong&gt;可觀測性（Observability）&lt;/strong&gt; 的重要性，以及它在了解分散式系統健康狀況與效能方面所扮演的關鍵角色。&lt;/p&gt;
&lt;p&gt;您現在已經了解可觀測性的&lt;strong&gt;三大支柱&lt;/strong&gt;——&lt;strong&gt;日誌（Logs）&lt;/strong&gt;、&lt;strong&gt;指標（Metrics）&lt;strong&gt;與&lt;/strong&gt;追蹤（Traces）&lt;/strong&gt;——以及它們如何各自發揮獨特作用，以提供系統行為的完整視野。本章也點出了現代化、多語言開發（Polyglot）及分散式應用程式所帶來的挑戰，例如日益增加的複雜度，以及難以跨多種服務來關聯 &lt;strong&gt;遙測資料（Telemetry data）&lt;/strong&gt; 的問題。&lt;/p&gt;
&lt;p&gt;我們探討了 &lt;strong&gt;OpenTelemetry&lt;/strong&gt; 是什麼——它是一個 &lt;strong&gt;供應商中立（Vendor-neutral）&lt;/strong&gt; 的開源工具，用於收集與標準化遙測資料——並釐清了它「不是」什麼。我們特別強調 OpenTelemetry 並非一個一站式的可觀測性平台，而是一個強大的整合與資料收集工具。&lt;/p&gt;
&lt;p&gt;最後，我們檢視了 OpenTelemetry 如何透過提供一種統一的方式，以高度適應性且跨平台的手法來收集追蹤、指標與日誌，從而解決傳統可觀測性解決方案的局限性。&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;6. 小試身手&lt;span class="hx:absolute hx:-mt-20" id="6-小試身手"&gt;&lt;/span&gt;
&lt;a href="#6-%e5%b0%8f%e8%a9%a6%e8%ba%ab%e6%89%8b" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;h3&gt;問題 1&lt;span class="hx:absolute hx:-mt-20" id="問題-1"&gt;&lt;/span&gt;
&lt;a href="#%e5%95%8f%e9%a1%8c-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;下列哪一項敘述最能貼切地描述可觀測性的三大支柱——&lt;strong&gt;指標 (Metrics)&lt;/strong&gt;、&lt;strong&gt;日誌 (Logs)&lt;/strong&gt; 與 &lt;strong&gt;追蹤 (Traces)&lt;/strong&gt;——如何各自協助我們理解系統的行為？&lt;/p&gt;
&lt;div class="indent-title-1"&gt;
&lt;p&gt;A. 指標 (Metrics) 提供個別錯誤的詳細解釋，日誌 (Logs) 總結整體效能，而追蹤 (Traces) 則記錄每個請求完成所需的時間。&lt;/p&gt;
&lt;p&gt;B. 追蹤 (Traces) 記錄即時 CPU 使用率，日誌 (Logs) 顯示效能趨勢，而指標 (Metrics) 則記錄請求在系統中的完整歷程。&lt;/p&gt;
&lt;p&gt;C. 指標 (Metrics) 與追蹤 (Traces) 用於記錄使用者行為，而日誌 (Logs) 則監控伺服器效能與錯誤。&lt;/p&gt;
&lt;p&gt;D. 日誌 (Logs) 捕捉用於故障排除的歷史資料，指標 (Metrics) 追蹤隨時間變化的系統效能，而追蹤 (Traces) 則跟隨請求在分散式系統中的路徑，以精準定位延遲或故障發生的位置。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;p&gt;here is why:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Logs (日誌)：紀錄發生了什麼事 (What happened? - 歷史事件)&lt;/li&gt;
&lt;li&gt;Metrics (指標)：紀錄系統狀態與趨勢 (Is it healthy? - 數值與趨勢)&lt;/li&gt;
&lt;li&gt;Traces (追蹤)：紀錄請求的路徑與因果關係 (Where is the latency? - 分散式路徑)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;問題 2&lt;span class="hx:absolute hx:-mt-20" id="問題-2"&gt;&lt;/span&gt;
&lt;a href="#%e5%95%8f%e9%a1%8c-2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;OpenTelemetry 是什麼？&lt;/p&gt;
&lt;div class="indent-title-1"&gt;
&lt;p&gt;A. OpenTelemetry 是一個針對分散式系統的完整監控與告警平台。&lt;/p&gt;
&lt;p&gt;B. OpenTelemetry 是一個針對遙測資料（日誌、指標與追蹤）的資料收集工具，並可與可觀測性平台進行整合。&lt;/p&gt;
&lt;p&gt;C. OpenTelemetry 是一個特定供應商專用的工具，用於在微服務環境中收集指標。&lt;/p&gt;
&lt;p&gt;D. OpenTelemetry 會自動最佳化（Optimize）分散式應用程式的效能。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;B&lt;/p&gt;
&lt;p&gt;here is why:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenTelemetry 專注於產生與收集資料（Telemetry），它本身不負責儲存資料後的分析與告警（那是 Backend 平台的工作，所以 A 錯）。&lt;/li&gt;
&lt;li&gt;它是供應商中立 (Vendor-neutral) 的，所以 C 錯。&lt;/li&gt;
&lt;li&gt;它是用來觀察系統的，而非主動去修改或優化系統效能，所以 D 錯。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;問題 3&lt;span class="hx:absolute hx:-mt-20" id="問題-3"&gt;&lt;/span&gt;
&lt;a href="#%e5%95%8f%e9%a1%8c-3" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;OpenTelemetry 是一個預先設定好（Pre-configured）的監控工具，用於收集與匯出資料。&lt;/p&gt;
&lt;p&gt;正確還是錯誤？&lt;/p&gt;
&lt;div class="indent-title-1"&gt;
&lt;p&gt;A. 正確 (True)&lt;/p&gt;
&lt;p&gt;B. 錯誤 (False)&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;B&lt;/p&gt;
&lt;p&gt;here is why:&lt;/p&gt;
&lt;p&gt;OpenTelemetry 是一套用於收集與匯出資料的工具組，但它需要經過設定並與其他系統進行整合。它並不自動提供開箱即用（out-of-the-box）的監控或告警功能。&lt;/p&gt;
&lt;h3&gt;問題 4&lt;span class="hx:absolute hx:-mt-20" id="問題-4"&gt;&lt;/span&gt;
&lt;a href="#%e5%95%8f%e9%a1%8c-4" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;情境&lt;/p&gt;
&lt;p&gt;貴公司的 Web 應用程式正面臨回應速度變慢的問題，但該系統是由多個&lt;strong&gt;微服務 (Microservices)&lt;/strong&gt; 所建構。每個服務都會產生自己的&lt;strong&gt;日誌 (Logs)&lt;/strong&gt;、&lt;strong&gt;指標 (Metrics)&lt;/strong&gt; 和&lt;strong&gt;追蹤 (Traces)&lt;/strong&gt;，但這些資料皆各自獨立儲存，缺乏跨所有服務的&lt;strong&gt;統一視圖 (Unified view)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;問題&lt;/p&gt;
&lt;p&gt;在嘗試找出並修復此問題時，您最可能面臨的主要挑戰是什麼？&lt;/p&gt;
&lt;div class="indent-title-1"&gt;
&lt;p&gt;A. 來自每個服務的資料會發生衝突，導致無法採信任何日誌或指標。&lt;/p&gt;
&lt;p&gt;B. 當偵測到效能問題時，每個服務會停止產生日誌，導致無法進行故障排除。&lt;/p&gt;
&lt;p&gt;C. 難以將跨服務的資訊進行關聯 (Correlate)，這使得難以追蹤請求的流向，或無法精準定位 (Pinpoint)問題發生的位置。&lt;/p&gt;
&lt;p&gt;D. 您將無法同時存取所有服務的日誌，導致在識別根本原因 (Root cause) 時產生延遲。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;C&lt;/p&gt;
&lt;p&gt;here is why:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A: 資料通常不會衝突，只是分散而已。&lt;/li&gt;
&lt;li&gt;B: 系統通常不會因為效能差就停止寫 Log（反而可能寫更多錯誤 Log）。&lt;/li&gt;
&lt;li&gt;C: 遙測資料孤島化 (Siloed telemetry) 意指日誌、指標與追蹤是針對個別服務分開儲存的，這使得難以看清請求在系統中流動的完整全貌。這種缺乏整合的情況，會導致在識別效能問題或錯誤時，增加複雜度並造成延誤。&lt;/li&gt;
&lt;li&gt;D: 「無法同時存取」通常是指權限或工具介面問題，但在這個情境下，真正的痛點不是「讀不到」，而是讀到了卻「看不出彼此的關係」。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>OpenTelemetry 框架概述</title><link>https://blog.kubeantony.com/archive/ops-automation/opentelemetry-%E6%A1%86%E6%9E%B6%E6%A6%82%E8%BF%B0/</link><pubDate>Tue, 16 Dec 2025 19:41:46 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/opentelemetry-%E6%A1%86%E6%9E%B6%E6%A6%82%E8%BF%B0/</guid><description>
&lt;h2&gt;0. Preface&lt;span class="hx:absolute hx:-mt-20" id="0-preface"&gt;&lt;/span&gt;
&lt;a href="#0-preface" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;本篇文章是翻譯 Getting Started with OpenTelemetry (LFS148) 的第三章節，想看原文可參考以下網址：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://training.linuxfoundation.org/training/getting-started-with-opentelemetry-lfs148/#"target="_blank" rel="noopener"&gt;https://training.linuxfoundation.org/training/getting-started-with-opentelemetry-lfs148/#&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;style&gt;
.indent-title-1{
margin-left: 1em;
}
.indent-title-2{
margin-left: 2em;
}
.indent-title-3{
margin-left: 3em;
}
&lt;/style&gt;
&lt;h2&gt;1. 學習目標在本章結束後，您應該能夠：&lt;span class="hx:absolute hx:-mt-20" id="1-學習目標在本章結束後您應該能夠"&gt;&lt;/span&gt;
&lt;a href="#1-%e5%ad%b8%e7%bf%92%e7%9b%ae%e6%a8%99%e5%9c%a8%e6%9c%ac%e7%ab%a0%e7%b5%90%e6%9d%9f%e5%be%8c%e6%82%a8%e6%87%89%e8%a9%b2%e8%83%bd%e5%a4%a0" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;解釋 &lt;strong&gt;OpenTelemetry 訊號規範 (Signal Specification)&lt;/strong&gt; 的目的，以及它如何確保跨語言和跨平台的一致性。&lt;/li&gt;
&lt;li&gt;描述 &lt;strong&gt;OTel SDK&lt;/strong&gt; 和 &lt;strong&gt;API&lt;/strong&gt; 規範，以及&lt;strong&gt;語意約定 (Semantic Conventions)&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;探討&lt;strong&gt;供應商中立 (Vendor-Agnostic) 的儀表化 (Instrumentation)&lt;/strong&gt; 概念，重點在於 OpenTelemetry 如何提供針對特定語言的儀表化功能，包含不同的儀表化層級。&lt;/li&gt;
&lt;li&gt;解釋 &lt;strong&gt;OpenTelemetry Collector&lt;/strong&gt; 作為&lt;strong&gt;遙測數據處理器 (Telemetry Processor)&lt;/strong&gt; 的角色，以及它如何協助處理與匯出遙測數據。&lt;/li&gt;
&lt;li&gt;探討 &lt;strong&gt;OTLP (OpenTelemetry Protocol)&lt;/strong&gt;，說明其作為傳輸遙測數據之&lt;strong&gt;傳輸協定 (Wire Protocol)&lt;/strong&gt; 的重要性，以及其在標準化不同元件間通訊的角色。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. Signal Specification 訊號規範 (Language-Agnostic / 跨語言通用)&lt;span class="hx:absolute hx:-mt-20" id="2-signal-specification-訊號規範-language-agnostic--跨語言通用"&gt;&lt;/span&gt;
&lt;a href="#2-signal-specification-%e8%a8%8a%e8%99%9f%e8%a6%8f%e7%af%84-language-agnostic--%e8%b7%a8%e8%aa%9e%e8%a8%80%e9%80%9a%e7%94%a8" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;從宏觀角度來看，OpenTelemetry 是由各種 &lt;strong&gt;訊號 (Signals)&lt;/strong&gt; 所組成的，主要包含 &lt;strong&gt;Tracing (追蹤)&lt;/strong&gt;、&lt;strong&gt;Metrics (指標)&lt;/strong&gt; 和 &lt;strong&gt;Logging (日誌)&lt;/strong&gt;。每一個訊號都是作為獨立的元件進行開發（但仍有方法可以將彼此的資料流串接起來）。&lt;/p&gt;
&lt;p&gt;這些訊號都被定義在 OpenTelemetry 的「&lt;a
href="https://opentelemetry.io/docs/specs/"target="_blank" rel="noopener"&gt;跨語言規範 (Language-Agnostic Specification)&lt;/a&gt;」中，這也是整個專案的核心所在。雖然終端使用者 (End-user) 可能不會直接接觸到這份規範，但它對於確保 OpenTelemetry 生態系中的一致性 (Consistency) 與互通性 (Interoperability) 扮演著至關重要的角色。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://hackmd.io/_uploads/B1lwsmy7-x.png" alt="image" loading="lazy" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;OpenTelemetry Specification (Language Agnostic)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;這份規範主要由三個部分組成。首先是&lt;a
href="https://opentelemetry.io/docs/specs/otel/glossary/"target="_blank" rel="noopener"&gt;術語定義&lt;/a&gt;，旨在建立共同的詞彙與認知，以避免混淆。其次，它詳述了每個訊號的技術設計細節。這包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;API 規範&lt;/strong&gt; (請參閱 &lt;a
href="https://opentelemetry.io/docs/specs/otel/trace/api/"target="_blank" rel="noopener"&gt;Tracing API&lt;/a&gt;, &lt;a
href="https://opentelemetry.io/docs/specs/otel/metrics/api/"target="_blank" rel="noopener"&gt;Metrics API&lt;/a&gt; 和 &lt;a
href="https://opentelemetry.io/docs/specs/otel/logs/"target="_blank" rel="noopener"&gt;OpenTelemetry Logging&lt;/a&gt;)
&lt;ul&gt;
&lt;li&gt;定義實作 (Implementations) 必須遵守的（概念性）介面。&lt;/li&gt;
&lt;li&gt;確保各個實作之間彼此相容。&lt;/li&gt;
&lt;li&gt;包含可用於產生、處理及匯出遙測數據 (Telemetry data) 的方法。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SDK 規範&lt;/strong&gt; (請參閱 &lt;a
href="https://opentelemetry.io/docs/specs/otel/trace/sdk/"target="_blank" rel="noopener"&gt;Tracing SDK&lt;/a&gt;, &lt;a
href="https://opentelemetry.io/docs/specs/otel/metrics/sdk/"target="_blank" rel="noopener"&gt;Metrics SDK&lt;/a&gt;, &lt;a
href="https://opentelemetry.io/docs/specs/otel/logs/sdk/"target="_blank" rel="noopener"&gt;Logs SDK&lt;/a&gt;)
&lt;ul&gt;
&lt;li&gt;作為開發人員的指引。&lt;/li&gt;
&lt;li&gt;定義特定語言的 API 實作必須滿足哪些需求才能符合標準 (Compliant)。&lt;/li&gt;
&lt;li&gt;包含關於遙測數據的設定 (Configuration)、處理和匯出的相關概念。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;除了訊號架構之外，該規範也涵蓋了與遙測數據相關的面向。例如，OpenTelemetry 定義了 &lt;strong&gt;&lt;a
href="https://opentelemetry.io/docs/specs/semconv/"target="_blank" rel="noopener"&gt;語意約定 (Semantic Conventions)&lt;/a&gt;&lt;/strong&gt;。透過推動通用遙測 Metadata 在命名與解釋上的一致性，OpenTelemetry 旨在減少對來自不同來源的數據進行「正規化 (Normalize)」的需求。&lt;/p&gt;
&lt;p&gt;最後，規範中還包含了 &lt;strong&gt;&lt;a
href="https://opentelemetry.io/docs/specs/otlp/"target="_blank" rel="noopener"&gt;OpenTelemetry Protocol (OTLP)&lt;/a&gt;&lt;/strong&gt;，我們將在本章稍後進行探討。&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;3. 供應商中立、針對特定語言的儀表化 (Instrumentation)&lt;span class="hx:absolute hx:-mt-20" id="3-供應商中立針對特定語言的儀表化-instrumentation"&gt;&lt;/span&gt;
&lt;a href="#3-%e4%be%9b%e6%87%89%e5%95%86%e4%b8%ad%e7%ab%8b%e9%87%9d%e5%b0%8d%e7%89%b9%e5%ae%9a%e8%aa%9e%e8%a8%80%e7%9a%84%e5%84%80%e8%a1%a8%e5%8c%96-instrumentation" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;&lt;img src="https://hackmd.io/_uploads/BJbJ0Xkm-g.png" alt="image" loading="lazy" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Generate and Emit Telemetry via the OTel API and SDK Packages&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;為了從應用程式中產生並發送遙測數據 (Telemetry)，我們使用遵循 OpenTelemetry 規範的「特定語言實作 (Language-specific implementations)」。OpenTelemetry 支援多種熱門的&lt;a
href="https://opentelemetry.io/docs/languages/#status-and-releases"target="_blank" rel="noopener"&gt;程式語言&lt;/a&gt;，且各語言的支援成熟度 (Maturity) 亦有所不同。一個訊號 (Signal) 的實作包含兩個部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;API&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;定義規範中列出的介面 (Interfaces) 與常數。&lt;/li&gt;
&lt;li&gt;供應用程式與函式庫開發者使用，以進行供應商中立 (Vendor-agnostic) 的儀表化。&lt;/li&gt;
&lt;li&gt;預設指向一個「無操作 (no-op)」的實作（即呼叫後不會執行任何動作）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SDK&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;實作了 OpenTelemetry API 的提供者 (Provider)。&lt;/li&gt;
&lt;li&gt;包含產生、處理並發送遙測數據的實際邏輯。&lt;/li&gt;
&lt;li&gt;OpenTelemetry 隨附了官方提供者作為「參考實作 (Reference Implementation)」（通常直接稱為 SDK）。&lt;/li&gt;
&lt;li&gt;您也可以自行撰寫 SDK。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一般來說，我們使用 OpenTelemetry API 將儀表化功能加入原始碼中。實際上，這可以透過多種方式達成，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;零程式碼 (Zero-code) 或自動儀表化 (Automatic Instrumentation)&lt;/strong&gt;（若可用，且為了避免修改程式碼）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;儀表化函式庫 (Instrumentation Libraries)&lt;/strong&gt; 提供簡化版 OpenTelemetry 整合的函式庫（可能需要或不需要修改程式碼）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;手動或基於程式碼的儀表化 (Manual Instrumentation)&lt;/strong&gt;（為了精細的控制，並深度嵌入程式碼中）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目前我們先跳過細節，專注於為何 OpenTelemetry 決定將 &lt;strong&gt;API&lt;/strong&gt; 與 &lt;strong&gt;SDK&lt;/strong&gt; 分離。在啟動時，應用程式會為每種類型的訊號註冊一個提供者 (Provider)。之後，對 API 的呼叫會被轉送 (Forwarded) 給相應的提供者。如果我們沒有明確註冊，OpenTelemetry 將使用一個備援 (Fallback) 提供者，將 API 呼叫轉換為無操作 (no-ops)。&lt;/p&gt;
&lt;p&gt;將 API 與 SDK 分離的主要原因，是為了讓開源函式庫更容易嵌入&lt;strong&gt;原生儀表化 (Native Instrumentation)&lt;/strong&gt; 功能。OpenTelemetry 的 API 被設計為輕量級且可安全依賴 (Safe to depend on)。相對地，由 SDK 提供的訊號實作則明顯複雜許多，且很可能包含對其他軟體的依賴 (Dependencies)。若強制使用者接受這些依賴，可能會導致與其特定的軟體環境 (Software stack) 發生衝突。&lt;/p&gt;
&lt;p&gt;透過在初始設定期間註冊提供者，允許使用者藉由選擇不同的實作來解決依賴衝突。此外，這讓我們能發布內建&lt;strong&gt;可觀測性 (Observability)&lt;/strong&gt; 的軟體，而不會將儀表化的執行成本 (Runtime cost) 強加給不需要的使用者。&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;4. 遙測數據處理器（獨立元件）Telemetry Processor (Standalone Component)&lt;span class="hx:absolute hx:-mt-20" id="4-遙測數據處理器獨立元件telemetry-processor-standalone-component"&gt;&lt;/span&gt;
&lt;a href="#4-%e9%81%99%e6%b8%ac%e6%95%b8%e6%93%9a%e8%99%95%e7%90%86%e5%99%a8%e7%8d%a8%e7%ab%8b%e5%85%83%e4%bb%b6telemetry-processor-standalone-component" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;&lt;img src="https://hackmd.io/_uploads/ry4lxEymWg.png" alt="image" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;到目前為止，我們已經看到 OpenTelemetry 為應用程式與函式庫開發者提供了&lt;strong&gt;供應商中立 (Vendor-agnostic)&lt;/strong&gt; 的儀表化工具。光是這一點就是一個重大的里程碑，但 OpenTelemetry 框架所涵蓋的範圍不僅止於此。&lt;/p&gt;
&lt;p&gt;在產生並發送遙測數據 (Telemetry) 後，&lt;strong&gt;維運人員 (Operators)&lt;/strong&gt; 負責管理這些數據，並將其&lt;strong&gt;攝取 (Ingest)&lt;/strong&gt; 到各自的後端系統中。這包含了以下任務：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;從各種來源收集數據。&lt;/li&gt;
&lt;li&gt;解析數據並進行轉換，以供下游處理。&lt;/li&gt;
&lt;li&gt;使用額外的 Metadata 進行&lt;strong&gt;豐富化 (Enrichment)&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;過濾掉不相關的數據，以減少雜訊並降低儲存需求。&lt;/li&gt;
&lt;li&gt;進行&lt;strong&gt;正規化 (Normalization)&lt;/strong&gt; 並套用轉換。&lt;/li&gt;
&lt;li&gt;進行&lt;strong&gt;緩衝 (Buffering)&lt;/strong&gt; 以提升&lt;strong&gt;韌性 (Resilience)&lt;/strong&gt; 與效能。&lt;/li&gt;
&lt;li&gt;進行&lt;strong&gt;路由 (Routing)&lt;/strong&gt;，將部分遙測數據引導至不同的目的地。&lt;/li&gt;
&lt;li&gt;轉送至後端系統。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;為了建構並設定這類遙測數據&lt;strong&gt;管線 (Pipelines)&lt;/strong&gt;，維運團隊通常會部署額外的基礎設施。一個常見的例子是 &lt;a
href="https://fluentbit.io/"target="_blank" rel="noopener"&gt;fluentbit&lt;/a&gt; 遙測代理程式 (Agent)。同樣地，OpenTelemetry 提供了一個具備這些能力的獨立元件：&lt;strong&gt;&lt;a
href="https://opentelemetry.io/docs/collector/"target="_blank" rel="noopener"&gt;OpenTelemetry Collector&lt;/a&gt;&lt;/strong&gt;。&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;5. 傳輸協定 (Wire Protocol)&lt;span class="hx:absolute hx:-mt-20" id="5-傳輸協定-wire-protocol"&gt;&lt;/span&gt;
&lt;a href="#5-%e5%82%b3%e8%bc%b8%e5%8d%94%e5%ae%9a-wire-protocol" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;為了完善標準化、數據產生及管理的整套方案，OpenTelemetry 也定義了如何在生產者 (Producers)、代理程式 (Agents) 和後端 (Backends) 之間傳輸遙測數據。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a
href="https://opentelemetry.io/docs/specs/otel/protocol/"target="_blank" rel="noopener"&gt;OpenTelemetry Protocol (OTLP)&lt;/a&gt;&lt;/strong&gt; 是一個開源且&lt;strong&gt;供應商中立 (Vendor-neutral)&lt;/strong&gt; 的&lt;strong&gt;傳輸格式 (Wire format)&lt;/strong&gt;，它定義了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;數據如何在記憶體中被編碼。&lt;/li&gt;
&lt;li&gt;用於在網路上傳輸該數據的協定。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，OTLP 被廣泛應用於整個&lt;strong&gt;可觀測性堆疊 (Observability stack)&lt;/strong&gt; 中。以 OTLP 格式發送遙測數據，意味著&lt;strong&gt;已儀表化 (Instrumented)&lt;/strong&gt; 的應用程式與第三方服務，能與無數的可觀測性解決方案相容。&lt;/p&gt;
&lt;p&gt;雖然 Collector 支援接收來自各種格式的遙測數據，也能匯出成各種格式（例如：Prometheus Metrics, Zipkin traces 等），但通常會優先選擇 OTLP，因為 Collector 內部正是使用 OTLP 來表示與處理遙測數據。藉此，我們避免了格式轉換的成本，並提升了一致性。這是因為該原生格式與框架提出的理念緊密契合（例如屬性遵循&lt;strong&gt;語意約定&lt;/strong&gt;、跨訊號關聯等）。&lt;/p&gt;
&lt;p&gt;同樣地，大多數可觀測性後端都&lt;strong&gt;開箱即用 (Right out of the box)&lt;/strong&gt; 地支援 OTLP。鑑於 OpenTelemetry 的快速普及，整合 OTLP 能讓你自動觸及廣大的潛在使用者群體。此外，一個開源且供應商中立的遙測協定，意味著可觀測性工具開發者的工作量更少。以前，你必須開發無數的&lt;strong&gt;轉接器 (Adapters)&lt;/strong&gt;，才能&lt;strong&gt;攝取 (Ingest)&lt;/strong&gt; 以各種&lt;strong&gt;專有格式 (Proprietary formats)&lt;/strong&gt; 傳來的數據。換句話說，OTLP 大力推動了可觀測性生態系中工具與服務間的&lt;strong&gt;互通性 (Interoperability)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;OTLP 提供了三種用於傳輸遙測數據的傳輸機制：HTTP/1.1、HTTP/2 和 gRPC。使用 OTLP 時，傳輸機制的選擇取決於應用程式需求，需考量效能、可靠性與安全性等因素。&lt;/p&gt;
&lt;p&gt;OTLP 數據通常使用 &lt;strong&gt;Protocol Buffers (Protobuf)&lt;/strong&gt; 二進位格式進行編碼，該格式精簡且網路傳輸效率高，並支援&lt;strong&gt;模式演進 (Schema Evolution)&lt;/strong&gt;，允許在不破壞相容性的情況下修改未來的資料模型。數據也可以編碼為 JSON 格式，這提供了&lt;strong&gt;人類可讀 (Human-readable)&lt;/strong&gt; 的格式，但缺點是網路流量較高且檔案較大。&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;6. 章節總結&lt;span class="hx:absolute hx:-mt-20" id="6-章節總結"&gt;&lt;/span&gt;
&lt;a href="#6-%e7%ab%a0%e7%af%80%e7%b8%bd%e7%b5%90" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;在本章中，我們探討了 &lt;strong&gt;OpenTelemetry 框架&lt;/strong&gt;的關鍵元件，涵蓋了它如何提供一種統一的方法來收集與傳輸遙測數據 (Telemetry data)。&lt;/p&gt;
&lt;p&gt;我們首先探討了 &lt;strong&gt;訊號規範 (Signal Specification)&lt;/strong&gt;，它是跨語言通用 (Language-agnostic) 的，確保了在不同平台與語言之間，定義和收集遙測數據（Log、Metric、Trace）的一致性。&lt;/p&gt;
&lt;p&gt;接著，我們討論了 &lt;strong&gt;供應商中立的儀表化 (Vendor-Agnostic Instrumentation)&lt;/strong&gt;，強調 OpenTelemetry 如何在特定程式語言中實現遙測數據的收集，同時保持獨立性，不被任何特定供應商的可觀測性工具組所綁定。&lt;/p&gt;
&lt;p&gt;隨後，我們檢視了 &lt;strong&gt;OpenTelemetry Collector&lt;/strong&gt; 作為&lt;strong&gt;遙測數據處理器 (Telemetry Processor)&lt;/strong&gt; 的角色，詳細說明它如何處理、轉換並匯出遙測數據至各種後端 (Backends)，讓管理可觀測性數據&lt;strong&gt;管線 (Pipelines)&lt;/strong&gt; 更具彈性。&lt;/p&gt;
&lt;p&gt;此外，我們介紹了 &lt;strong&gt;OTLP (OpenTelemetry Protocol)&lt;/strong&gt;，它標準化了整個系統中的遙測數據傳輸，確保不同元件之間能有可靠的通訊。&lt;/p&gt;
&lt;p&gt;最後，我們提及了 &lt;strong&gt;OTel SDK&lt;/strong&gt; 與 &lt;strong&gt;API 規範&lt;/strong&gt;的重要性，它們定義了開發者如何與 OpenTelemetry 互動；以及 &lt;strong&gt;語意約定 (Semantic Conventions)&lt;/strong&gt;，它為遙測數據提供一致的標籤 (Labeling) 與結構，提升了所收集資訊的清晰度與實用性。&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;7. 小試身手&lt;span class="hx:absolute hx:-mt-20" id="7-小試身手"&gt;&lt;/span&gt;
&lt;a href="#7-%e5%b0%8f%e8%a9%a6%e8%ba%ab%e6%89%8b" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;h3&gt;問題 1&lt;span class="hx:absolute hx:-mt-20" id="問題-1"&gt;&lt;/span&gt;
&lt;a href="#%e5%95%8f%e9%a1%8c-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;OpenTelemetry 訊號規範 (Signal Specification) 的目的是什麼？&lt;/p&gt;
&lt;div class="indent-title-1"&gt;
&lt;p&gt;A. 指定使用 OpenTelemetry 的供應商需求 (Vendor requirements)&lt;/p&gt;
&lt;p&gt;B. 定義針對特定語言 (Language-specific) 的 Tracing (追蹤) 協定&lt;/p&gt;
&lt;p&gt;C. 提供一種一致且跨語言通用 (Language-agnostic) 的遙測數據收集方法&lt;/p&gt;
&lt;p&gt;D. 建立自定義訊號以監控網路流量&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;C&lt;/p&gt;
&lt;p&gt;here is why:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;跨語言通用 (Language-Agnostic)&lt;/strong&gt;：
本文中明確提到「Signals are defined inside OpenTelemetry’s &lt;strong&gt;language-agnostic specification&lt;/strong&gt;（訊號定義在 OpenTelemetry 的跨語言規範中）」。這表示規範本身不綁定特定語言，而是作為一個通用的標準，讓各種程式語言（如 Java, Python, Go）的實作去遵循。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一致性 (Consistency)&lt;/strong&gt;：
本文中提到該規範的角色是「ensuring &lt;strong&gt;consistency&lt;/strong&gt; and interoperability（確保一致性與互通性）」。這正是選項 c 中提到的重點。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;為什麼其他選項不正確？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A. 指定使用 OpenTelemetry 的供應商需求&lt;/strong&gt;：OpenTelemetry 的核心原則是「供應商中立 (Vendor-Agnostic)」，目的是&lt;strong&gt;不被&lt;/strong&gt;特定廠商綁定，而不是為了制定廠商的需求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B. 定義針對特定語言的 Tracing 協定&lt;/strong&gt;：規範本身是&lt;strong&gt;跨語言通用 (Language-Agnostic)&lt;/strong&gt; 的，而不是針對特定語言 (Language-specific)。「特定語言」的部分是在 SDK 實作層面，而非核心規範層面。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D. 建立自定義訊號以監控網路流量&lt;/strong&gt;：雖然 OpenTelemetry 可以用於監控，但訊號規範的主要目的在於定義標準的三大訊號（Tracing, Metrics, Logging），而非專注於建立「監控網路流量的自定義訊號」。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;問題 2&lt;span class="hx:absolute hx:-mt-20" id="問題-2"&gt;&lt;/span&gt;
&lt;a href="#%e5%95%8f%e9%a1%8c-2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;OpenTelemetry 中的供應商中立儀表化 (Vendor-Agnostic Instrumentation) 如何讓開發者受益？&lt;/p&gt;
&lt;div class="indent-title-1"&gt;
&lt;p&gt;A. 它確保所有儀表化都在應用程式層級 (Application level) 處理
B. 它支援跨不同程式語言的自動 (Automatic) 與手動 (Manual) 儀表化
C. 它將儀表化僅限於高階效能指標
D. 它提供針對各家雲端供應商 (Cloud Provider) 的預建儀表化功能&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;B&lt;/p&gt;
&lt;p&gt;here is why:&lt;/p&gt;
&lt;p&gt;根據前文「Vendor-Agnostic, Language-Specific Instrumentation」章節的內容：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;支援多種模式&lt;/strong&gt;：文中明確提到儀表化可以透過「零程式碼或自動儀表化 (zero-code or automatic instrumentation)」以及「手動或基於程式碼的儀表化 (manual or code-based instrumentation)」來達成。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨語言支援&lt;/strong&gt;：文中提到 OTel 支援「廣泛的熱門程式語言 (wide-range of popular programming languages)」。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;供應商中立&lt;/strong&gt;：選項 D 提到「針對特定雲端供應商」，這與 Vendor-Agnostic（不被廠商綁定）的核心精神相違背。OTel 的目的是讓你的程式碼不依賴特定廠商的 SDK。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;問題 3&lt;span class="hx:absolute hx:-mt-20" id="問題-3"&gt;&lt;/span&gt;
&lt;a href="#%e5%95%8f%e9%a1%8c-3" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;OpenTelemetry 中的語意約定 (Semantic Conventions) 是什麼？&lt;/p&gt;
&lt;div class="indent-title-1"&gt;
&lt;p&gt;A. 用於透過網際網路傳輸遙測數據的預定義格式
B. 僅用於 OpenTelemetry 日誌中的自定義命名慣例
C. 一種透過機器學習演算法處理追蹤 (Traces) 的方法
D. 一套用於一致地組織與標記 (Labeling) 遙測數據的規則&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;p&gt;根據前文「Signal Specification」章節的內容：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定義與目的&lt;/strong&gt;：文中提到 OpenTelemetry 定義語意約定是為了推動「通用遙測 Metadata 在命名與解釋上的一致性 (consistency in the naming and interpretation of common telemetry metadata)」。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;減少正規化需求&lt;/strong&gt;：透過這些規則，目的是減少對來自不同來源的數據進行正規化的需求，讓數據結構標準化。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;為什麼其他選項不正確？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A. 傳輸格式&lt;/strong&gt;：這是 &lt;strong&gt;OTLP (OpenTelemetry Protocol)&lt;/strong&gt; 的功能，屬於傳輸協定 (Wire Protocol) 的範疇。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B. 僅用於日誌&lt;/strong&gt;：語意約定適用於&lt;strong&gt;所有&lt;/strong&gt;訊號（Tracing, Metrics 和 Logging），並非僅限於日誌。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C. 機器學習&lt;/strong&gt;：這與語意約定的定義完全無關。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Installing the Red Hat build of OpenTelemetry by using the CLI</title><link>https://blog.kubeantony.com/archive/ops-automation/installing-the-red-hat-build-of-opentelemetry-by-using-the-cli/</link><pubDate>Thu, 18 Sep 2025 12:23:02 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/installing-the-red-hat-build-of-opentelemetry-by-using-the-cli/</guid><description>
&lt;p&gt;可以從命令列安裝 Red Hat 版的 OpenTelemetry。&lt;/p&gt;
&lt;h2&gt;1. 本篇文章 Openshift 環境資訊&lt;span class="hx:absolute hx:-mt-20" id="1-本篇文章-openshift-環境資訊"&gt;&lt;/span&gt;
&lt;a href="#1-%e6%9c%ac%e7%af%87%e6%96%87%e7%ab%a0-openshift-%e7%92%b0%e5%a2%83%e8%b3%87%e8%a8%8a" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Openshift version: &lt;code&gt;4.18.22&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;1. 先決條件&lt;span class="hx:absolute hx:-mt-20" id="1-先決條件"&gt;&lt;/span&gt;
&lt;a href="#1-%e5%85%88%e6%b1%ba%e6%a2%9d%e4%bb%b6" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;具備 cluster-admin 角色的叢集管理員，且已啟用 OpenShift CLI（oc）的工作階段。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;2. 開始安裝 Red Hat 版 OpenTelemetry Operator：&lt;span class="hx:absolute hx:-mt-20" id="2-開始安裝-red-hat-版-opentelemetry-operator"&gt;&lt;/span&gt;
&lt;a href="#2-%e9%96%8b%e5%a7%8b%e5%ae%89%e8%a3%9d-red-hat-%e7%89%88-opentelemetry-operator" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;執行下列指令，為 Red Hat 版 OpenTelemetry Operator 建立專案：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;oc apply -f - &amp;lt;&amp;lt; EOF
apiVersion: project.openshift.io/v1
kind: Project
metadata:
labels:
kubernetes.io/metadata.name: openshift-opentelemetry-operator
openshift.io/cluster-monitoring: &amp;#34;true&amp;#34;
name: openshift-opentelemetry-operator
EOF&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;執行下列指令，建立 OperatorGroup：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;oc apply -f - &amp;lt;&amp;lt; EOF
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: openshift-opentelemetry-operator
namespace: openshift-opentelemetry-operator
spec:
upgradeStrategy: Default
EOF&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;執行下列指令，建立 Subscription：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;oc apply -f - &amp;lt;&amp;lt; EOF
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: opentelemetry-product
namespace: openshift-opentelemetry-operator
spec:
channel: stable
installPlanApproval: Automatic
name: opentelemetry-product
source: cs-redhat-operator-index
sourceNamespace: openshift-marketplace
EOF&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;執行下列指令，檢查該 Operator 的狀態：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;oc get csv -n openshift-opentelemetry-operator&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行結果 :&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;NAME DISPLAY VERSION REPLACES PHASE
opentelemetry-operator.v0.127.0-2 Red Hat build of OpenTelemetry 0.127.0-2 opentelemetry-operator.v0.127.0-1 Succeeded&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;3. 建立的 OpenTelemetry Collector instance，建立一個您選擇的允許專案（permitted project）：&lt;span class="hx:absolute hx:-mt-20" id="3-建立的-opentelemetry-collector-instance建立一個您選擇的允許專案permitted-project"&gt;&lt;/span&gt;
&lt;a href="#3-%e5%bb%ba%e7%ab%8b%e7%9a%84-opentelemetry-collector-instance%e5%bb%ba%e7%ab%8b%e4%b8%80%e5%80%8b%e6%82%a8%e9%81%b8%e6%93%87%e7%9a%84%e5%85%81%e8%a8%b1%e5%b0%88%e6%a1%88permitted-project" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;若要建立不含 metadata 的專案，請執行下列指令：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;oc new-project opentelemetry&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;若要建立包含 metadata 的專案，請執行下列指令：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;oc apply -f - &amp;lt;&amp;lt; EOF
apiVersion: project.openshift.io/v1
kind: Project
metadata:
name: opentelemetry
EOF&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;備註&lt;/p&gt;
&lt;p&gt;可以在同一個叢集上的不同專案中，建立多個 OpenTelemetry Collector instance 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;建立與切換工作目錄&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;mkdir -p &amp;#34;${HOME}&amp;#34;/wulin/openTelemetr;
cd &amp;#34;${HOME}&amp;#34;/wulin/openTelemetr&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;自訂 OpenTelemetryCollector 自訂資源 (CR)&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;nano openTelemetryCollector.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檔案內容如下:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
name: otel
namespace: opentelemetry
spec:
mode: deployment
config:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
send_batch_size: 10000
timeout: 10s
memory_limiter:
check_interval: 1s
limit_percentage: 50
spike_limit_percentage: 30
exporters:
debug: {}
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter,batch]
exporters: [debug]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;為 OpenTelemetryCollector 部署所選擇的&lt;strong&gt;project&lt;/strong&gt;。不允許使用 &lt;code&gt;openshift-&lt;/code&gt; 前綴開頭的 project 名稱。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;請執行以下指令以&lt;strong&gt;建立&lt;/strong&gt;自訂後的 CR：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;oc -n opentelemetry apply -f openTelemetryCollector.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;請執行以下指令，以驗證 OpenTelemetry Collector Pod 的 &lt;code&gt;status.phase&lt;/code&gt; 為 &lt;code&gt;Running&lt;/code&gt;，且其條件的 &lt;code&gt;type&lt;/code&gt; 為 &lt;code&gt;Ready&lt;/code&gt;：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;oc -n opentelemetry get pod \
-l app.kubernetes.io/managed-by=opentelemetry-operator,app.kubernetes.io/instance=opentelemetry.otel \
-o jsonpath=&amp;#39;{range .items[*]}{.metadata.name}{&amp;#34;\t&amp;#34;}{.status.phase}{&amp;#34;\t&amp;#34;}{.status.conditions[?(@.type==&amp;#34;Ready&amp;#34;)].status}{&amp;#34;\n&amp;#34;}{end}&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行結果 :&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;otel-collector-75bfc8d889-4klkq Running True&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;請執行以下指令以取得 OpenTelemetry Collector 服務：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;oc -n opentelemetry get service \
-l app.kubernetes.io/managed-by=opentelemetry-operator,app.kubernetes.io/instance=opentelemetry.otel&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行結果 :&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
otel-collector ClusterIP 10.98.50.143 &amp;lt;none&amp;gt; 14250/TCP,14268/TCP,6831/UDP,6832/UDP,9411/TCP 3m51s
otel-collector-headless ClusterIP None &amp;lt;none&amp;gt; 14250/TCP,14268/TCP,6831/UDP,6832/UDP,9411/TCP 3m51s
otel-collector-monitoring ClusterIP 10.98.180.38 &amp;lt;none&amp;gt; 8888/TCP 3m51s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;自動建立所需的 RBAC 資源&lt;/p&gt;
&lt;p&gt;某些收集器 (Collector) 元件需要設定 RBAC 資源。&lt;/p&gt;
&lt;p&gt;將下列權限新增至 &lt;code&gt;opentelemetry-operator-controller-manage&lt;/code&gt; 服務帳戶，如此一來 Red Hat build of OpenTelemetry Operator 就能自動建立它們：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;oc apply -f - &amp;lt;&amp;lt; EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: generate-processors-rbac
rules:
- apiGroups:
- rbac.authorization.k8s.io
resources:
- clusterrolebindings
- clusterroles
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: generate-processors-rbac
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: generate-processors-rbac
subjects:
- kind: ServiceAccount
name: opentelemetry-operator-controller-manager
namespace: openshift-opentelemetry-operator
EOF&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Get started with OpenTelemetry in Java</title><link>https://blog.kubeantony.com/archive/ops-automation/get-started-with-opentelemetry-in-java/</link><pubDate>Thu, 18 Sep 2025 02:05:24 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/get-started-with-opentelemetry-in-java/</guid><description>
&lt;h2&gt;0. Preface&lt;span class="hx:absolute hx:-mt-20" id="0-preface"&gt;&lt;/span&gt;
&lt;a href="#0-preface" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;本頁面將說明如何在 Java 中開始使用 OpenTelemetry。&lt;/p&gt;
&lt;p&gt;您將學習如何自動檢測 (instrument) 一個簡單的 Java 應用程式，使其能夠將&lt;strong&gt;追蹤 (trace)&lt;/strong&gt;、&lt;strong&gt;指標 (metric)&lt;/strong&gt; 與&lt;strong&gt;日誌 (log)&lt;/strong&gt; 輸出到主控台。&lt;/p&gt;
&lt;h2&gt;1. 先決條件&lt;span class="hx:absolute hx:-mt-20" id="1-先決條件"&gt;&lt;/span&gt;
&lt;a href="#1-%e5%85%88%e6%b1%ba%e6%a2%9d%e4%bb%b6" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;由於使用 Spring Boot 3，因此需要 Java JDK 17+； 否則需要 Java 8+&lt;/li&gt;
&lt;li&gt;Gradle 8.14&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;2. 範例應用&lt;span class="hx:absolute hx:-mt-20" id="2-範例應用"&gt;&lt;/span&gt;
&lt;a href="#2-%e7%af%84%e4%be%8b%e6%87%89%e7%94%a8" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;下列範例使用了一個基本的 Spring Boot 網站應用程式。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;依賴套件&lt;/strong&gt;&lt;span class="hx:absolute hx:-mt-20" id="依賴套件"&gt;&lt;/span&gt;
&lt;a href="#%e4%be%9d%e8%b3%b4%e5%a5%97%e4%bb%b6" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;首先，請在一個名為 &lt;code&gt;java-simple&lt;/code&gt; 的新目錄中設定環境。&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;mkdir -p &amp;#34;${HOME}&amp;#34;/wulin/java-simple; cd &amp;#34;${HOME}&amp;#34;/wulin/java-simple&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在該目錄中，建立一個名為 &lt;code&gt;build.gradle.kts&lt;/code&gt; 的檔案，其內容如下：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;nano build.gradle.kts&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&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="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;java&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&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="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;org.springframework.boot&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;3.0.6&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&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="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;io.spring.dependency-management&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;1.1.0&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&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;&lt;span class="w"&gt;
&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;sourceSets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&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="n"&gt;main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&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="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSrcDirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;setOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&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;&lt;span class="w"&gt;
&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;repositories&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&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="n"&gt;mavenCentral&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&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;&lt;span class="w"&gt;
&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&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="n"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;org.springframework.boot:spring-boot-starter-web&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&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;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;建立一個名為 &lt;code&gt;DiceApplication.java&lt;/code&gt; 的文件，並將以下程式碼新增至該文件：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;nano DiceApplication.java&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;otel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.springframework.boot.Banner&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.springframework.boot.SpringApplication&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.springframework.boot.autoconfigure.SpringBootApplication&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@SpringBootApplication&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DiceApplication&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&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="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&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="n"&gt;SpringApplication&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SpringApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DiceApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&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="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBannerMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Banner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Mode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&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="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&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;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;建立另一個名為 &lt;code&gt;RollController.java&lt;/code&gt; 的文件，並將以下程式碼新增至該文件：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;nano RollController.java&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;otel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.util.Optional&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.util.concurrent.ThreadLocalRandom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.slf4j.Logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.slf4j.LoggerFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.springframework.web.bind.annotation.GetMapping&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.springframework.web.bind.annotation.RequestParam&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.springframework.web.bind.annotation.RestController&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RollController&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&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="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LoggerFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RollController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&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&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="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/rolldice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&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="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;player&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&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="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRandomNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&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="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPresent&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&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="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;{} is rolling the dice: {}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&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="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Anonymous player is rolling the dice: {}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&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="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&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&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="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getRandomNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&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="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ThreadLocalRandom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;current&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="na"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&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;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;請使用下列指令來建置並執行應用程式&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;gradle assemble
java -jar ./build/libs/java-simple.jar&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;透過網路存取 &lt;code&gt;http://localhost:8080/rolldice&lt;/code&gt;，以確保它能正常運作&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;curl http://localhost:8080/rolldice; echo&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;6&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;按 &lt;code&gt;Ctrl + c&lt;/code&gt; 停止網站應用程序&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;將以上步驟 1 ~ 5 寫進 Dockerfile&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;nano Dockerfile-v2-nonroot&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檔案內容如下：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;registry.suse.com/bci/bci-base:15.7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;useradder&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ARG user&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; RUN groupadd &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; useradd -m -d /home/&lt;span class="nv"&gt;$user&lt;/span&gt; -g &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;docker.io/library/gradle:8.14.3-jdk17-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ARG user&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /etc/passwd /etc/passwd&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /etc/group /etc/group&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /etc/shadow /etc/shadow&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /home/&lt;span class="nv"&gt;$user&lt;/span&gt; /home/&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY build.gradle.kts DiceApplication.java RollController.java /java-simple&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; WORKDIR /java-simple&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; RUN chown -R &lt;span class="nv"&gt;$user&lt;/span&gt;:&lt;span class="nv"&gt;$user&lt;/span&gt; /java-simple &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; gradle assemble&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; USER &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;registry.suse.com/bci/openjdk:17&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ARG user&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /etc/passwd /etc/passwd&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /etc/group /etc/group&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /etc/shadow /etc/shadow&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /home/&lt;span class="nv"&gt;$user&lt;/span&gt; /home/&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; RUN mkdir /app&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; WORKDIR /app&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;build --chown&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;:&lt;span class="nv"&gt;$user&lt;/span&gt; /java-simple/build/libs/java-simple.jar /app/java-simple.jar&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; USER &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; EXPOSE &lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ENTRYPOINT &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;java&amp;#34;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;#34;-jar&amp;#34;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;#34;/app/java-simple.jar&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;製作 image&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;podman build --no-cache \
--squash-all \
--build-arg user=bigred \
-t java-simple:v2-nonroot \
-f Dockerfile-v2-nonroot&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run java app container 測試是否符合預期&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;podman run -d \
--name java-simple \
-p 9999:8080 \
localhost/java-simple:v2-nonroot&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;檢視 app container 運作狀態&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;podman ps -a --filter name=java-simple&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;正確執行結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3c1739039eed localhost/java-simple:v2-nonroot 14 minutes ago Up 14 minutes 0.0.0.0:9999-&amp;gt;8080/tcp java-simple&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;透過網路存取 &lt;code&gt;http://192.168.11.21:9999/rolldice&lt;/code&gt;，以確保它能正常運作&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;curl http://192.168.11.21:9999/rolldice; echo&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;移除 java app container&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;podman rm -f java-simple&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;3. Instrumentation&lt;span class="hx:absolute hx:-mt-20" id="3-instrumentation"&gt;&lt;/span&gt;
&lt;a href="#3-instrumentation" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;接下來，您將使用 Java 代理程式 (Java agent)，在應用程式啟動時自動為其進行 instrument。雖然設定 Java 代理程式的方式有很多種，但以下步驟將採用環境變數來完成。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;請從 &lt;code&gt;opentelemetry-java-instrumentation&lt;/code&gt; 儲存庫 (repository) 的 Releases 頁面下載 &lt;code&gt;opentelemetry-javaagent.jar&lt;/code&gt;。這個 JAR 檔案包含了代理程式 (agent) 以及所有 automatic instrumentation 所需的套件：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;curl -L -O https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;請設定並匯出用於指定 Java 代理程式（Java agent）JAR 檔與主控台匯出器（console exporter）的環境變數。請使用適合您 shell／終端機環境的語法——我們將示範適用於 bash 系列 shell 的語法：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;export JAVA_TOOL_OPTIONS=&amp;#34;-javaagent:$(pwd)/opentelemetry-javaagent.jar&amp;#34; \
OTEL_TRACES_EXPORTER=logging \
OTEL_METRICS_EXPORTER=logging \
OTEL_LOGS_EXPORTER=logging \
OTEL_METRIC_EXPORT_INTERVAL=15000&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;重要&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;請注意上述範例中的 &lt;code&gt;$(pwd)/opentelemetry-javaagent.jar&lt;/code&gt; 替換為您存放 JAR 檔的&lt;strong&gt;實際路徑&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;只有在&lt;strong&gt;測試時&lt;/strong&gt;，才將 &lt;code&gt;OTEL_METRIC_EXPORT_INTERVAL&lt;/code&gt; 的值設定得遠低於預設值（如上所示），這能幫助您更快地確認指標（metrics）是否已正確產生。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;再次執行您的應用程式&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;java -jar ./build/libs/java-simple.jar&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;從另一個終端，使用 &lt;code&gt;curl&lt;/code&gt; 發送請求&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;curl http://localhost:8080/rolldice; echo&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;按 &lt;code&gt;Ctrl + c&lt;/code&gt; 停止網站應用程序&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在&lt;strong&gt;步驟 4&lt;/strong&gt;，您應該會看到來自伺服器和用戶端的追蹤 (trace) 與日誌 (log) 輸出，內容大致如下 (為方便閱讀，追蹤輸出內容已自動換行)：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;2025-09-17T07:47:41.594Z INFO &amp;#39;Anonymous player is rolling the dice: 6&amp;#39; : 0a4494bc657323e1cfc1bd2ca0f1fb9b 01edf287800f72ee [scopeInfo: otel.RollController:] {}
2025-09-17T15:47:41.594&amp;#43;08:00 INFO 22570 --- [io-8080-exec-10] otel.RollController : Anonymous player is rolling the dice: 6
[otel.javaagent 2025-09-17 15:47:41:595 &amp;#43;0800] [http-nio-8080-exec-10] INFO io.opentelemetry.exporter.logging.LoggingSpanExporter - &amp;#39;GET /rolldice&amp;#39; : 0a4494bc657323e1cfc1bd2ca0f1fb9b 01edf287800f72ee SERVER [tracer: io.opentelemetry.tomcat-10.0:2.20.0-alpha] AttributesMap{data={http.route=/rolldice, http.request.method=GET, url.path=/rolldice, server.address=localhost, client.address=0:0:0:0:0:0:0:1, network.peer.address=0:0:0:0:0:0:0:1, network.peer.port=58634, network.protocol.version=1.1, thread.id=33, http.response.status_code=200, user_agent.original=curl/7.76.1, server.port=8080, url.scheme=http, thread.name=http-nio-8080-exec-10}, capacity=128, totalAddedValues=14}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在&lt;strong&gt;步驟 5&lt;/strong&gt;，當停止伺服器時，您應該會看到所有已收集指標 (metrics) 的輸出 (為方便閱讀，指標輸出內容已自動換行並經過簡化)：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;[otel.javaagent 2025-09-17 17:03:02:686 &amp;#43;0800] [Thread-0] INFO io.opentelemetry.exporter.logging.LoggingMetricExporter - Received a collection of 2 metrics for export.
[otel.javaagent 2025-09-17 17:03:02:686 &amp;#43;0800] [Thread-0] INFO io.opentelemetry.exporter.logging.LoggingMetricExporter - metric: ImmutableMetricData{resource=Resource{schemaUrl=https://opentelemetry.io/schemas/1.24.0, attributes={container.id=&amp;#34;1c59603168a7210a0d1f7edadc57129fcd3788da67ddbb0dad0ffd99def32bd2&amp;#34;, host.arch=&amp;#34;amd64&amp;#34;, host.name=&amp;#34;bastion.topgun.kubeantony.com&amp;#34;, os.description=&amp;#34;Linux 5.14.0-570.44.1.el9_6.x86_64&amp;#34;, os.type=&amp;#34;linux&amp;#34;, process.command_args=[/usr/lib/jvm/java-17-openjdk-17.0.16.0.8-2.el9.x86_64/bin/java, -jar, ./build/libs/java-simple.jar], process.executable.path=&amp;#34;/usr/lib/jvm/java-17-openjdk-17.0.16.0.8-2.el9.x86_64/bin/java&amp;#34;, process.pid=23849, process.runtime.description=&amp;#34;Red Hat, Inc. OpenJDK 64-Bit Server VM 17.0.16&amp;#43;8-LTS&amp;#34;, process.runtime.name=&amp;#34;OpenJDK Runtime Environment&amp;#34;, process.runtime.version=&amp;#34;17.0.16&amp;#43;8-LTS&amp;#34;, service.instance.id=&amp;#34;12b46158-6949-48ee-b8b6-54aff876afaa&amp;#34;, service.name=&amp;#34;java-simple&amp;#34;, telemetry.distro.name=&amp;#34;opentelemetry-java-instrumentation&amp;#34;, telemetry.distro.version=&amp;#34;2.20.0&amp;#34;, telemetry.sdk.language=&amp;#34;java&amp;#34;, telemetry.sdk.name=&amp;#34;opentelemetry&amp;#34;, telemetry.sdk.version=&amp;#34;1.54.0&amp;#34;}}, instrumentationScopeInfo=InstrumentationScopeInfo{name=io.opentelemetry.runtime-telemetry-java8, version=2.20.0-alpha, schemaUrl=null, attributes={}}, name=jvm.gc.duration, description=Duration of JVM garbage collection actions., unit=s, type=HISTOGRAM, data=ImmutableHistogramData{aggregationTemporality=CUMULATIVE, points=[ImmutableHistogramPointData{getStartEpochNanos=1758099741657518036, getEpochNanos=1758099782686024415, getAttributes={jvm.gc.action=&amp;#34;end of minor GC&amp;#34;, jvm.gc.name=&amp;#34;G1 Young Generation&amp;#34;}, getSum=0.041, getCount=9, hasMin=true, getMin=0.002, hasMax=true, getMax=0.008, getBoundaries=[0.01, 0.1, 1.0, 10.0], getCounts=[9, 0, 0, 0, 0], getExemplars=[]}]}}
[otel.javaagent 2025-09-17 17:03:02:686 &amp;#43;0800] [Thread-0] INFO io.opentelemetry.exporter.logging.LoggingMetricExporter - metric: ImmutableMetricData{resource=Resource{schemaUrl=https://opentelemetry.io/schemas/1.24.0, attributes={container.id=&amp;#34;1c59603168a7210a0d1f7edadc57129fcd3788da67ddbb0dad0ffd99def32bd2&amp;#34;, host.arch=&amp;#34;amd64&amp;#34;, host.name=&amp;#34;bastion.topgun.kubeantony.com&amp;#34;, os.description=&amp;#34;Linux 5.14.0-570.44.1.el9_6.x86_64&amp;#34;, os.type=&amp;#34;linux&amp;#34;, process.command_args=[/usr/lib/jvm/java-17-openjdk-17.0.16.0.8-2.el9.x86_64/bin/java, -jar, ./build/libs/java-simple.jar], process.executable.path=&amp;#34;/usr/lib/jvm/java-17-openjdk-17.0.16.0.8-2.el9.x86_64/bin/java&amp;#34;, process.pid=23849, process.runtime.description=&amp;#34;Red Hat, Inc. OpenJDK 64-Bit Server VM 17.0.16&amp;#43;8-LTS&amp;#34;, process.runtime.name=&amp;#34;OpenJDK Runtime Environment&amp;#34;, process.runtime.version=&amp;#34;17.0.16&amp;#43;8-LTS&amp;#34;, service.instance.id=&amp;#34;12b46158-6949-48ee-b8b6-54aff876afaa&amp;#34;, service.name=&amp;#34;java-simple&amp;#34;, telemetry.distro.name=&amp;#34;opentelemetry-java-instrumentation&amp;#34;, telemetry.distro.version=&amp;#34;2.20.0&amp;#34;, telemetry.sdk.language=&amp;#34;java&amp;#34;, telemetry.sdk.name=&amp;#34;opentelemetry&amp;#34;, telemetry.sdk.version=&amp;#34;1.54.0&amp;#34;}}, instrumentationScopeInfo=InstrumentationScopeInfo{name=io.opentelemetry.tomcat-10.0, version=2.20.0-alpha, schemaUrl=null, attributes={}}, name=http.server.request.duration, description=Duration of HTTP server requests., unit=s, type=HISTOGRAM, data=ImmutableHistogramData{aggregationTemporality=CUMULATIVE, points=[ImmutableHistogramPointData{getStartEpochNanos=1758099741657518036, getEpochNanos=1758099782686024415, getAttributes=FilteredAttributes{http.request.method=GET,http.response.status_code=200,http.route=/rolldice,network.protocol.version=1.1,url.scheme=http}, getSum=0.08728259, getCount=1, hasMin=true, getMin=0.08728259, hasMax=true, getMax=0.08728259, getBoundaries=[0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1.0, 2.5, 5.0, 7.5, 10.0], getCounts=[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], getExemplars=[]}]}}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;將步驟 1-2 融入 Dockerfile&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;nano Dockerfile-v3-opentelemetry-instrumentation&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檔案內容如下：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;registry.suse.com/bci/bci-base:15.7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;useradder&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ARG user&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; RUN groupadd &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; useradd -m -d /home/&lt;span class="nv"&gt;$user&lt;/span&gt; -g &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;docker.io/library/gradle:8.14.3-jdk17-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ARG user&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /etc/passwd /etc/passwd&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /etc/group /etc/group&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /etc/shadow /etc/shadow&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /home/&lt;span class="nv"&gt;$user&lt;/span&gt; /home/&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY build.gradle.kts DiceApplication.java RollController.java /java-simple&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; WORKDIR /java-simple&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; RUN chown -R &lt;span class="nv"&gt;$user&lt;/span&gt;:&lt;span class="nv"&gt;$user&lt;/span&gt; /java-simple &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; gradle assemble&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; USER &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;registry.suse.com/bci/openjdk:17&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ARG user&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /etc/passwd /etc/passwd&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /etc/group /etc/group&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /etc/shadow /etc/shadow&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;useradder /home/&lt;span class="nv"&gt;$user&lt;/span&gt; /home/&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; RUN install -g &lt;span class="nv"&gt;$user&lt;/span&gt; -o &lt;span class="nv"&gt;$user&lt;/span&gt; -d /app&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; WORKDIR /app&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; COPY --from&lt;span class="o"&gt;=&lt;/span&gt;build --chown&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;:&lt;span class="nv"&gt;$user&lt;/span&gt; /java-simple/build/libs/java-simple.jar /app/java-simple.jar&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; USER &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; RUN curl -L -O https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ENV &lt;span class="nv"&gt;JAVA_TOOL_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;-javaagent:/app/opentelemetry-javaagent.jar&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;OTEL_TRACES_EXPORTER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;logging &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;OTEL_METRICS_EXPORTER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;logging &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;OTEL_LOGS_EXPORTER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;logging &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;OTEL_METRIC_EXPORT_INTERVAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;15000&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; EXPOSE &lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ENTRYPOINT &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;java&amp;#34;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;#34;-jar&amp;#34;&lt;/span&gt;, &lt;span class="s2"&gt;&amp;#34;/app/java-simple.jar&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;製作 image&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;podman build --no-cache \
--squash-all \
--build-arg user=bigred \
-t java-simple:v3-opentelemetry-instrumentation \
-f Dockerfile-v3-opentelemetry-instrumentation&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run java app container 測試是否符合預期&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;podman run -d \
--name java-simple \
-p 9999:8080 \
localhost/java-simple:v3-opentelemetry-instrumentation&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;檢視 app container 運作狀態&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;podman ps -a --filter name=java-simple&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;正確執行結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
01805e4e24f3 localhost/java-simple:v3-opentelemetry-instrumentation 4 minutes ago Up 4 minutes 0.0.0.0:9999-&amp;gt;8080/tcp java-simple&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;透過網路存取 &lt;code&gt;http://192.168.11.21:9999/rolldice&lt;/code&gt;，以確保它能正常運作&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;curl http://192.168.11.21:9999/rolldice; echo&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;6&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;檢視 log 是否擁有 trace 資訊&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;podman logs java-simple&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;2025-09-18T02:04:52.34Z INFO &amp;#39;Anonymous player is rolling the dice: 3&amp;#39; : 4dd621a6aa359c6caa6cb710fa10963a d192f1ee1b7afd06 [scopeInfo: otel.RollController:] {}
2025-09-18T02:04:52.340Z INFO 1 --- [nio-8080-exec-4] otel.RollController : Anonymous player is rolling the dice: 3
[otel.javaagent 2025-09-18 02:04:52:341 &amp;#43;0000] [http-nio-8080-exec-4] INFO io.opentelemetry.exporter.logging.LoggingSpanExporter - &amp;#39;GET /rolldice&amp;#39; : 4dd621a6aa359c6caa6cb710fa10963a d192f1ee1b7afd06 SERVER [tracer: io.opentelemetry.tomcat-10.0:2.20.0-alpha] AttributesMap{data={server.address=192.168.11.21, client.address=169.254.1.2, network.peer.address=169.254.1.2, url.path=/rolldice, http.request.method=GET, network.peer.port=60368, http.route=/rolldice, url.scheme=http, thread.name=http-nio-8080-exec-4, user_agent.original=curl/7.76.1, http.response.status_code=200, thread.id=27, server.port=9999, network.protocol.version=1.1}, capacity=128, totalAddedValues=14}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;移除 java app container&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;podman rm -f java-simple&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Certified GitOps Associate (CGOA) B 卷</title><link>https://blog.kubeantony.com/archive/ops-automation/certified-gitops-associate-cgoa-b-%E5%8D%B7/</link><pubDate>Mon, 25 Aug 2025 14:39:30 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/certified-gitops-associate-cgoa-b-%E5%8D%B7/</guid><description>
&lt;h2&gt;Q1&lt;span class="hx:absolute hx:-mt-20" id="q1"&gt;&lt;/span&gt;
&lt;a href="#q1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;As a Certitled GitOps Associate, what should you focus on besides the delivery/deployment of configurations to your system?&lt;/p&gt;
&lt;p&gt;A. Interoperability with tools that provide Notifications, Observability, and Continuous Integration.
B. Interoperability with tools that provide only Continuous Integration.
C. Interoperability with tools that provide only Observabilty.
D. Only the delivery/deployment of configurations to your system.&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q2&lt;span class="hx:absolute hx:-mt-20" id="q2"&gt;&lt;/span&gt;
&lt;a href="#q2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;In a GitOps setup, how do event driven systems respond to changes compared to pull based systems?&lt;/p&gt;
&lt;p&gt;A. Event-driven systems initiate updates only during scheduled maintenance, while pull based systems update as soon as changes are detected.
B. Even&amp;rsquo;t dhan systerms update imenediately in response to changes, while pull based systems routinely check for and apply for updates.
C. Pull-based systems are designed for rapid, imediate updates, contrasting with the gradual updates of event driven systems.
D. In event driven systems, updates are manually triggered, whereas pull based systems automate the update process.&lt;/p&gt;
&lt;p&gt;B&lt;/p&gt;</description></item><item><title>Prometheus certified associate</title><link>https://blog.kubeantony.com/archive/ops-automation/prometheus-certified-associate/</link><pubDate>Mon, 11 Aug 2025 13:10:14 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/prometheus-certified-associate/</guid><description>
&lt;h2&gt;Q1&lt;span class="hx:absolute hx:-mt-20" id="q1"&gt;&lt;/span&gt;
&lt;a href="#q1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;How does Prometheus collect metrics?&lt;/p&gt;
&lt;p&gt;A. Applications send metrics to Prometheus vis UDP.
B. Applications send metrics to Prometheus via GRPC.
C. Prometheus scrapes metrics from instrumented application&amp;rsquo;s HTTP Server
D. Prometheus scrapes metrics from instrumented application&amp;rsquo;s UDP Server&lt;/p&gt;
&lt;p&gt;C&lt;/p&gt;
&lt;h2&gt;Q2&lt;span class="hx:absolute hx:-mt-20" id="q2"&gt;&lt;/span&gt;
&lt;a href="#q2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;If you offer a free service, which of the following do you want?&lt;/p&gt;
&lt;p&gt;A. SLO&amp;rsquo;s and SLI&amp;rsquo;s.
B. SLI&amp;rsquo;s, SLO&amp;rsquo;s and SLAs
C. SLAS.
D. SLIS.&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q3&lt;span class="hx:absolute hx:-mt-20" id="q3"&gt;&lt;/span&gt;
&lt;a href="#q3" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;What are the changes in numerical data recorded over time called?&lt;/p&gt;
&lt;p&gt;A. time series
B. data dashboard
C. metrics
D. time table&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q4&lt;span class="hx:absolute hx:-mt-20" id="q4"&gt;&lt;/span&gt;
&lt;a href="#q4" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;What is a trace?&lt;/p&gt;
&lt;p&gt;A. Trace is a set of events triggered by a singie logical operation, consolord so s
B. Trace is a simple mechanism for propagating name/value pairs.
C. Trace is a numerical measurement about a service, captured at runtime
D. Trace is a timestamped text record, either structured (recommended) or unst&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q5&lt;span class="hx:absolute hx:-mt-20" id="q5"&gt;&lt;/span&gt;
&lt;a href="#q5" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;With a SLO of 99.9%, what is the error budget?
A. 0.1%
B. Insufficient data to tell.
C. 99.9%
D. 100%.&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q6&lt;span class="hx:absolute hx:-mt-20" id="q6"&gt;&lt;/span&gt;
&lt;a href="#q6" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;How many metrics types does Prometheus text format support&lt;/p&gt;
&lt;p&gt;A. 40
B. 4
C. 8
D. 10&lt;/p&gt;
&lt;p&gt;B&lt;/p&gt;
&lt;h2&gt;Q7&lt;span class="hx:absolute hx:-mt-20" id="q7"&gt;&lt;/span&gt;
&lt;a href="#q7" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Which one of the following item should not belong to a metrics?&lt;/p&gt;
&lt;p&gt;A. environment
D. username
C. server name
D. response code&lt;/p&gt;
&lt;p&gt;B&lt;/p&gt;
&lt;h2&gt;Q8&lt;span class="hx:absolute hx:-mt-20" id="q8"&gt;&lt;/span&gt;
&lt;a href="#q8" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Why can&amp;rsquo;t you send logs to Prometheus?&lt;/p&gt;
&lt;p&gt;A. Default Prometheus installations will store deta only for a few weeks.
B. PromQL language is inefficient for parsing log files.
C. It is best practice to avoid mixing logs and metries wihin a Prometheus instance.
D. Prometheus handles metrics but logs are text-based events.&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;h2&gt;Q9&lt;span class="hx:absolute hx:-mt-20" id="q9"&gt;&lt;/span&gt;
&lt;a href="#q9" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Which of the following Kubernetes SD configurations &amp;ldquo;key allow rerieing scarape targets from Kubernetes REST API?&lt;/p&gt;
&lt;p&gt;A. &lt;code&gt;&amp;lt;kubernetes_scrape_config&amp;gt;&lt;/code&gt;
B. &lt;code&gt;&amp;lt;kube-apiserver_sd_config&amp;gt;&lt;/code&gt;
C. &lt;code&gt;&amp;lt;kube-piserver_scrape_config&amp;gt;&lt;/code&gt;
D. &lt;code&gt;&amp;lt;kubernetes_sd_config&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;h2&gt;Q10&lt;span class="hx:absolute hx:-mt-20" id="q10"&gt;&lt;/span&gt;
&lt;a href="#q10" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Your publicly available web server receives 1000 requests per hour with a 1-3% average error tes sos the tando wit aut?&lt;/p&gt;
&lt;p&gt;A. Rate of requests, errors, and request times
B. Stack traces of successful requests
C. Detailed web server logs for failed requests
D. Stack traces of error requests&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q11&lt;span class="hx:absolute hx:-mt-20" id="q11"&gt;&lt;/span&gt;
&lt;a href="#q11" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Which of the following metric is unsuitable for a Promethes setup?&lt;/p&gt;
&lt;p&gt;A. &lt;code&gt;prometheus_engine_query_log_enabled&lt;/code&gt;
B. &lt;code&gt;user_last_login_tinestamp_seconds{email=&amp;quot;john.doe@example.com&amp;quot;}&lt;/code&gt;
C. &lt;code&gt;http_response_total{handler=&amp;quot;/static/*filepath&amp;quot;}&lt;/code&gt;
D. &lt;code&gt;promhttp_metric_handler_requests_total{code=&amp;quot;580&amp;quot;}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;B&lt;/p&gt;
&lt;h2&gt;Q12&lt;span class="hx:absolute hx:-mt-20" id="q12"&gt;&lt;/span&gt;
&lt;a href="#q12" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;What is &lt;code&gt;api_http_requests_total&lt;/code&gt; in the following metric?
&lt;code&gt;api_http_requests_total{method=&amp;quot;POST&amp;quot;, handler=&amp;quot;/messages&amp;quot;}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;A. &amp;ldquo;api_http_requests_total&amp;rdquo; is a metric type.
B. &amp;ldquo;api_http_requests_total&amp;rdquo; is a metric name.
C. &amp;ldquo;api_http_requests_total&amp;rdquo; is a metric field.
D. &amp;ldquo;api_http_requests_total&amp;rdquo; is a metric label name.&lt;/p&gt;
&lt;p&gt;B&lt;/p&gt;
&lt;h2&gt;Q13&lt;span class="hx:absolute hx:-mt-20" id="q13"&gt;&lt;/span&gt;
&lt;a href="#q13" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;You&amp;rsquo;d like to monitor a short lived batch job. What Prometheus component wold you want?&lt;/p&gt;
&lt;p&gt;A. PullGateway
B. PushGateway
C. PullProxy
D. PushProxy&lt;/p&gt;
&lt;p&gt;B&lt;/p&gt;
&lt;h2&gt;Q14&lt;span class="hx:absolute hx:-mt-20" id="q14"&gt;&lt;/span&gt;
&lt;a href="#q14" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;What Prometheus component would you use if targets are runnning beind Firewal NAT?&lt;/p&gt;
&lt;p&gt;A. Pull Gateway
B. Pull Proxy
C. HA Proxy
D. PushProx&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;h2&gt;Q15&lt;span class="hx:absolute hx:-mt-20" id="q15"&gt;&lt;/span&gt;
&lt;a href="#q15" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;What&amp;rsquo;s &amp;ldquo;wrong&amp;rdquo; with the &lt;code&gt;myapp_file_uploads_total{userid=&amp;quot;5123&amp;quot;, status=&amp;quot;failed&amp;quot;}&lt;/code&gt; metrics?
A. The &lt;code&gt;_total&lt;/code&gt; suffic should be omitted
B. The &lt;code&gt;userid&lt;/code&gt; should not be exposed as a label.
C. The status should not be exposed as a label.
D. The metric name should consist of dashes instead of underscores&lt;/p&gt;
&lt;p&gt;B&lt;/p&gt;
&lt;h2&gt;Q16&lt;span class="hx:absolute hx:-mt-20" id="q16"&gt;&lt;/span&gt;
&lt;a href="#q16" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;How can you send metrics from your Prometheus setup to a remote system, e.g. for long term storage?&lt;/p&gt;
&lt;p&gt;A. With S3 Buckets
B. With &amp;ldquo;scraping&amp;rdquo;
C. With &amp;ldquo;remote write&amp;rdquo;
D. With &amp;ldquo;federation&amp;rdquo;&lt;/p&gt;
&lt;p&gt;C&lt;/p&gt;
&lt;h2&gt;Q17&lt;span class="hx:absolute hx:-mt-20" id="q17"&gt;&lt;/span&gt;
&lt;a href="#q17" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;What is a difference between a counter and a gauge?&lt;/p&gt;
&lt;p&gt;A. Counters change value on each scrape and a gauges remain static.
B. Counters are only incremented, while gauge can go up and down.
C. Counters have no labels while gauges can have many labels.
D. Counters and gauges are different names for the same thing.&lt;/p&gt;
&lt;p&gt;B&lt;/p&gt;
&lt;h2&gt;Q18&lt;span class="hx:absolute hx:-mt-20" id="q18"&gt;&lt;/span&gt;
&lt;a href="#q18" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Which of the following is a valid metric name?&lt;/p&gt;
&lt;p&gt;A. go_goroutines
B. 99_goroutines
C. go routines
D. go.goroutines&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q19&lt;span class="hx:absolute hx:-mt-20" id="q19"&gt;&lt;/span&gt;
&lt;a href="#q19" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Which exporter would be best suited for basic HITP probing?&lt;/p&gt;
&lt;p&gt;A. SNMP exporter
B. Apache exporter
C. Blackbox exporter
D. JMX exporter&lt;/p&gt;
&lt;p&gt;C&lt;/p&gt;
&lt;h2&gt;Q20&lt;span class="hx:absolute hx:-mt-20" id="q20"&gt;&lt;/span&gt;
&lt;a href="#q20" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;What does scrape_interval configure in Prometheus?&lt;/p&gt;
&lt;p&gt;A. It defines how frequently to scrape targets.
B. It defines how often to send alerts.
C. It defines how frequently to evaluate rules.
D. It defines how often to refresh metrics.&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q21&lt;span class="hx:absolute hx:-mt-20" id="q21"&gt;&lt;/span&gt;
&lt;a href="#q21" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;What is an example of a single-target exporter?&lt;/p&gt;
&lt;p&gt;A. Blackbox Exporter
B. SNMP Exporter
C. Redis Exporter
D. Node Exporter&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;h2&gt;Q22&lt;span class="hx:absolute hx:-mt-20" id="q22"&gt;&lt;/span&gt;
&lt;a href="#q22" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;How do you configure the rule evaluation interval in Prometheus?&lt;/p&gt;
&lt;p&gt;A. You can configure the evaluation interval in the Prometheus TSDB configuration file and in the rule configuration file.
B. You can configure the evaluation interval in the globel configuration file and in the rule configuration file.
C. You can configure the evaluation intenval in the service discovery configurtion and in the command-line flags.
D. You can configure the evaluation interval in the scraping job configuration file and in the command-line flags.&lt;/p&gt;
&lt;p&gt;B&lt;/p&gt;
&lt;h2&gt;Q23&lt;span class="hx:absolute hx:-mt-20" id="q23"&gt;&lt;/span&gt;
&lt;a href="#q23" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Which kind of metrics are associated with the function &lt;code&gt;deriv&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;A. Summaries
B. Counters
C. Histograms
D. Gauges&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here is why:
&lt;code&gt;deriv&lt;/code&gt; should only be used with gauges and only works for float samples.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;參考文件：https://prometheus.io/docs/prometheus/latest/querying/functions/#deriv:~:text=deriv%20should%20only%20be%20used%20with%20gauges%20and%20only%20works%20for%20float%20samples.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Q24&lt;span class="hx:absolute hx:-mt-20" id="q24"&gt;&lt;/span&gt;
&lt;a href="#q24" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Given the metric &lt;code&gt;prometheus_tsdb_lowest_timestamp_secoods&lt;/code&gt;, how do you know in which month belongs the&lt;/p&gt;
&lt;p&gt;A. &lt;code&gt;format_date(prometheus_tsdb_lowest_timestamp_seconds, &amp;quot;5m&amp;quot;)&lt;/code&gt;
B. &lt;code&gt;(time() - prometheus_tsdb_lowest_timestamp_secceds) / 86400&lt;/code&gt;
C. &lt;code&gt;prometheus_tsdb_lowest_tinestamp_seconds % month&lt;/code&gt;
D. &lt;code&gt;month(prometheus_tsdb_lowest_timestamp_seconds)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;h2&gt;Q25&lt;span class="hx:absolute hx:-mt-20" id="q25"&gt;&lt;/span&gt;
&lt;a href="#q25" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Which PromQL expression computes how many requests in total are currently in-flight for time series ?&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;apiserver_current_inflight_requests{instance=&amp;#34;1&amp;#34;} 5
apiserver_current_inflight_requests{instances=&amp;#34;2&amp;#34;} 7&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A. &lt;code&gt;sum(apiserver_current_inflight_requests)&lt;/code&gt;
B. &lt;code&gt;max(apiserver_current_inflight_requests)&lt;/code&gt;
C. &lt;code&gt;sum_over_time(apiserver_current_inflight_requests, reperts[10m])&lt;/code&gt;
D. &lt;code&gt;min(apiserver_current_inflight_requests)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q26&lt;span class="hx:absolute hx:-mt-20" id="q26"&gt;&lt;/span&gt;
&lt;a href="#q26" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;How do you calculate the average request duration during the last 5 minutes from a histograms on summany called http_request_duration_seconds ?&lt;/p&gt;
&lt;p&gt;A. &lt;code&gt;rate(http_request_duration_seconds_total[5m]) / rate(http_request_duration_seconds_average[5m])&lt;/code&gt;
B. &lt;code&gt;rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_average&lt;/code&gt;
C. &lt;code&gt;rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m])&lt;/code&gt;
D. &lt;code&gt;rate(http_request_duration_seconds_total[5m)) / rate(http_request_duration_seconds_count[5m]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;C&lt;/p&gt;
&lt;h2&gt;Q27&lt;span class="hx:absolute hx:-mt-20" id="q27"&gt;&lt;/span&gt;
&lt;a href="#q27" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Which PromQL statement returns the average free bytes of the fliesystems over the last hour?&lt;/p&gt;
&lt;p&gt;A. avg_over_time(node_filesystem_avail_bytes[1h])
B. sum_over_time(node_filesystem_avail_bytes[1h])
C. sum(node_filesystem_avail_bytes[1h])
D. avg(node_filesystem_avail_bytes[1h])&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q28&lt;span class="hx:absolute hx:-mt-20" id="q28"&gt;&lt;/span&gt;
&lt;a href="#q28" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;How can you use the &lt;code&gt;delta&lt;/code&gt; PromQL function?&lt;/p&gt;
&lt;p&gt;A. On counter metrics to compute the difference between the first and last value of each time series element.
B. On counter metrics to compute the number of metric resets within the provided time range.
C. On gauge metrics to compute the number of metric resets within the provided time range.
D. On gauge metrics to compute the difference between the first and last value of each time series element.&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;h2&gt;Q29&lt;span class="hx:absolute hx:-mt-20" id="q29"&gt;&lt;/span&gt;
&lt;a href="#q29" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Which of the following PromQL query is invalid?&lt;/p&gt;
&lt;p&gt;A. max without (instance, job) up
B. max without (instance) up
C. max by (instance) up
D. max on (instance) (up)&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;h2&gt;Q30&lt;span class="hx:absolute hx:-mt-20" id="q30"&gt;&lt;/span&gt;
&lt;a href="#q30" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Given the following Histogram metric data, how many requests took less than or equal to 0.1 seconds?'&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;apiserver_request_duration_seconds_bucket(job=&amp;#34;kube-apiserver&amp;#34;,le=&amp;#34;&amp;#43;Inf&amp;#34;) 3
apiserver_request_duration_seconds_bucket(job=&amp;#34;kube-apiserver&amp;#34;,le=&amp;#34;0.05&amp;#34;) 0
apiserver_request_duration_seconds_bucket(job=&amp;#34;kube-apiserver&amp;#34;,le=&amp;#34;0.1&amp;#34;) 1
apiserver_request_duration_seconds_bucket(job=&amp;#34;kube-apiserver&amp;#34;,le=&amp;#34;1&amp;#34;) 3
apiserver_request_duration_seconds_count(job=&amp;#34;kube-apiserver&amp;#34;) 3
apiserver_request_duration_seconds_sum(jbb=&amp;#34;kube-apiserver&amp;#34;) 0.554003785&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A. 0.554003785
B. 3
C. 0
D. 1&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;h2&gt;Q31&lt;span class="hx:absolute hx:-mt-20" id="q31"&gt;&lt;/span&gt;
&lt;a href="#q31" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;What function calculates the φ-quantile from a histoggam?&lt;/p&gt;
&lt;p&gt;A. predict_linear()
B. avg_over_time()
C. histogram()
D. histogram_quantile()&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;h2&gt;Q32&lt;span class="hx:absolute hx:-mt-20" id="q32"&gt;&lt;/span&gt;
&lt;a href="#q32" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;How can you select all the &lt;code&gt;up&lt;/code&gt; metrics whose &lt;code&gt;instance&lt;/code&gt; label match the regex &lt;code&gt;fe-.*&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;A. &lt;code&gt;up{instance=regexp(fe-.*)}&lt;/code&gt;
B. &lt;code&gt;up{instance=&amp;quot;fe-.*&amp;quot;}&lt;/code&gt;
C. &lt;code&gt;up{instance~&amp;quot;fe-.*&amp;quot;}&lt;/code&gt;
D. &lt;code&gt;up{instance=~&amp;quot;fe-.*&amp;quot;}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;h2&gt;Q33&lt;span class="hx:absolute hx:-mt-20" id="q33"&gt;&lt;/span&gt;
&lt;a href="#q33" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Which PromQL expression computes the rate of API Server requests across the different cloud providers from the following metrics?&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;apiserver_request_total{job=&amp;#34;kube-apiserver&amp;#34;, instance=&amp;#34;192.168.1.228:6443, cloud=&amp;#34;aws&amp;#34;} 1
apiserver_request_total{job=&amp;#34;kube-apiserver&amp;#34;, instance=&amp;#34;192.168.1.121:6443, clmud=&amp;#34;gcloud&amp;#34; 5&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;A. rate(sum by (cloud)(apiserver_request_total{job=&amp;ldquo;kube- apisever&amp;rdquo;})(5m))
B. sum by (cloud)(rate(apiserver_request_total{job=&amp;ldquo;kube-apisrver&amp;rdquo;}[5m]))
C. sum by (cloud) (apiserver_request_total{job=&amp;ldquo;kube-apiserver})
D. rate(apiserver_request_total{job=&amp;ldquo;kube-apiserver&amp;rdquo;[5m]) by (cloud)&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;h2&gt;Q34&lt;span class="hx:absolute hx:-mt-20" id="q34"&gt;&lt;/span&gt;
&lt;a href="#q34" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;which expression calculates the average uptime of targets over the last hour?&lt;/p&gt;
&lt;p&gt;A. avg(up[1h])
B. average_over_time(up[1h])
C. avg_over_time(up[1h])
D. avg(up-1h)&lt;/p&gt;
&lt;p&gt;C&lt;/p&gt;
&lt;h2&gt;Q35&lt;span class="hx:absolute hx:-mt-20" id="q35"&gt;&lt;/span&gt;
&lt;a href="#q35" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;which PromQL statement returns the sum of all values of the metric &lt;code&gt;node_memory_MemAvailable_bytes&lt;/code&gt; from 10 minutes ago?&lt;/p&gt;
&lt;p&gt;A. offset sum(node_memory_MemAvailable_bytes[10m])
B. sum(node_memory_MemAvailable_bytes) setoff 10m
C. sum(node_memory_MemAvailable_bytes) offset 10m
D. sum(node_memory_MemAvailable_bytes offset 10m)&lt;/p&gt;
&lt;p&gt;D&lt;/p&gt;
&lt;h2&gt;Q36&lt;span class="hx:absolute hx:-mt-20" id="q36"&gt;&lt;/span&gt;
&lt;a href="#q36" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Which metric type uses the delta() function?&lt;/p&gt;
&lt;p&gt;A. Info
B. Histogram
C. Gauge
D. Counter&lt;/p&gt;
&lt;p&gt;C&lt;/p&gt;
&lt;h2&gt;Q37&lt;span class="hx:absolute hx:-mt-20" id="q37"&gt;&lt;/span&gt;
&lt;a href="#q37" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;If the vector selector &lt;code&gt;foo[5m]&lt;/code&gt; contains &lt;code&gt;1 1 NaN 0&lt;/code&gt; , what would max_over_time(foo[5m])) return?&lt;/p&gt;
&lt;p&gt;A. &lt;code&gt;1&lt;/code&gt;
B. It errors out.
C. &lt;code&gt;NaN&lt;/code&gt;
D. No answer.&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q38&lt;span class="hx:absolute hx:-mt-20" id="q38"&gt;&lt;/span&gt;
&lt;a href="#q38" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Which of the following is an invalid @ modifier expression?&lt;/p&gt;
&lt;p&gt;A. &lt;code&gt;sum(http_requests_total{method=&amp;quot;GET&amp;quot;}) @ 1609746000&lt;/code&gt;
B. &lt;code&gt;go_goroutines @ end()&lt;/code&gt;
C. &lt;code&gt;sum(http_requests_total{method=&amp;quot;GET&amp;quot;} @ 1609746000)&lt;/code&gt;
D. &lt;code&gt;go_goroutines @ start()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;C&lt;/p&gt;
&lt;h2&gt;Q39&lt;span class="hx:absolute hx:-mt-20" id="q39"&gt;&lt;/span&gt;
&lt;a href="#q39" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;With the following metrics over the last 5 minutes:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;up{instance=&amp;#34;localhost&amp;#34;} 1 1 1 1 1
up{instance=&amp;#34;server1&amp;#34;} 1 0 0 0 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;What does the following query retum: &lt;code&gt;min_over_time(up[5m])&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;A. &lt;code&gt;up{instance=&amp;quot;localhost&amp;quot;} 1&lt;/code&gt;
&lt;code&gt;up{instance=&amp;quot;server1&amp;quot;} 0&lt;/code&gt;
B. &lt;code&gt;{instance=&amp;quot;localhost&amp;quot;} 1&lt;/code&gt;
&lt;code&gt;{instance=&amp;quot;server1&amp;quot;} 0&lt;/code&gt;
C. &lt;code&gt;up{instance=&amp;quot;server1&amp;quot;} 0&lt;/code&gt;
D. &lt;code&gt;{instance=&amp;quot;server1&amp;quot;} 0&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q40&lt;span class="hx:absolute hx:-mt-20" id="q40"&gt;&lt;/span&gt;
&lt;a href="#q40" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The following is a list of metrics exposed by an application.&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;http_requests_total{code=&amp;#34;508&amp;#34;} 10
http_requests_total{code=&amp;#34;200&amp;#34;} 20
http_requests_total{code=&amp;#34;408&amp;#34;} 30
http_requests_total{verb=&amp;#34;POST&amp;#34;} 30
http_requests_total{verb=&amp;#34;GET&amp;#34;} 30&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;What is the issue with the metric family?&lt;/p&gt;
&lt;p&gt;A. &lt;code&gt;verb&lt;/code&gt; label content should be normalized to lowercase.
B. Metric names are missing a prefix to indicate which application is exposing the query.
C. The value represents two different thigs accross the dimensions: code and verb.
D. Unit is missing in the &lt;code&gt;http_requests_total&lt;/code&gt; meticname.&lt;/p&gt;
&lt;p&gt;C&lt;/p&gt;
&lt;h2&gt;Q41&lt;span class="hx:absolute hx:-mt-20" id="q41"&gt;&lt;/span&gt;
&lt;a href="#q41" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;What is the difference between client libraries and exporters?&lt;/p&gt;
&lt;p&gt;A. Exporters expose metrics for scraping. Client libraries push metrics via Remote White.
B. Exporters run next to the services to monitor, and use client libraries internally.
C. Exporters are written in Go. Client libraries are written in many languages.
D. Exporters and client libraries mean the same thing.&lt;/p&gt;
&lt;p&gt;A&lt;/p&gt;
&lt;h2&gt;Q42&lt;span class="hx:absolute hx:-mt-20" id="q42"&gt;&lt;/span&gt;
&lt;a href="#q42" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;What should you do with counters that have labels?&lt;/p&gt;
&lt;p&gt;A. Instantiate them with their possible label values when creating them so they are expoved with a zero value.
B. Investigate if you can move their label value inside their metic name to limit the numbe of lebels.
C. Make sure every counters with labels has an extra counter, aggregated, without lebels.
D. Save their state between application runs so you can restore their last value on startup.&lt;/p&gt;</description></item><item><title>設定 Alertmanager 觸發告警時去執行 Bash Script</title><link>https://blog.kubeantony.com/archive/ops-automation/%E8%A8%AD%E5%AE%9A-alertmanager-%E8%A7%B8%E7%99%BC%E5%91%8A%E8%AD%A6%E6%99%82%E5%8E%BB%E5%9F%B7%E8%A1%8C-bash-script/</link><pubDate>Mon, 28 Jul 2025 05:49:08 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/%E8%A8%AD%E5%AE%9A-alertmanager-%E8%A7%B8%E7%99%BC%E5%91%8A%E8%AD%A6%E6%99%82%E5%8E%BB%E5%9F%B7%E8%A1%8C-bash-script/</guid><description>
&lt;h2&gt;1. 安裝 kube-prometheus-stack&lt;span class="hx:absolute hx:-mt-20" id="1-安裝-kube-prometheus-stack"&gt;&lt;/span&gt;
&lt;a href="#1-%e5%ae%89%e8%a3%9d-kube-prometheus-stack" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;安裝 kube‑prometheus stack 的核心元件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Prometheus Operator&lt;/li&gt;
&lt;li&gt;Highly available Prometheus&lt;/li&gt;
&lt;li&gt;Highly available Alertmanager&lt;/li&gt;
&lt;li&gt;Prometheus node-exporter&lt;/li&gt;
&lt;li&gt;Prometheus blackbox-exporter&lt;/li&gt;
&lt;li&gt;Prometheus Adapter for Kubernetes Metrics APIs&lt;/li&gt;
&lt;li&gt;kube-state-metrics&lt;/li&gt;
&lt;li&gt;Grafana&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;1.1. 先決條件&lt;span class="hx:absolute hx:-mt-20" id="11-先決條件"&gt;&lt;/span&gt;
&lt;a href="#11-%e5%85%88%e6%b1%ba%e6%a2%9d%e4%bb%b6" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; K8s 已安裝完畢&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; 已安裝好 StorageClass&lt;/li&gt;
&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; 已安裝好 IngressClass&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;1.2. 開始安裝&lt;span class="hx:absolute hx:-mt-20" id="12-開始安裝"&gt;&lt;/span&gt;
&lt;a href="#12-%e9%96%8b%e5%a7%8b%e5%ae%89%e8%a3%9d" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;安裝 helm&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;建立 K8s namespace&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;kubectl create ns monitoring-system&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;將 Prometheus 社群維護的 Helm 圖表倉庫加入本地 Helm 用戶端，以便拉取 Prometheus 相關的 Helm Chart&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;helm repo add prometheus-community https://prometheus-community.github.io/helm-charts &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更新本地緩存中所有已加入倉庫的圖表清單，確保可以取得最新版本的 Chart&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;helm repo update&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;建立並切換工作目錄&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;mkdir ~/monitoring-system; cd ~/monitoring-system&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;編輯 kube-prometheus-stack helm 安裝設定檔&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;nano values.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檔案內容如下 ：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;kubelet:
enabled: true
serviceMonitor:
cAdvisorMetricRelabelings: []
prometheus:
prometheusSpec:
storageSpec:
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: nfs-client
additionalScrapeConfigsSecret:
enabled: true
name: additional-scrape-configs
key: additional.yaml
service:
type: NodePort
ingress:
enabled: true
ingressClassName: &amp;#34;cilium&amp;#34;
alertmanager:
alertmanagerSpec:
storage:
volumeClaimTemplate:
spec:
storageClassName: nfs-client
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
alertmanagerConfigSelector:
matchLabels:
resource: prometheus
service:
type: NodePort
ingress:
enabled: true
ingressClassName: &amp;#34;cilium&amp;#34;
grafana:
persistence:
enabled: true
type: sts
storageClassName: &amp;#34;nfs-client&amp;#34;
accessModes:
- ReadWriteOnce
size: 20Gi
finalizers:
- kubernetes.io/pvc-protection
service:
type: NodePort
ingress:
enabled: true
ingressClassName: &amp;#34;cilium&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;主要會設定&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Deploying GKE Clusters with Terraform from scratch</title><link>https://blog.kubeantony.com/archive/ops-automation/deploying-gke-clusters-with-terraform-from-scratch/</link><pubDate>Fri, 06 Jun 2025 07:10:30 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/deploying-gke-clusters-with-terraform-from-scratch/</guid><description>
&lt;h2&gt;1. 先決條件&lt;span class="hx:absolute hx:-mt-20" id="1-先決條件"&gt;&lt;/span&gt;
&lt;a href="#1-%e5%85%88%e6%b1%ba%e6%a2%9d%e4%bb%b6" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;建立 Google Mail 帳號&lt;/li&gt;
&lt;li&gt;申請免費試用 Google Cloud Platform 資格 (注意，需要一張 VISA 或信用卡)
&lt;a
href="https://console.cloud.google.com/getting-started"target="_blank" rel="noopener"&gt;https://console.cloud.google.com/getting-started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;在 Google Cloud Platform 建立 &lt;code&gt;project&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;點選左上角 &amp;ldquo;My First Project&amp;rdquo; 專案的按鈕
&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/rypBkB1Qgg.png" alt="image" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;點選右上角 &amp;ldquo;新增專案&amp;rdquo; 按鈕
&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/B14w1HyQxe.png" alt="image" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;輸入 &lt;code&gt;testgke&lt;/code&gt;，點選 &amp;ldquo;建立&amp;rdquo; 按鈕
&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/HyX9JrJXlg.png" alt="image" loading="lazy" /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;確認在剛建立的 &lt;code&gt;gketest&lt;/code&gt; 專案後，點選左上角按鈕
&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/rJsNzryQgx.png" alt="image" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;點選 &lt;code&gt;Kubernetes Engine&lt;/code&gt; 按鈕
&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/SJf2zSyQxe.png" alt="image" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;點選 &amp;ldquo;啟用&amp;rdquo; 按鈕，啟用 Kubernetes Engine API
&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/HybHmBk7gl.png" alt="image" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;點選右上角 &amp;ldquo;Cloud Shell&amp;rdquo; 按鈕，並授權 Cloud Shell
&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/HJNWNrJ7gx.png" alt="image" loading="lazy" /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;2. 開始部署&lt;span class="hx:absolute hx:-mt-20" id="2-開始部署"&gt;&lt;/span&gt;
&lt;a href="#2-%e9%96%8b%e5%a7%8b%e9%83%a8%e7%bd%b2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ mkdir gcp-terraform; cd gcp-terraform
$ nano gke.tf
resource &amp;#34;google_container_cluster&amp;#34; &amp;#34;gke_cluster&amp;#34; {
name = &amp;#34;k1&amp;#34;
location = &amp;#34;asia-east1-b&amp;#34;
initial_node_count = 1
network = google_compute_network.vpc.name
subnetwork = google_compute_subnetwork.subnet.name
networking_mode = &amp;#34;VPC_NATIVE&amp;#34;
logging_service = &amp;#34;none&amp;#34;
monitoring_service = &amp;#34;none&amp;#34;
private_cluster_config {
enable_private_endpoint = false
enable_private_nodes = true
master_ipv4_cidr_block = &amp;#34;10.13.0.0/28&amp;#34;
}
ip_allocation_policy {
cluster_ipv4_cidr_block = &amp;#34;10.98.0.0/16&amp;#34;
services_ipv4_cidr_block = &amp;#34;10.244.0.0/16&amp;#34;
}
node_config {
machine_type = &amp;#34;e2-custom-4-12288&amp;#34;
}
}
output &amp;#34;cluster_endpoint&amp;#34; {
value = google_container_cluster.gke_cluster.endpoint
}
output &amp;#34;cluster_ca_certificate&amp;#34; {
value = google_container_cluster.gke_cluster.master_auth.0.cluster_ca_certificate
sensitive = true
}
$ nano variable.tf
#PROJECT INFO
variable &amp;#34;PROJECT_ID&amp;#34; {
default = &amp;#34;gketest-462015&amp;#34;
}
variable &amp;#34;REGION&amp;#34; {
default = &amp;#34;asia-east1&amp;#34;
}
#VPC
variable &amp;#34;VPC_NAME&amp;#34; {
default = &amp;#34;k8s-vpc&amp;#34;
}
variable &amp;#34;VPC_NAME2&amp;#34; {
default = &amp;#34;k8s-vpc2&amp;#34;
}
variable &amp;#34;VPC_SUBNET_NAME&amp;#34; {
default = &amp;#34;asia-east1&amp;#34;
}
variable &amp;#34;VPC_SUBNET_NAME2&amp;#34; {
default = &amp;#34;asia-east1-2&amp;#34;
}
variable &amp;#34;IP_CIDR_RANGE&amp;#34; {
default = &amp;#34;10.10.0.0/24&amp;#34;
}
variable &amp;#34;IP_CIDR_RANGE2&amp;#34; {
default = &amp;#34;10.10.1.0/24&amp;#34;
}
variable &amp;#34;ROUTER_NAME&amp;#34; {
default = &amp;#34;demo-route&amp;#34;
}
variable &amp;#34;ROUTER_NAME2&amp;#34; {
default = &amp;#34;demo-route2&amp;#34;
}
variable &amp;#34;NAT_NAME&amp;#34; {
default = &amp;#34;demo-nat&amp;#34;
}
variable &amp;#34;NAT_NAME2&amp;#34; {
default = &amp;#34;demo-nat2&amp;#34;
}
#GKE
variable &amp;#34;GKE_LOCATION&amp;#34; {
default = &amp;#34;asia-east1-b&amp;#34;
}
variable &amp;#34;GKE_MACHINE_TYPE&amp;#34; {
default = &amp;#34;e2-custom-2-8192&amp;#34;
}
$ nano vpc.tf
resource &amp;#34;google_compute_network&amp;#34; &amp;#34;vpc&amp;#34; {
name = var.VPC_NAME
auto_create_subnetworks = &amp;#34;false&amp;#34;
}
resource &amp;#34;google_compute_subnetwork&amp;#34; &amp;#34;subnet&amp;#34; {
name = &amp;#34;${var.VPC_SUBNET_NAME}-subnet&amp;#34;
region = var.REGION
network = google_compute_network.vpc.name
ip_cidr_range = var.IP_CIDR_RANGE
private_ip_google_access = true
}
#resource &amp;#34;google_compute_subnetwork&amp;#34; &amp;#34;subnet2&amp;#34; {
# name = &amp;#34;${var.VPC_SUBNET_NAME}2-subnet&amp;#34;
# region = var.REGION
# network = google_compute_network.vpc.name
# ip_cidr_range = var.IP_CIDR_RANGE2
# private_ip_google_access = true
#}
resource &amp;#34;google_compute_router&amp;#34; &amp;#34;router&amp;#34; {
name = var.ROUTER_NAME
region = google_compute_subnetwork.subnet.region
network = google_compute_network.vpc.id
}
#resource &amp;#34;google_compute_address&amp;#34; &amp;#34;address&amp;#34; {
# count = 2
# name = &amp;#34;nat-manual-ip-${count.index}&amp;#34;
# region = google_compute_subnetwork.subnet.region
#}
resource &amp;#34;google_compute_address&amp;#34; &amp;#34;r1-address&amp;#34; {
name = &amp;#34;nat-address&amp;#34;
region = google_compute_subnetwork.subnet.region
}
#resource &amp;#34;google_compute_address&amp;#34; &amp;#34;r1-address-2&amp;#34; {
# name = &amp;#34;nat-address2&amp;#34;
# region = google_compute_subnetwork.subnet.region
#}
resource &amp;#34;google_compute_router_nat&amp;#34; &amp;#34;nat_manual&amp;#34; {
name = var.NAT_NAME
router = google_compute_router.router.name
region = google_compute_router.router.region
nat_ip_allocate_option = &amp;#34;MANUAL_ONLY&amp;#34;
nat_ips = [google_compute_address.r1-address.self_link]
enable_dynamic_port_allocation = true
enable_endpoint_independent_mapping = false
min_ports_per_vm = 4096
max_ports_per_vm = 65536
source_subnetwork_ip_ranges_to_nat = &amp;#34;LIST_OF_SUBNETWORKS&amp;#34;
subnetwork {
name = google_compute_subnetwork.subnet.id
source_ip_ranges_to_nat = [&amp;#34;ALL_IP_RANGES&amp;#34;]
}
}
#resource &amp;#34;google_compute_router&amp;#34; &amp;#34;router2&amp;#34; {
# name = var.ROUTER_NAME2
# region = google_compute_subnetwork.subnet2.region
# network = google_compute_network.vpc.id
#}
#resource &amp;#34;google_compute_address&amp;#34; &amp;#34;r2-address&amp;#34; {
# name = &amp;#34;r2-nat-address&amp;#34;
# region = google_compute_subnetwork.subnet2.region
#}
#resource &amp;#34;google_compute_router_nat&amp;#34; &amp;#34;nat_manual2&amp;#34; {
# name = var.NAT_NAME2
# router = google_compute_router.router2.name
# region = google_compute_router.router2.region
# nat_ip_allocate_option = &amp;#34;MANUAL_ONLY&amp;#34;
# nat_ips = google_compute_address.r2-address.*.self_link
# enable_dynamic_port_allocation = true
# enable_endpoint_independent_mapping = false
# min_ports_per_vm = 4096
# max_ports_per_vm = 65536
# source_subnetwork_ip_ranges_to_nat = &amp;#34;LIST_OF_SUBNETWORKS&amp;#34;
# subnetwork {
# name = google_compute_subnetwork.subnet2.id
# source_ip_ranges_to_nat = [&amp;#34;ALL_IP_RANGES&amp;#34;]
# }
#}
#Firewall Rule
#resource &amp;#34;google_compute_firewall&amp;#34; &amp;#34;datalake-prod-composer-internal-ingress&amp;#34; {
# name = &amp;#34;datalake-prod-composer-internal-ingress&amp;#34;
# network = google_compute_network.prod-vpc.name
# allow {
# protocol = &amp;#34;tcp&amp;#34;
# }
# allow {
# protocol = &amp;#34;udp&amp;#34;
# }
# priority = 1000
# source_ranges = var.datalake_prod_composer_ingress_allow_source_ip
# target_tags = var.datalake_prod_composer_ingress_target_tag
#}
$ nano provider.tf
terraform {
required_providers {
google = {
source = &amp;#34;hashicorp/google&amp;#34;
version = &amp;#34;4.40.0&amp;#34;
}
}
required_version = &amp;#34;&amp;gt;= 0.14&amp;#34;
}
provider &amp;#34;google&amp;#34; {
project = var.PROJECT_ID
region = var.REGION
}
$ terraform init
$ terraform plan
$ terraform apply
$ gcloud container clusters get-credentials k1 --zone asia-east1-b --project $(gcloud config get-value project 2&amp;gt; /dev/null)
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
gke-k1-default-pool-e0781567-7ljm Ready &amp;lt;none&amp;gt; 5m39s v1.32.4-gke.1106006&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;3. 清理環境 (窮到只剩錢的人可跳過此步驟)&lt;span class="hx:absolute hx:-mt-20" id="3-清理環境-窮到只剩錢的人可跳過此步驟"&gt;&lt;/span&gt;
&lt;a href="#3-%e6%b8%85%e7%90%86%e7%92%b0%e5%a2%83-%e7%aa%ae%e5%88%b0%e5%8f%aa%e5%89%a9%e9%8c%a2%e7%9a%84%e4%ba%ba%e5%8f%af%e8%b7%b3%e9%81%8e%e6%ad%a4%e6%ad%a5%e9%a9%9f" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;不做的話，殘留在 Google Cloud 上的物件會一直產生費用&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;# 將所有建立的物件清除
$ terraform destroy
# 移除 billing account 與 Project 的連結
$ gcloud billing projects unlink $GOOGLE_CLOUD_PROJECT
billingAccountName: &amp;#39;&amp;#39;
billingEnabled: false
name: projects/gketest-462015/billingInfo
projectId: gketest-462015
# 刪除 project
$ gcloud projects delete -q $GOOGLE_CLOUD_PROJECT
Deleted [https://cloudresourcemanager.googleapis.com/v1/projects/gketest-462015].
You can undo this operation for a limited period by running the command below.
$ gcloud projects undelete gketest-462015
See https://cloud.google.com/resource-manager/docs/creating-managing-projects for information on shutting down projects.
# 確認 project 已被刪除
$ gcloud projects describe $GOOGLE_CLOUD_PROJECT
createTime: &amp;#39;2025-06-05T15:39:13.542189Z&amp;#39;
lifecycleState: DELETE_REQUESTED
name: gketest
projectId: gketest-462015
projectNumber: &amp;#39;876476350521&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Bash Script Debug mode</title><link>https://blog.kubeantony.com/archive/ops-automation/bash-script-debug-mode/</link><pubDate>Wed, 21 May 2025 01:32:00 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/bash-script-debug-mode/</guid><description>
&lt;h2&gt;實作目標&lt;span class="hx:absolute hx:-mt-20" id="實作目標"&gt;&lt;/span&gt;
&lt;a href="#%e5%af%a6%e4%bd%9c%e7%9b%ae%e6%a8%99" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;將 Bash Function 裡面，命令的正確執行結果 + 錯誤輸出 + 真正執行的命令(變數會變成值) 通通都倒到同一個檔案中，不用手動一行一行在行尾加上 &lt;code&gt;&amp;amp; &amp;gt; /dev/null&lt;/code&gt;，而且加上行號、function 名稱，好讓你以後除錯時超清楚！&lt;/p&gt;
&lt;h2&gt;注意事項&lt;span class="hx:absolute hx:-mt-20" id="注意事項"&gt;&lt;/span&gt;
&lt;a href="#%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a0%85" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;因 log file 的目錄區是在 &lt;code&gt;/var/log&lt;/code&gt; 底下，所以以下範例需要由 root 使用者或 sudo user 執行。&lt;/li&gt;
&lt;li&gt;log 的檔名前面有加 &lt;code&gt;.&lt;/code&gt; 代表隱藏檔案，所以不能用 &lt;code&gt;ll&lt;/code&gt;，大部分的 &lt;code&gt;ll&lt;/code&gt; 都是 &lt;code&gt;alias ll=&amp;quot;ls -l&amp;quot;&lt;/code&gt;，要記得用 &lt;code&gt;ls -al&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;範例程式&lt;span class="hx:absolute hx:-mt-20" id="範例程式"&gt;&lt;/span&gt;
&lt;a href="#%e7%af%84%e4%be%8b%e7%a8%8b%e5%bc%8f" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
TRACE_LOG() {
Command_log_file=&amp;#34;/var/log/.$(basename &amp;#34;${BASH_SOURCE[0]}&amp;#34;).log&amp;#34;
exec &amp;gt;&amp;gt;&amp;#34;${Command_log_file}&amp;#34; 2&amp;gt;&amp;amp;1
exec 3&amp;gt;&amp;gt; &amp;#34;${Command_log_file}&amp;#34;
export BASH_XTRACEFD=3 PS4=&amp;#39;($BASH_SOURCE:$LINENO:$FUNCNAME): &amp;#39;
set -x
}
TEST() {
TRACE_LOG
for i in {1..10};
do
echo ${i}
done
# failed command
fdsffa
fdsafasf
set &amp;#43;x
}
TEST&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;程式重點介紹&lt;span class="hx:absolute hx:-mt-20" id="程式重點介紹"&gt;&lt;/span&gt;
&lt;a href="#%e7%a8%8b%e5%bc%8f%e9%87%8d%e9%bb%9e%e4%bb%8b%e7%b4%b9" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;TRACE_LOG() {&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;這是宣告一個 Bash function，叫做 &lt;code&gt;TRACE_LOG&lt;/code&gt;，之後你可以在 script 其他地方用 &lt;code&gt;TRACE_LOG&lt;/code&gt; 來呼叫它。&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt; Command_log_file=&amp;#34;/var/log/.$(basename &amp;#34;${BASH_SOURCE[0]}&amp;#34;).log&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;設定 log 檔的檔名與路徑。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$(basename &amp;quot;${BASH_SOURCE[0]}&amp;quot;)&lt;/code&gt; 會取得目前這個 script 的檔名，例如 &lt;code&gt;myscript.sh&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;結果會變成這樣的一個 log 路徑，例如：
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;/var/log/.myscript.sh.log&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;這樣做的目的是：自動為每個 script 建立一個獨立的 log 檔，方便紀錄。&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt; exec &amp;gt;&amp;gt;&amp;#34;${Command_log_file}&amp;#34; 2&amp;gt;&amp;amp;1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;把所有之後的「正常輸出（stdout）」與「錯誤訊息（stderr）」全部寫進前面設定的 log 檔中。&lt;/li&gt;
&lt;li&gt;從這一行開始，像 &lt;code&gt;echo&lt;/code&gt; 或 &lt;code&gt;ls&lt;/code&gt; 等指令的輸出都不會出現在螢幕上，而是寫進 log 檔。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt; exec 3&amp;gt;&amp;gt; &amp;#34;${Command_log_file}&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;開啟一個「新的資料管道」，叫做「檔案描述符 3（FD 3）」，也指向同一個 log 檔。&lt;/li&gt;
&lt;li&gt;這行本身不會產生輸出，它只是預先準備好「FD 3」，之後會專門用來記錄除錯訊息（debug trace）。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt; export BASH_XTRACEFD=3 PS4=&amp;#39;($BASH_SOURCE:$LINENO:$FUNCNAME): &amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;這是在啟用 Bash 的「除錯模式」所需的變數。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BASH_XTRACEFD=3&lt;/code&gt;：告訴 Bash，把除錯訊息（由 &lt;code&gt;set -x&lt;/code&gt; 產生的 trace）寫入「檔案描述符 3」，也就是 log 檔。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PS4='($BASH_SOURCE:$LINENO:$FUNCNAME): '&lt;/code&gt;：設定每一行除錯訊息的開頭格式，包括：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$BASH_SOURCE&lt;/code&gt;：是哪個 script 檔案&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$LINENO&lt;/code&gt;：是哪一行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$FUNCNAME&lt;/code&gt;：是在哪個 function 裡&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;舉例產生的 log 可能會長這樣：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;(myscript.sh:15:myfunc): echo &amp;#34;啟動中&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;這樣可以清楚知道程式執行到哪裡、哪一行。&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&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;set&lt;/span&gt; -x&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;這行開啟 Bash 的「指令追蹤模式（debug trace mode）」。&lt;/li&gt;
&lt;li&gt;開啟後，Bash 每執行一行指令，都會先印出該指令的內容（寫入你上面指定的 log 檔，因為有設定 &lt;code&gt;BASH_XTRACEFD&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;使用方式&lt;span class="hx:absolute hx:-mt-20" id="使用方式"&gt;&lt;/span&gt;
&lt;a href="#%e4%bd%bf%e7%94%a8%e6%96%b9%e5%bc%8f" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;你只要在 script 裡面某個地方寫：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&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;TRACE_LOG&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;從那一行開始，這支 script 的輸出和行為紀錄就會開始寫進 log 檔 &lt;code&gt;/var/log/.xxx.log&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;查看 Log&lt;span class="hx:absolute hx:-mt-20" id="查看-log"&gt;&lt;/span&gt;
&lt;a href="#%e6%9f%a5%e7%9c%8b-log" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;# cat /var/log/.test.sh.log&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行結果 :&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;(./test.sh:17:test): for i in {1..10}
(./test.sh:19:test): echo 1
1
(./test.sh:17:test): for i in {1..10}
(./test.sh:19:test): echo 2
2
(./test.sh:17:test): for i in {1..10}
(./test.sh:19:test): echo 3
3
(./test.sh:17:test): for i in {1..10}
(./test.sh:19:test): echo 4
4
(./test.sh:17:test): for i in {1..10}
(./test.sh:19:test): echo 5
5
(./test.sh:17:test): for i in {1..10}
(./test.sh:19:test): echo 6
6
(./test.sh:17:test): for i in {1..10}
(./test.sh:19:test): echo 7
7
(./test.sh:17:test): for i in {1..10}
(./test.sh:19:test): echo 8
8
(./test.sh:17:test): for i in {1..10}
(./test.sh:19:test): echo 9
9
(./test.sh:17:test): for i in {1..10}
(./test.sh:19:test): echo 10
10
(./test.sh:23:test): fdsffa
./test.sh: line 23: fdsffa: command not found
(./test.sh:24:test): fdsafasf
./test.sh: line 24: fdsafasf: command not found
(./test.sh:25:test): set &amp;#43;x&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Test Webhook</title><link>https://blog.kubeantony.com/archive/ops-automation/test-webhook/</link><pubDate>Thu, 04 Jul 2024 02:15:32 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/test-webhook/</guid><description>
&lt;h2&gt;What are webhooks and why use them?&lt;span class="hx:absolute hx:-mt-20" id="what-are-webhooks-and-why-use-them"&gt;&lt;/span&gt;
&lt;a href="#what-are-webhooks-and-why-use-them" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Webhooks are HTTP callbacks that allow you to send alerts to external services or applications. You can use webhooks to integrate Alertmanager with chat platforms, notification systems, ticketing tools, or any other web-based service that can receive and process HTTP requests. Webhooks give you more flexibility and control over how you handle and respond to alerts.&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;# 1. 安裝 Golang
$ suseconnect -p PackageHub/15.6/x86_64
$ zypper -n in go
$ git clone https://github.com/yunlzheng/alertmanaer-dingtalk-webhook.git &amp;amp;&amp;amp; \
cd alertmanaer-dingtalk-webhook
$ go mod init
$ go mod download
$ cd cmd/webhook
$ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a webhook.go
$ &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>SRE 課程學習筆記連結-Overview</title><link>https://blog.kubeantony.com/archive/ops-automation/sre-%E8%AA%B2%E7%A8%8B%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98%E9%80%A3%E7%B5%90-overview/</link><pubDate>Thu, 07 Dec 2023 07:35:16 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/sre-%E8%AA%B2%E7%A8%8B%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98%E9%80%A3%E7%B5%90-overview/</guid><description>
&lt;h2&gt;前言&lt;span class="hx:absolute hx:-mt-20" id="前言"&gt;&lt;/span&gt;
&lt;a href="#%e5%89%8d%e8%a8%80" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;這裡放了我學習 SRE 課程的所有筆記連結&lt;/li&gt;
&lt;li&gt;還有同學們的筆記連結&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;陳松林老師&lt;/h1&gt;&lt;h2&gt;Linux Process&lt;span class="hx:absolute hx:-mt-20" id="linux-process"&gt;&lt;/span&gt;
&lt;a href="#linux-process" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/misc/linux-process-part1/"&gt;Linux Process Part 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/misc/linux-process-part2/"&gt;Linux Process Part 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Container&lt;span class="hx:absolute hx:-mt-20" id="container"&gt;&lt;/span&gt;
&lt;a href="#container" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/container/container-core-tech/"&gt;Container-Core-Tech&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/container/container-runtime-cri/"&gt;Container-Runtime-CRI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Docker&lt;span class="hx:absolute hx:-mt-20" id="docker"&gt;&lt;/span&gt;
&lt;a href="#docker" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/container/docker-appcontainer-part1/"&gt;Docker-AppContainer-Part1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/container/docker-image/"&gt;Docker-Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/container/docker-appcontainer-part3/"&gt;Docker-AppContainer-Part3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Podman&lt;span class="hx:absolute hx:-mt-20" id="podman"&gt;&lt;/span&gt;
&lt;a href="#podman" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/container/podman-overview/"&gt;Podman Overview link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/container/podman-skopeo-buildah/"&gt;Podman-Skopeo-Buildah&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Kubernetes&lt;span class="hx:absolute hx:-mt-20" id="kubernetes"&gt;&lt;/span&gt;
&lt;a href="#kubernetes" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/kubernetes/kubernetes-%e6%9c%89%e8%88%b5%e6%89%8b%e7%9a%84%e6%84%8f%e6%80%9d/"&gt;Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/kubernetes/kubernetes-first-steps/"&gt;Kubernetes-First-Steps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/kubernetes/kubernetes-objects/"&gt;Kubernetes-Objects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/kubernetes/kubernetes-deployment/"&gt;Kubernetes Deployment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/kubernetes/kubernetes-statefulset/"&gt;Kubernetes StatefulSet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/kubernetes/kubernetes-resource-cpu-memory/"&gt;Kubernetes-Resource-CPU-Memory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/kubernetes/kubernetes-resource-storage/"&gt;Kubernetes Resource Storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/kubernetes/kubernetes-rbac-context/"&gt;Kubernetes-RBAC-Context&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;DataTechnology&lt;span class="hx:absolute hx:-mt-20" id="datatechnology"&gt;&lt;/span&gt;
&lt;a href="#datatechnology" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/data-platform/datatechnology-overview/"&gt;DataTechnology - Overview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;世宏老師&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/misc/%e6%a5%8a%e4%b8%96%e5%ae%8f%e8%80%81%e5%b8%ab-iot-intro/"&gt;楊世宏老師 : IOT Intro&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;莊明城老師&lt;/h1&gt;&lt;h2&gt;Linux KVM&lt;span class="hx:absolute hx:-mt-20" id="linux-kvm"&gt;&lt;/span&gt;
&lt;a href="#linux-kvm" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/virtualization/linux-kvm/"&gt;Linux KVM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Kubernetes&lt;span class="hx:absolute hx:-mt-20" id="kubernetes-1"&gt;&lt;/span&gt;
&lt;a href="#kubernetes-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/security/multi-tenancy-security-aaa/"&gt;Multi Tenancy Security AAA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/container/project-quay-%e7%b7%b4%e7%bf%92/"&gt;Project Quay 練習&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/kubernetes/kubernetes-deployment/"&gt;Kubernetes Deployment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/kubernetes/kubernetes-statefulset/"&gt;Kubernetes StatefulSet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/kubernetes/kubernetes-resource-storage-by-%e6%98%8e%e5%9f%8e%e8%80%81%e5%b8%ab/"&gt;Kubernetes Resource Storage by 明城老師&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;楊承羲老師&lt;/h1&gt;&lt;h2&gt;Linux&lt;span class="hx:absolute hx:-mt-20" id="linux"&gt;&lt;/span&gt;
&lt;a href="#linux" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/misc/linux-startup-process-%e9%96%8b%e6%a9%9f%e6%b5%81%e7%a8%8b/"&gt;Linux startup Process 開機流程&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;CI/CD Overview&lt;span class="hx:absolute hx:-mt-20" id="cicd-overview"&gt;&lt;/span&gt;
&lt;a href="#cicd-overview" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/ops-automation/ci-cd-overview/"&gt;CI/CD Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/ops-automation/rest-api/"&gt;REST API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/ops-automation/jenkins/"&gt;Jenkins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/ops-automation/jenkins-part-2/"&gt;Jenkins - Part 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/ops-automation/canary-deployment/"&gt;Canary Deployment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Git&lt;span class="hx:absolute hx:-mt-20" id="git"&gt;&lt;/span&gt;
&lt;a href="#git" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/ops-automation/git/"&gt;Git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/ops-automation/git-part-2/"&gt;Git - Part 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Bash Script&lt;span class="hx:absolute hx:-mt-20" id="bash-script"&gt;&lt;/span&gt;
&lt;a href="#bash-script" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://blog.kubeantony.com/ops-automation/bash-script-%e7%ad%86%e8%a8%98/"&gt;bash script 筆記&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://devhints.io/bash#conditionals"target="_blank" rel="noopener"&gt;Bash scripting cheatsheet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;同學的筆記連結&lt;/h1&gt;&lt;h2&gt;宇志的第二期 SRE 課程學習筆記連結&lt;span class="hx:absolute hx:-mt-20" id="宇志的第二期-sre-課程學習筆記連結"&gt;&lt;/span&gt;
&lt;a href="#%e5%ae%87%e5%bf%97%e7%9a%84%e7%ac%ac%e4%ba%8c%e6%9c%9f-sre-%e8%aa%b2%e7%a8%8b%e5%ad%b8%e7%bf%92%e7%ad%86%e8%a8%98%e9%80%a3%e7%b5%90" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://hackmd.io/@RayLin9981/Sy6eRKHzt#SRE%E8%AA%B2%E7%A8%8B"target="_blank" rel="noopener"&gt;SRE-part1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://hackmd.io/@RayLin9981/SJCIjcIBY"target="_blank" rel="noopener"&gt;SRE-part2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;東軒的程式筆記&lt;span class="hx:absolute hx:-mt-20" id="東軒的程式筆記"&gt;&lt;/span&gt;
&lt;a href="#%e6%9d%b1%e8%bb%92%e7%9a%84%e7%a8%8b%e5%bc%8f%e7%ad%86%e8%a8%98" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://hackmd.io/@7vxmAdNPTmmlYGSRMuvbmw/r1z6A83w9"target="_blank" rel="noopener"&gt;Bash Script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://hackmd.io/@7vxmAdNPTmmlYGSRMuvbmw/BkoVhaZD5"target="_blank" rel="noopener"&gt;MySQL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;我的筆記小站&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://braveantony.github.io"target="_blank" rel="noopener"&gt;MyWeb&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Backstage 首頁</title><link>https://blog.kubeantony.com/archive/ops-automation/backstage-%E9%A6%96%E9%A0%81/</link><pubDate>Sat, 04 Nov 2023 03:04:08 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/backstage-%E9%A6%96%E9%A0%81/</guid><description>
&lt;h2&gt;正式內容&lt;span class="hx:absolute hx:-mt-20" id="正式內容"&gt;&lt;/span&gt;
&lt;a href="#%e6%ad%a3%e5%bc%8f%e5%85%a7%e5%ae%b9" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;DropBox&lt;span class="hx:absolute hx:-mt-20" id="dropbox"&gt;&lt;/span&gt;
&lt;a href="#dropbox" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://hackmd.io/@QI-AN/GettingStarted-configuring-Backstage/edit"target="_blank" rel="noopener"&gt;Getting Started, configuring Backstage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://hackmd.io/@QI-AN/B1QNWskmT"target="_blank" rel="noopener"&gt;在 Kubernetes 建置 bobo 企業網站應用系統&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Build backstage Container Image</title><link>https://blog.kubeantony.com/archive/ops-automation/build-backstage-container-image/</link><pubDate>Tue, 10 Oct 2023 08:19:22 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/build-backstage-container-image/</guid><description>
&lt;style&gt;
.indent-title-1{
margin-left: 1em;
}
.indent-title-2{
margin-left: 2em;
}
.indent-title-3{
margin-left: 3em;
}
&lt;/style&gt;
&lt;h2&gt;Preface&lt;span class="hx:absolute hx:-mt-20" id="preface"&gt;&lt;/span&gt;
&lt;a href="#preface" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;本篇文章會主要會介紹如何，透過 Podman 工具設計並製作 Backstage 的 Container Image&lt;/p&gt;
&lt;p&gt;可以透過點擊以下目錄，選擇想看的內容，跳轉至特定章節&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Prerequisites&lt;span class="hx:absolute hx:-mt-20" id="prerequisites"&gt;&lt;/span&gt;
&lt;a href="#prerequisites" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;h3&gt;Hareware Requisites&lt;span class="hx:absolute hx:-mt-20" id="hareware-requisites"&gt;&lt;/span&gt;
&lt;a href="#hareware-requisites" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;MEM: 8 Gi&lt;/li&gt;
&lt;li&gt;CPU: 4 Core&lt;/li&gt;
&lt;li&gt;Disk: 100 GB&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;System Requisites&lt;span class="hx:absolute hx:-mt-20" id="system-requisites"&gt;&lt;/span&gt;
&lt;a href="#system-requisites" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;須能上網&lt;/li&gt;
&lt;li&gt;作業系統
&lt;ul&gt;
&lt;li&gt;Ubuntu Server 22.04 LTS&lt;/li&gt;
&lt;li&gt;Alpine 3.18&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;可以執行 &lt;code&gt;sudo&lt;/code&gt; 的使用者帳號&lt;/li&gt;
&lt;li&gt;以下套件須先安裝
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Podman&lt;/code&gt; (Version: 4.6.2+)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;系統環境準備&lt;span class="hx:absolute hx:-mt-20" id="系統環境準備"&gt;&lt;/span&gt;
&lt;a href="#%e7%b3%bb%e7%b5%b1%e7%92%b0%e5%a2%83%e6%ba%96%e5%82%99" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;h3&gt;安裝 Podman 4&lt;span class="hx:absolute hx:-mt-20" id="安裝-podman-4"&gt;&lt;/span&gt;
&lt;a href="#%e5%ae%89%e8%a3%9d-podman-4" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;h4&gt;Step 1: Add Necessary Repository&lt;span class="hx:absolute hx:-mt-20" id="step-1-add-necessary-repository"&gt;&lt;/span&gt;
&lt;a href="#step-1-add-necessary-repository" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;使用 root 權限執行以下 shell Script&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;echo $&amp;#39;#!/bin/sh
ubuntu_version=&amp;#39;22.04&amp;#39;
key_url=&amp;#34;https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/xUbuntu_${ubuntu_version}/Release.key&amp;#34;
sources_url=&amp;#34;https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/xUbuntu_${ubuntu_version}&amp;#34;
echo &amp;#34;deb $sources_url/ /&amp;#34; | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list
curl -fsSL $key_url | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/devel_kubic_libcontainers_unstable.gpg &amp;gt; /dev/null&amp;#39; | sudo sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4&gt;Step 2: Install Podman&lt;span class="hx:absolute hx:-mt-20" id="step-2-install-podman"&gt;&lt;/span&gt;
&lt;a href="#step-2-install-podman" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo apt install podman&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4&gt;Step 3: 檢查 Podman 版本&lt;span class="hx:absolute hx:-mt-20" id="step-3-檢查-podman-版本"&gt;&lt;/span&gt;
&lt;a href="#step-3-%e6%aa%a2%e6%9f%a5-podman-%e7%89%88%e6%9c%ac" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ podman -v&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;螢幕輸出 :&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;podman version 4.6.2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;撰寫 Backstage-Backend Container file&lt;span class="hx:absolute hx:-mt-20" id="撰寫-backstage-backend-container-file"&gt;&lt;/span&gt;
&lt;a href="#%e6%92%b0%e5%af%ab-backstage-backend-container-file" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;h3&gt;建立工作目錄&lt;span class="hx:absolute hx:-mt-20" id="建立工作目錄"&gt;&lt;/span&gt;
&lt;a href="#%e5%bb%ba%e7%ab%8b%e5%b7%a5%e4%bd%9c%e7%9b%ae%e9%8c%84" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ mkdir -p ~/backstage/build-image/ &amp;amp;&amp;amp; cd ~/backstage/build-image/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;建置過程分為兩個不同階段 :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一階段
&lt;ul&gt;
&lt;li&gt;安裝所有 &lt;code&gt;package.json&lt;/code&gt; 檔案，以便快取安裝所有依賴項的初始 &lt;code&gt;yarn install&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;第二階段
&lt;ul&gt;
&lt;li&gt;將所有內容打包成最終映像，與主機建置的 Dockerfile 類似。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;建立 Container file&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano Containerfile.backend&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;以下是 Container file 的內容&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;# Stage 1 - Download and Install Backstage Backend App as a base Layer
FROM docker.io/library/ubuntu:latest AS Base
ENV HOME=/root \
NODE_VERSION=v18.17.1
# Install required packages for Backstage
RUN apt-get update &amp;amp;&amp;amp; \
DEBIAN_FRONTEND=noninteractive \
apt-get install -y --no-install-recommends make python3 g&amp;#43;&amp;#43; build-essential git-all curl &amp;amp;&amp;amp; \
## Setup Time Zone
TZ=Asia/Taipei &amp;amp;&amp;amp; \
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime &amp;amp;&amp;amp; \
echo $TZ &amp;gt; /etc/timezone &amp;amp;&amp;amp; \
dpkg-reconfigure -f noninteractive tzdata &amp;amp;&amp;amp; \
## Using nvm install node.js (LTS)
curl -so - https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash &amp;amp;&amp;amp; \
export NVM_DIR=&amp;#34;$HOME/.nvm&amp;#34; &amp;amp;&amp;amp; \
[ -s &amp;#34;$NVM_DIR/nvm.sh&amp;#34; ] &amp;amp;&amp;amp; \
. &amp;#34;$NVM_DIR/nvm.sh&amp;#34; &amp;amp;&amp;amp; \
nvm install $NODE_VERSION &amp;amp;&amp;amp; \
nvm use $NODE_VERSION &amp;amp;&amp;amp; \
## Install yarn and npx
npm install --global yarn &amp;amp;&amp;amp; \
## Configure yarn use python3
yarn config set python /usr/bin/python3 &amp;amp;&amp;amp; \
## Create Backstage App
echo backstage | npx -y @backstage/create-app@latest
ENV NVM_DIR=&amp;#34;$HOME/.nvm&amp;#34; \
NODE_PATH=$NVM_DIR/$NODE_VERSION/lib/node_modules \
PATH=$NVM_DIR/$NODE_VERSION/bin:$PATH
WORKDIR backstage/
# Setup Git
RUN git init &amp;amp;&amp;amp; \
git config --global user.email &amp;#34;bobo@backstage.com&amp;#34; &amp;amp;&amp;amp; \
git config --global user.name &amp;#34;bobo&amp;#34; &amp;amp;&amp;amp; \
git add . &amp;amp;&amp;amp; \
git commit -m &amp;#34;Initial commit&amp;#34;
# build Backstage Backend
RUN . &amp;#34;$NVM_DIR/nvm.sh&amp;#34; &amp;amp;&amp;amp; \
yarn install --frozen-lockfile --network-timeout 600000 &amp;amp;&amp;amp; \
yarn tsc &amp;amp;&amp;amp; \
yarn --cwd packages/backend build
RUN mkdir packages/backend/dist/skeleton packages/backend/dist/bundle \
&amp;amp;&amp;amp; tar xzf packages/backend/dist/skeleton.tar.gz -C packages/backend/dist/skeleton \
&amp;amp;&amp;amp; tar xzf packages/backend/dist/bundle.tar.gz -C packages/backend/dist/bundle
# Stage 2 - Build the actual backend image and install production dependencies
FROM node:18-bookworm-slim
# Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend.
RUN apt-get update &amp;amp;&amp;amp; \
apt-get install -y --no-install-recommends python3 g&amp;#43;&amp;#43; build-essential &amp;amp;&amp;amp; \
yarn config set python /usr/bin/python3
# From here on we use the least-privileged `node` user to run the backend.
USER node
# This should create the app dir as `node`.
# If it is instead created as `root` then the `tar` command below will fail: `can&amp;#39;t create directory &amp;#39;packages/&amp;#39;: Permission denied`.
# If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) so the app dir is correctly created as `node`.
WORKDIR /app
# Copy the install dependencies from the build stage and context
COPY --from=Base --chown=node:node /backstage/yarn.lock /backstage/package.json /backstage/packages/backend/dist/skeleton/ ./
RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \
yarn install --frozen-lockfile --production --network-timeout 600000
# Copy the built packages from the build stage
COPY --from=Base --chown=node:node /backstage/packages/backend/dist/bundle/ ./
# Copy any other files that we need at runtime
COPY --from=Base --chown=node:node /backstage/app-config.yaml ./
# This switches many Node.js dependencies to production mode.
ENV NODE_ENV production
CMD [&amp;#34;node&amp;#34;, &amp;#34;packages/backend&amp;#34;, &amp;#34;--config&amp;#34;, &amp;#34;app-config.yaml&amp;#34;]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Build Backstage-Backend Container Image&lt;span class="hx:absolute hx:-mt-20" id="build-backstage-backend-container-image"&gt;&lt;/span&gt;
&lt;a href="#build-backstage-backend-container-image" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo podman build --no-cache -t backstage-backend:v1 -f Containerfile.backend&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;撰寫 Backstage-Backend Podman Pod Yaml File&lt;span class="hx:absolute hx:-mt-20" id="撰寫-backstage-backend-podman-pod-yaml-file"&gt;&lt;/span&gt;
&lt;a href="#%e6%92%b0%e5%af%ab-backstage-backend-podman-pod-yaml-file" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano ~/backstage/podman-pod/backstage-backend.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檔案內容如下&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
name: backstage
spec:
containers:
- name: backstage-backend
image: localhost/backstage-backend:v1
volumeMounts:
- name: app-config
mountPath: /app/app-config.yaml
subPath: app-config.yaml
- name: backstage-frontend
image: localhost/backstage-frontend:v1
volumes:
- name: app-config
hostPath:
path: ~/backstage/backstage/app-config.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;建立並測試 Backstage-Backend Pod&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo podman run -it -d --mount type=bind,source=app-config.yaml,destination=/app/app-config.yaml localhost/backstage-backend:v1 bash&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Getting Started, configuring Backstage</title><link>https://blog.kubeantony.com/archive/ops-automation/getting-started-configuring-backstage/</link><pubDate>Thu, 05 Oct 2023 09:40:46 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/getting-started-configuring-backstage/</guid><description>
&lt;style&gt;
.indent-title-1{
margin-left: 1em;
}
.indent-title-2{
margin-left: 2em;
}
.indent-title-3{
margin-left: 3em;
}
&lt;/style&gt;
&lt;h2&gt;Preface&lt;span class="hx:absolute hx:-mt-20" id="preface"&gt;&lt;/span&gt;
&lt;a href="#preface" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;本篇文章會主要會分做 3 個部分介紹&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;甚麼是 Backstage&lt;/li&gt;
&lt;li&gt;透過 Podman Pod 建立與設定 Backstage 要使用的 Database - PostgreSQL&lt;/li&gt;
&lt;li&gt;透過 Podman Pod 建立與設定 Backstage&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;可以透過點擊展開以下目錄，選擇想看的內容，跳轉至特定章節&lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;p&gt;標題：Backstage
副標：解析企業開發導入 IDP 的需求與解決方案
簡報大綱規劃（持續調整中）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一章｜What is Backstage?
&lt;ul&gt;
&lt;li&gt;Objectives and methods&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;第二章｜系統架構
&lt;ul&gt;
&lt;li&gt;Concepts&lt;/li&gt;
&lt;li&gt;Architecture&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;第三章｜環境部署
&lt;ul&gt;
&lt;li&gt;Containerize&lt;/li&gt;
&lt;li&gt;相關服務的準備（ex:SQL）&lt;/li&gt;
&lt;li&gt;配置檔案修改&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;第四章｜應用實例
&lt;ul&gt;
&lt;li&gt;先以個別解說優先（後續完善再組裝起來）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;研究方向&lt;span class="hx:absolute hx:-mt-20" id="研究方向"&gt;&lt;/span&gt;
&lt;a href="#%e7%a0%94%e7%a9%b6%e6%96%b9%e5%90%91" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/HknTG0rk6.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;目前完成 Backstage Containerize 接下來研究 Software Catalog、Software Templates 功能，將 Backstage 部署與 Software Catalog、Software Templates 功能實作流程寫入 TechDocs，後續針對 Kubernetes 相關 plugin 進行實作，Search 於最後進行功能驗證。&lt;/p&gt;
&lt;p&gt;下一步&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首要目標：
&lt;ul&gt;
&lt;li&gt;完善基礎設施，先串接 CI/CD 有一個完整的 Demo 流程後，Backstage 再上 K8s&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;後續項目
&lt;ul&gt;
&lt;li&gt;修正導入誘因，不能只單獨強調整合的特點，還要列出實際解決的問題&lt;/li&gt;
&lt;li&gt;Kubernetes 部署 Backstage&lt;/li&gt;
&lt;li&gt;要了解開發人員，在合作開發中的問題點，如開新專案的流程，專案的交接步驟等，backstage 可以怎麼執行&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1&gt;What is Backstage&lt;/h1&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;Backstage 是 Spotify 公司開發的一個開放平台，用來建立開發人員的入口網站 ( developer portals )。&lt;/p&gt;
&lt;p&gt;它旨在&lt;strong&gt;提供開發者一個統一的平台，讓團隊成員能夠&lt;font color=red&gt;釐清&lt;/font&gt;、&lt;font color=red&gt;管理&lt;/font&gt;、&lt;font color=red&gt;維運&lt;/font&gt;和&lt;font color=red&gt;自動化部屬&lt;/font&gt;企業應用系統和基礎架構&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Backstage 的核心目標：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;它旨在提供統一的開發平台，讓企業能有效率的開發和管理應用系統。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;建立企業的開發平台，有效使用開發資源與提升管理效率。&lt;/p&gt;
&lt;p&gt;在既有的基礎設施上，套上一層管理工具，提供統一介面，使團隊擁有一致的開發資源、資訊，如同傳送門匯聚在一起&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Backstage 的實現手段：
Backstage is aggregator｜它著重的是基礎設施的聚合，而非替代
在既有的基礎設施上，套上一層管理工具，使團隊擁有一致的開發資訊界面，並透過高度彈性的外掛功能，實現不同的企業開發需求。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;目前屬於 CNCF 的孵化專案
&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/B1CD3Gj1T.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2&gt;System Architecture overview&lt;span class="hx:absolute hx:-mt-20" id="system-architecture-overview"&gt;&lt;/span&gt;
&lt;a href="#system-architecture-overview" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;There are 3 main components in this architecture:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The core Backstage UI&lt;/li&gt;
&lt;li&gt;The UI plugins and their backing services&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;整體組成架構：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Core：由開源專案的核心開發人員所建立的基本功能。&lt;/li&gt;
&lt;li&gt;App：Backstage 應用程式的實例，由應用程式開發人員（通常是公司內的生產力團隊）負責部署和調整。App 將核心功能與額外的插件結合在一起。&lt;/li&gt;
&lt;li&gt;Plugins：使您的 Backstage 應用程式對公司有用的額外功能。插件可以是特定於公司的，也可以是開源和可重用的。
&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/SklBBHakp.png" alt="" loading="lazy" /&gt;
&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/By3zF4TyT.png" alt="" loading="lazy" /&gt;
&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/SJT_BNTyT.png" alt="" loading="lazy" /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2&gt;backstage core functionalities&lt;span class="hx:absolute hx:-mt-20" id="backstage-core-functionalities"&gt;&lt;/span&gt;
&lt;a href="#backstage-core-functionalities" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;Backstage offers five core functionalities:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;a software catalog&lt;/li&gt;
&lt;li&gt;software templates&lt;/li&gt;
&lt;li&gt;a documentation generator&lt;/li&gt;
&lt;li&gt;a Kubernetes cluster visualizer&lt;/li&gt;
&lt;li&gt;cross-ecosystem search capabilities.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;h3&gt;Introducing the Software Catalog&lt;span class="hx:absolute hx:-mt-20" id="introducing-the-software-catalog"&gt;&lt;/span&gt;
&lt;a href="#introducing-the-software-catalog" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;&lt;font size=4&gt;&lt;strong&gt;目的&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;div class="indent-title-1"&gt;
&lt;p&gt;將企業中的所有應用系統，包括網站、API、程式庫和資源，映射到一個集中式目錄。這種集中化旨在幫助團隊管理技術並實現可發現性。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;font size=4&gt;&lt;strong&gt;重點功能&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;div class="indent-title-1"&gt;
&lt;p&gt;Catalog 能持續追蹤每個 Application 的 metadata ( 元數據 )、所有權和依賴關係，從而生成一個軟體圖，其中包含孤立的 entities。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;font size=4&gt;&lt;strong&gt;描述&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;div class="indent-title-1"&gt;
&lt;p&gt;Catalog 非常靈活，可以容納各種 Application，在 Backstage 中稱為 entities。 由於網站與資料處理管道截然不同，因此 entities 可以按 &lt;em&gt;Kind&lt;/em&gt; 種類區分。此外，即使在 entities 的種類中，也可以定義 &lt;em&gt;Kind&lt;/em&gt;。&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;font size=4&gt;&lt;strong&gt;如何實現&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;div class="indent-title-1"&gt;
&lt;p&gt;Catalog 由儲存在 YAML 檔案中的 metadata 提供支持，YAML 檔案描述了每個檔案中單一 entitiy 的 kind ( 種類 )、type ( 類型 )、 name ( 名稱 )、owner ( 所有者 ) 和更多細節。 這些檔案通常儲存在各自的程式碼庫中，因此會經常更新。 有些 entities 類型可能有權威來源，但程式庫中沒有體現，例如，Okta 規定的使用者和團隊。&lt;/p&gt;
&lt;p&gt;追蹤所有權和依賴關係是 Catalog 最重要的用例之一。 這些也在描述軟體元件的 YAML 檔案中聲明。 只有一個團隊可以成為元件的擁有者，這個團隊也必須作為一個 entities 在 Catalog 中註冊。 至於依賴關係，Backstage 可以讓你定義元件如何依賴另一個 entities ，以及元件暴露了哪些內容，以便其他人可以使用它。&lt;/p&gt;
&lt;p&gt;根據這些 metadata 繪製的軟體圖可以發現一些問題，例如孤兒 entities ，這意味著它們沒有父 entities 。 此外，由於 Catalog 中存儲了有關所有軟體資產的大量信息，因此您還可以從中了解成熟度準備情況或安全警告等信息。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;Introducing the Software Template&lt;span class="hx:absolute hx:-mt-20" id="introducing-the-software-template"&gt;&lt;/span&gt;
&lt;a href="#introducing-the-software-template" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;&lt;font size=4&gt;&lt;strong&gt;目的&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;div class="indent-title-1"&gt;
&lt;p&gt;Software Template 是一種工具，可幫助您在 Backstage 中建立元件。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;Podman Pod Install and configure Backstage database - PostgreSQL&lt;/h1&gt;&lt;h2&gt;建立工作目錄&lt;span class="hx:absolute hx:-mt-20" id="建立工作目錄"&gt;&lt;/span&gt;
&lt;a href="#%e5%bb%ba%e7%ab%8b%e5%b7%a5%e4%bd%9c%e7%9b%ae%e9%8c%84" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ mkdir -p ~/backstage/{build-image,database,podman-pod,k8s-app}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;撰寫 PostgreSQL Pod Yaml&lt;span class="hx:absolute hx:-mt-20" id="撰寫-postgresql-pod-yaml"&gt;&lt;/span&gt;
&lt;a href="#%e6%92%b0%e5%af%ab-postgresql-pod-yaml" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano ~/backstage/podman-pod/postgres.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檔案內容如下 :&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;apiVersion: apps/v1
kind: Pod
metadata:
name: postgres
spec:
containers:
- name: postgres
image: postgres:13.2-alpine
ports:
- containerPort: 5432
hostPort: 5432
env:
- name: POSTGRES_USER
value: &amp;#34;bigred&amp;#34;
- name: POSTGRES_PASSWORD
value: &amp;#34;bigred&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;建立並測試 PostgreSQL Pod&lt;span class="hx:absolute hx:-mt-20" id="建立並測試-postgresql-pod"&gt;&lt;/span&gt;
&lt;a href="#%e5%bb%ba%e7%ab%8b%e4%b8%a6%e6%b8%ac%e8%a9%a6-postgresql-pod" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo podman play kube ~/backstage/podman-pod/postgres.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;檢視 Pod 運作狀態&lt;span class="hx:absolute hx:-mt-20" id="檢視-pod-運作狀態"&gt;&lt;/span&gt;
&lt;a href="#%e6%aa%a2%e8%a6%96-pod-%e9%81%8b%e4%bd%9c%e7%8b%80%e6%85%8b" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo podman ps -a --pod&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;螢幕輸出 :&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD ID PODNAME
6572b0f07e57 localhost/podman-pause:4.5.1-1691040180 19 seconds ago Up 8 seconds 0.0.0.0:5432-&amp;gt;5432/tcp ed1a0e48edbc-infra ed1a0e48edbc postgres
8d79400d332e docker.io/library/postgres:13.2-alpine postgres 8 seconds ago Up 8 seconds 0.0.0.0:5432-&amp;gt;5432/tcp postgres-postgres ed1a0e48edbc postgres&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;使用 bigred 帳號登入測試 PostgreSQL&lt;span class="hx:absolute hx:-mt-20" id="使用-bigred-帳號登入測試-postgresql"&gt;&lt;/span&gt;
&lt;a href="#%e4%bd%bf%e7%94%a8-bigred-%e5%b8%b3%e8%99%9f%e7%99%bb%e5%85%a5%e6%b8%ac%e8%a9%a6-postgresql" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo podman exec -it postgres-postgres bash
bash-5.1# psql -U $POSTGRES_USER&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;螢幕輸出 :&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;psql (13.2)
Type &amp;#34;help&amp;#34; for help.
bigred=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------&amp;#43;--------&amp;#43;----------&amp;#43;------------&amp;#43;------------&amp;#43;-------------------
bigred | bigred | UTF8 | en_US.utf8 | en_US.utf8 |
postgres | bigred | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | bigred | UTF8 | en_US.utf8 | en_US.utf8 | =c/bigred &amp;#43;
| | | | | bigred=CTc/bigred
template1 | bigred | UTF8 | en_US.utf8 | en_US.utf8 | =c/bigred &amp;#43;
| | | | | bigred=CTc/bigred
(4 rows)
bigred=# exit
bash-5.1# exit
exit&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;Podman Pod Install and configure backstage&lt;/h1&gt;&lt;h2&gt;撰寫 Backstage-Base Dockerfile&lt;span class="hx:absolute hx:-mt-20" id="撰寫-backstage-base-dockerfile"&gt;&lt;/span&gt;
&lt;a href="#%e6%92%b0%e5%af%ab-backstage-base-dockerfile" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano ~/backstage/build-image/Dockerfile&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檔案內容如下&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;FROM quay.io/hahappyman/alpine:3.18.3
RUN apk update; apk add -U --update nodejs npm bash git curl python3 make g&amp;#43;&amp;#43; grep nano sudo
RUN npm install --global yarn
RUN echo backstage | npx -y @backstage/create-app@latest
CMD [&amp;#34;bash&amp;#34;,&amp;#34;-c&amp;#34;,&amp;#34;sleep infinity&amp;#34;]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;Build Image&lt;span class="hx:absolute hx:-mt-20" id="build-image"&gt;&lt;/span&gt;
&lt;a href="#build-image" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo podman build --no-cache -t backstage:test-v3 ~/backstage/build-image/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;撰寫 Pod Yaml 檔&lt;span class="hx:absolute hx:-mt-20" id="撰寫-pod-yaml-檔"&gt;&lt;/span&gt;
&lt;a href="#%e6%92%b0%e5%af%ab-pod-yaml-%e6%aa%94" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano ~/backstage/podman-pod/backstage.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檔案內容如下&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
name: backstage
spec:
hostNetwork: true
containers:
- name: backstage
image: localhost/backstage:test-v3&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;建立 Pod&lt;span class="hx:absolute hx:-mt-20" id="建立-pod"&gt;&lt;/span&gt;
&lt;a href="#%e5%bb%ba%e7%ab%8b-pod" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo podman play kube ~/backstage/podman-pod/backstage.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;檢視 Pod 運作狀態&lt;span class="hx:absolute hx:-mt-20" id="檢視-pod-運作狀態-1"&gt;&lt;/span&gt;
&lt;a href="#%e6%aa%a2%e8%a6%96-pod-%e9%81%8b%e4%bd%9c%e7%8b%80%e6%85%8b-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo podman ps -a --pod&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;螢幕輸出&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD ID PODNAME
5c988d43542e localhost/podman-pause:4.5.1-1691040180 18 minutes ago Up 18 minutes 0.0.0.0:5432-&amp;gt;5432/tcp a04d6f726984-infra a04d6f726984 postgres
6b82228580d5 docker.io/library/postgres:13.2-alpine postgres 18 minutes ago Up 18 minutes 0.0.0.0:5432-&amp;gt;5432/tcp postgres-postgres a04d6f726984 postgres
b7446c631837 localhost/podman-pause:4.5.1-1691040180 13 minutes ago Up 13 minutes e16d6198a544-infra e16d6198a544 backstage
56c72ba57f21 localhost/backstage:test-v3 bash -c sleep inf... 13 minutes ago Up 13 minutes backstage-backstage e16d6198a544 backstage&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;設定 Backstage&lt;span class="hx:absolute hx:-mt-20" id="設定-backstage"&gt;&lt;/span&gt;
&lt;a href="#%e8%a8%ad%e5%ae%9a-backstage" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo podman exec -it backstage-backstage bash
backstage:/# cd backstage &amp;amp;&amp;amp; nano -l app-config.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;app-config.yaml 要修改的檔案內容如下&lt;span class="hx:absolute hx:-mt-20" id="app-configyaml-要修改的檔案內容如下"&gt;&lt;/span&gt;
&lt;a href="#app-configyaml-%e8%a6%81%e4%bf%ae%e6%94%b9%e7%9a%84%e6%aa%94%e6%a1%88%e5%85%a7%e5%ae%b9%e5%a6%82%e4%b8%8b" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;## Setup IP Address and organization.Name
1 app:
2 title: Scaffolded Backstage App
3 baseUrl: http://192.168.61.4:3000
...
5 organization:
6 name: Bobo_backstage
...
8 backend:
15 baseUrl: http://192.168.61.4:7007
24 cors:
25 origin: http://192.168.61.4:3000
...
## Setting Up PostgreSQL
30 database:
31 client: pg
32 connection:
33 host: 192.168.61.4
34 port: 5432
35 user: bigred
36 password: bigred
...
## Setting up a GitHub Integration
42 integrations:
43 github:
44 - host: github.com
47 token: XXX
...
## 待確認
76 scaffolder:
77 github:
78 token: XXX&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;app-config.production.yaml 要修改的檔案內容如下&lt;span class="hx:absolute hx:-mt-20" id="app-configproductionyaml-要修改的檔案內容如下"&gt;&lt;/span&gt;
&lt;a href="#app-configproductionyaml-%e8%a6%81%e4%bf%ae%e6%94%b9%e7%9a%84%e6%aa%94%e6%a1%88%e5%85%a7%e5%ae%b9%e5%a6%82%e4%b8%8b" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano -l app-config.production.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;## Setup IP Address and organization.Name
1 app:
2 # Should be the same as backend.baseUrl when using the `app-backend` plugin.
3 baseUrl: http://192.168.61.4:7007
...
5 backend:
11 baseUrl: http://192.168.61.4:7007
...
## Setting Up PostgreSQL
17 database:
18 client: pg
19 connection:
20 host: 192.168.61.4
21 port: 5432
22 user: bigred
23 password: bigred&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;進入工作目錄並初始化 git&lt;span class="hx:absolute hx:-mt-20" id="進入工作目錄並初始化-git"&gt;&lt;/span&gt;
&lt;a href="#%e9%80%b2%e5%85%a5%e5%b7%a5%e4%bd%9c%e7%9b%ae%e9%8c%84%e4%b8%a6%e5%88%9d%e5%a7%8b%e5%8c%96-git" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;backstage:/backstage# git init&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;設置 git 使用者資訊&lt;span class="hx:absolute hx:-mt-20" id="設置-git-使用者資訊"&gt;&lt;/span&gt;
&lt;a href="#%e8%a8%ad%e7%bd%ae-git-%e4%bd%bf%e7%94%a8%e8%80%85%e8%b3%87%e8%a8%8a" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;backstage:/backstage# git config --global user.email &amp;#34;test@backstage.com&amp;#34;
backstage:/backstage# git config --global user.name &amp;#34;root&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;將工作目錄追加至 git stage&lt;span class="hx:absolute hx:-mt-20" id="將工作目錄追加至-git-stage"&gt;&lt;/span&gt;
&lt;a href="#%e5%b0%87%e5%b7%a5%e4%bd%9c%e7%9b%ae%e9%8c%84%e8%bf%bd%e5%8a%a0%e8%87%b3-git-stage" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;backstage:/backstage# git add .&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;進行初次 git commit&lt;span class="hx:absolute hx:-mt-20" id="進行初次-git-commit"&gt;&lt;/span&gt;
&lt;a href="#%e9%80%b2%e8%a1%8c%e5%88%9d%e6%ac%a1-git-commit" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;backstage:/backstage# git commit -m &amp;#34;Initial commit&amp;#34; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;安裝相依檔案&lt;span class="hx:absolute hx:-mt-20" id="安裝相依檔案"&gt;&lt;/span&gt;
&lt;a href="#%e5%ae%89%e8%a3%9d%e7%9b%b8%e4%be%9d%e6%aa%94%e6%a1%88" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;backstage:/backstage# yarn install&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;部屬 Backstage&lt;span class="hx:absolute hx:-mt-20" id="部屬-backstage"&gt;&lt;/span&gt;
&lt;a href="#%e9%83%a8%e5%b1%ac-backstage" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="indent-title-1"&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;backstage:/backstage# yarn dev &amp;amp;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4&gt;打開瀏覽器，連線至 &lt;code&gt;http://Podman_Host_主機_IP:3000&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="打開瀏覽器連線至-httppodman_host_主機_ip3000"&gt;&lt;/span&gt;
&lt;a href="#%e6%89%93%e9%96%8b%e7%80%8f%e8%a6%bd%e5%99%a8%e9%80%a3%e7%b7%9a%e8%87%b3-httppodman_host_%e4%b8%bb%e6%a9%9f_ip3000" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h4&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;&lt;img src="https://blog.kubeantony.com/images/hackmd-uploads/SJVn41pR3.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h1&gt;DropBox&lt;/h1&gt;&lt;h2&gt;What is Backstage?&lt;span class="hx:absolute hx:-mt-20" id="what-is-backstage-1"&gt;&lt;/span&gt;
&lt;a href="#what-is-backstage-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Backstage 是 Spotify 開發的開源、可自訂的 IDP 工具，目前由 CNCF 維護&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;戰略目標：
&lt;ul&gt;
&lt;li&gt;透過統一介面，提供團隊一致的開發環境。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;詳細描述：
&lt;ul&gt;
&lt;li&gt;Backstage 實現在統一的介面，進行開發與資源管理，免去跨工具的資訊統合問題，更有效率的開發與管理應用系統，使團隊成員更能掌握目前的開發狀態。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Backstage 核心組件&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TechDocs&lt;/li&gt;
&lt;li&gt;Softwre Catalog&lt;/li&gt;
&lt;li&gt;Softwre Templates&lt;/li&gt;
&lt;li&gt;Search&lt;/li&gt;
&lt;li&gt;Plugin&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What is IDP?&lt;span class="hx:absolute hx:-mt-20" id="what-is-idp"&gt;&lt;/span&gt;
&lt;a href="#what-is-idp" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;IDP｜Internal Developer Platform企業為內部開發人員提供的一個平台，用於開發、部署和運營應用系統。幫助開發人員提高生產力、降低成本，並改善應用系統的品質。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IDP 工具的核心關鍵&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提供效益
&lt;ul&gt;
&lt;li&gt;提高生產力｜自動化開發和部署流程，提高開發人員生產力&lt;/li&gt;
&lt;li&gt;降低成本｜減少人工成本，並提高資源利用率&lt;/li&gt;
&lt;li&gt;改善品質｜確保應用程式的品質和可靠性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;應用工具
&lt;ul&gt;
&lt;li&gt;開發工具｜提供 IDE、編輯器、測試工具等開發工具，幫助開發人員快速有效地開發應用程式&lt;/li&gt;
&lt;li&gt;部署工具｜提供 CI/CD 工具、容器化工具等部署工具，幫助開發人員將應用程式部署到生產環境&lt;/li&gt;
&lt;li&gt;運營工具｜提供監控工具、報表工具等運營工具，幫助開發人員管理和監控應用程式的運行狀態&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;本機部署流程&lt;span class="hx:absolute hx:-mt-20" id="本機部署流程"&gt;&lt;/span&gt;
&lt;a href="#%e6%9c%ac%e6%a9%9f%e9%83%a8%e7%bd%b2%e6%b5%81%e7%a8%8b" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;Ubuntu
流程：nodejs &amp;raquo; 相依套件 &amp;raquo; git 初始化 &amp;amp; first commit &amp;raquo; yarn 相依檔案安裝與部署&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#更新套件清單
sudo apt update
#安裝相依套件
sudo apt install make python3 g&amp;#43;&amp;#43; build-essential git-all
#安裝 nvm
curl -so - https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
#確認 nvm 版本
nvm -v
0.39.5
#使用 nvm 安裝指定版本 nodejs（LTS）
nvm install v18.17.1
Downloading and installing node v18.17.1...
Downloading https://nodejs.org/dist/v18.17.1/node-v18.17.1-linux-x64.tar.xz...
############################################################################################################################################################################# 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v18.17.1 (npm v9.6.7)
Creating default alias: default -&amp;gt; 18.17.1 (-&amp;gt; v18.17.1)
#指定使用 nodejs 版本
nvm use v18.17.1
Now using node v18.17.1 (npm v9.6.7)
#安裝 yarn
npm install yarn
## Ub Server 22.04 安裝 yarn
npm install --global yarn&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#安裝 backstage
npx @backstage/create-app@latest
...
🥇 Successfully created backstage
All set! Now you might want to:
Install the dependencies: cd backstage &amp;amp;&amp;amp; yarn install
Run the app: cd backstage &amp;amp;&amp;amp; yarn dev
Set up the software catalog: https://backstage.io/docs/features/software-catalog/configuration
Add authentication: https://backstage.io/docs/auth/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#進入工作目錄並初始化 git
cd backstage &amp;amp;&amp;amp; git init
#設置 git 使用者資訊
git config --global user.email &amp;#34;test@backstage.com&amp;#34;
git config --global user.name &amp;#34;backstage&amp;#34;
#將工作目錄追加至 git stage
git add .
#進行初次 git commit
git commit -m &amp;#34;Initial commit&amp;#34;
#使用 yarn 安裝相依檔案
yarn install
#使用 yarn 部署 backstage
yarn dev
yarn run v1.22.19
$ concurrently &amp;#34;yarn start&amp;#34; &amp;#34;yarn start-backend&amp;#34;
$ yarn workspace backend start
$ yarn workspace app start
$ backstage-cli package start
$ backstage-cli package start
[1] Build succeeded
[0] Loaded config from app-config.yaml
[0] &amp;lt;i&amp;gt; [webpack-dev-server] Project is running at:
[0] &amp;lt;i&amp;gt; [webpack-dev-server] On Your Network (IPv4): http://192.168.115.80:3000/
[0] &amp;lt;i&amp;gt; [webpack-dev-server] Content not from webpack is served from &amp;#39;/home/bigred/backstage/packages/app/public&amp;#39; directory
[0] &amp;lt;i&amp;gt; [webpack-dev-server] 404s will fallback to &amp;#39;/index.html&amp;#39;
[1] Loaded config from app-config.yaml
[1] 2023-09-11T17:56:52.343Z backstage info Found 2 new secrets in config that will be redacted
[1] 2023-09-11T17:56:52.358Z backstage info Created UrlReader predicateMux{readers=azure{host=dev.azure.com,authed=false},bitbucketCloud{host=bitbucket.org,authed=false},github{host=github.com,authed=false},gitlab{host=gitlab.com,authed=false},awsS3{host=amazonaws.com,authed=false},fetch{}
[1] 2023-09-11T17:56:52.399Z catalog info Performing database migration type=plugin
[1] 2023-09-11T17:56:52.991Z auth info Configuring &amp;#34;database&amp;#34; as KeyStore provider type=plugin
[1] 2023-09-11T17:56:53.009Z techdocs info Creating Local publisher for TechDocs type=plugin
[1] 2023-09-11T17:56:53.015Z search info Added DefaultCatalogCollatorFactory collator factory for type software-catalog type=plugin
[1] 2023-09-11T17:56:53.016Z search info Added DefaultTechDocsCollatorFactory collator factory for type techdocs type=plugin
[1] 2023-09-11T17:56:53.017Z search info Starting all scheduled search tasks. type=plugin
[1] 2023-09-11T17:56:53.193Z backstage info Listening on :7007
[1] 2023-09-11T17:56:53.211Z backstage info Task worker starting: search_index_software_catalog, {&amp;#34;version&amp;#34;:2,&amp;#34;cadence&amp;#34;:&amp;#34;PT10M&amp;#34;,&amp;#34;initialDelayDuration&amp;#34;:&amp;#34;PT3S&amp;#34;,&amp;#34;timeoutAfterDuration&amp;#34;:&amp;#34;PT15M&amp;#34;} type=taskManager task=search_index_software_catalog
[1] 2023-09-11T17:56:53.213Z backstage info Task worker starting: search_index_techdocs, {&amp;#34;version&amp;#34;:2,&amp;#34;cadence&amp;#34;:&amp;#34;PT10M&amp;#34;,&amp;#34;initialDelayDuration&amp;#34;:&amp;#34;PT3S&amp;#34;,&amp;#34;timeoutAfterDuration&amp;#34;:&amp;#34;PT15M&amp;#34;} type=taskManager task=search_index_techdocs
[0] &amp;lt;i&amp;gt; [webpack-dev-middleware] wait until bundle finished: /
[0] &amp;lt;i&amp;gt; [webpack-dev-middleware] wait until bundle finished: /apple-touch-icon-precomposed.png
[0] &amp;lt;i&amp;gt; [webpack-dev-middleware] wait until bundle finished: /apple-touch-icon.png
[0] &amp;lt;i&amp;gt; [webpack-dev-middleware] wait until bundle finished: /favicon.ico
[0] &amp;lt;i&amp;gt; [webpack-dev-middleware] wait until bundle finished: /apple-touch-icon-precomposed.png
[0] &amp;lt;i&amp;gt; [webpack-dev-middleware] wait until bundle finished: /
[0] &amp;lt;i&amp;gt; [webpack-dev-middleware] wait until bundle finished: /favicon.ico
[0] &amp;lt;i&amp;gt; [webpack-dev-middleware] wait until bundle finished: /apple-touch-icon.png
[1] 2023-09-11T17:56:56.218Z search info Collating documents for software-catalog via DefaultCatalogCollatorFactory type=plugin documentType=software-catalog
[1] 2023-09-11T17:56:56.247Z search info Collating documents for techdocs via DefaultTechDocsCollatorFactory type=plugin documentType=techdocs
[1] 2023-09-11T17:56:56.331Z backstage info ::ffff:127.0.0.1 - - [11/Sep/2023:17:56:56 &amp;#43;0000] &amp;#34;GET /api/catalog/entities?filter=metadata.annotations.backstage.io%2Ftechdocs-ref&amp;amp;fields=kind,namespace,metadata.annotations,metadata.name,metadata.title,metadata.namespace,spec.type,spec.lifecycle,relations&amp;amp;offset=0&amp;amp;limit=500 HTTP/1.1&amp;#34; 200 2 &amp;#34;-&amp;#34; &amp;#34;node-fetch/1.0 (&amp;#43;https://github.com/bitinn/node-fetch)&amp;#34; type=incomingRequest
[1] 2023-09-11T17:56:56.344Z search warn Index for techdocs was not created: indexer received 0 documents type=plugin documentType=techdocs
[1] 2023-09-11T17:56:56.347Z search info Collating documents for techdocs succeeded type=plugin documentType=techdocs
[1] 2023-09-11T17:56:56.353Z backstage info ::ffff:127.0.0.1 - - [11/Sep/2023:17:56:56 &amp;#43;0000] &amp;#34;GET /api/catalog/entities?offset=0&amp;amp;limit=500 HTTP/1.1&amp;#34; 200 - &amp;#34;-&amp;#34; &amp;#34;node-fetch/1.0 (&amp;#43;https://github.com/bitinn/node-fetch)&amp;#34; type=incomingRequest
[1] 2023-09-11T17:56:56.382Z search info Collating documents for software-catalog succeeded type=plugin documentType=software-catalog
[0] webpack compiled successfully
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Backstage OverView</title><link>https://blog.kubeantony.com/archive/ops-automation/backstage-overview/</link><pubDate>Sat, 23 Sep 2023 06:46:00 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/backstage-overview/</guid><description>
&lt;style&gt;
.indent-title-1{
margin-left: 1em;
}
.indent-title-2{
margin-left: 2em;
}
.indent-title-3{
margin-left: 3em;
}
&lt;/style&gt;
&lt;h2&gt;Preface&lt;span class="hx:absolute hx:-mt-20" id="preface"&gt;&lt;/span&gt;
&lt;a href="#preface" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="indent-title-1"&gt;
&lt;p&gt;本篇文章會主要會分做 3 個部分介紹&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;甚麼是 Backstage&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;可以透過點擊展開以下目錄，選擇想看的內容，跳轉至特定章節&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Backstage Instance&lt;span class="hx:absolute hx:-mt-20" id="backstage-instance"&gt;&lt;/span&gt;
&lt;a href="#backstage-instance" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Backstage 實例是使用 Backstage 核心庫建立的 Node/React 應用程序，您可以在其上安裝社群和私人插件。&lt;/p&gt;
&lt;p&gt;Backstage 使用三層模型來解釋如何使用其框架建立開發人員入口網站 :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://hackmd.io/_uploads/HysgbJok6.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Core
這是 Backstage 團隊維護和以開源方式發布的內容。除非您想為該專案做出貢獻，否則您可能不需要從一開始就了解這部分。&lt;/li&gt;
&lt;li&gt;App
該應用程式是您提供給開發人員的 Developer Portal ( 開發人員入口網站 )。 在採用 Backstage 的過程中，您將與此部分進行最多的互動。&lt;/li&gt;
&lt;li&gt;Plugins
您可以安裝 Plugins 來擴展您的實例功能。即使是基本的功能也被抽象為 Plugins ，包括 Catalog。因此，您將始終使用少量的 Plugins 。有幾十個社群 Plugins 可用來整合流行的服務。您也可以自己創建 Plugins 。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;backstage core functionalities&lt;span class="hx:absolute hx:-mt-20" id="backstage-core-functionalities"&gt;&lt;/span&gt;
&lt;a href="#backstage-core-functionalities" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Backstage offers five core functionalities:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;a software catalog&lt;/li&gt;
&lt;li&gt;software templates&lt;/li&gt;
&lt;li&gt;a documentation generator&lt;/li&gt;
&lt;li&gt;a Kubernetes cluster visualizer&lt;/li&gt;
&lt;li&gt;cross-ecosystem search capabilities.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Introducing the Software Catalog&lt;span class="hx:absolute hx:-mt-20" id="introducing-the-software-catalog"&gt;&lt;/span&gt;
&lt;a href="#introducing-the-software-catalog" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Catalog 的目的是將企業中的所有應用系統，包括網站、API、程式庫和資源，映射到一個集中式目錄。這種集中化旨在幫助團隊管理技術並實現可發現性。Catalog 能持續追蹤每個 Application 的 metadata ( 元數據 )、所有權和依賴關係，從而生成一個軟體圖，其中包含孤立的 entities。&lt;/p&gt;
&lt;p&gt;Catalog 非常靈活，可以容納各種 Application，在 Backstage 中稱為 entities。 由於網站與資料處理管道截然不同，因此 entities 可以按 &lt;em&gt;Kind&lt;/em&gt; 種類區分。此外，即使在 entities 的種類中，也可以定義 &lt;em&gt;Kind&lt;/em&gt;。&lt;/p&gt;
&lt;p&gt;Catalog 由儲存在 YAML 檔案中的 metadata 提供支持，YAML 檔案描述了每個檔案中單一 entitiy 的種類、類型、名稱、所有者和更多細節。 這些檔案通常儲存在各自的程式碼庫中，因此會經常更新。 有些 entities 類型可能有權威來源，但程式庫中沒有體現，例如，Okta 規定的使用者和團隊。&lt;/p&gt;
&lt;p&gt;追蹤所有權和依賴關係是 Catalog 最重要的用例之一。 這些也在描述軟體元件的 YAML 檔案中聲明。 只有一個團隊可以成為元件的擁有者，這個團隊也必須作為一個 entities 在 Catalog 中註冊。 至於依賴關係，Backstage 可以讓你定義元件如何依賴另一個 entities ，以及元件暴露了哪些內容，以便其他人可以使用它。&lt;/p&gt;
&lt;p&gt;根據這些 metadata 繪製的軟體圖可以發現一些問題，例如孤兒 entities ，這意味著它們沒有父 entities 。 此外，由於 Catalog 中存儲了有關所有軟體資產的大量信息，因此您還可以從中了解成熟度準備情況或安全警告等信息。&lt;/p&gt;
&lt;h3&gt;Introducing the Software Template&lt;span class="hx:absolute hx:-mt-20" id="introducing-the-software-template"&gt;&lt;/span&gt;
&lt;a href="#introducing-the-software-template" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Backstage 中的 Software Template 軟體範本是一種工具，可幫助您在 Backstage 中建立元件。預設情況下，它可以加載程式碼的骨架，將範本包含在某些變數中，然後將範本發佈到 GitHub 或 GitLab 等位置。&lt;/p&gt;
&lt;p&gt;Software Template 在 YAML 檔案中定義，該檔案指定要執行的參數和步驟。Backstage 將根據在 Software Template 中指定的參數，在 Scaffolder 中生成 UI。對於步驟，您可以使用內建動作來執行常見的取用操作，但您也可以定義自己的動作。&lt;/p&gt;
&lt;p&gt;範本存儲在 Catalog 中的 template 種類下。此外，由 Scaffolder 初始化的所有元件都會自動添加到 Catalog 中。因此，Scaffolder 和 Catalog 之間有一個良性循環，可以促進可發現性和標準化。&lt;/p&gt;</description></item><item><title>bash script 筆記</title><link>https://blog.kubeantony.com/archive/ops-automation/bash-script-%E7%AD%86%E8%A8%98/</link><pubDate>Thu, 20 Jul 2023 07:40:42 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/bash-script-%E7%AD%86%E8%A8%98/</guid><description>
&lt;h1&gt;初學&lt;/h1&gt;&lt;h2&gt;bash script 開始下達指令&lt;span class="hx:absolute hx:-mt-20" id="bash-script-開始下達指令"&gt;&lt;/span&gt;
&lt;a href="#bash-script-%e9%96%8b%e5%a7%8b%e4%b8%8b%e9%81%94%e6%8c%87%e4%bb%a4" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;bigred@m1:~$ command [-option] parameter1 parameter2
指令 選項 參數1 參數2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;上述指令詳細說明如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;一行指令中第一個輸入的部分絕對是『指令(command)』或『可執行檔案(例如批次腳本,script)』&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;command 為指令的名稱，例如變換工作目錄的指令為 cd 等等；&lt;/li&gt;
&lt;li&gt;中刮號[]並不存在於實際的指令中，而加入選項設定時，通常選項前會帶 - 號，例如 -h；有時候會使用選項的完整全名，則選項前帶有 &amp;ndash; 符號，例如 &amp;ndash;help；&lt;/li&gt;
&lt;li&gt;parameter1 parameter2.. 為依附在選項後面的參數，或者是 command 的參數；&lt;/li&gt;
&lt;li&gt;指令, 選項, 參數等這幾個咚咚中間以空格來區分，&lt;strong&gt;不論空幾格 shell 都視為一格&lt;/strong&gt;。&lt;strong&gt;所以空格是很重要的特殊字元！&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;按下[Enter]按鍵後，該指令就立即執行。&lt;strong&gt;[Enter]按鍵代表著一行指令的開始啟動&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;指令太長的時候，可以使用反斜線 () 來跳脫[Enter]符號，使指令連續到下一行。注意！反斜線後就立刻接特殊字符，才能跳脫！&lt;/li&gt;
&lt;li&gt;其他：
&lt;ul&gt;
&lt;li&gt;在 Linux 系統中，&lt;strong&gt;英文大小寫字母是不一樣的&lt;/strong&gt;。舉例來說， cd 與 CD 並不同。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;查看環境變數 PATH&lt;span class="hx:absolute hx:-mt-20" id="查看環境變數-path"&gt;&lt;/span&gt;
&lt;a href="#%e6%9f%a5%e7%9c%8b%e7%92%b0%e5%a2%83%e8%ae%8a%e6%95%b8-path" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;echo $PATH&lt;/code&gt; ➡️ linux 輸入法&lt;/li&gt;
&lt;li&gt;&lt;code&gt;echo %PATH%&lt;/code&gt; ➡️ windows 輸入法&lt;/li&gt;
&lt;li&gt;環境變數PATH：
&lt;ul&gt;
&lt;li&gt;記錄所有可執行命令所在的目錄路徑，因此若命令的儲存路徑沒有記錄在PATH中，則無法執行。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$PATH&lt;/code&gt; 告知 OS 哪裡會存放可執行的檔案，會依照先後順序找檔名，並且執行。若要執行的檔案不放在 $PATH 的目錄裡的話則需要使用相對/絕對路徑來執行&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Linux重要的幾個熱鍵&lt;span class="hx:absolute hx:-mt-20" id="linux重要的幾個熱鍵"&gt;&lt;/span&gt;
&lt;a href="#linux%e9%87%8d%e8%a6%81%e7%9a%84%e5%b9%be%e5%80%8b%e7%86%b1%e9%8d%b5" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;h3&gt;[Tab]按鍵&lt;span class="hx:absolute hx:-mt-20" id="tab按鍵"&gt;&lt;/span&gt;
&lt;a href="#tab%e6%8c%89%e9%8d%b5" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;[Tab]按鍵算是Linux的Bash shell最棒的功能之一了！他具有『命令補全』與『檔案補齊』的功能喔！ 重點是，可以避免我們打錯指令或檔案名稱呢！很棒吧！但是[Tab]按鍵在不同的地方輸入，會有不一樣的結果喔！ 我們舉下面的例子來說明。上一小節我們不是提到 cal 這個指令嗎？如果我在指令列輸入 ca 再按兩次 [tab] 按鍵， 會出現什麼訊息？&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;bigred@m1:~$ ca[tab][tab] &amp;lt;==[tab]按鍵是緊接在 a 字母後面！
cal caller capsh case cat
# 上面的 [tab] 指的是『按下那個tab鍵』，不是輸入中括號內的tab&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;以ca為開頭的指令都被顯示出來了，如果輸入『ls -al ~/.bash』再加兩個[tab]會出現什麼？&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;[ dmtsai@study ~]$ ls -al ~/.bash[tab][tab]
.bash_history .bash_logout .bash_profile .bashrc&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;該目錄下面所有以 .bash 為開頭的檔案名稱都會被顯示出來了，我們按[tab]按鍵的地方如果是在command(第一個輸入的資料)後面時，他就代表著 『命令補全』，如果是接在第二個字以後的，就會變成『檔案補齊』的功能！但是在某些特殊的指令底下，檔案補齊的功能可能會變成『參數/選項補齊』！ 我們同樣使用 date 這個指令來查一下：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;[dmtsai@study ~]$ date --[tab][tab] &amp;lt;==[tab]按鍵是緊接在 -- 後面！
--date --help --reference= --rfc-3339= --universal
--date= --iso-8601 --rfc-2822 --set= --version
# 系統會列出來 date 這個指令可以使用的選項有哪些喔～包括未來會用到的 --date 等項目&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;總結:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[Tab] 接在一串指令的第一個字的後面，則為『命令補全』&lt;/li&gt;
&lt;li&gt;[Tab] 接在一串指令的第二個字以後時，則為『檔案補齊』&lt;/li&gt;
&lt;li&gt;若安裝 bash-completion 軟體，則在某些指令後面使用 [tab] 按鍵時，可以進行『選項/參數的補齊』功能
&lt;strong&gt;善用 [tab] 按鍵真的是個很好的習慣！可以避免掉很多輸入錯誤的機會！&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;[Ctrl]-c 按鍵&lt;span class="hx:absolute hx:-mt-20" id="ctrl-c-按鍵"&gt;&lt;/span&gt;
&lt;a href="#ctrl-c-%e6%8c%89%e9%8d%b5" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;如果你在Linux底下輸入了錯誤的指令或參數，有的時候這個指令或程式會在系統底下『跑不停』這個時候怎麼辦？別擔心， 如果你想讓當前的程式『停掉』的話，可以輸入：[Ctrl]與c按鍵(先按著[Ctrl]不放，且再按下c按鍵，是組合按鍵)， 那就是中斷目前程式的按鍵！舉例來說，如果你輸入了『find /』這個指令時，系統會開始跑一些東西(先不要理會這個指令串的意義)，此時你給他按下 [Ctrl]-c 組合按鍵，嘿嘿！是否立刻發現這個指令串被終止&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;[bigred@m1 ~]$ find /
....(一堆東西都省略)....
# 此時螢幕會很花，你看不到命令提示字元的！直接按下[ctrl]-c即可！
[bigred@m1 ~]$ &amp;lt;==此時提示字元就會回來了！find程式就被中斷！&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;[Ctrl]-e 按鍵&lt;span class="hx:absolute hx:-mt-20" id="ctrl-e-按鍵"&gt;&lt;/span&gt;
&lt;a href="#ctrl-e-%e6%8c%89%e9%8d%b5" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;游標 (cursor) 移到行首&lt;/p&gt;
&lt;h3&gt;[Ctrl]-a 按鍵&lt;span class="hx:absolute hx:-mt-20" id="ctrl-a-按鍵"&gt;&lt;/span&gt;
&lt;a href="#ctrl-a-%e6%8c%89%e9%8d%b5" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;游標 (cursor) 移到行尾&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Linux文書編輯器： &lt;code&gt;nano&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="linux文書編輯器-nano"&gt;&lt;/span&gt;
&lt;a href="#linux%e6%96%87%e6%9b%b8%e7%b7%a8%e8%bc%af%e5%99%a8-nano" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;nano的使用，可以直接加上檔名就能夠開啟一個舊檔或新檔&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;[dmtsai@study ~]$ nano text.txt
# 不管text.txt存不存在都沒有關係！存在就開啟舊檔，不存在就開啟新檔
GNU nano 2.3.1 File: text.txt
&amp;lt;==這個是游標所在處
[ New File ]
^G Get Help ^O WriteOut ^R Read File ^Y Prev Page ^K Cut Text ^C Cur Pos
^X Exit ^J Justify ^W Where Is ^V Next Page ^U UnCut Te ^T To Spell
# 上面兩行是指令說明列，其中^代表的是[ctrl]的意思&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;如上所示，可以看到第一行反白的部分，那僅是在宣告nano的版本與檔名(File: text.txt)而已。 之後你會看到最底下的三行，分別是檔案的狀態(New File)與兩行指令說明列。指令說明列反白的部分就是組合鍵， 接的則是該組合鍵的功能。那個指數符號(^)代表的是鍵盤的[Ctrl]按鍵啦！底下先來說說比較重要的幾個組合按鍵：&lt;/p&gt;
&lt;p&gt;[ctrl]-G：取得線上說明(help)
[ctrl]-X：離開nano軟體，若有修改過檔案會提示是否需要儲存
[ctrl]-O：儲存檔案，若有權限的話就能夠儲存檔案了
[ctrl]-R：從其他檔案讀入資料，可以將某個檔案的內容貼在本檔案中
[ctrl]-W：搜尋字串
[ctrl]-C：說明目前游標所在處的行數與列數等資訊
&lt;del&gt;[ctrl]-_：可以直接輸入行號，讓游標快速移動到該行；&lt;/del&gt; #m1沒有
&lt;del&gt;[alt]-Y：校正語法功能開啟或關閉(按一下開、再按一下關)&lt;/del&gt; #m1沒有
&lt;del&gt;[alt]-M：可以支援滑鼠來移動游標的功能&lt;/del&gt; #m1沒有&lt;/p&gt;
&lt;h2&gt;以上資料參考自&lt;a
href="https://linux.vbird.org/linux_basic/centos7/0160startlinux.php"target="_blank" rel="noopener"&gt;鳥哥的私房菜第四篇&lt;/a&gt;&lt;span class="hx:absolute hx:-mt-20" id="以上資料參考自鳥哥的私房菜第四篇"&gt;&lt;/span&gt;
&lt;a href="#%e4%bb%a5%e4%b8%8a%e8%b3%87%e6%96%99%e5%8f%83%e8%80%83%e8%87%aa%e9%b3%a5%e5%93%a5%e7%9a%84%e7%a7%81%e6%88%bf%e8%8f%9c%e7%ac%ac%e5%9b%9b%e7%af%87" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;hr&gt;
&lt;h2&gt;Linux查看記憶體指令—&lt;code&gt;free&lt;/code&gt;:&lt;span class="hx:absolute hx:-mt-20" id="linux查看記憶體指令free"&gt;&lt;/span&gt;
&lt;a href="#linux%e6%9f%a5%e7%9c%8b%e8%a8%98%e6%86%b6%e9%ab%94%e6%8c%87%e4%bb%a4free" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;顯示系統內部實體記憶體及Swap的使用情況，初步會以KB為單位
改進單位轉換成Bytes，MB和GB，分別是-b，-m和-g，加上 -t 參數，會顯示實體記憶體加上 Swap 的合共記憶體:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;g06220565@cloudshell:~ (peppy-amplifier-324003)$ free -g -t
total used free shared buff/cache available
Mem: 15 1 13 0 1 14
Swap: 0 0 0
Total: 15 1 13&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;加上 -s 參數會在特定秒數自動重新執行 free 指令, 例如下面會以 MB 為單位, 並會每 5 秒印出一次新資料:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;g06220565@cloudshell:~$ free -gt -s 5
total used free shared buff/cache available
Mem: 15 1 13 0 1 13
Swap: 0 0 0
Total: 15 1 13
total used free shared buff/cache available
Mem: 15 1 13 0 1 13
Swap: 0 0 0
Total: 15 1 13&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;要終止執行按 Ctrl + C 。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;mem：實體記憶體統計。
swap：硬碟上交換分割槽的使用情況。只有mem被當前程序實際佔用完,即沒有了buffers和cache時，才會使用到swap。&lt;/p&gt;
&lt;p&gt;mem 行（第一行）資料說明：
total：實體記憶體總大小。
used：總計分配給快取（包含buffers 與cache ）使用的數量，但其中可能部分快取並未實際使用。
free：未被分配的記憶體。
shared：共享記憶體，一般系統不會用到。
buffers(緩衝區)：系統分配但未被使用的buffers 數量。
cached(緩存)：系統分配但未被使用的cache 數量。&lt;/p&gt;
&lt;p&gt;補充:
緩衝區(buffers)是尚未被&amp;quot;寫入&amp;quot;磁盤的東西。
緩存(cached)是指已經從磁盤上&amp;quot;讀&amp;quot;出並存儲起來供以後使用的東西。&lt;/p&gt;
&lt;p&gt;更詳細的解釋參考：Difference Between Buffer and Cache&lt;/p&gt;
&lt;p&gt;Buffer：緩衝區，一個用於存儲速度不同步的設備或優先級不同的設備之間傳輸數據的區域。通過緩衝區，可以使進程之間的相互等待變少，從而使從速度慢的設備讀入數據時，速度快的設備的操作進程不發生間斷。&lt;/p&gt;
&lt;p&gt;Cache：高速緩存，是位於CPU與主記憶體間的一種容量較小但速度很高的記憶體。由於CPU的速度遠高於主記憶體，CPU直接從記憶體中存取數據要等待一定時間週期，Cache中保存著CPU剛用過或迴圈使用的一部分數據，當CPU再次使用該部分數據時可從Cache中直接調用,這樣就減少了CPU的等待時間,提高了系統的效率。Cache又分為一級Cache(L1 Cache)和二級Cache(L2 Cache)，L 1 C ache集成在CPU內部，L 2 C ache早期一般是焊在主板上,現在也都集成在CPU內部，常見的容量有256KB或512KB L2 Cache。&lt;/p&gt;
&lt;p&gt;Free中的buffer和cache（它們都是佔用記憶體）：
　　buffer : 作為buffer cache的記憶體，是塊設備的讀寫緩衝區
　　cache : 作為page cache的記憶體, 文件系統的cache&lt;/p&gt;
&lt;p&gt;　　如果 cache 的值很大，說明cache住的文件數很多。如果頻繁訪問到的文件都能被cache住，那麼磁片的讀IO bi會非常小。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;bash script 練習&lt;span class="hx:absolute hx:-mt-20" id="bash-script-練習"&gt;&lt;/span&gt;
&lt;a href="#bash-script-%e7%b7%b4%e7%bf%92" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;請撰寫 mysys 程式, 執行功能如下 :&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;$ ./mysys
./mysys [add|del|start|stop|list] object&lt;/p&gt;
&lt;p&gt;$ ./mysys add xx
add xx&lt;/p&gt;
&lt;p&gt;$ ./mysys start
start&lt;/p&gt;
&lt;p&gt;$ ./mysys test
./mysys [add|del|start|stop|list] object&lt;/p&gt;
&lt;p&gt;答案:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;g06220565@cloudshell:~$ nano mysys
#!/bin/bash
case $1 in
add)
echo $0
;;
del)
echo $@
;;
start)
echo $@
;;
stop)
echo $@
;;
list)
echo $@
;;
*)
echo &amp;#34;./nysys [add|del|start|stop|list] odject&amp;#34;
;;
esac
g06220565@cloudshell:~$ ./mysys ## &amp;#34;.&amp;#34;代表的是g06220565的家目錄&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;改裝&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
case $1 in
add)
echo -e &amp;#34;$2\n$2&amp;#34; | sudo adduser -s /bin/bash $2
;;
del)
sudo deluser --remove-home $2
;;
start)
echo &amp;#34;Oops&amp;#34;
;;
stop)
echo &amp;#34;Oops&amp;#34;
;;
list)
echo &amp;#34;Oops&amp;#34;
;;
*)
echo &amp;#34;./nysys [add|del|start|stop|list] odject&amp;#34;
;;
esac&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h1&gt;進階&lt;/h1&gt;&lt;h2&gt;sed ( stream editor )&lt;span class="hx:absolute hx:-mt-20" id="sed--stream-editor-"&gt;&lt;/span&gt;
&lt;a href="#sed--stream-editor-" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;取代檔案的特定行數內容&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sed -i &amp;#34;5cxxx&amp;#34; sigd.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;-i&lt;/code&gt; ，代表要對檔案進行修改
&lt;code&gt;5c&lt;/code&gt; ，第一個數字代表第幾行，後面的c，代表會直接將原本第五行的內容取代
&lt;code&gt;xxx&lt;/code&gt; ，代表要更改的字串
&lt;code&gt;sighd.sh&lt;/code&gt; ，要更改的檔案&lt;/p&gt;
&lt;p&gt;對檔案特定行數插入內容，如果該行有內容，會自動往下移一行，該行之後的內容也是&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sed -i &amp;#34;5ixxx&amp;#34; sigd.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;-i&lt;/code&gt; ，代表要對檔案進行修改
&lt;code&gt;5ixxx&lt;/code&gt; ，第一個數字是指定要第幾行，後面的&lt;code&gt;i&lt;/code&gt;則是會在第五行插入後面的xxx，如果原本的檔案第五行之後還有更多行內容，則全部往下移一行。&lt;/p&gt;
&lt;p&gt;&lt;a
href="https://terryl.in/zh/linux-sed-command/"target="_blank" rel="noopener"&gt;sed 參考文件 ( 初學 )&lt;/a&gt;
&lt;a
href="https://www.gnu.org/software/sed/manual/sed.html"target="_blank" rel="noopener"&gt;sed 參考文件 ( 原文 )&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;&lt;code&gt;sigh.sh&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="sighsh"&gt;&lt;/span&gt;
&lt;a href="#sighsh" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;功能：自動設定 ip , gateway , dns 的 ip 位址 （ Alpine Linux 版本 ）
使用：dns 的 ip 透過參數給定， ip 與 gateway 執行程式後再給&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
read -p &amp;#34;ip / gateway&amp;#34; ans1 ans2
sudo tee /etc/network/interfaces&amp;lt;&amp;lt;EOF
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address $ans1
gateway $ans2
EOF
if [ &amp;#34;$#&amp;#34; -ge &amp;#34;1&amp;#34; ];then
echo &amp;#34;&amp;#34; | sudo tee /etc/resolv.conf 1&amp;gt;/dev/null
echo &amp;#34;search localdomain&amp;#34; | sudo tee /etc/resolv.conf 1&amp;gt;/dev/null
no=0
for c in $@
do
abc[$no]=$c
no=$((no&amp;#43;1))
done
no=0
while((no&amp;lt;$#))
do
echo &amp;#34;nameserver ${abc[$no]}&amp;#34; | sudo tee -a /etc/resolv.conf
no=$((no&amp;#43;1))
done
else
echo &amp;#34;請給 DNS 的參數，謝謝！&amp;#34;
fi&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;變數處理&lt;span class="hx:absolute hx:-mt-20" id="變數處理"&gt;&lt;/span&gt;
&lt;a href="#%e8%ae%8a%e6%95%b8%e8%99%95%e7%90%86" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;name=&amp;#34;John&amp;#34;
echo ${name}
echo ${name/J/j} #=&amp;gt; &amp;#34;john&amp;#34; (substitution)
echo ${name:0:2} #=&amp;gt; &amp;#34;Jo&amp;#34; (slicing)
echo ${name::2} #=&amp;gt; &amp;#34;Jo&amp;#34; (slicing)
echo ${name::-1} #=&amp;gt; &amp;#34;Joh&amp;#34; (slicing)
echo ${name:(-1)} #=&amp;gt; &amp;#34;n&amp;#34; (slicing from right)
echo ${name:(-2):1} #=&amp;gt; &amp;#34;h&amp;#34; (slicing from right)
echo ${food:-Cake} #=&amp;gt; $food or &amp;#34;Cake&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;STR=&amp;#34;/path/to/foo.cpp&amp;#34;
echo ${STR%.cpp} # /path/to/foo
echo ${STR%.cpp}.o # /path/to/foo.o
echo ${STR%/*} # /path/to
echo ${STR##*.} # cpp (extension)
echo ${STR##*/} # foo.cpp (basepath)
echo ${STR#*/} # path/to/foo.cpp
echo ${STR##*/} # foo.cpp
echo ${STR/foo/bar} # /path/to/bar.cpp
STR=&amp;#34;Hello world&amp;#34;
echo ${STR:6:5} # &amp;#34;world&amp;#34;
echo ${STR: -5:5} # &amp;#34;world&amp;#34;
SRC=&amp;#34;/path/to/foo.cpp&amp;#34;
BASE=${SRC##*/} #=&amp;gt; &amp;#34;foo.cpp&amp;#34; (basepath)
DIR=${SRC%$BASE} #=&amp;gt; &amp;#34;/path/to/&amp;#34; (dirpath)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a
href="https://devhints.io/bash#conditionals"target="_blank" rel="noopener"&gt;補充連結&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a
href="https://wiki.bash-hackers.org/syntax/pe"target="_blank" rel="noopener"&gt;Bash Hackers 連結&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;可以埋進開機登入後的第一支程式&lt;span class="hx:absolute hx:-mt-20" id="可以埋進開機登入後的第一支程式"&gt;&lt;/span&gt;
&lt;a href="#%e5%8f%af%e4%bb%a5%e5%9f%8b%e9%80%b2%e9%96%8b%e6%a9%9f%e7%99%bb%e5%85%a5%e5%be%8c%e7%9a%84%e7%ac%ac%e4%b8%80%e6%94%af%e7%a8%8b%e5%bc%8f" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
#從不解析名字的路由表，找目的地為本機的路由資訊
gw=$(route -n | grep -e &amp;#34;^0.0.0.0 &amp;#34;)
#宣告$gw的網卡資訊為環境變數
export GWIF=${gw##* }
#從ifconfig找本機的IP位址、網路遮罩、廣播位址
ips=$(ifconfig $GWIF | grep &amp;#39;inet &amp;#39;)
#宣告本機IP為環境變數
export IP=$(echo $ips | cut -d&amp;#39; &amp;#39; -f2 | cut -d&amp;#39;:&amp;#39; -f2)
#宣告本機之Class C網段位址為環境變數
export NETID=${IP%.*}
#宣告本機的路由Gateway為環境變數
export GW=$(route -n | grep -e &amp;#39;^0.0.0.0&amp;#39; | tr -s \ - | cut -d &amp;#39; &amp;#39; -f2)
#將hostname寫入/tmp/sinfo
echo &amp;#34;[System]&amp;#34; &amp;gt; /tmp/sinfo
echo &amp;#34;Hostname : `hostname`&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
#將記憶體大小寫入/tmp/sinfo
m=$(free -mh | grep Mem: | tr -s &amp;#39; &amp;#39; | cut -d&amp;#39; &amp;#39; -f2)
echo &amp;#34;Memory : ${m}M&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
#將CPU的型號及核心數寫入/tmp/sinfo
cname=$(cat /proc/cpuinfo | grep &amp;#39;model name&amp;#39; | head -n 1 | cut -d &amp;#39;:&amp;#39; -f2)
cnumber=$(cat /proc/cpuinfo | grep &amp;#39;model name&amp;#39; | wc -l)
echo &amp;#34;CPU : $cname (core: $cnumber)&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
#將硬碟大小資訊寫入/tmp/sinfo
m=$(df -h | grep /dev/sda)
ds=$(echo $m | cut -d &amp;#39; &amp;#39; -f2)
echo &amp;#34;Disk : $ds&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
echo &amp;#34;&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
#將IP位址、Gateway資訊寫入/tmp/sinfo
echo &amp;#34;[Network]&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
echo &amp;#34;IP : $IP&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
echo &amp;#34;Gateway : $GW&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
#將域名的名稱伺服器寫入/tmp/sinfo
cat /etc/resolv.conf | grep &amp;#39;nameserver&amp;#39; | head -n 1 &amp;gt;&amp;gt; /tmp/sinfo
#ping外網，若有通則將&amp;#34;Internet OK&amp;#34;寫入/tmp/sinfo
/bin/ping -c 1 www.hinet.net
[ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ] &amp;amp;&amp;amp; echo &amp;#34;Internet OK&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Alpine 開機自動執行程式&lt;span class="hx:absolute hx:-mt-20" id="alpine-開機自動執行程式"&gt;&lt;/span&gt;
&lt;a href="#alpine-%e9%96%8b%e6%a9%9f%e8%87%aa%e5%8b%95%e5%9f%b7%e8%a1%8c%e7%a8%8b%e5%bc%8f" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo nano /etc/local.d/*.start&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Alpine 開機時會自動執行在 /etc/local.d/ 目錄下 &lt;code&gt;*.start&lt;/code&gt; 的檔案&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo chmod &amp;#43;x /etc/local.d/*.start&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;記得給權限&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;設定當前使用者執行 sudo 免密碼&lt;span class="hx:absolute hx:-mt-20" id="設定當前使用者執行-sudo-免密碼"&gt;&lt;/span&gt;
&lt;a href="#%e8%a8%ad%e5%ae%9a%e7%95%b6%e5%89%8d%e4%bd%bf%e7%94%a8%e8%80%85%e5%9f%b7%e8%a1%8c-sudo-%e5%85%8d%e5%af%86%e7%a2%bc" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ vi init.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檔案內容 :&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
# Debug mode
set -x
# test sudo, run as root
if ! command -v sudo &amp;amp;&amp;gt;/dev/null; then
echo &amp;#34;pls install sudo command: zypper in -y sudo, or you can run as root&amp;#34;
fi
# var
line_base_a=$(sudo cat /etc/sudoers | grep -n &amp;#39;NOPASSWD: ALL&amp;#39;)
line_base_b=$(cat /etc/group | grep -nw &amp;#34;^wheel&amp;#34;)
user_name=$(id -un)
# check var
if [[ -z &amp;#34;${line_base_a%%:*}&amp;#34; ]] || [[ -z &amp;#34;${line_base_b%%:*}&amp;#34; ]];then
echo &amp;#34;var has error&amp;#34; &amp;amp;&amp;amp; exit 0
fi
# 設定 wheel 群組執行 sudo 命令時免密碼
sudo sed -i &amp;#34;${line_base_a%%:*}s|#||&amp;#34; /etc/sudoers
# 將當前使用者加入 wheel 群組
sudo sed -i &amp;#34;${line_base_b%%:*}s|$|${user_name}|&amp;#34; /etc/group&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl -s https://raw.githubusercontent.com/braveantony/bash-script/bbc34c7729a9b4164ab9dcc282cb771cb9d94e83/init.sh | bash&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h6&gt;tags: &lt;code&gt;Shell Script&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="tags-shell-script"&gt;&lt;/span&gt;
&lt;a href="#tags-shell-script" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h6&gt;</description></item><item><title>cgidb.sh program</title><link>https://blog.kubeantony.com/archive/ops-automation/cgidb.sh-program/</link><pubDate>Sat, 01 Jul 2023 13:13:52 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/cgidb.sh-program/</guid><description>
&lt;h2&gt;2023/07/01&lt;span class="hx:absolute hx:-mt-20" id="20230701"&gt;&lt;/span&gt;
&lt;a href="#20230701" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
echo &amp;#34;Content-type: text/html&amp;#34;
echo &amp;#34;&amp;#34;
echo &amp;#39;&amp;lt;html&amp;gt;&amp;#39;
echo &amp;#39; &amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;#34;utf-8&amp;#34; /&amp;gt; &amp;lt;/head&amp;gt;&amp;#39;
echo &amp;#39;&amp;lt;body&amp;gt;&amp;#39;
# MySQL Server Connection test
[ ! -f /opt/www/cgi/dagger.ini ] &amp;amp;&amp;amp; echo &amp;#34;&amp;lt;h1&amp;gt;&amp;lt;center&amp;gt;pls setup first ! &amp;lt;a href=&amp;#34;/setup&amp;#34;&amp;gt;setup&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/center&amp;gt;&amp;lt;/h1&amp;gt;&amp;#34; &amp;amp;&amp;amp; exit 0
source &amp;#34;/opt/www/cgi/dagger.ini&amp;#34;
if ! mysql --connect-timeout=1 -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;show databases;&amp;#34; &amp;amp;&amp;gt;/dev/null; then
echo &amp;#39;&amp;lt;h1&amp;gt;&amp;lt;center&amp;gt;MySQL Cluster connection &amp;lt;font color=&amp;#34;red&amp;#34;&amp;gt;failed&amp;lt;/font&amp;gt; !
&amp;lt;p&amp;gt;pls Setup again, thx!
&amp;lt;a href=&amp;#34;/setup&amp;#34;&amp;gt;setup&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/center&amp;gt;&amp;lt;/h1&amp;gt;&amp;#39; &amp;amp;&amp;amp; exit 0
fi
# var
HTML=$(echo ${QUERY_STRING%=*} | cut -d &amp;#34;=&amp;#34; -f 1)
Action=$(echo $QUERY_STRING | cut -d &amp;#39;=&amp;#39; -f3 | cut -d &amp;#39;&amp;#43;&amp;#39; -f1)
ALL_COMMAND=$(echo $REQUEST_URI | cut -d &amp;#39;=&amp;#39; -f3 | sed &amp;#39;s/&amp;#43;/ /g&amp;#39; | sed &amp;#39;s/%28/(/g&amp;#39; | sed &amp;#39;s/%29/)/g&amp;#39; | sed &amp;#39;s/%2C/,/g&amp;#39; | sed &amp;#39;s/%3B/;/g&amp;#39; | sed &amp;#34;s/%27/&amp;#39;/g&amp;#34; | sed &amp;#39;s/%22/&amp;#34;/g&amp;#39; | sed &amp;#39;s/%3D/=/g&amp;#39; | sed &amp;#39;s/%0D%0A/ /g&amp;#39;)
ALL_COMMAND_tbl=${ALL_COMMAND%%&amp;amp;*}
Action_tbl=${QUERY_STRING##*=}
tbl=$(mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;use $DB_name;$ALL_COMMAND_tbl&amp;#34;)
tbl_name=$(echo ${QUERY_STRING%&amp;amp;*} | cut -d &amp;#34;=&amp;#34; -f 3)
# Debug
#echo &amp;#34;&amp;lt;br&amp;gt;REQUEST_URI=${REQUEST_URI}&amp;lt;/br&amp;gt;&amp;#34;
#echo &amp;#34;&amp;lt;br&amp;gt;QUERY_STRING=${QUERY_STRING}&amp;lt;/br&amp;gt;&amp;#34;
#echo &amp;#34;&amp;lt;br&amp;gt;DBname=$DB_name&amp;lt;/br&amp;gt;&amp;#34;
#echo &amp;#34;&amp;lt;br&amp;gt;HTML=$HTML&amp;lt;/br&amp;gt;&amp;#34;
#echo &amp;#34;&amp;lt;br&amp;gt;Action=$Action&amp;lt;/br&amp;gt;&amp;#34;
#echo &amp;#34;&amp;lt;br&amp;gt;Action_tbl=$Action_tbl&amp;lt;/br&amp;gt;&amp;#34;
#echo &amp;#34;&amp;lt;br&amp;gt;ALL_COMMAND=${ALL_COMMAND}&amp;lt;/br&amp;gt;&amp;#34;
#echo &amp;#34;&amp;lt;br&amp;gt;ALL_COMMAND_tbl=${ALL_COMMAND_tbl}&amp;lt;/br&amp;gt;&amp;#34;
#echo &amp;#34;&amp;lt;br&amp;gt;tbl_name=$tbl_name&amp;lt;/br&amp;gt;&amp;#34;
# function
DB_list() {
set -f # disable globbing
saveIFS=$IFS
IFS=$&amp;#39;\n&amp;#39; # set field separator to NL (only)
ALL_DB=$(mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;show databases;&amp;#34;)
cat /dev/null &amp;gt;/opt/www/cgi/db.txt
for i in ${ALL_DB[@]}; do
if [ &amp;#34;$i&amp;#34; != &amp;#34;Database&amp;#34; ]; then
echo &amp;#34; &amp;lt;option&amp;gt;$i&amp;lt;/option&amp;gt;&amp;#34; &amp;gt;&amp;gt;/opt/www/cgi/db.txt
else
echo &amp;#34; &amp;lt;option&amp;gt;請選擇資料庫名稱&amp;lt;/option&amp;gt;&amp;#34; &amp;gt;&amp;gt;/opt/www/cgi/db.txt
fi
done
IFS=$saveIFS
set &amp;#43;f
sed -i &amp;#34;/&amp;lt;option&amp;gt;/d&amp;#34; /opt/www/html/tbl.html
line=$(cat /opt/www/html/tbl.html | grep -n &amp;#39;select type&amp;#39; | cut -d &amp;#34;:&amp;#34; -f 1)
sed -i &amp;#34;${line} r /opt/www/cgi/db.txt&amp;#34; /opt/www/html/tbl.html
}
tbl_action() {
mysql --show-warnings -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;use $DB_name;$ALL_COMMAND_tbl&amp;#34; 1&amp;gt; /tmp/out.txt 2&amp;gt; /tmp/err-out.txt
[[ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ]] &amp;amp;&amp;amp; echo -e &amp;#34;&amp;lt;h1 style=&amp;#34;color:blue&amp;#34;&amp;gt;\nCommand success&amp;lt;/h1&amp;gt;&amp;#34;
[[ -s /tmp/err-out.txt ]] &amp;amp;&amp;amp; show_err
}
show() {
echo &amp;#34;&amp;lt;pre&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;font size=&amp;#34;6&amp;#34;&amp;gt;&amp;#34;
cat /tmp/out.txt
echo &amp;#34;&amp;lt;/pre&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;/font&amp;gt;&amp;#34;
}
show_err() {
echo &amp;#34;&amp;lt;pre&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;font size=&amp;#34;6&amp;#34;&amp;gt;&amp;#34;
cat /tmp/err-out.txt
echo &amp;#34;&amp;lt;/pre&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;/font&amp;gt;&amp;#34;
}
show_db() {
echo &amp;#34;&amp;lt;pre&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;font size=&amp;#34;6&amp;#34;&amp;gt;&amp;#34;
cat /tmp/dbout.txt
echo &amp;#34;&amp;lt;/pre&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;/font&amp;gt;&amp;#34;
}
DB_list
if [[ &amp;#34;$HTML&amp;#34; == &amp;#34;tblname&amp;#34; ]]; then
DB_name=$(echo ${QUERY_STRING%%&amp;amp;*} | cut -d &amp;#34;=&amp;#34; -f 2)
case ${Action_tbl} in
DROP)
if ! echo &amp;#34;$ALL_COMMAND_tbl&amp;#34; | grep &amp;#39;drop&amp;#39;; then
if mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;use ${DB_name}; DROP TABLE ${tbl_name}&amp;#34;; then
echo -e &amp;#34;&amp;lt;h1 style=&amp;#34;color:blue&amp;#34;&amp;gt;\nCommand success&amp;lt;/h1&amp;gt;&amp;#34;
else
echo -e &amp;#34;&amp;lt;h1 style=&amp;#34;color:red&amp;#34;&amp;gt;\nCommand fail&amp;lt;/h1&amp;gt;&amp;#34;
fi
else
tbl_action
show
fi
;;
*)
tbl_action
show
;;
esac
echo &amp;#39;&amp;lt;h1&amp;gt;&amp;lt;center&amp;gt;&amp;lt;a href=&amp;#34;../html/tbl.html&amp;#34;&amp;gt;返回上一頁&amp;lt;/a&amp;gt;&amp;lt;/center&amp;gt;&amp;lt;/h1&amp;gt;&amp;#39;
else
if [[ $Action == &amp;#34;SHOW&amp;#34; ]]; then
mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;SHOW DATABASES&amp;#34; &amp;gt;/tmp/dbout.txt &amp;amp;&amp;amp; show_db
else
DB_name=$(echo ${QUERY_STRING%%&amp;amp;*} | cut -d &amp;#34;=&amp;#34; -f 2)
mysql --show-warnings -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;${Action} DATABASE ${DB_name}&amp;#34; &amp;gt;/tmp/dbout.txt
if ! cat /tmp/dbout.txt | grep &amp;#39;Error&amp;#39;; then
mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;SHOW DATABASES&amp;#34; &amp;gt;/tmp/dbout.txt &amp;amp;&amp;amp; show_db &amp;amp;&amp;amp; DB_list
else
show_db &amp;amp;&amp;amp; DB_list
fi
fi
fi
echo &amp;#39;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;#39;
exit 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;2023/1/10 最新版&lt;span class="hx:absolute hx:-mt-20" id="2023110-最新版"&gt;&lt;/span&gt;
&lt;a href="#2023110-%e6%9c%80%e6%96%b0%e7%89%88" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
echo &amp;#34;Content-type: text/html&amp;#34;
echo &amp;#34;&amp;#34;
echo &amp;#39;&amp;lt;html&amp;gt;&amp;#39;
echo &amp;#39; &amp;lt;head&amp;gt;&amp;lt;meta charset=&amp;#34;utf-8&amp;#34; /&amp;gt; &amp;lt;/head&amp;gt;&amp;#39;
echo &amp;#39;&amp;lt;body&amp;gt;&amp;#39;
echo &amp;#39;&amp;lt;h1&amp;gt;call from mydb.sh&amp;lt;/h1&amp;gt;&amp;#39;
# var
DB_user=&amp;#34;dagger&amp;#34;
DB_passwd=&amp;#34;dagger&amp;#34;
DB_ip=&amp;#34;10.98.0.203&amp;#34;
DB_name=$(echo ${QUERY_STRING%%&amp;amp;*} | cut -d &amp;#34;=&amp;#34; -f 2)
HTML=$(echo ${QUERY_STRING%=*} | cut -d &amp;#34;=&amp;#34; -f 1)
Action=$(echo $QUERY_STRING | cut -d &amp;#39;=&amp;#39; -f3 | cut -d &amp;#39;&amp;#43;&amp;#39; -f1)
ALL_COMMAND=$(echo $REQUEST_URI | cut -d &amp;#39;=&amp;#39; -f3 | sed &amp;#39;s/&amp;#43;/ /g&amp;#39; | sed &amp;#39;s/%28/(/g&amp;#39; | sed &amp;#39;s/%29/)/g&amp;#39; | sed &amp;#39;s/%2C/,/g&amp;#39; | sed &amp;#39;s/%3B/;/g&amp;#39; | sed &amp;#34;s/%27/&amp;#39;/g&amp;#34; | sed &amp;#39;s/%22/&amp;#34;/g&amp;#39; | sed &amp;#39;s/%3D/=/g&amp;#39; | sed &amp;#39;s/%0D%0A/ /g&amp;#39;)
ALL_COMMAND_tbl=${ALL_COMMAND%%&amp;amp;*}
Action_tbl=${QUERY_STRING##*=}
tbl=$(mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;use $DB_name;$ALL_COMMAND_tbl&amp;#34;)
tbl_name=$(echo ${QUERY_STRING%&amp;amp;*} | cut -d &amp;#34;=&amp;#34; -f 3)
# Debug
echo &amp;#34;&amp;lt;br&amp;gt;REQUEST_URI=${REQUEST_URI}&amp;lt;/br&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;br&amp;gt;QUERY_STRING=${QUERY_STRING}&amp;lt;/br&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;br&amp;gt;DBname=$DB_name&amp;lt;/br&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;br&amp;gt;HTML=$HTML&amp;lt;/br&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;br&amp;gt;Action=$Action&amp;lt;/br&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;br&amp;gt;Action_tbl=$Action_tbl&amp;lt;/br&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;br&amp;gt;ALL_COMMAND=${ALL_COMMAND}&amp;lt;/br&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;br&amp;gt;ALL_COMMAND_tbl=${ALL_COMMAND_tbl}&amp;lt;/br&amp;gt;&amp;#34;
echo &amp;#34;&amp;lt;br&amp;gt;tbl_name=$tbl_name&amp;lt;/br&amp;gt;&amp;#34;
# function
DB_list() {
set -f # disable globbing
saveIFS=$IFS
IFS=$&amp;#39;\n&amp;#39; # set field separator to NL (only)
ALL_DB=$(mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;show databases;&amp;#34;)
cat /dev/null &amp;gt; /opt/www/cgi/db.txt
for i in ${ALL_DB[@]}
do
if [ &amp;#34;$i&amp;#34; != &amp;#34;Database&amp;#34; ]; then
echo &amp;#34; &amp;lt;option&amp;gt;$i&amp;lt;/option&amp;gt;&amp;#34; &amp;gt;&amp;gt; /opt/www/cgi/db.txt
else
echo &amp;#34; &amp;lt;option&amp;gt;&amp;lt;b&amp;gt;請選擇資料庫名稱&amp;lt;/b&amp;gt;&amp;lt;/option&amp;gt;&amp;#34; &amp;gt;&amp;gt; /opt/www/cgi/db.txt
fi
done
IFS=$saveIFS
set &amp;#43;f
sed -i &amp;#34;/&amp;lt;option&amp;gt;/d&amp;#34; /opt/www/html/tbl.html
line=$(cat /opt/www/html/tbl.html | grep -n &amp;#39;select type&amp;#39; | cut -d &amp;#34;:&amp;#34; -f 1)
sed -i &amp;#34;${line} r /opt/www/cgi/db.txt&amp;#34; /opt/www/html/tbl.html
}
display() {
echo &amp;#34;&amp;lt;h1&amp;gt;${tbl}&amp;lt;/h1&amp;gt;&amp;#34;
if [ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ]; then
echo -e &amp;#34;&amp;lt;h1 style=&amp;#34;color:blue&amp;#34;&amp;gt;\nCommand success&amp;lt;/h1&amp;gt;&amp;#34;
else
echo -e &amp;#34;&amp;lt;h1 style=&amp;#34;color:red&amp;#34;&amp;gt;\nCommand fail&amp;lt;/h1&amp;gt;&amp;#34;
fi
}
if [[ $HTML == tblname ]]; then
case ${Action_tbl} in
CREATE)
display
;;
DROP)
if ! echo &amp;#34;$ALL_COMMAND_tbl&amp;#34; | grep &amp;#39;drop&amp;#39;; then
if mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;use ${DB_name}; DROP TABLE ${tbl_name}&amp;#34;; then
echo -e &amp;#34;&amp;lt;h1 style=&amp;#34;color:blue&amp;#34;&amp;gt;\nCommand success&amp;lt;/h1&amp;gt;&amp;#34;
else
echo -e &amp;#34;&amp;lt;h1 style=&amp;#34;color:red&amp;#34;&amp;gt;\nCommand fail&amp;lt;/h1&amp;gt;&amp;#34;
fi
else
display
fi
;;
*)
display
;;
esac
else
if [[ $Action == SHOW ]]; then
if ! mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;SHOW DATABASES&amp;#34;; then
echo -e &amp;#34;&amp;lt;h1 style=&amp;#34;color:red&amp;#34;&amp;gt;\nCommand fail&amp;lt;/h1&amp;gt;&amp;#34;
fi
else
if mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;${Action} DATABASE ${DB_name}&amp;#34;; then
DB_list &amp;amp;&amp;amp; echo -e &amp;#34;&amp;lt;h1 style=&amp;#34;color:blue&amp;#34;&amp;gt;\nCommand success&amp;lt;/h1&amp;gt;&amp;#34;
else
DB_list &amp;amp;&amp;amp; echo -e &amp;#34;&amp;lt;h1 style=&amp;#34;color:red&amp;#34;&amp;gt;\nCommand fail&amp;lt;/h1&amp;gt;&amp;#34;
fi
fi
fi
echo &amp;#39;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;#39;
exit 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;舊版&lt;span class="hx:absolute hx:-mt-20" id="舊版"&gt;&lt;/span&gt;
&lt;a href="#%e8%88%8a%e7%89%88" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
echo &amp;#34;Content-type: text/html; charset=utf-8&amp;#34;
echo &amp;#34;&amp;#34;
echo &amp;#39;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;#39;
echo &amp;#39;Hello From cgidb.sh&amp;#39;
echo &amp;#39;&amp;lt;pre&amp;gt;&amp;#39;
# var
DB_name=$(echo ${QUERY_STRING%&amp;amp;*} | cut -d &amp;#34;=&amp;#34; -f 2)
action=${QUERY_STRING##*&amp;amp;}
Action=${action%%=*}
DB_user=&amp;#34;bobo&amp;#34;
DB_ip=&amp;#34;120.96.143.84&amp;#34;
DB_passwd=&amp;#34;bobo123&amp;#34;
# Debug
#echo &amp;#34;REQUEST_URI=${REQUEST_URI}&amp;#34;
#echo &amp;#34;QUERY_STRING=${QUERY_STRING}&amp;#34;
#echo &amp;#34;DBname=$DB_name&amp;#34;
#echo &amp;#34;Action=$Action&amp;#34;
Action_Db() {
mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; &amp;lt;&amp;lt;EOF
${Action,,} DATABASE ${DB_name};
EOF
}
DB_list() {
set -f # disable globbing
saveIFS=$IFS
IFS=$&amp;#39;\n&amp;#39; # set field separator to NL (only)
ALL_DB=$(mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;show databases;&amp;#34;)
cat /dev/null &amp;gt; /www/cgi/db.txt
for i in ${ALL_DB[@]}
do
if [ &amp;#34;$i&amp;#34; != &amp;#34;Database&amp;#34; ]; then
echo &amp;#34; &amp;lt;option&amp;gt;$i&amp;lt;/option&amp;gt;&amp;#34; &amp;gt;&amp;gt; /www/cgi/db.txt
else
echo &amp;#34; &amp;lt;option&amp;gt;&amp;lt;b&amp;gt;請選擇資料庫名稱&amp;lt;/b&amp;gt;&amp;lt;/option&amp;gt;&amp;#34; &amp;gt;&amp;gt; /www/cgi/db.txt
fi
done
IFS=$saveIFS
set &amp;#43;f
sed -i &amp;#34;/&amp;lt;option&amp;gt;/d&amp;#34; /www/html/tbl.html
line=$(cat /www/html/tbl.html | grep -n &amp;#39;select type&amp;#39; | cut -d &amp;#34;:&amp;#34; -f 1)
sed -i &amp;#34;${line} r /www/cgi/db.txt&amp;#34; /www/html/tbl.html
}
case ${Action,,} in
create)
if Action_Db; then
DB_list &amp;amp;&amp;amp; echo &amp;#34;&amp;lt;h1 style=&amp;#34;color:red&amp;#34;&amp;gt;Create ${DB_name} Database Success!&amp;lt;/h1&amp;gt;&amp;#34;
else
echo &amp;#34;&amp;lt;h1 style=&amp;#34;color: red&amp;#34;&amp;gt;Error! pls try again!&amp;lt;/h1&amp;gt;&amp;#34;
fi
;;
drop)
if Action_Db; then
DB_list &amp;amp;&amp;amp; echo &amp;#34;&amp;lt;h1 style=&amp;#34;color:red&amp;#34;&amp;gt;Success!&amp;lt;/h1&amp;gt;&amp;#34;
else
echo &amp;#34;&amp;lt;h1 style=&amp;#34;color:red&amp;#34;&amp;gt;Error! pls try again!&amp;lt;/h1&amp;gt;&amp;#34;
fi
;;
show)
if [ &amp;#34;$DB_name&amp;#34; != &amp;#34;&amp;#34; ]; then
echo &amp;#34;&amp;lt;h1&amp;gt; 資料庫查詢結果：&amp;lt;/h1&amp;gt;&amp;#34;
mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;show database like ${DB_name};&amp;#34;
else
mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;show databases;&amp;#34;
fi
;;
*)
echo -e &amp;#34;Error ! \nYour SQL Command now is &amp;gt; ${Action} DATABASE ${DB_name};&amp;#34;
;;
esac
echo &amp;#39;&amp;lt;/pre&amp;gt;&amp;#39;
echo &amp;#39;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;#39;
exit 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/sFoEtnt.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bebo 不可執行 curl (命令攔截), bobo 可以 curl ，openssh container&lt;/li&gt;
&lt;li&gt;mysql rbean 使用者&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;mydb&lt;/h1&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
echo &amp;#34;Content-type: text/html; charset=utf-8&amp;#34;
echo &amp;#34;&amp;#34;
echo &amp;#39;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;#39;
echo &amp;#39;Hello From MyDb&amp;#39;
# Debug
echo &amp;#34;REQUEST_URI=${REQUEST_URI}&amp;#34;
echo &amp;#34;QUERY_STRING=${QUERY_STRING}&amp;#34;
# QUERY_STRING=&amp;#34;DB_user_account&amp;amp;DB_user_password&amp;amp;DB_Server_IP&amp;#34;
# e.g., curl &amp;#39;http://120.96.143.110:80/login?rbean&amp;amp;rbean&amp;amp;120.96.143.111&amp;#39;
login_info() {
# var
DB_USER=$(echo &amp;#34;${QUERY_STRING%%&amp;amp;*}&amp;#34;)
DB_PASSWD=$(echo &amp;#34;${QUERY_STRING%&amp;amp;*}&amp;#34; | cut -d &amp;#34;&amp;amp;&amp;#34; -f 2)
DB_IP=$(echo &amp;#34;${QUERY_STRING##*&amp;amp;}&amp;#34;)
if mysql -u ${DB_USER} -h ${DB_IP} -p${DB_PASSWD}; then
echo &amp;#34;${DB_USER},${DB_PASSWD},${DB_IP}&amp;#34; &amp;gt; /tmp/hello
[ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ] &amp;amp;&amp;amp; echo -e &amp;#34;\n${DB_USER} login success !&amp;#34; || echo &amp;#34;login failed&amp;#34;
fi
}
create_Db() {
mysql -u ${DB_USER} -h ${DB_IP} -p${DB_PASSWD} &amp;lt;&amp;lt;EOF
CREATE DATABASE ${db_name};
EOF
}
list_Db() {
mysql -u ${DB_USER} -h ${DB_IP} -p${DB_PASSWD} &amp;lt;&amp;lt;EOF
SHOW DATABASES;
EOF
}
rm_Db() {
mysql -u ${DB_USER} -h ${DB_IP} -p${DB_PASSWD} &amp;lt;&amp;lt;EOF
DROP DATABASE ${db_name};
EOF
}
# var
DB_USER=$(cat /tmp/hello | cut -d &amp;#34;,&amp;#34; -f 1)
DB_PASSWD=$(cat /tmp/hello | cut -d &amp;#34;,&amp;#34; -f 2)
DB_IP=$(cat /tmp/hello | cut -d &amp;#34;,&amp;#34; -f 3)
# Login check
if [ &amp;#34;$DB_USER&amp;#34; == &amp;#34;&amp;#34; ] || [ &amp;#34;${DB_PASSWD}&amp;#34; == &amp;#34;&amp;#34; ] || [ &amp;#34;${DB_PASSWD}&amp;#34; == &amp;#34;&amp;#34; ]; then
echo &amp;#34;MySQL Login Error,pls login !&amp;#34; &amp;amp;&amp;amp; exit 1
fi
# Login, Create, list, rm Database
a=$(echo ${REQUEST_URI%?$QUERY_STRING}
db_name=${QUERY_STRING}
case ${a,,} in
/login)
login_info
;;
/db/create)
create_Db
;;
/db/list)
list_Db
;;
/db/rm)
rm_Db
;;
esac
echo &amp;#39;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;#39;
exit 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;new gocgi&lt;/h1&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;package main
import (
&amp;#34;net/http&amp;#34;
&amp;#34;net/http/cgi&amp;#34;
)
func cgiDB(w http.ResponseWriter, r *http.Request) {
handler := cgi.Handler{Path: &amp;#34;./www/cgi/cgidb.sh&amp;#34;}
handler.ServeHTTP(w, r)
}
func cgiTBL(w http.ResponseWriter, r *http.Request) {
handler := cgi.Handler{Path: &amp;#34;./www/cgi/cgitbl.sh&amp;#34;}
handler.ServeHTTP(w, r)
}
func main() {
static := http.FileServer(http.Dir(&amp;#34;./www/&amp;#34;))
http.Handle(&amp;#34;/&amp;#34;,static)
http.HandleFunc(&amp;#34;/db&amp;#34;, cgiDB)
http.HandleFunc(&amp;#34;/tbl&amp;#34;, cgiTBL)
http.ListenAndServe(&amp;#34;:8080&amp;#34;, nil)
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;index : bobo Database application&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a
href="http://bl.ocks.org/ndarville/7075823"target="_blank" rel="noopener"&gt;http://bl.ocks.org/ndarville/7075823&lt;/a&gt;&lt;/p&gt;</description></item><item><title>SREPBP</title><link>https://blog.kubeantony.com/archive/ops-automation/srepbp/</link><pubDate>Wed, 05 Oct 2022 06:03:34 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/srepbp/</guid><description>
&lt;h2&gt;Install Chocolatey&lt;span class="hx:absolute hx:-mt-20" id="install-chocolatey"&gt;&lt;/span&gt;
&lt;a href="#install-chocolatey" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;用&lt;strong&gt;系統管理員&lt;/strong&gt;啟動 CMD，執行以下命令&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;@&amp;#34;%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe&amp;#34; -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command &amp;#34;[System.Net.ServicePointManager]::SecurityProtocol = 3072; iex ((New-Object System.Net.WebClient).DownloadString(&amp;#39;https://community.chocolatey.org/install.ps1&amp;#39;))&amp;#34; &amp;amp;&amp;amp; SET &amp;#34;PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;allow TLS v1.2 (Required for requests to Chocolatey.org)
Getting latest version of the Chocolatey package for download.
Not using proxy.
Getting Chocolatey from https://community.chocolatey.org/api/v2/package/chocolatey/1.1.0.
Downloading https://community.chocolatey.org/api/v2/package/chocolatey/1.1.0 to C:\Users\bigred\AppData\Local\Temp\chocolatey\chocoInstall\chocolatey.zip
Not using proxy.
Extracting C:\Users\bigred\AppData\Local\Temp\chocolatey\chocoInstall\chocolatey.zip to C:\Users\bigred\AppData\Local\Temp\chocolatey\chocoInstall
Installing Chocolatey on the local machine
Creating ChocolateyInstall as an environment variable (targeting &amp;#39;Machine&amp;#39;)
Setting ChocolateyInstall to &amp;#39;C:\ProgramData\chocolatey&amp;#39;
WARNING: It&amp;#39;s very likely you will need to close and reopen your shell
before you can use choco.
Restricting write permissions to Administrators
We are setting up the Chocolatey package repository.
The packages themselves go to &amp;#39;C:\ProgramData\chocolatey\lib&amp;#39;
(i.e. C:\ProgramData\chocolatey\lib\yourPackageName).
A shim file for the command line goes to &amp;#39;C:\ProgramData\chocolatey\bin&amp;#39;
and points to an executable in &amp;#39;C:\ProgramData\chocolatey\lib\yourPackageName&amp;#39;.
Creating Chocolatey folders if they do not already exist.
WARNING: You can safely ignore errors related to missing log files when
upgrading from a version of Chocolatey less than 0.9.9.
&amp;#39;Batch file could not be found&amp;#39; is also safe to ignore.
&amp;#39;The system cannot find the file specified&amp;#39; - also safe.
chocolatey.nupkg file not installed in lib.
Attempting to locate it from bootstrapper.
PATH environment variable does not have C:\ProgramData\chocolatey\bin in it. Adding...
警告: Not setting tab completion: Profile file does not exist at
&amp;#39;C:\Users\bigred\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1&amp;#39;.
Chocolatey (choco.exe) is now ready.
You can call choco from anywhere, command line or powershell by typing choco.
Run choco /? for a list of functions.
You may need to shut down and restart powershell and/or consoles
first prior to using choco.
Ensuring Chocolatey commands are on the path
Ensuring chocolatey.nupkg is in the lib folder&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;安裝 套件&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;choco install -y nano wget tree&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Install kubectl on windows&lt;span class="hx:absolute hx:-mt-20" id="install-kubectl-on-windows"&gt;&lt;/span&gt;
&lt;a href="#install-kubectl-on-windows" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;安裝 &lt;code&gt;kubectl&lt;/code&gt; 命令&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;curl -LO &amp;#34;https://dl.k8s.io/release/v1.25.0/bin/windows/amd64/kubectl.exe&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Validate the binary (optional)&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;curl -LO &amp;#34;https://dl.k8s.io/v1.25.0/bin/windows/amd64/kubectl.exe.sha256&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢查 &lt;code&gt;kubectl&lt;/code&gt; 版本&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;kubectl version --client&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;切換到家目錄&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;cd %USERPROFILE%&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;建立 &lt;code&gt;.kube&lt;/code&gt; 目錄&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;mkdir .kube&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;切換到 &lt;code&gt;.kube&lt;/code&gt; 目錄&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;cd .kube&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;將要遠端操作的 K8S Cluster 路口憑證檔拷貝至當前目錄&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;scp bigred@120.96.143.103:/home/bigred/.kube/config .&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;修改 API Server IP&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;nano config&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;將&lt;code&gt;clusters.cluster.server&lt;/code&gt; 的設定值，設為 API-Server 的 IP 位址&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;檢查連線到的 K8S Cluster 資訊&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;kubectl cluster-info&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;output :&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;Kubernetes control plane is running at https://120.96.143.103:6443
CoreDNS is running at https://120.96.143.103:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;測試 kubectl 命令&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;kubectl run nginx --image=quay.io/cloudwalker/nginx --dry-run -o yaml &amp;gt; pod-nginx.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;產生 pod&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;kubectl apply -f pod-nginx.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;看 pod 狀態&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;kubectl get pod&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;output :&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 43m&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;References&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;&lt;a
href="https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/#install-kubectl-binary-with-curl-on-windows"target="_blank" rel="noopener"&gt;Install and Set Up kubectl on Windows - Kubernetes DOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://dev.mysql.com/downloads/file/?id=512282"target="_blank" rel="noopener"&gt;MySQL Community Downloads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://docs.chocolatey.org/en-us/choco/setup"target="_blank" rel="noopener"&gt;SETUP / INSTALL Chocolately - Chocolatey DOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://docs.chocolatey.org/en-us/choco/uninstallation"target="_blank" rel="noopener"&gt;Uninstall Chocolately - Chocolatey DOC &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;install.bat 程式內容&lt;/h1&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;@echo off
@&amp;#34;%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe&amp;#34; -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command &amp;#34;[System.Net.ServicePointManager]::SecurityProtocol = 3072; iex ((New-Object System.Net.WebClient).DownloadString(&amp;#39;https://community.chocolatey.org/install.ps1&amp;#39;))&amp;#34; &amp;gt; nul &amp;amp;&amp;amp; SET &amp;#34;PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin&amp;#34; &amp;gt; nul &amp;amp;&amp;amp; powershell -Command &amp;#34;choco upgrade chocolatey&amp;#34; &amp;gt; nul
if %ERRORLEVEL% == 0 echo &amp;#34;Chocolatey ok&amp;#34;
powershell -Command &amp;#34;choco install -y nano&amp;#34; &amp;gt; nul
if %ERRORLEVEL% == 0 echo &amp;#34;nano ok&amp;#34;
powershell -Command &amp;#34;choco install -y wget&amp;#34; &amp;gt; nul
if %ERRORLEVEL% == 0 echo &amp;#34;wget ok&amp;#34;
powershell -Command &amp;#34;choco install -y tree&amp;#34; &amp;gt; nul
if %ERRORLEVEL% == 0 echo &amp;#34;tree ok&amp;#34;
powershell -Command &amp;#34;choco install -y sed&amp;#34; &amp;gt; nul&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>cgidb.sh</title><link>https://blog.kubeantony.com/archive/ops-automation/cgidb.sh/</link><pubDate>Mon, 05 Sep 2022 07:14:20 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/cgidb.sh/</guid><description>
&lt;h2&gt;描述&lt;span class="hx:absolute hx:-mt-20" id="描述"&gt;&lt;/span&gt;
&lt;a href="#%e6%8f%8f%e8%bf%b0" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;新增、刪除和顯示 Database&lt;/p&gt;
&lt;h2&gt;完整程式內容&lt;span class="hx:absolute hx:-mt-20" id="完整程式內容"&gt;&lt;/span&gt;
&lt;a href="#%e5%ae%8c%e6%95%b4%e7%a8%8b%e5%bc%8f%e5%85%a7%e5%ae%b9" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
echo &amp;#34;Content-type: text/html; charset=utf-8&amp;#34;
echo &amp;#34;&amp;#34;
echo &amp;#39;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;#39;
echo &amp;#39;Hello From cgidb.sh&amp;#39;
echo &amp;#39;&amp;lt;pre&amp;gt;&amp;#39;
# var
DB_name=$(echo ${QUERY_STRING%&amp;amp;*} | cut -d &amp;#34;=&amp;#34; -f 2)
action=${QUERY_STRING##*&amp;amp;}
Action=${action%%=*}
DB_user=&amp;#34;bobo&amp;#34;
DB_passwd=&amp;#34;bobo&amp;#34;
DB_ip=&amp;#34;120.96.143.77&amp;#34;
# Debug
#echo &amp;#34;REQUEST_URI=${REQUEST_URI}&amp;#34;
#echo &amp;#34;QUERY_STRING=${QUERY_STRING}&amp;#34;
#echo &amp;#34;DBname=$DB_name&amp;#34;
#echo &amp;#34;Action=$Action&amp;#34;
Action_Db() {
mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; &amp;lt;&amp;lt;EOF
${Action} DATABASE ${DB_name};
EOF
}
case ${Action,,} in
create)
if Action_Db; then
echo &amp;#34;&amp;lt;h1 style=&amp;#34;color:blue&amp;#34;&amp;gt;Create ${DB_name} Database Success!&amp;lt;/h1&amp;gt;&amp;#34;
else
echo &amp;#34;&amp;lt;h1 style=&amp;#34;color: red&amp;#34;&amp;gt;Error! pls try again!&amp;lt;/h1&amp;gt;&amp;#34;
fi
;;
drop)
if Action_Db; then
echo &amp;#34;&amp;lt;h1 style=&amp;#34;color:blue&amp;#34;&amp;gt;Success!&amp;lt;/h1&amp;gt;&amp;#34;
else
echo &amp;#34;&amp;lt;h1 style=&amp;#34;color:red&amp;#34;&amp;gt;Error! pls try again!&amp;lt;/h1&amp;gt;&amp;#34;
fi
;;
show)
if [ &amp;#34;$DB_name&amp;#34; != &amp;#34;&amp;#34; ]; then
echo &amp;#34;&amp;lt;h1&amp;gt;資料庫查詢結果：&amp;lt;/h1&amp;gt;&amp;#34;
a=$(mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;show databases like &amp;#39;${DB_name}&amp;#39;;&amp;#34;)
echo &amp;#34;&amp;lt;h1&amp;gt; $a &amp;lt;/h1&amp;gt;&amp;#34;
else
echo &amp;#34;&amp;lt;h1&amp;gt; 資料庫查詢結果：&amp;lt;/h1&amp;gt;&amp;#34;
b=$(mysql -u &amp;#34;$DB_user&amp;#34; -h &amp;#34;$DB_ip&amp;#34; -p&amp;#34;$DB_passwd&amp;#34; -e &amp;#34;show databases;&amp;#34;)
echo &amp;#34;&amp;lt;h1&amp;gt; $b &amp;lt;/h1&amp;gt;&amp;#34;
fi
;;
*)
echo -e &amp;#34;Error ! \nYour SQL Command now is &amp;gt; ${Action} DATABASE ${DB_name};&amp;#34;
;;
esac
echo &amp;#39;&amp;lt;/pre&amp;gt;&amp;#39;
echo &amp;#39;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;#39;
exit 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>rest-api.sh</title><link>https://blog.kubeantony.com/archive/ops-automation/rest-api.sh/</link><pubDate>Sat, 27 Aug 2022 11:26:26 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/rest-api.sh/</guid><description>
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
#set -x # debug mode
# var
script_dir=$(cd &amp;#34;$(dirname &amp;#34;${BASH_SOURCE[0]}&amp;#34;)&amp;#34; &amp;amp;&amp;gt;/dev/null &amp;amp;&amp;amp; pwd -P)
# function
usage() {
cat &amp;lt;&amp;lt;EOF
Usage:
$(basename &amp;#34;${BASH_SOURCE[0]}&amp;#34;) [options]
Available options:
test test config
create create from mapping.list
delete delete from mapping.list
EOF
exit
}
get_token() {
token=$(curl -s --location --request POST &amp;#34;${GUACAMOLESERVER}/api/tokens&amp;#34; \
--header &amp;#39;Content-Type: application/x-www-form-urlencoded&amp;#39; \
--data-urlencode &amp;#34;username=${GUACADMIN}&amp;#34; \
--data-urlencode &amp;#34;password=${GUACPASS}&amp;#34; | jq -r &amp;#39;.authToken&amp;#39;)
[ &amp;#34;${token}&amp;#34; == &amp;#34;null&amp;#34; ] &amp;amp;&amp;amp; echo &amp;#39;Get token fail, Please check config&amp;#39; &amp;amp;&amp;amp; exit 1
}
get_connection_groupID() {
groups=$(curl -s --location --request GET &amp;#34;${GUACAMOLESERVER}/api/session/data/${DATASOURCE}/connectionGroups?token=${token}&amp;#34;)
groupIndex=$(echo &amp;#34;${groups}&amp;#34; | jq -r .[].identifier)
for num in ${groupIndex}; do
echo &amp;#34;${groups}&amp;#34; | jq -r &amp;#34;.\&amp;#34;${num}\&amp;#34;.name&amp;#34; | grep &amp;#34;${connGroup}&amp;#34; &amp;amp;&amp;gt;/dev/null &amp;amp;&amp;amp;
connGroupID=$(echo &amp;#34;${groups}&amp;#34; | jq -r &amp;#34;.\&amp;#34;${num}\&amp;#34;.identifier&amp;#34;)
done
}
get_connection_nameid() {
conns=$(curl -s --location --request GET &amp;#34;${GUACAMOLESERVER}/api/session/data/${DATASOURCE}/connections?token=${token}&amp;#34;)
connsIndex=$(echo &amp;#34;${conns}&amp;#34; | jq -r .[].identifier)
for num in ${connsIndex}; do
echo &amp;#34;${conns}&amp;#34; | jq -r &amp;#34;.\&amp;#34;${num}\&amp;#34;.name&amp;#34; | grep &amp;#34;${connName}&amp;#34; &amp;amp;&amp;gt;/dev/null &amp;amp;&amp;amp;
connNameID=$(echo &amp;#34;${conns}&amp;#34; | jq -r &amp;#34;.\&amp;#34;${num}\&amp;#34;.identifier&amp;#34;)
done
}
check_connection_service() {
if ! nmap -Pn -p &amp;#34;${connPort}&amp;#34; &amp;#34;${connIP}&amp;#34; | grep &amp;#39;open&amp;#39; &amp;amp;&amp;gt;/dev/null; then
connName=&amp;#34;${connName}.X&amp;#34;
fi
}
create_user() {
curl -s -w &amp;#39;\n&amp;#39; --location --request POST &amp;#34;${GUACAMOLESERVER}/api/session/data/${DATASOURCE}/users?token=${token}&amp;#34; \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--data-raw &amp;#34;{
\&amp;#34;username\&amp;#34;: \&amp;#34;${userAccount}\&amp;#34;,
\&amp;#34;password\&amp;#34;: \&amp;#34;${userPassword}\&amp;#34;,
\&amp;#34;attributes\&amp;#34;: {}
}&amp;#34;
}
create_connection_group() {
curl -s -w &amp;#39;\n&amp;#39; --location --request POST &amp;#34;${GUACAMOLESERVER}/api/session/data/${DATASOURCE}/connectionGroups?token=${token}&amp;#34; \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--data-raw &amp;#34;{
\&amp;#34;name\&amp;#34;: \&amp;#34;${connGroup}\&amp;#34;,
\&amp;#34;type\&amp;#34;: \&amp;#34;ORGANIZATIONAL\&amp;#34;,
\&amp;#34;attributes\&amp;#34;: {
\&amp;#34;max-connections\&amp;#34;: \&amp;#34;\&amp;#34;,
\&amp;#34;max-connections-per-user\&amp;#34;: \&amp;#34;\&amp;#34;,
\&amp;#34;enable-session-affinity\&amp;#34;: \&amp;#34;\&amp;#34;
}
}&amp;#34;
}
create_connection_rdp() {
curl -s -w &amp;#39;\n&amp;#39; --location --request POST &amp;#34;${GUACAMOLESERVER}/api/session/data/${DATASOURCE}/connections?token=${token}&amp;#34; \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--data-raw &amp;#34;{
\&amp;#34;parentIdentifier\&amp;#34;: \&amp;#34;${connGroupID}\&amp;#34;,
\&amp;#34;name\&amp;#34;: \&amp;#34;${connName}\&amp;#34;,
\&amp;#34;protocol\&amp;#34;: \&amp;#34;rdp\&amp;#34;,
\&amp;#34;parameters\&amp;#34;: {
\&amp;#34;hostname\&amp;#34;: \&amp;#34;${connIP}\&amp;#34;,
\&amp;#34;port\&amp;#34;: \&amp;#34;${connPort}\&amp;#34;,
\&amp;#34;username\&amp;#34;: \&amp;#34;${connAccount}\&amp;#34;,
\&amp;#34;password\&amp;#34;: \&amp;#34;${connPassword}\&amp;#34;,
\&amp;#34;security\&amp;#34;: \&amp;#34;nla\&amp;#34;,
\&amp;#34;ignore-cert\&amp;#34;: \&amp;#34;true\&amp;#34;
},
\&amp;#34;attributes\&amp;#34;: {
\&amp;#34;max-connections\&amp;#34;: \&amp;#34;\&amp;#34;,
\&amp;#34;max-connections-per-user\&amp;#34;: \&amp;#34;\&amp;#34;
}
}&amp;#34;
}
create_connection_ssh() {
curl -s -w &amp;#39;\n&amp;#39; --location --request POST &amp;#34;${GUACAMOLESERVER}/api/session/data/${DATASOURCE}/connections?token=${token}&amp;#34; \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--data-raw &amp;#34;{
\&amp;#34;parentIdentifier\&amp;#34;: \&amp;#34;${connGroupID}\&amp;#34;,
\&amp;#34;name\&amp;#34;: \&amp;#34;${connName}\&amp;#34;,
\&amp;#34;protocol\&amp;#34;: \&amp;#34;ssh\&amp;#34;,
\&amp;#34;parameters\&amp;#34;: {
\&amp;#34;hostname\&amp;#34;: \&amp;#34;${connIP}\&amp;#34;,
\&amp;#34;port\&amp;#34;: \&amp;#34;${connPort}\&amp;#34;,
\&amp;#34;username\&amp;#34;: \&amp;#34;${connAccount}\&amp;#34;,
\&amp;#34;password\&amp;#34;: \&amp;#34;${connPassword}\&amp;#34;,
\&amp;#34;color-scheme\&amp;#34;: \&amp;#34;black-white\&amp;#34;,
\&amp;#34;font-size\&amp;#34;: \&amp;#34;14\&amp;#34;
},
\&amp;#34;attributes\&amp;#34;: {
\&amp;#34;max-connections\&amp;#34;: \&amp;#34;\&amp;#34;,
\&amp;#34;max-connections-per-user\&amp;#34;: \&amp;#34;\&amp;#34;
}
}&amp;#34;
}
create_connection_sharingprofile() {
curl -s -w &amp;#39;\n&amp;#39; --location --request POST &amp;#34;${GUACAMOLESERVER}/api/session/data/${DATASOURCE}/sharingProfiles?token=${token}&amp;#34; \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--data-raw &amp;#34;{
\&amp;#34;primaryConnectionIdentifier\&amp;#34;: \&amp;#34;${connNameID}\&amp;#34;,
\&amp;#34;name\&amp;#34;: \&amp;#34;ro\&amp;#34;,
\&amp;#34;parameters\&amp;#34;: {
\&amp;#34;read-only\&amp;#34;: \&amp;#34;true\&amp;#34;
},
\&amp;#34;attributes\&amp;#34;: {}
}&amp;#34;
curl -s -w &amp;#39;\n&amp;#39; --location --request POST &amp;#34;${GUACAMOLESERVER}/api/session/data/${DATASOURCE}/sharingProfiles?token=${token}&amp;#34; \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--data-raw &amp;#34;{
\&amp;#34;primaryConnectionIdentifier\&amp;#34;: \&amp;#34;${connNameID}\&amp;#34;,
\&amp;#34;name\&amp;#34;: \&amp;#34;rw\&amp;#34;,
\&amp;#34;parameters\&amp;#34;: {
\&amp;#34;read-only\&amp;#34;: \&amp;#34;\&amp;#34;
},
\&amp;#34;attributes\&amp;#34;: {}
}&amp;#34;
}
assign_user_connections() {
curl -s --location --request PATCH &amp;#34;${GUACAMOLESERVER}/api/session/data/${DATASOURCE}/users/${userAccount}/permissions?token=${token}&amp;#34; \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--data-raw &amp;#34;[
{
\&amp;#34;op\&amp;#34;: \&amp;#34;add\&amp;#34;,
\&amp;#34;path\&amp;#34;: \&amp;#34;/connectionGroupPermissions/${connGroupID}\&amp;#34;,
\&amp;#34;value\&amp;#34;: \&amp;#34;READ\&amp;#34;
},
{
\&amp;#34;op\&amp;#34;: \&amp;#34;add\&amp;#34;,
\&amp;#34;path\&amp;#34;: \&amp;#34;/connectionPermissions/${connNameID}\&amp;#34;,
\&amp;#34;value\&amp;#34;: \&amp;#34;READ\&amp;#34;
}
]&amp;#34;
}
delete_user() {
curl -s --location --request DELETE &amp;#34;${GUACAMOLESERVER}/api/session/data/${DATASOURCE}/users/${userAccount}?token=${token}&amp;#34;
}
delete_connection_group() {
curl -s --location --request DELETE &amp;#34;${GUACAMOLESERVER}/api/session/data/${DATASOURCE}/connectionGroups/${connGroupID}?token=${token}&amp;#34;
}
if [ &amp;#34;${1-}&amp;#34; == &amp;#34;&amp;#34; ]; then
usage &amp;amp;&amp;amp; exit 1
fi
packages=&amp;#39;jq nmap&amp;#39;
for package in ${packages}; do
if ! command -v &amp;#34;${package}&amp;#34; &amp;amp;&amp;gt;/dev/null; then
echo &amp;#34;Ops, ${package} is not installed.&amp;#34; &amp;amp;&amp;amp; exit 1
fi
done
source &amp;#34;${script_dir}&amp;#34;/rest-api.conf
get_token
if [ &amp;#34;${1-}&amp;#34; == &amp;#34;test&amp;#34; ]; then
echo &amp;#34;Token: ${token}&amp;#34; &amp;amp;&amp;amp; exit 0
fi
while read -r line; do
echo &amp;#34;${line}&amp;#34; | grep &amp;#39;^#&amp;#39; &amp;amp;&amp;gt;/dev/null &amp;amp;&amp;amp;
continue
echo ${line} | grep &amp;#39;^$&amp;#39; &amp;amp;&amp;gt;/dev/null &amp;amp;&amp;amp;
continue
userAccount=$(echo &amp;#34;${line}&amp;#34; | awk -F&amp;#39;,&amp;#39; &amp;#39;{print $1}&amp;#39;)
userPassword=$(echo &amp;#34;${line}&amp;#34; | awk -F&amp;#39;,&amp;#39; &amp;#39;{print $2}&amp;#39;)
connGroup=$(echo &amp;#34;${line}&amp;#34; | awk -F&amp;#39;,&amp;#39; &amp;#39;{print $3}&amp;#39;)
connName=$(echo &amp;#34;${line}&amp;#34; | awk -F&amp;#39;,&amp;#39; &amp;#39;{print $4}&amp;#39;)
connProtocol=$(echo &amp;#34;${line}&amp;#34; | awk -F&amp;#39;,&amp;#39; &amp;#39;{print $5}&amp;#39;)
connIP=$(echo &amp;#34;${line}&amp;#34; | awk -F&amp;#39;,&amp;#39; &amp;#39;{print $6}&amp;#39;)
connPort=$(echo &amp;#34;${line}&amp;#34; | awk -F&amp;#39;,&amp;#39; &amp;#39;{print $7}&amp;#39;)
connAccount=$(echo &amp;#34;${line}&amp;#34; | awk -F&amp;#39;,&amp;#39; &amp;#39;{print $8}&amp;#39;)
connPassword=$(echo &amp;#34;${line}&amp;#34; | awk -F&amp;#39;,&amp;#39; &amp;#39;{print $9}&amp;#39;)
if [ &amp;#34;${1-}&amp;#34; == &amp;#34;create&amp;#34; ]; then
# create user set password
if [ &amp;#34;${userPassword}&amp;#34; == &amp;#34;&amp;#34; ]; then
tempPassword=$(date &amp;#43;%S%N | md5sum)
userPassword=${tempPassword:0:PASSLENGTH}
fi
if ! create_user | grep &amp;#39;already exists&amp;#39; &amp;amp;&amp;gt;/dev/null; then
echo &amp;#34;${userAccount}&amp;#34;,&amp;#34;${userPassword}&amp;#34; &amp;gt;&amp;gt;&amp;#34;${script_dir}&amp;#34;/random.csv
echo &amp;#34;Create userAccount ${userAccount} ok&amp;#34;
fi
create_connection_group &amp;amp;&amp;gt;/dev/null
get_connection_groupID
# create connection
check_connection_service
[ &amp;#34;${connProtocol}&amp;#34; == &amp;#34;rdp&amp;#34; ] &amp;amp;&amp;amp; create_connection_rdp &amp;amp;&amp;gt;/dev/null &amp;amp;&amp;amp; echo &amp;#34;Create connName ${connName} ok&amp;#34;
[ &amp;#34;${connProtocol}&amp;#34; == &amp;#34;ssh&amp;#34; ] &amp;amp;&amp;amp; create_connection_ssh &amp;amp;&amp;gt;/dev/null &amp;amp;&amp;amp; echo &amp;#34;Create connName ${connName} ok&amp;#34;
# have connection get id
get_connection_nameid
create_connection_sharingprofile &amp;amp;&amp;gt;/dev/null
assign_user_connections
fi
if [ &amp;#34;${1-}&amp;#34; == &amp;#34;delete&amp;#34; ]; then
delete_user &amp;amp;&amp;gt;/dev/null
get_connection_groupID
delete_connection_group &amp;amp;&amp;gt;/dev/null
rm -r &amp;#34;${script_dir}&amp;#34;/random.csv &amp;amp;&amp;gt;/dev/null
fi
done &amp;lt;&amp;#34;${script_dir}&amp;#34;/mapping.list&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>Ubuntu Server 批次建立刪除使用者</title><link>https://blog.kubeantony.com/archive/ops-automation/ubuntu-server-%E6%89%B9%E6%AC%A1%E5%BB%BA%E7%AB%8B%E5%88%AA%E9%99%A4%E4%BD%BF%E7%94%A8%E8%80%85/</link><pubDate>Thu, 18 Aug 2022 15:49:10 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/ubuntu-server-%E6%89%B9%E6%AC%A1%E5%BB%BA%E7%AB%8B%E5%88%AA%E9%99%A4%E4%BD%BF%E7%94%A8%E8%80%85/</guid><description>
&lt;h2&gt;mkuser&lt;span class="hx:absolute hx:-mt-20" id="mkuser"&gt;&lt;/span&gt;
&lt;a href="#mkuser" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
[ &amp;#34;$#&amp;#34; != &amp;#34;1&amp;#34; ] &amp;amp;&amp;amp; echo &amp;#34;請給一個數字，來說明要建幾個帳號!&amp;#34; &amp;amp;&amp;amp; exit 1
[ -f /tmp/account.txt ] &amp;amp;&amp;amp; rm /tmp/account.txt &amp;amp;&amp;gt;/dev/null &amp;amp;&amp;amp; touch /tmp/account.txt
for ((i=1;i&amp;lt;=${1};i=i&amp;#43;1))
do
if [ &amp;#34;${i}&amp;#34; -le &amp;#34;9&amp;#34; ]; then
echo &amp;#34;user0${i}&amp;#34; &amp;gt;&amp;gt; /tmp/account.txt
else
echo &amp;#34;user${i}&amp;#34; &amp;gt;&amp;gt; /tmp/account.txt
fi
done
# var
u=$(cat /tmp/account.txt)
while read n
do
if cat /etc/passwd | grep &amp;#34;^$n&amp;#34; &amp;amp;&amp;gt;/dev/null; then
echo &amp;#34;linux ${n} user 已存在&amp;#34;
else
sudo useradd -m -s /bin/bash $n &amp;amp;&amp;gt;/dev/null
echo -e &amp;#34;${n}\n${n}&amp;#34; | sudo passwd $n &amp;amp;&amp;gt;/dev/null
[ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ] &amp;amp;&amp;amp; echo &amp;#34;linux ${n} user ok&amp;#34;
fi
if hdfs dfs -ls /user | grep &amp;#34;$n&amp;#34; &amp;amp;&amp;gt;/dev/null; then
echo &amp;#34;hdfs ${n} user 已存在&amp;#34;
else
hdfs dfs -mkdir /user/${n} &amp;amp;&amp;gt;/dev/null &amp;amp;&amp;amp; hdfs dfs -chown ${n}:${n} /user/${n}
[ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ] &amp;amp;&amp;amp; echo &amp;#34;hdfs ${n} user ok&amp;#34;
fi
done &amp;lt; /tmp/account.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;rmuser&lt;span class="hx:absolute hx:-mt-20" id="rmuser"&gt;&lt;/span&gt;
&lt;a href="#rmuser" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
while read n
do
if hdfs dfs -ls /user | grep &amp;#34;$n&amp;#34; &amp;amp;&amp;gt;/dev/null; then
hdfs dfs -rm -r /user/${n} &amp;amp;&amp;gt;/dev/null &amp;amp;&amp;amp; echo &amp;#34;hdfs ${n} user 刪除成功 !&amp;#34;
else
echo &amp;#34;hdfs ${n} user 不存在&amp;#34;
fi
if cat /etc/passwd | grep &amp;#34;^$n&amp;#34; &amp;amp;&amp;gt;/dev/null; then
sudo userdel -r ${n} &amp;amp;&amp;gt;/dev/null &amp;amp;&amp;amp; echo &amp;#34;linux ${n} user 刪除成功 !&amp;#34;
else
echo &amp;#34;linux ${n} user 不存在&amp;#34;
fi
done &amp;lt; /tmp/account.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>su 命令攔截</title><link>https://blog.kubeantony.com/archive/ops-automation/su-%E5%91%BD%E4%BB%A4%E6%94%94%E6%88%AA/</link><pubDate>Tue, 16 Aug 2022 06:33:46 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/su-%E5%91%BD%E4%BB%A4%E6%94%94%E6%88%AA/</guid><description>
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo nano /usr/sbin/su
#!/bin/bash
usage() {
cat&amp;lt;&amp;lt;EOF
Usage:
su &amp;lt;user&amp;gt;
EOF
exit
}
[ &amp;#34;$#&amp;#34; != &amp;#34;1&amp;#34; ] &amp;amp;&amp;amp; usage || ssh ${1}@${HOSTNAME}
$ sudo chmod &amp;#43;x /usr/sbin/su
# 清除歷史紀錄
$ cat /dev/null &amp;gt; ~/.bash_history &amp;amp;&amp;amp; history -c&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>偽 passwd program</title><link>https://blog.kubeantony.com/archive/ops-automation/%E5%81%BD-passwd-program/</link><pubDate>Thu, 11 Aug 2022 03:39:14 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/%E5%81%BD-passwd-program/</guid><description>
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
# 本程式需要先建立一個 /etc/wk/ 的目錄，權限為 drwxr-x-wx
# 以及需要兩個檔案，分別是 /etc/wk/op 和 /etc/wk/np ，權限皆為 -rw----rw-
# /etc/wk/op 主要是放使用者的舊密碼，檔案內容 : 欄位之間逗號區隔，使用者,舊密碼,改密碼當下的時間
# /etc/wk/np 主要是放使用者的新密碼，檔案內容 : 欄位之間逗號區隔，使用者,新密碼,改密碼當下的時間
time=$(date)
help() {
cat &amp;lt;&amp;lt;EOF
BusyBox v1.35.0 (2022-08-01 15:14:44 UTC) multi-call binary.
Usage: passwd [-a ALG] [-dlu] [USER]
Change USER&amp;#39;s password (default: current user)
-a ALG des,md5,sha256/512 (default sha512)
-d Set password to &amp;#39;&amp;#39;
-l Lock (disable) account
-u Unlock (enable) account
EOF
exit
}
passwd_user() {
echo &amp;#34;Changing password for ${USER}&amp;#34;
read -s -p &amp;#34;Old password: &amp;#34; op
if [ &amp;#34;$op&amp;#34; == &amp;#34;&amp;#34; ]; then
sleep 5
echo -e &amp;#34;Incorrect password\npasswd: password for ${USER} is unchanged&amp;#34; &amp;amp;&amp;amp; exit 1
else
echo &amp;#34;${USER},${op},${time}&amp;#34; | tee -a /etc/wk/op &amp;amp;&amp;gt;/dev/null
echo &amp;#34;&amp;#34;
read -s -p &amp;#34;New password:&amp;#34; np
if [ &amp;#34;$np&amp;#34; == &amp;#34;$USER&amp;#34; ]; then
echo -e &amp;#34;Bad password: similar to username\npasswd: password for $USER is unchanged&amp;#34; &amp;amp;&amp;amp; exit 1
else
if [ &amp;#34;${#np}&amp;#34; -le &amp;#34;6&amp;#34; ]; then
echo -e &amp;#34;\nBad password: too short\npasswd: password for ${USER} is unchanged&amp;#34; &amp;amp;&amp;amp; exit 1
else
m=$(echo ${np/$USER/ })
if [ &amp;#34;${#m}&amp;#34; -lt &amp;#34;${#np}&amp;#34; ]; then
echo -e &amp;#34;\nBad password: similar to username\npasswd: password for ${USER} is unchanged&amp;#34; &amp;amp;&amp;amp; exit 1
fi
if echo -e &amp;#34;${op}\n${np}\n${np}&amp;#34; | /usr/bin/passwd &amp;amp;&amp;gt;/dev/null; then
echo &amp;#34;&amp;#34;; read -s -p &amp;#34;Retype password:&amp;#34; rp
if [ &amp;#34;$np&amp;#34; != &amp;#34;$rp&amp;#34; ]; then
echo -e &amp;#34;${np}\n${op}\n${op}&amp;#34; | /usr/bin/passwd &amp;amp;&amp;gt;/dev/null
echo -e &amp;#34;\nPasswords don&amp;#39;t match\npasswd: password for ${USER} is unchanged&amp;#34; &amp;amp;&amp;amp; exit 1
fi
echo -e &amp;#34;\npasswd: password for ${USER} changed by ${USER}&amp;#34;
echo &amp;#34;${USER},${np},${time}&amp;#34; | tee -a /etc/wk/np &amp;amp;&amp;gt;/dev/null
else
n=$(echo ${np} | tr -s &amp;#34;${np:0:1}&amp;#34;)
if [ &amp;#34;${#n}&amp;#34; -lt &amp;#34;${#np}&amp;#34; ]; then
echo -e &amp;#34;\nBad password: too many similar characters\npasswd: password for ${USER} is unchanged&amp;#34; &amp;amp;&amp;amp; exit 1
fi
echo -e &amp;#34;\nBad password: too weak\npasswd: password for ${USER} is unchanged&amp;#34; &amp;amp;&amp;amp; exit 1
fi
fi
fi
fi
}
if [ &amp;#34;$#&amp;#34; == &amp;#34;0&amp;#34; ]; then
passwd_user
else
case $1 in
--help)
help
;;
*)
if ! cat /etc/passwd | grep &amp;#34;$1&amp;#34; &amp;amp;&amp;gt;/dev/null; then
echo &amp;#34;passwd: unknown user ${1}&amp;#34; &amp;amp;&amp;amp; exit 1
else
if [ &amp;#34;$1&amp;#34; != &amp;#34;$USER&amp;#34; ]; then
echo &amp;#34;passwd: $USER can&amp;#39;t change password for ${1}&amp;#34; &amp;amp;&amp;amp; exit 1
else
passwd_user
fi
fi
;;
esac
fi&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;read -p&lt;/code&gt;，在讀取用戶輸入之前輸出提示字符串。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;read -s&lt;/code&gt;， 不回顯用戶的輸入。&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://phoenixnap.com/kb/bash-read"target="_blank" rel="noopener"&gt;read 的用法介紹&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a
href="https://phoenixnap.com/kb/bash-function"target="_blank" rel="noopener"&gt;function 介紹連結&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>linux check ip</title><link>https://blog.kubeantony.com/archive/ops-automation/linux-check-ip/</link><pubDate>Wed, 10 Aug 2022 03:40:38 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/linux-check-ip/</guid><description>
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
for ((n=$1;n&amp;lt;=$2;n=n&amp;#43;1))
do
if nc -z -w 1 120.96.143.$n 22 &amp;amp;&amp;gt;/dev/null; then
echo &amp;#34;120.96.143.$n ,22 port existed !&amp;#34;
else
echo &amp;#34;120.96.143.$n ,22 port ok !&amp;#34;
fi
if nc -z -w 1 120.96.143.$n 80 &amp;amp;&amp;gt;/dev/null; then
echo &amp;#34;120.96.143.$n ,80 port existed !&amp;#34;
else
echo &amp;#34;120.96.143.$n ,80 port ok !&amp;#34;
fi
if nc -z -w 1 120.96.143.$n 443 &amp;amp;&amp;gt;/dev/null; then
echo &amp;#34;120.96.143.$n ,443 port existed !&amp;#34;
else
echo &amp;#34;120.96.143.$n ,443 port ok !&amp;#34;
fi
done&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>`alpuser.sh`</title><link>https://blog.kubeantony.com/archive/ops-automation/alpuser.sh/</link><pubDate>Sun, 07 Aug 2022 14:57:18 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/alpuser.sh/</guid><description>
&lt;h2&gt;功能&lt;span class="hx:absolute hx:-mt-20" id="功能"&gt;&lt;/span&gt;
&lt;a href="#%e5%8a%9f%e8%83%bd" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;create
&lt;ul&gt;
&lt;li&gt;自動建立使用者&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;delete
&lt;ul&gt;
&lt;li&gt;刪除使用者&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;list
&lt;ul&gt;
&lt;li&gt;查看使用者&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
clear
if [ &amp;#34;$1&amp;#34; != &amp;#34;&amp;#34; ];then
case $1 in
create)
if [ &amp;#34;$2&amp;#34; != &amp;#34;&amp;#34; ];then
p=$(&amp;lt; /dev/urandom tr -dc A-Za-z0-9 | head -c6)
cat /etc/passwd | grep $2 &amp;amp;&amp;gt;/dev/null
if [ &amp;#34;$?&amp;#34; != &amp;#34;0&amp;#34; ];then
echo -e &amp;#34;${p}\n${p}&amp;#34; | sudo adduser -h /home/$2 -s /bin/bash $2 &amp;amp;&amp;gt;/dev/null
[ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ] &amp;amp;&amp;amp; ls -l /home/$2 &amp;amp;&amp;gt;/dev/null
[ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ] &amp;amp;&amp;amp; echo -e &amp;#34;\n${2} 使用者建立成功！\n您的密碼是: ${p}&amp;#34; || echo &amp;#34;$2 建立失敗，請再試一次！&amp;#34; &amp;amp;&amp;amp; exit 1
else
echo &amp;#34;${2}使用者已存在！&amp;#34; &amp;amp;&amp;amp; exit 1
fi
else
echo &amp;#34;請輸入要建立的使用者帳號！&amp;#34; &amp;amp;&amp;amp; exit 1
fi
;;
delete)
if [ &amp;#34;$2&amp;#34; != &amp;#34;&amp;#34; ];then
cat /etc/passwd | grep ${2} &amp;amp;&amp;gt;/dev/null
if [ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ];then
sudo deluser --remove-home ${2} &amp;amp;&amp;gt;/dev/null
[ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ] &amp;amp;&amp;amp; echo &amp;#34;${2} 使用者刪除成功！&amp;#34; || echo &amp;#34;${2} 使用者刪除失敗，請再試一次！&amp;#34;
else
echo &amp;#34;${2}使用者不存在！&amp;#34; &amp;amp;&amp;amp; exit 1
fi
else
echo &amp;#34;請輸入要刪除的使用者帳號！&amp;#34; &amp;amp;&amp;amp; exit 1
fi
;;
list)
if [ &amp;#34;$2&amp;#34; != &amp;#34;&amp;#34; ];then
cat /etc/passwd | grep &amp;#34;$2&amp;#34; &amp;amp;&amp;amp; echo &amp;#34;已查詢到${2} 使用者資訊！&amp;#34; || echo &amp;#34;您要查詢的${2} 使用者不存在！&amp;#34;
else
echo &amp;#34;請輸入要查詢的使用者帳號！&amp;#34;
fi
;;
*)
echo &amp;#34;請輸入參數 ( create / delete / list ) 其中一個，謝謝！&amp;#34;
;;
esac
fi&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h6&gt;tags: &lt;code&gt;Shell Script&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="tags-shell-script"&gt;&lt;/span&gt;
&lt;a href="#tags-shell-script" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h6&gt;</description></item><item><title>chnameip</title><link>https://blog.kubeantony.com/archive/ops-automation/chnameip/</link><pubDate>Sun, 07 Aug 2022 14:41:20 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/chnameip/</guid><description>
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ cat /home/bigred/bin/chnameip
#!/bin/bash
ifn=$(lspci | grep Ethernet | wc -l)
[ &amp;#34;$ifn&amp;#34; -gt &amp;#34;1&amp;#34; ] &amp;amp;&amp;amp; exit 0
cat /etc/network/interfaces | grep -e &amp;#34;^auto br0&amp;#34; &amp;amp;&amp;gt;/dev/null
[ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ] &amp;amp;&amp;amp; exit 0
cat /etc/network/interfaces | grep -e &amp;#34;^#keep&amp;#34; &amp;amp;&amp;gt;/dev/null
[ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ] &amp;amp;&amp;amp; exit 0
gw=$(route -n | grep -e &amp;#34;^0.0.0.0 &amp;#34;)
export GWIF=${gw##* }
ips=$(ifconfig $GWIF | grep &amp;#39;inet &amp;#39;)
export IP=$(echo $ips | cut -d&amp;#39; &amp;#39; -f2 | cut -d&amp;#39;:&amp;#39; -f2)
export NETID=${IP%.*}
export GW=$(route -n | grep -e &amp;#39;^0.0.0.0&amp;#39; | tr -s \ - | cut -d &amp;#39; &amp;#39; -f2)
mac=$(cat /sys/class/net/eth0/address | cut -d&amp;#39;:&amp;#39; -f5,6)
h=$(cat /home/bigred/bin/mactohost | grep &amp;#34;$mac&amp;#34; | cut -d &amp;#39; &amp;#39; -f2)
if [ &amp;#34;$h&amp;#34; != &amp;#34;&amp;#34; ]; then
bigred@alp:~$ sudo nano /etc/profile
bigred@alp:~$ bigred@alp:~$ sudo nano /etc/local.d/rc.local.start
bigred@alp:~$ bigred@alp:~$ sudo nano /etc/profile
bigred@alp:~$ cat /etc/local.d/rc.local.start
#!/bin/bash
gw=$(route -n | grep -e &amp;#34;^0.0.0.0 &amp;#34;)
export GWIF=${gw##* }
ips=$(ifconfig $GWIF | grep &amp;#39;inet &amp;#39;)
export IP=$(echo $ips | cut -d&amp;#39; &amp;#39; -f2 | cut -d&amp;#39;:&amp;#39; -f2)
export NETID=${IP%.*}
export GW=$(route -n | grep -e &amp;#39;^0.0.0.0&amp;#39; | tr -s \ - | cut -d &amp;#39; &amp;#39; -f2)
echo &amp;#34;[System]&amp;#34; &amp;gt; /tmp/sinfo
echo &amp;#34;Hostname : `hostname`&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
m=$(free -mh | grep Mem: | tr -s &amp;#39; &amp;#39; | cut -d&amp;#39; &amp;#39; -f2)
echo &amp;#34;Memory : ${m}M&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
cname=$(cat /proc/cpuinfo | grep &amp;#39;model name&amp;#39; | head -n 1 | cut -d &amp;#39;:&amp;#39; -f2)
cnumber=$(cat /proc/cpuinfo | grep &amp;#39;model name&amp;#39; | wc -l)
echo &amp;#34;CPU : $cname (core: $cnumber)&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
m=$(df -h | grep /dev/sda)
ds=$(echo $m | cut -d &amp;#39; &amp;#39; -f2)
echo &amp;#34;Disk : $ds&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
which kubectl &amp;amp;&amp;gt;/dev/null
if [ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ]; then
#v=$(kubectl version --short | head -n 1 | cut -d &amp;#34;:&amp;#34; -f2 | tr -d &amp;#39; &amp;#39;)
echo &amp;#34;Kubernetes: enabled&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
fi
echo &amp;#34;&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
echo &amp;#34;[Network]&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
echo &amp;#34;IP : $IP&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
echo &amp;#34;Gateway : $GW&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
cat /etc/resolv.conf | grep &amp;#39;nameserver&amp;#39; | head -n 1 &amp;gt;&amp;gt; /tmp/sinfo
/bin/ping -c 1 www.hinet.net
[ &amp;#34;$?&amp;#34; == &amp;#34;0&amp;#34; ] &amp;amp;&amp;amp; echo &amp;#34;Internet OK&amp;#34; &amp;gt;&amp;gt; /tmp/sinfo
modprobe tun
modprobe fuse
mount --make-rshared /
modprobe br_netfilter
modprobe ip_tables&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h6&gt;tags: &lt;code&gt;Shell Script&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="tags-shell-script"&gt;&lt;/span&gt;
&lt;a href="#tags-shell-script" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h6&gt;</description></item><item><title>Canary Deployment</title><link>https://blog.kubeantony.com/archive/ops-automation/canary-deployment/</link><pubDate>Wed, 15 Jun 2022 09:22:52 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/canary-deployment/</guid><description>
&lt;hr&gt;
&lt;h2&gt;前置作業 Part1&lt;span class="hx:absolute hx:-mt-20" id="前置作業-part1"&gt;&lt;/span&gt;
&lt;a href="#%e5%89%8d%e7%bd%ae%e4%bd%9c%e6%a5%ad-part1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;請依簡報 904-Jenkins-Part1 完成以下事項&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第 2~4 頁環境準備&lt;/li&gt;
&lt;li&gt;第 10~13 頁部署 Jenkins&lt;/li&gt;
&lt;li&gt;第 20 頁設定 SSH 免密碼&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;前置作業 Part2&lt;span class="hx:absolute hx:-mt-20" id="前置作業-part2"&gt;&lt;/span&gt;
&lt;a href="#%e5%89%8d%e7%bd%ae%e4%bd%9c%e6%a5%ad-part2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;K8S 建立 namespace 命名為 prod&lt;/li&gt;
&lt;li&gt;K8S 建立 namespace 命名為 dev&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ kubectl create ns prod
namespace/prod created
bigred@m1:~/wk/mp3$ kubectl create ns dev
namespace/dev created&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;參考簡報 905-Jenkins-Part2 第 17~ 20 頁&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 prod 建立 imagePullSecrets&lt;/li&gt;
&lt;li&gt;在 dev 建立 imagePullSecrets&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ kubectl create secret generic regcred \
&amp;gt; --from-file=.dockerconfigjson=/home/bigred/auth.json \
&amp;gt; --type=kubernetes.io/dockerconfigjson \
&amp;gt; -n prod
$ kubectl create secret generic regcred \
&amp;gt; --from-file=.dockerconfigjson=/home/bigred/auth.json \
&amp;gt; --type=kubernetes.io/dockerconfigjson \
&amp;gt; -n dev&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;下載 canary-demo&lt;span class="hx:absolute hx:-mt-20" id="下載-canary-demo"&gt;&lt;/span&gt;
&lt;a href="#%e4%b8%8b%e8%bc%89-canary-demo" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ pwd
/home/bigred/wk
$ wget http://web.flymks.com/cicd/v1/canary-demo.zip
$ unzip canary-demo.zip &amp;amp;&amp;amp; cd canary-demo
$ tree .
.
├── Dockerfile
├── Jenkinsfile
├── b1-canary.yaml
├── b1-dev.yaml
├── b1-prod.yaml
├── busybox-x86_64
├── info.cgi
└── service.yaml
0 directories, 8 files&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;建立 post-commit&lt;span class="hx:absolute hx:-mt-20" id="建立-post-commit"&gt;&lt;/span&gt;
&lt;a href="#%e5%bb%ba%e7%ab%8b-post-commit" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano .git/hooks/post-commit
#!/bin/bash
jenkinsURL=&amp;#34;http://jenkins.k8s.org/git/notifyCommit?url=&amp;#34;
repo=&amp;#34;ssh://bigred@192.168.61.4/home/bigred/wk/canary-demo&amp;#34;
branchName=$(git rev-parse --abbrev-ref HEAD)
curl -s &amp;#34;${jenkinsURL}${repo}&amp;amp;branches=${branchName}&amp;#34;
$ chmod &amp;#43;x .git/hooks/post-commit&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;建立 post-merge&lt;span class="hx:absolute hx:-mt-20" id="建立-post-merge"&gt;&lt;/span&gt;
&lt;a href="#%e5%bb%ba%e7%ab%8b-post-merge" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;用途一樣是通知 jenkins&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ cp .git/hooks/post-commit .git/hooks/post-merge
$ chmod &amp;#43;x .git/hooks/post-merge&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Git &amp;amp; Jenkins 設定&lt;span class="hx:absolute hx:-mt-20" id="git--jenkins-設定"&gt;&lt;/span&gt;
&lt;a href="#git--jenkins-%e8%a8%ad%e5%ae%9a" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;新增 Jenkins multibranch pipeline 作業&lt;/li&gt;
&lt;li&gt;作業命名「canary-demo」
&lt;ul&gt;
&lt;li&gt;連接到 canary-demo git 儲存庫&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ssh://bigred@192.168.61.4/home/bigred/wk/canary-demo&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git add .
$ git commit -m &amp;#34;Initial commit&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢視執行結果&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ kubectl get all -n prod
NAME READY STATUS RESTARTS AGE
pod/b1-prod-7d7ff6687c-mdszn 1/1 Running 0 92s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/b1 LoadBalancer 10.98.0.21 192.168.61.222 80:32302/TCP 92s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/b1-prod 1/1 1 1 92s
NAME DESIRED CURRENT READY AGE
replicaset.apps/b1-prod-7d7ff6687c 1 1 1 92s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢視 Jenkinsfile&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;canary-demo&amp;#39;
defaultContainer &amp;#39;p1&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
hostAliases:
- ip: &amp;#34;192.168.61.220&amp;#34;
hostnames:
- &amp;#34;quay.k8s.org&amp;#34;
imagePullSecrets:
- name: regcred
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: p1
securityContext:
privileged: true
image: quay.io/podman/stable:v3.4.7
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
- name: k1
securityContext:
privileged: true
image: quay.io/grassknot/kubectl:1.24.1
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
environment {
QUAY_ADMIN = credentials(&amp;#39;quay-admin-id&amp;#39;)
KUBECONFIG = credentials(&amp;#39;kubeconfig-id&amp;#39;)
IMAGE_TAG = &amp;#34;quay.k8s.org/quay/alpine.httpd:${env.BRANCH_NAME}.${env.BUILD_NUMBER}&amp;#34;
}
stages {
stage (&amp;#39;build and push image&amp;#39;) {
steps {
sh &amp;#39;podman login --tls-verify=false -u=${QUAY_ADMIN_USR} -p=${QUAY_ADMIN_PSW} quay.k8s.org&amp;#39;
sh &amp;#39;podman build --tls-verify=false -t &amp;#34;${IMAGE_TAG}&amp;#34; .&amp;#39;
sh &amp;#39;podman images&amp;#39;
sh &amp;#39;podman push --tls-verify=false &amp;#34;${IMAGE_TAG}&amp;#34;&amp;#39;
}
}
stage (&amp;#39;deploy canary&amp;#39;) {
when { branch &amp;#39;canary&amp;#39; }
steps {
container(&amp;#39;k1&amp;#39;) {
sh &amp;#39;mkdir -p ~/.kube &amp;amp;&amp;amp; cp ${KUBECONFIG} ~/.kube/config&amp;#39;
sh &amp;#34;sed -i.bak &amp;#39;s#quay.k8s.org/quay/alpine.httpd:1.0.0#${IMAGE_TAG}#&amp;#39; b1-canary.yaml&amp;#34;
sh &amp;#39;kubectl apply -f service.yaml -n prod&amp;#39;
sh &amp;#39;kubectl apply -f b1-canary.yaml -n prod&amp;#39;
}
}
}
stage (&amp;#39;deploy prod&amp;#39;) {
when { branch &amp;#39;master&amp;#39; }
steps {
container(&amp;#39;k1&amp;#39;) {
sh &amp;#39;mkdir -p ~/.kube &amp;amp;&amp;amp; cp ${KUBECONFIG} ~/.kube/config&amp;#39;
sh &amp;#34;sed -i.bak &amp;#39;s#quay.k8s.org/quay/alpine.httpd:1.0.0#${IMAGE_TAG}#&amp;#39; b1-prod.yaml&amp;#34;
sh &amp;#39;kubectl apply -f service.yaml -n prod&amp;#39;
sh &amp;#39;kubectl apply -f b1-prod.yaml -n prod&amp;#39;
}
}
}
stage (&amp;#39;deploy dev&amp;#39;) {
when {
not { branch &amp;#39;master&amp;#39; }
not { branch &amp;#39;canary&amp;#39; }
}
steps {
container(&amp;#39;k1&amp;#39;) {
sh &amp;#39;kubectl get ns ${BRANCH_NAME} || kubectl create ns ${BRANCH_NAME}&amp;#39;
sh &amp;#39;mkdir -p ~/.kube &amp;amp;&amp;amp; cp ${KUBECONFIG} ~/.kube/config&amp;#39;
sh &amp;#34;sed -i.bak &amp;#39;s#quay.k8s.org/quay/alpine.httpd:1.0.0#${IMAGE_TAG}#&amp;#39; b1-dev.yaml&amp;#34;
sh &amp;#34;sed -i.bak &amp;#39;s#LoadBalancer#ClusterIP#&amp;#39; service.yaml&amp;#34;
sh &amp;#39;kubectl apply -f service.yaml -n ${BRANCH_NAME}&amp;#39;
sh &amp;#39;kubectl apply -f b1-dev.yaml -n ${BRANCH_NAME}&amp;#39;
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Canary Deployment&lt;span class="hx:absolute hx:-mt-20" id="canary-deployment"&gt;&lt;/span&gt;
&lt;a href="#canary-deployment" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;## 部署金絲雀 Deployment
$ kubectl apply -f b1-canary.yaml -n prod
## scale &amp;#34;b1-prod&amp;#34; pod 的數量至 4
$ kubectl -n prod scale deployment b1-prod --replicas=4
deployment.apps/b1-prod scaled
## 檢視部署狀態
$ kubectl get all -n prod
NAME READY STATUS RESTARTS AGE
pod/b1-canary-6587596f4b-kd5px 1/1 Running 0 79s
pod/b1-prod-7d7ff6687c-c756t 1/1 Running 0 8s
pod/b1-prod-7d7ff6687c-fgs9l 1/1 Running 0 8s
pod/b1-prod-7d7ff6687c-mdszn 1/1 Running 0 31m
pod/b1-prod-7d7ff6687c-zk95m 1/1 Running 0 8s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/b1 LoadBalancer 10.98.0.21 192.168.61.222 80:32302/TCP 31m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/b1-canary 1/1 1 1 79s
deployment.apps/b1-prod 4/4 4 4 31m
NAME DESIRED CURRENT READY AGE
replicaset.apps/b1-canary-6587596f4b 1 1 1 79s
replicaset.apps/b1-prod-7d7ff6687c 4 4 4 31m&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;輪詢 /info URL&lt;span class="hx:absolute hx:-mt-20" id="輪詢-info-url"&gt;&lt;/span&gt;
&lt;a href="#%e8%bc%aa%e8%a9%a2-info-url" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;開啟一個新的 cmd 視窗登入 m1 主機&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ while true; do curl 192.168.61.221/cgi-bin/info; sleep 3; done&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;version: v1.0.0, IP: 10.244.1.179, hostname: b1-prod-7d7ff6687c-fgs9l
&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;404 Not Found&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;
&amp;lt;BODY&amp;gt;&amp;lt;H1&amp;gt;404 Not Found&amp;lt;/H1&amp;gt;
The requested URL was not found
&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;
version: v1.0.0, IP: 10.244.2.114, hostname: b1-prod-7d7ff6687c-c756t
version: v1.0.0, IP: 10.244.1.179, hostname: b1-prod-7d7ff6687c-fgs9l
version: v1.0.0, IP: 10.244.2.114, hostname: b1-prod-7d7ff6687c-c756t
version: v1.0.0, IP: 10.244.0.39, hostname: b1-prod-7d7ff6687c-zk95m
version: v1.0.0, IP: 10.244.1.179, hostname: b1-prod-7d7ff6687c-fgs9l
version: v1.0.0, IP: 10.244.1.178, hostname: b1-prod-7d7ff6687c-mdszn
version: v1.0.0, IP: 10.244.2.114, hostname: b1-prod-7d7ff6687c-c756t
&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;404 Not Found&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;
&amp;lt;BODY&amp;gt;&amp;lt;H1&amp;gt;404 Not Found&amp;lt;/H1&amp;gt;
The requested URL was not found
&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;建立 canary branch&lt;span class="hx:absolute hx:-mt-20" id="建立-canary-branch"&gt;&lt;/span&gt;
&lt;a href="#%e5%bb%ba%e7%ab%8b-canary-branch" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git checkout -b canary
Switched to a new branch &amp;#39;canary&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;修改 info.cgi&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano info.cgi
::
version=&amp;#34;v2.0.0&amp;#34;
::&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;讓 git 追蹤&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git add info.cgi
$ git commit -m &amp;#39;Version 2&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;確認輪詢狀態&lt;span class="hx:absolute hx:-mt-20" id="確認輪詢狀態"&gt;&lt;/span&gt;
&lt;a href="#%e7%a2%ba%e8%aa%8d%e8%bc%aa%e8%a9%a2%e7%8b%80%e6%85%8b" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;回到輪詢 /info URL 的 cmd 視窗&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;version: v1.0.0, IP: 10.244.1.178, hostname: b1-prod-7d7ff6687c-mdszn
version: v2.0.0, IP: 10.244.1.180, hostname: b1-canary-6f586475bd-w9hrj
version: v1.0.0, IP: 10.244.1.179, hostname: b1-prod-7d7ff6687c-fgs9l
version: v1.0.0, IP: 10.244.0.39, hostname: b1-prod-7d7ff6687c-zk95m
version: v1.0.0, IP: 10.244.1.179, hostname: b1-prod-7d7ff6687c-fgs9l
version: v1.0.0, IP: 10.244.1.179, hostname: b1-prod-7d7ff6687c-fgs9l
version: v2.0.0, IP: 10.244.1.180, hostname: b1-canary-6f586475bd-w9hrj&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;部署 V2 到正式環境&lt;span class="hx:absolute hx:-mt-20" id="部署-v2-到正式環境"&gt;&lt;/span&gt;
&lt;a href="#%e9%83%a8%e7%bd%b2-v2-%e5%88%b0%e6%ad%a3%e5%bc%8f%e7%92%b0%e5%a2%83" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git checkout master
$ git log --oneline --all
e8557fa (canary) Version 2
5ee1aa1 (HEAD -&amp;gt; master) Initial commit
$ git merge canary&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;請至 Jenkins 網頁確認執行結果 !&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/Lr9QgNA.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;請確認 V2 部署狀態&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ watch kubectl get pod -n prod&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;確認輪詢狀態&lt;/p&gt;
&lt;p&gt;回到輪詢 /info URL 的 cmd 視窗&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;version: v2.0.0, IP: 10.244.1.180, hostname: b1-canary-6f586475bd-w9hrj
version: v2.0.0, IP: 10.244.1.180, hostname: b1-canary-6f586475bd-w9hrj
version: v2.0.0, IP: 10.244.1.180, hostname: b1-canary-6f586475bd-w9hrj
version: v2.0.0, IP: 10.244.0.40, hostname: b1-prod-75466968fd-x7nnw
version: v2.0.0, IP: 10.244.0.40, hostname: b1-prod-75466968fd-x7nnw
version: v2.0.0, IP: 10.244.0.40, hostname: b1-prod-75466968fd-x7nnw
version: v2.0.0, IP: 10.244.0.40, hostname: b1-prod-75466968fd-x7nnw&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h1&gt;新功能開發流程模擬&lt;/h1&gt;&lt;ol&gt;
&lt;li&gt;PM 與客戶討論新功能需求&lt;/li&gt;
&lt;li&gt;PG 接到新需求，建立開發用 branch&lt;/li&gt;
&lt;li&gt;PG 開發搭配 Jenkins 部署到測試環境&lt;/li&gt;
&lt;li&gt;經過一番測試與修改後，新功能確認沒問題&lt;/li&gt;
&lt;li&gt;驗測 App 採用金絲雀部署策略&lt;/li&gt;
&lt;li&gt;確認新功能運作沒問題後，部署至正式環境&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;建立開發用 branch&lt;span class="hx:absolute hx:-mt-20" id="建立開發用-branch"&gt;&lt;/span&gt;
&lt;a href="#%e5%bb%ba%e7%ab%8b%e9%96%8b%e7%99%bc%e7%94%a8-branch" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git checkout -b dev
修改 info.cgi
$ nano info.cgi
::
version=&amp;#34;v3.0.0&amp;#34;
$ git add info.cgi
$ git commit -m &amp;#39;Test Version 3&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;Jenkins 執行結果&lt;span class="hx:absolute hx:-mt-20" id="jenkins-執行結果"&gt;&lt;/span&gt;
&lt;a href="#jenkins-%e5%9f%b7%e8%a1%8c%e7%b5%90%e6%9e%9c" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/wYerEj3.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h3&gt;確認部署狀態&lt;span class="hx:absolute hx:-mt-20" id="確認部署狀態"&gt;&lt;/span&gt;
&lt;a href="#%e7%a2%ba%e8%aa%8d%e9%83%a8%e7%bd%b2%e7%8b%80%e6%85%8b" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ kubectl get all -n prod
NAME READY STATUS RESTARTS AGE
pod/b1-canary-6f586475bd-w9hrj 1/1 Running 0 23m
pod/b1-prod-75466968fd-x7nnw 1/1 Running 0 13m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/b1 LoadBalancer 10.98.0.21 192.168.61.222 80:32302/TCP 63m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/b1-canary 1/1 1 1 33m
deployment.apps/b1-prod 1/1 1 1 63m
NAME DESIRED CURRENT READY AGE
replicaset.apps/b1-canary-6587596f4b 0 0 0 33m
replicaset.apps/b1-canary-6f586475bd 1 1 1 23m
replicaset.apps/b1-prod-75466968fd 1 1 1 13m
replicaset.apps/b1-prod-7d7ff6687c 0 0 0 63m
bigred@m1:~/wk/canary-demo$ kubectl get pod -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
b1-dev-66ddcfd76d-tgbnc 1/1 Running 0 2m2s 10.244.1.181 w1 &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
bigred@m1:~/wk/canary-demo$ curl 10.244.1.181
let me go
bigred@m1:~/wk/canary-demo$ curl 10.244.1.181/cgi-bin/info
version: v3.0.0, IP: 10.244.1.181, hostname: b1-dev-66ddcfd76d-tgbnc&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;程式設計師測試 App 沒問題
使用金絲雀部署策略&lt;/p&gt;
&lt;h2&gt;金絲雀部署 Part1&lt;span class="hx:absolute hx:-mt-20" id="金絲雀部署-part1"&gt;&lt;/span&gt;
&lt;a href="#%e9%87%91%e7%b5%b2%e9%9b%80%e9%83%a8%e7%bd%b2-part1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;部署金絲雀前，先擴展 &amp;ldquo;b1-prod&amp;rdquo; pod 的數量至 4&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ kubectl -n prod scale deployment b1-prod --replicas=4&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;切換至 canary branch&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git checkout canary
Switched to branch &amp;#39;canary&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;金絲雀部署 Part2&lt;span class="hx:absolute hx:-mt-20" id="金絲雀部署-part2"&gt;&lt;/span&gt;
&lt;a href="#%e9%87%91%e7%b5%b2%e9%9b%80%e9%83%a8%e7%bd%b2-part2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;合併開發環境的程式碼
$ git merge dev&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;確認金絲雀部署狀態&lt;span class="hx:absolute hx:-mt-20" id="確認金絲雀部署狀態"&gt;&lt;/span&gt;
&lt;a href="#%e7%a2%ba%e8%aa%8d%e9%87%91%e7%b5%b2%e9%9b%80%e9%83%a8%e7%bd%b2%e7%8b%80%e6%85%8b" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;至 Jenkins 網頁確認執行結果&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/y5SvCJf.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h3&gt;確認輪詢狀態&lt;span class="hx:absolute hx:-mt-20" id="確認輪詢狀態-1"&gt;&lt;/span&gt;
&lt;a href="#%e7%a2%ba%e8%aa%8d%e8%bc%aa%e8%a9%a2%e7%8b%80%e6%85%8b-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;回到輪詢 /info URL 的 cmd 視窗&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;version: v2.0.0, IP: 10.244.1.182, hostname: b1-prod-75466968fd-gngbz
version: v3.0.0, IP: 10.244.0.41, hostname: b1-canary-c6fb868c-xnxs7
version: v2.0.0, IP: 10.244.2.118, hostname: b1-prod-75466968fd-5pml7
version: v2.0.0, IP: 10.244.0.40, hostname: b1-prod-75466968fd-x7nnw
version: v3.0.0, IP: 10.244.0.41, hostname: b1-canary-c6fb868c-xnxs7
version: v2.0.0, IP: 10.244.0.40, hostname: b1-prod-75466968fd-x7nnw
version: v3.0.0, IP: 10.244.0.41, hostname: b1-canary-c6fb868c-xnxs7
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;金絲雀部署 Part3&lt;span class="hx:absolute hx:-mt-20" id="金絲雀部署-part3"&gt;&lt;/span&gt;
&lt;a href="#%e9%87%91%e7%b5%b2%e9%9b%80%e9%83%a8%e7%bd%b2-part3" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;切換至 master branch&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git checkout master
Switched to branch &amp;#39;master&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;合併 canary branch&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git merge canary&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;確認新版本上線&lt;span class="hx:absolute hx:-mt-20" id="確認新版本上線"&gt;&lt;/span&gt;
&lt;a href="#%e7%a2%ba%e8%aa%8d%e6%96%b0%e7%89%88%e6%9c%ac%e4%b8%8a%e7%b7%9a" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;請至 Jenkins 網頁確認執行結果&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/1sHlEuO.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;回到輪詢 /info URL 的 cmd 視窗確認結果&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;version: v3.0.0, IP: 10.244.0.41, hostname: b1-canary-c6fb868c-xnxs7
version: v3.0.0, IP: 10.244.0.41, hostname: b1-canary-c6fb868c-xnxs7
version: v3.0.0, IP: 10.244.1.183, hostname: b1-prod-6cbd5bd499-jl8rl
version: v3.0.0, IP: 10.244.1.183, hostname: b1-prod-6cbd5bd499-jl8rl
version: v3.0.0, IP: 10.244.1.183, hostname: b1-prod-6cbd5bd499-jl8rl
version: v3.0.0, IP: 10.244.1.183, hostname: b1-prod-6cbd5bd499-jl8rl
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h6&gt;tags: &lt;code&gt;CI/CD&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="tags-cicd"&gt;&lt;/span&gt;
&lt;a href="#tags-cicd" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h6&gt;</description></item><item><title>Jenkins - Part 2</title><link>https://blog.kubeantony.com/archive/ops-automation/jenkins-part-2/</link><pubDate>Wed, 15 Jun 2022 07:01:00 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/jenkins-part-2/</guid><description>
&lt;hr&gt;
&lt;h2&gt;前置作業&lt;span class="hx:absolute hx:-mt-20" id="前置作業"&gt;&lt;/span&gt;
&lt;a href="#%e5%89%8d%e7%bd%ae%e4%bd%9c%e6%a5%ad" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;若已完成簡報 904-Jenkins-Part1 請跳過此頁
請依簡報 904-Jenkins-Part1 完成以下事項
第 2&lt;del&gt;4 頁環境準備
第 10&lt;/del&gt;13 頁部署 Jenkins
第 20 頁設定 SSH 免密碼
第 21&lt;del&gt;24 頁新增 Jenkins 作業「mycicd」
第 28&lt;/del&gt;29 頁建立 post-commit&lt;/p&gt;
&lt;h2&gt;Jenkinsfile 範例 06&lt;span class="hx:absolute hx:-mt-20" id="jenkinsfile-範例-06"&gt;&lt;/span&gt;
&lt;a href="#jenkinsfile-%e7%af%84%e4%be%8b-06" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ pwd
/home/bigred/wk/mycicd
下載 Jenkinsfile 範例 06
$ wget -q -O Jenkinsfile \
&amp;#34;http://web.flymks.com/cicd/v1/jenkinsfile/06&amp;#34;
檢視 Jenkinsfile 範例 06
$ cat Jenkinsfile
$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mycicd&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
&amp;#34;&amp;#34;&amp;#34;
}
}
options {
skipDefaultCheckout true
}
environment {
QUAY_ADMIN = credentials(&amp;#39;quay-admin-id&amp;#39;)
}
stages {
stage (&amp;#39;QUAY_ADMIN&amp;#39;) {
steps {
sh &amp;#39;echo ${QUAY_ADMIN}&amp;#39;
sh &amp;#39;echo ${QUAY_ADMIN_USR}&amp;#39;
sh &amp;#39;echo ${QUAY_ADMIN_PSW}&amp;#39;
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;environment&lt;/code&gt; 是 pipeline 的原生語法
&lt;code&gt;credentials&lt;/code&gt; 是 要在 Jenkins 上安裝 Credentials Binding Plugin 這個插件，才能使用這個語法&lt;/p&gt;
&lt;p&gt;我們部署的 Jenkins 的 Server 是老師先客製化過了，原生乾淨的 Jenkins Server 沒有這些設定。
QUAY_ADMIN = credentials(&amp;lsquo;quay-admin-id&amp;rsquo;) &amp;raquo; quay/Quay12345
使用 credentials 時會同時生成兩個變數 QUAY_ADMIN_USR、QUAY_ADMIN_PSW
密碼會被遮罩處理 &amp;raquo; ****&lt;/p&gt;
&lt;h2&gt;動手修改範例 06&lt;span class="hx:absolute hx:-mt-20" id="動手修改範例-06"&gt;&lt;/span&gt;
&lt;a href="#%e5%8b%95%e6%89%8b%e4%bf%ae%e6%94%b9%e7%af%84%e4%be%8b-06" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ cat Jenkinsfile
$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mycicd&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
hostAliases:
- ip: &amp;#34;192.168.61.220&amp;#34;
hostnames:
- &amp;#34;quay.k8s.org&amp;#34;
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: p1
securityContext:
privileged: true
image: quay.io/podman/stable:v3.4.7
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
options {
skipDefaultCheckout true
}
environment {
QUAY_ADMIN = credentials(&amp;#39;quay-admin-id&amp;#39;)
}
stages {
stage (&amp;#39;QUAY_ADMIN&amp;#39;) {
steps {
sh &amp;#39;echo ${QUAY_ADMIN}&amp;#39;
sh &amp;#39;echo ${QUAY_ADMIN_USR}&amp;#39;
sh &amp;#39;echo ${QUAY_ADMIN_PSW}&amp;#39;
}
}
stage (&amp;#39;podman login&amp;#39;) {
steps {
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;podman login --tls-verify=false quay.k8s.org -u=${QUAY_ADMIN_USR} -p=${QUAY_ADMIN_PSW}&amp;#39;
}
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Jenkinsfile 範例 07&lt;span class="hx:absolute hx:-mt-20" id="jenkinsfile-範例-07"&gt;&lt;/span&gt;
&lt;a href="#jenkinsfile-%e7%af%84%e4%be%8b-07" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;請至落地 Qauy 將 alpine 設定為 private
下載 Jenkinsfile 範例 07&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ wget -q -O Jenkinsfile \
&amp;#34;http://web.flymks.com/cicd/v1/jenkinsfile/07&amp;#34;
## 檢視 Jenkinsfile 範例 07
$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mycicd&amp;#39;
defaultContainer &amp;#39;p1&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
hostAliases:
- ip: &amp;#34;192.168.61.220&amp;#34;
hostnames:
- &amp;#34;quay.k8s.org&amp;#34;
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: p1
securityContext:
privileged: true
image: quay.io/podman/stable:v3.4.7
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
environment {
QUAY_ADMIN = credentials(&amp;#39;quay-admin-id&amp;#39;)
IMAGE_TAG = &amp;#39;quay.k8s.org/quay/alpine.httpd:1.0.0&amp;#39;
}
stages {
stage (&amp;#39;podman login&amp;#39;) {
steps {
sh &amp;#39;podman login --tls-verify=false -u=${QUAY_ADMIN_USR} -p=${QUAY_ADMIN_PSW} quay.k8s.org&amp;#39;
}
}
stage (&amp;#39;build image&amp;#39;) {
steps {
sh &amp;#39;podman build --tls-verify=false -t &amp;#34;${IMAGE_TAG}&amp;#34; .&amp;#39;
sh &amp;#39;podman images&amp;#39;
}
}
}
}
$ nano Dockerfile
FROM quay.k8s.org/quay/alpine:3.15.4
RUN \
apk update &amp;amp;&amp;amp; \
apk add --no-cache nano sudo bash wget curl git tree grep &amp;amp;&amp;amp; \
wget https://busybox.net/downloads/binaries/1.28.1-defconfig-multiarch/busybox-x86_64 &amp;amp;&amp;amp; \
chmod &amp;#43;x busybox-x86_64 &amp;amp;&amp;amp; \
mv busybox-x86_64 bin/busybox1.28 &amp;amp;&amp;amp; \
mkdir -p /opt/www &amp;amp;&amp;amp; echo &amp;#34;let me go&amp;#34; &amp;gt; /opt/www/index.html
ENTRYPOINT [&amp;#34;/bin/busybox1.28&amp;#34;]
CMD [&amp;#34;httpd&amp;#34;, &amp;#34;-f&amp;#34;, &amp;#34;-h&amp;#34;, &amp;#34;/opt/www&amp;#34;]
$ git add Dockerfile Jenkinsfile
$ git commit -m &amp;#39;test 07&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;動手修改範例 07&lt;span class="hx:absolute hx:-mt-20" id="動手修改範例-07"&gt;&lt;/span&gt;
&lt;a href="#%e5%8b%95%e6%89%8b%e4%bf%ae%e6%94%b9%e7%af%84%e4%be%8b-07" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;修改 Jenkinsfile 範例 07
新增一個 stage 叫 push image
將 alpine.httpd:1.0.0 push 到落地 Quay
至落地 Quay 確認是否上傳成功&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mycicd&amp;#39;
defaultContainer &amp;#39;p1&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
hostAliases:
- ip: &amp;#34;192.168.61.220&amp;#34;
hostnames:
- &amp;#34;quay.k8s.org&amp;#34;
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: p1
securityContext:
privileged: true
image: quay.io/podman/stable:v3.4.7
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
environment {
QUAY_ADMIN = credentials(&amp;#39;quay-admin-id&amp;#39;)
IMAGE_TAG = &amp;#39;quay.k8s.org/quay/alpine.httpd:1.0.0&amp;#39;
}
stages {
stage (&amp;#39;podman login&amp;#39;) {
steps {
sh &amp;#39;podman login --tls-verify=false -u=${QUAY_ADMIN_USR} -p=${QUAY_ADMIN_PSW} quay.k8s.org&amp;#39;
}
}
stage (&amp;#39;build image&amp;#39;) {
steps {
sh &amp;#39;podman build --tls-verify=false -t &amp;#34;${IMAGE_TAG}&amp;#34; .&amp;#39;
sh &amp;#39;podman images&amp;#39;
}
}
stage (&amp;#39;push image&amp;#39;) {
steps {
sh &amp;#39;podman push --tls-verify=false &amp;#34;${IMAGE_TAG}&amp;#34;&amp;#39;
}
}
}
}
$ git commit -a -m &amp;#34;test-07-1&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Jenkinsfile 範例 08&lt;span class="hx:absolute hx:-mt-20" id="jenkinsfile-範例-08"&gt;&lt;/span&gt;
&lt;a href="#jenkinsfile-%e7%af%84%e4%be%8b-08" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;下載 Jenkinsfile 範例 08&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ wget -q -O Jenkinsfile \
&amp;#34;http://web.flymks.com/cicd/v1/jenkinsfile/08&amp;#34;
檢視 Jenkinsfile 範例 08
$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mycicd&amp;#39;
defaultContainer &amp;#39;k1&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: k1
securityContext:
privileged: true
image: quay.io/grassknot/kubectl:1.24.1
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
options {
skipDefaultCheckout true
}
environment {
KUBECONFIG = credentials(&amp;#39;kubeconfig-id&amp;#39;)
}
stages {
stage (&amp;#39;get node&amp;#39;) {
steps {
sh &amp;#39;mkdir -p ~/.kube &amp;amp;&amp;amp; cp ${KUBECONFIG} ~/.kube/config&amp;#39;
sh &amp;#39;kubectl get nodes -o wide&amp;#39;
}
}
}
}
$ git add Jenkinsfile; git commit -m &amp;#34;test 08&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: jenkins
name: jenkins
namespace: jenkins
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app: jenkins
name: jenkins
namespace: jenkins
rules:
- apiGroups:
- &amp;#34;&amp;#34;
resources:
- pods
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- &amp;#34;&amp;#34;
resources:
- pods/exec
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- &amp;#34;&amp;#34;
resources:
- pods/log
verbs:
- get
- list
- watch
- apiGroups:
- &amp;#34;&amp;#34;
resources:
- events
verbs:
- watch
- apiGroups:
- &amp;#34;&amp;#34;
resources:
- secrets
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app: jenkins
name: jenkins
namespace: jenkins
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: jenkins
subjects:
- kind: ServiceAccount
name: jenkins
namespace: jenkins
---
apiVersion: v1
data:
credentials.yaml: |
Y3JlZGVudGlhbHM6CiAgc3lzdGVtOgogICAgZG9tYWluQ3JlZGVudGlhbHM6CiAgICAgIC
0gY3JlZGVudGlhbHM6CiAgICAgICAgICAtIHVzZXJuYW1lUGFzc3dvcmQ6CiAgICAgICAg
ICAgICAgaWQ6ICJnaXRlYS1hZG1pbi1pZCIKICAgICAgICAgICAgICB1c2VybmFtZTogIm
dpdGVhIgogICAgICAgICAgICAgIHBhc3N3b3JkOiAiR2l0ZWExMjM0NSIKICAgICAgICAg
ICAgICBkZXNjcmlwdGlvbjogImdpdGVhIGFkbWluIgogICAgICAgICAgICAgIHNjb3BlOi
BHTE9CQUwKICAgICAgICAgIC0gdXNlcm5hbWVQYXNzd29yZDoKICAgICAgICAgICAgICBp
ZDogInF1YXktYWRtaW4taWQiCiAgICAgICAgICAgICAgdXNlcm5hbWU6ICJxdWF5IgogIC
AgICAgICAgICAgIHBhc3N3b3JkOiAiUXVheTEyMzQ1IgogICAgICAgICAgICAgIGRlc2Ny
aXB0aW9uOiAicXVheSBhZG1pbiIKICAgICAgICAgICAgICBzY29wZTogR0xPQkFMCiAgIC
AgICAgICAtIGJhc2ljU1NIVXNlclByaXZhdGVLZXk6CiAgICAgICAgICAgICAgaWQ6ICJz
c2gtcHJpdmF0ZS1rZXktaWQiCiAgICAgICAgICAgICAgdXNlcm5hbWU6ICJzc2gtcHJpdm
F0ZS1rZXkiCiAgICAgICAgICAgICAgZGVzY3JpcHRpb246ICJzc2ggcHJpdmF0ZSBrZXki
CiAgICAgICAgICAgICAgc2NvcGU6IEdMT0JBTAogICAgICAgICAgICAgIHByaXZhdGVLZX
lTb3VyY2U6CiAgICAgICAgICAgICAgICBkaXJlY3RFbnRyeToKICAgICAgICAgICAgICAg
ICAgcHJpdmF0ZUtleTogIiR7cmVhZEZpbGU6L3Zhci9qZW5raW5zX2hvbWUvLnNzaC9zc2
hfaG9zdF9yc2Ffa2V5fSIKICAgICAgICAgIC0gZmlsZToKICAgICAgICAgICAgICBpZDog
Imt1YmVjb25maWctaWQiCiAgICAgICAgICAgICAgZmlsZU5hbWU6ICJrdWJlY29uZmlnIg
ogICAgICAgICAgICAgIHNlY3JldEJ5dGVzOiAiJHtyZWFkRmlsZUJhc2U2NDovcnVuL3Nl
Y3JldHMva3ViZWNvbmZpZy9jb25maWd9IgogICAgICAgICAgICAgIGRlc2NyaXB0aW9uOi
Aia3ViZWNvbmZpZyIKICAgICAgICAgICAgICBzY29wZTogR0xPQkFM
jenkins.yaml: |
dW5jbGFzc2lmaWVkOgogIGxvY2F0aW9uOgogICAgdXJsOiAiJHtKRU5LSU5TX1VSTDotaH
R0cDovL2plbmtpbnMuazhzLm9yZy99IgogIGdpdGVhU2VydmVyczoKICAgIHNlcnZlcnM6
CiAgICAgIC0gY3JlZGVudGlhbHNJZDogImdpdGVhLWFkbWluLWlkIgogICAgICAgIGRpc3
BsYXlOYW1lOiAiZ2l0ZWEiCiAgICAgICAgbWFuYWdlSG9va3M6IHRydWUKICAgICAgICBz
ZXJ2ZXJVcmw6ICJodHRwOi8vZ2l0ZWEuZ2l0ZWE6MzAwMC8iCmplbmtpbnM6CiAgZGlzYW
JsZWRBZG1pbmlzdHJhdGl2ZU1vbml0b3JzOgogICAgLSAiamVua2lucy5zZWN1cml0eS5R
dWV1ZUl0ZW1BdXRoZW50aWNhdG9yTW9uaXRvciIKICAgIC0gImplbmtpbnMuZGlhZ25vc3
RpY3MuQ29udHJvbGxlckV4ZWN1dG9yc0FnZW50cyIKICBjbG91ZHM6CiAgICAtIGt1YmVy
bmV0ZXM6CiAgICAgICAgbmFtZTogImt1YmVybmV0ZXMiCiAgICAgICAgbmFtZXNwYWNlOi
AiamVua2lucyIKICAgICAgICBqZW5raW5zVXJsOiAiaHR0cDovL2plbmtpbnMiCiAgbGFi
ZWxTdHJpbmc6ICJtYXN0ZXIiCiAgc2VjdXJpdHlSZWFsbToKICAgIGxvY2FsOgogICAgIC
BhbGxvd3NTaWdudXA6IGZhbHNlCiAgICAgIHVzZXJzOgogICAgICAgIC0gaWQ6ICIke0pF
TktJTlNfQURNSU5fSUQ6LWplbmtpbnN9IgogICAgICAgICAgcGFzc3dvcmQ6ICIke0pFTk
tJTlNfQURNSU5fUFc6LUplbmtpbnMxMjM0NX0iCiAgYXV0aG9yaXphdGlvblN0cmF0ZWd5
OgogICAgZ2xvYmFsTWF0cml4OgogICAgICBwZXJtaXNzaW9uczoKICAgICAgICAtICJVU0
VSOk92ZXJhbGwvQWRtaW5pc3Rlcjoke0pFTktJTlNfQURNSU5fSUQ6LWplbmtpbnN9Igog
ICAgICAgIC0gIkdST1VQOk92ZXJhbGwvUmVhZDphdXRoZW50aWNhdGVkIgogIHJlbW90aW
5nU2VjdXJpdHk6CiAgICBlbmFibGVkOiB0cnVlCnNlY3VyaXR5OgogIHF1ZXVlSXRlbUF1
dGhlbnRpY2F0b3I6CiAgICBhdXRoZW50aWNhdG9yczoKICAgICAgLSBnbG9iYWw6CiAgIC
AgICAgICBzdHJhdGVneTogdHJpZ2dlcmluZ1VzZXJzQXV0aG9yaXphdGlvblN0cmF0ZWd5
Cg==
jobs.yaml: |
am9iczoKICAtIHNjcmlwdDogPgogICAgICBwaXBlbGluZUpvYignZmlyc3Qtam9iJykgew
ogICAgICAgIGRlZmluaXRpb24gewogICAgICAgICAgY3BzIHsKICAgICAgICAgICAgc2Fu
ZGJveCgpCiAgICAgICAgICAgIHNjcmlwdCgiIiJcCiAgICAgICAgICAgICAgcGlwZWxpbm
UgewogICAgICAgICAgICAgICAgYWdlbnQgeyBsYWJlbCAnbWFzdGVyJyB9CiAgICAgICAg
ICAgICAgICBzdGFnZXMgewogICAgICAgICAgICAgICAgICBzdGFnZSAoJ2VjaG8nKSB7Ci
AgICAgICAgICAgICAgICAgICAgc3RlcHMgewogICAgICAgICAgICAgICAgICAgICAgZWNo
byAiSGVsbG8hIgogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgfQ
ogICAgICAgICAgICAgICAgICBzdGFnZSAoJ3NoZWxsJykgewogICAgICAgICAgICAgICAg
ICAgIHN0ZXBzIHsKICAgICAgICAgICAgICAgICAgICAgIHNoICdjYXQgL2V0Yy9vcy1yZW
xlYXNlJwogICAgICAgICAgICAgICAgICAgICAgc2ggJ2hvc3RuYW1lJwogICAgICAgICAg
ICAgICAgICAgICAgc2ggJ2hvc3RuYW1lIC1pJwogICAgICAgICAgICAgICAgICAgICAgc2
ggJ3dob2FtaScKICAgICAgICAgICAgICAgICAgICAgIHNoICdwd2QnCiAgICAgICAgICAg
ICAgICAgICAgICBzaCAnbHMgLWFsJwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgIC
AgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0iIiIuc3Ry
aXBJbmRlbnQoKSkKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0K
kind: Secret
metadata:
labels:
app: jenkins
name: jenkins-casc
namespace: jenkins
type: Opaque
---
apiVersion: v1
kind: Service
metadata:
labels:
app: jenkins
name: jenkins
namespace: jenkins
spec:
ports:
- name: jenkins-http
port: 80
targetPort: 8080
- name: jenkins-agent
port: 50000
protocol: TCP
targetPort: 50000
selector:
app: jenkins
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-pvc
namespace: jenkins
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: local-path
volumeMode: Filesystem
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jenkins-ingress
namespace: jenkins
spec:
ingressClassName: ig1
rules:
- host: jenkins.k8s.org
http:
paths:
- backend:
service:
name: jenkins
port:
number: 80
path: /
pathType: Prefix
---
apiVersion: v1
kind: Pod
metadata:
labels:
app: jenkins
name: jenkins
namespace: jenkins
spec:
containers:
- env:
- name: LIMITS_MEMORY
valueFrom:
resourceFieldRef:
divisor: 1Mi
resource: limits.memory
- name: JAVA_OPTS
value: -Djenkins.install.runSetupWizard=false -Dorg.apache.commons.jelly.tags.fmt.timeZone=Asia/Taipei
-Xmx$(LIMITS_MEMORY)m -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0
-Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85
image: quay.io/grassknot/jenkins:jcasc
imagePullPolicy: Always
name: jenkins
ports:
- containerPort: 8080
- containerPort: 50000
resources:
limits:
cpu: 1
memory: 2Gi
requests:
cpu: 0.5
memory: 500Mi
volumeMounts:
- mountPath: /usr/jenkins_config/
name: jenkins-config
- mountPath: /var/jenkins_home
name: jenkins-storage
- mountPath: /run/secrets/kubeconfig
name: kubeconfig
readOnly: true
securityContext:
fsGroup: 1000
runAsUser: 1000
serviceAccountName: jenkins
volumes:
- name: jenkins-storage
persistentVolumeClaim:
claimName: jenkins-pvc
- name: jenkins-config
secret:
secretName: jenkins-casc
- name: kubeconfig
secret:
secretName: kubeconfig&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Jenkins 在 Kubernetes 裡面的權限只能對 pod 做管理，其他的 k8s 物件是沒有權限的，所以才要要讓 Jenkins 能使用 Kubectl 來對整個 Kubernetes 來做管理。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/dYgwTQO.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;動手修改範例 08&lt;span class="hx:absolute hx:-mt-20" id="動手修改範例-08"&gt;&lt;/span&gt;
&lt;a href="#%e5%8b%95%e6%89%8b%e4%bf%ae%e6%94%b9%e7%af%84%e4%be%8b-08" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mycicd&amp;#39;
defaultContainer &amp;#39;k1&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: k1
securityContext:
privileged: true
image: quay.io/grassknot/kubectl:1.24.1
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
options {
skipDefaultCheckout true
}
environment {
KUBECONFIG = credentials(&amp;#39;kubeconfig-id&amp;#39;)
}
stages {
stage (&amp;#39;get node&amp;#39;) {
steps {
sh &amp;#39;mkdir -p ~/.kube &amp;amp;&amp;amp; cp ${KUBECONFIG} ~/.kube/config&amp;#39;
sh &amp;#39;kubectl get nodes -o wide&amp;#39;
}
}
stage (&amp;#39;get jenkins&amp;#39;) {
steps {
sh &amp;#39;kubectl get all -n Jenkins&amp;#39;
}
}
stage (&amp;#39;get quay&amp;#39;) {
steps {
sh &amp;#39;kubectl get all -n quay&amp;#39;
}
}
stage (&amp;#39;get default&amp;#39;) {
steps {
sh &amp;#39;kubectl get all&amp;#39;
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;實作練習&lt;/h1&gt;&lt;p&gt;請先在 K8S 叢集建立一個 namespace 命名為 cicd
首先撰寫 pod-a1.yaml
a1 pod 部署在 cicd namespace
image 使用 &lt;code&gt;quay.k8s.org/quay/alpine.httpd&lt;/code&gt;
imagePullPolicy 設定 Always&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ kubectl create ns cicd
$ nano Jenkinsfile
$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mycicd&amp;#39;
defaultContainer &amp;#39;k1&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: k1
securityContext:
privileged: true
image: quay.io/grassknot/kubectl:1.24.1
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
environment {
KUBECONFIG = credentials(&amp;#39;kubeconfig-id&amp;#39;)
}
stages {
stage (&amp;#39;deploy a1&amp;#39;) {
steps {
sh &amp;#39;mkdir -p ~/.kube &amp;amp;&amp;amp; cp ${KUBECONFIG} ~/.kube/config&amp;#39;
sh &amp;#39;kubectl delete -f pod-a1.yml || exit 0&amp;#39;
sh &amp;#39;kubectl apply -f pod-a1.yml&amp;#39;
}
}
stage (&amp;#39;get cicd&amp;#39;) {
steps {
sh &amp;#39;kubectl get pod -n cicd&amp;#39;
}
}
}
}
$ nano Dockerfile
FROM quay.k8s.org/quay/alpine:3.15.4
RUN \
apk update &amp;amp;&amp;amp; \
apk add --no-cache nano sudo bash wget curl git tree grep &amp;amp;&amp;amp; \
wget https://busybox.net/downloads/binaries/1.28.1-defconfig-multiarch/busybox-x86_64 &amp;amp;&amp;amp; \
chmod &amp;#43;x busybox-x86_64 &amp;amp;&amp;amp; \
mv busybox-x86_64 bin/busybox1.28 &amp;amp;&amp;amp; \
mkdir -p /opt/www &amp;amp;&amp;amp; echo &amp;#34;let me go&amp;#34; &amp;gt; /opt/www/index.html
ENTRYPOINT [&amp;#34;/bin/busybox1.28&amp;#34;]
CMD [&amp;#34;httpd&amp;#34;, &amp;#34;-f&amp;#34;, &amp;#34;-h&amp;#34;, &amp;#34;/opt/www&amp;#34;]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;總練習 1&lt;span class="hx:absolute hx:-mt-20" id="總練習-1"&gt;&lt;/span&gt;
&lt;a href="#%e7%b8%bd%e7%b7%b4%e7%bf%92-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;請把落地 Quay 中的 alpine.httpd 刪除
參考前面的 Jenkinsfile 範例 07 08 與練習
撰寫四個 stage
podman login
build image
push image
deploy a1&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mycicd&amp;#39;
defaultContainer &amp;#39;k1&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
hostAliases:
- ip: &amp;#34;192.168.61.220&amp;#34;
hostnames:
- &amp;#34;quay.k8s.org&amp;#34;
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: k1
securityContext:
privileged: true
image: quay.io/grassknot/kubectl:1.24.1
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
- name: p1
securityContext:
privileged: true
image: quay.io/podman/stable:v3.4.7
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
environment {
KUBECONFIG = credentials(&amp;#39;kubeconfig-id&amp;#39;)
QUAY_ADMIN = credentials(&amp;#39;quay-admin-id&amp;#39;)
IMAGE_TAG = &amp;#39;quay.k8s.org/quay/alpine.httpd:1.0.0&amp;#39;
}
stages {
stage (&amp;#39;podman login&amp;#39;) {
steps {
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;podman login --tls-verify=false -u=${QUAY_ADMIN_USR} -p=${QUAY_ADMIN_PSW} quay.k8s.org&amp;#39;
}
}
}
stage (&amp;#39;build image&amp;#39;) {
steps {
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;podman build --tls-verify=false -t &amp;#34;${IMAGE_TAG}&amp;#34; .&amp;#39;
sh &amp;#39;podman images&amp;#39;
}
}
}
stage (&amp;#39;push image&amp;#39;) {
steps {
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;podman push --tls-verify=false &amp;#34;${IMAGE_TAG}&amp;#34;&amp;#39;
}
}
}
stage (&amp;#39;deploy a1&amp;#39;) {
steps {
sh &amp;#39;mkdir -p ~/.kube &amp;amp;&amp;amp; cp ${KUBECONFIG} ~/.kube/config&amp;#39;
sh &amp;#39;kubectl delete -f pod-a1.yml || exit 0&amp;#39;
sh &amp;#39;kubectl apply -f pod-a1.yml&amp;#39;
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;imagePullSecrets&lt;span class="hx:absolute hx:-mt-20" id="imagepullsecrets"&gt;&lt;/span&gt;
&lt;a href="#imagepullsecrets" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在 m1 主機登入落地 Quay&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo podman login --tls-verify=false quay.k8s.org -u quay -p Quay12345&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢視 auth.json&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo cat /run/containers/0/auth.json
{
&amp;#34;auths&amp;#34;: {
&amp;#34;quay.k8s.org&amp;#34;: {
&amp;#34;auth&amp;#34;: &amp;#34;cXVheTpRdWF5MTIzNDU=&amp;#34;
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;複製 auth.json 到家目錄並變更擁有者&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo cp /run/containers/0/auth.json ~
$ sudo chown bigred:bigred ~/auth.json&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;建立 K8S Secret&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ kubectl create secret generic regcred \
--from-file=.dockerconfigjson=/home/bigred/auth.json \
--type=kubernetes.io/dockerconfigjson \
-n cicd&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;regcred = registry + credential (都是名字，可以自取)&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;spec:
containers:
- name: a1
image: quay.k8s.org/quay/alpine.httpd:1.0.0
imagePullPolicy: Always
imagePullSecrets:
- name: regcred&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;總練習 2 前置作業&lt;span class="hx:absolute hx:-mt-20" id="總練習-2-前置作業"&gt;&lt;/span&gt;
&lt;a href="#%e7%b8%bd%e7%b7%b4%e7%bf%92-2-%e5%89%8d%e7%bd%ae%e4%bd%9c%e6%a5%ad" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ pwd
/home/bigred/wk
$ wget http://web.flymks.com/cicd/v1/bi2.zip
$ unzip bi2.zip
$ cd bi2
$ ls
Dockerfile invdb.sh inventory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;總練習 2-1&lt;span class="hx:absolute hx:-mt-20" id="總練習-2-1"&gt;&lt;/span&gt;
&lt;a href="#%e7%b8%bd%e7%b7%b4%e7%bf%92-2-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;題目：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先將 bi2 專案資料夾完成 git 初始化&lt;/li&gt;
&lt;li&gt;Build Image Tag 如下
&lt;code&gt;quay.k8s.org/quay/bookstore-inventory:1.0.0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;撰寫 K8S YAML 部署庫存管理系統 (pod-b1.yaml)&lt;/li&gt;
&lt;li&gt;b1 pod 部署在 cicd namespace&lt;/li&gt;
&lt;li&gt;imagePullPolicy 設定 Always&lt;/li&gt;
&lt;li&gt;新增 Jenkins multibranch pipeline 作業，作業命名「bi2」並連接到 bi2 git 儲存庫&lt;/li&gt;
&lt;li&gt;記得建立 git hook post-commit&lt;/li&gt;
&lt;li&gt;參考總練習 1 撰寫 Jenkinsfile&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;答案：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;## git 初始化
$ git init
$ ls -al
total 24
drwxr-sr-x 3 bigred bigred 4096 Jun 15 09:26 .
drwxr-sr-x 9 bigred bigred 4096 Jun 15 09:20 ..
drwxr-sr-x 7 bigred bigred 4096 Jun 15 09:26 .git
-rw-r--r-- 1 bigred bigred 616 Jun 9 23:41 Dockerfile
-rwxr-xr-x 1 bigred bigred 711 Jun 9 23:39 invdb.sh
-rwxr-xr-x 1 bigred bigred 476 Jun 9 23:41 inventory
## 建立 post-commit
$ cat &amp;lt;&amp;lt; EOF &amp;gt; .git/hooks/post-commit
#!/bin/bash
curl -s http://jenkins.k8s.org/git/notifyCommit?url=ssh://bigred@192.168.61.4/home/bigred/wk/bi2/
EOF
## 務必賦予執行權限
$ chmod &amp;#43;x .git/hooks/post-commit&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;新增 Jenkins Job&lt;/p&gt;
&lt;p&gt;回到 Jenkins Dashboard&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;點選左側新增作業
&lt;ul&gt;
&lt;li&gt;item name 輸入 bi2&lt;/li&gt;
&lt;li&gt;下方選擇 Multibranch Pipeline&lt;/li&gt;
&lt;li&gt;按下 OK&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;點選 Branch Sources 頁籤&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;點選 Add source 下拉選 Git&lt;/li&gt;
&lt;li&gt;Project Repository 輸入(紅字請替換為 m1 主機 IP)
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ssh://bigred@192.168.61.4/home/bigred/wk/bi2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Credentials 選擇 ssh-private-key&lt;/li&gt;
&lt;li&gt;最後按下 Save&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;編輯 pod-b1.yml&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano pod-b1.yml
apiVersion: v1
kind: Pod
metadata:
name: b1
namespace: cicd
spec:
containers:
- name: b1
image: quay.k8s.org/quay/bookstore-inventory:1.0.0
imagePullPolicy: Always
imagePullSecrets:
- name: regcred&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;編輯 Jenkinsfile&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;bi2&amp;#39;
defaultContainer &amp;#39;k1&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
hostAliases:
- ip: &amp;#34;192.168.61.220&amp;#34;
hostnames:
- &amp;#34;quay.k8s.org&amp;#34;
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: k1
securityContext:
privileged: true
image: quay.io/grassknot/kubectl:1.24.1
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
- name: p1
securityContext:
privileged: true
image: quay.io/podman/stable:v3.4.7
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
environment {
KUBECONFIG = credentials(&amp;#39;kubeconfig-id&amp;#39;)
QUAY_ADMIN = credentials(&amp;#39;quay-admin-id&amp;#39;)
IMAGE_TAG = &amp;#39;quay.k8s.org/quay/bookstore-inventory:1.0.0&amp;#39;
}
stages {
stage (&amp;#39;podman login&amp;#39;) {
steps {
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;podman login --tls-verify=false -u=${QUAY_ADMIN_USR} -p=${QUAY_ADMIN_PSW} quay.k8s.org&amp;#39;
}
}
}
stage (&amp;#39;build image&amp;#39;) {
steps {
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;podman build --tls-verify=false -t &amp;#34;${IMAGE_TAG}&amp;#34; .&amp;#39;
sh &amp;#39;podman images&amp;#39;
}
}
}
stage (&amp;#39;push image&amp;#39;) {
steps {
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;podman push --tls-verify=false &amp;#34;${IMAGE_TAG}&amp;#34;&amp;#39;
}
}
}
stage (&amp;#39;deploy b1&amp;#39;) {
steps {
sh &amp;#39;mkdir -p ~/.kube &amp;amp;&amp;amp; cp ${KUBECONFIG} ~/.kube/config&amp;#39;
sh &amp;#39;kubectl delete -f pod-b1.yml || exit 0&amp;#39;
sh &amp;#39;kubectl apply -f pod-b1.yml&amp;#39;
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;git add *
git status
git commit -m &amp;#39;Build Project test&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/aJnH03D.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ kubectl get pod -n cicd -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
b1 1/1 Running 0 4m25s 10.244.1.169 w1 &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
$ curl 10.244.1.169/cgi-bin/inventory
[{&amp;#34;id&amp;#34;:1,&amp;#34;isbn&amp;#34;:&amp;#34;1492090719&amp;#34;,&amp;#34;quantity&amp;#34;:17},
{&amp;#34;id&amp;#34;:2,&amp;#34;isbn&amp;#34;:&amp;#34;9865024918&amp;#34;,&amp;#34;quantity&amp;#34;:11},
{&amp;#34;id&amp;#34;:3,&amp;#34;isbn&amp;#34;:&amp;#34;1492092304&amp;#34;,&amp;#34;quantity&amp;#34;:16},
{&amp;#34;id&amp;#34;:4,&amp;#34;isbn&amp;#34;:&amp;#34;9864760785&amp;#34;,&amp;#34;quantity&amp;#34;:10},
{&amp;#34;id&amp;#34;:5,&amp;#34;isbn&amp;#34;:&amp;#34;9865028042&amp;#34;,&amp;#34;quantity&amp;#34;:12}]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;總練習 2-2&lt;span class="hx:absolute hx:-mt-20" id="總練習-2-2"&gt;&lt;/span&gt;
&lt;a href="#%e7%b8%bd%e7%b7%b4%e7%bf%92-2-2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;請先完成總練習 2-1&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;將 podman login 指令移至 build image stage 中&lt;/li&gt;
&lt;li&gt;將 podman login stage 刪除&lt;/li&gt;
&lt;li&gt;在 build image stage 之前新增兩個 stage
&lt;ul&gt;
&lt;li&gt;第一個 stage 命名為 shellcheck
&lt;ul&gt;
&lt;li&gt;負責檢查 &lt;code&gt;invdb.sh&lt;/code&gt; 以及 &lt;code&gt;inventory&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;image 使用 &lt;code&gt;quay.io/grassknot/shellcheck-alpine:stable&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;第二個 stage 命名為 Test
&lt;ul&gt;
&lt;li&gt;image 使用 &lt;code&gt;quay.k8s.org/quay/alpine.httpd:1.0.0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;使用 curl 將 API 結果輸出，執行結果可參考下圖&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;答案：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ kubectl create secret generic regcred \
&amp;gt; --from-file=.dockerconfigjson=/home/bigred/auth.json \
&amp;gt; --type=kubernetes.io/dockerconfigjson \
&amp;gt; -n jenkins
$ kubectl get secret -n jenkins
NAME TYPE DATA AGE
jenkins-casc Opaque 3 5d22h
kubeconfig Opaque 1 5d22h
regcred kubernetes.io/dockerconfigjson 1 2s
$ nano Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;bi2&amp;#39;
defaultContainer &amp;#39;k1&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
hostAliases:
- ip: &amp;#34;192.168.61.220&amp;#34;
hostnames:
- &amp;#34;quay.k8s.org&amp;#34;
imagePullSecrets:
- name: regcred
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: s1
image: quay.io/grassknot/shellcheck-alpine:stable
securityContext:
privileged: true
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
- name: t1
image: quay.k8s.org/quay/alpine.httpd:1.0.0
securityContext:
privileged: true
- name: k1
securityContext:
privileged: true
image: quay.io/grassknot/kubectl:1.24.1
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
- name: p1
securityContext:
privileged: true
image: quay.io/podman/stable:v3.4.7
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
environment {
KUBECONFIG = credentials(&amp;#39;kubeconfig-id&amp;#39;)
QUAY_ADMIN = credentials(&amp;#39;quay-admin-id&amp;#39;)
IMAGE_TAG = &amp;#39;quay.k8s.org/quay/bookstore-inventory:1.0.0&amp;#39;
}
stages {
stage (&amp;#39;shellcheck&amp;#39;) {
steps {
container(&amp;#39;s1&amp;#39;) {
sh &amp;#39;shellcheck invdb.sh&amp;#39;
sh &amp;#39;shellcheck inventory&amp;#39;
}
}
}
stage (&amp;#39;test&amp;#39;) {
steps {
container(&amp;#39;t1&amp;#39;) {
sh &amp;#39;&amp;#39;&amp;#39;
#!/bin/bash
apk update &amp;amp;&amp;amp; apk add sqlite
mkdir -p /root/bookstore-inventory/ &amp;amp;&amp;amp; mkdir -p /opt/www/cgi-bin
cp invdb.sh /root/bookstore-inventory/ &amp;amp;&amp;amp; cp inventory /opt/www/cgi-bin
cd /root/bookstore-inventory/
bash invdb.sh create
&amp;#39;&amp;#39;&amp;#39;
sh &amp;#39;curl -s localhost&amp;#39;
sh &amp;#39;curl -s localhost/cgi-bin/inventory?id=1&amp;#39;
sh &amp;#39;curl -s localhost/cgi-bin/inventory?isbn=1492090719&amp;#39;
}
}
}
stage (&amp;#39;build image&amp;#39;) {
steps {
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;podman login --tls-verify=false -u=${QUAY_ADMIN_USR} -p=${QUAY_ADMIN_PSW} quay.k8s.org&amp;#39;
sh &amp;#39;podman build --tls-verify=false -t &amp;#34;${IMAGE_TAG}&amp;#34; .&amp;#39;
sh &amp;#39;podman images&amp;#39;
}
}
}
stage (&amp;#39;push image&amp;#39;) {
steps {
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;podman push --tls-verify=false &amp;#34;${IMAGE_TAG}&amp;#34;&amp;#39;
}
}
}
stage (&amp;#39;deploy b1&amp;#39;) {
steps {
sh &amp;#39;mkdir -p ~/.kube &amp;amp;&amp;amp; cp ${KUBECONFIG} ~/.kube/config&amp;#39;
sh &amp;#39;kubectl delete -f pod-b1.yml || exit 0&amp;#39;
sh &amp;#39;kubectl apply -f pod-b1.yml&amp;#39;
}
}
}
}
$ git add Jenkinsfile ; git commit -m &amp;#34;t2&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/tj2gniM.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;範例 09&lt;/h1&gt;&lt;h2&gt;前置作業 1&lt;span class="hx:absolute hx:-mt-20" id="前置作業-1"&gt;&lt;/span&gt;
&lt;a href="#%e5%89%8d%e7%bd%ae%e4%bd%9c%e6%a5%ad-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;建立 mp3 專案資料夾 (請先不要建立 post-commit)&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;~/wk$ mkdir mp3; cd mp3
$ git init
建立 Jenkinsfile，內容從備忘稿複製
$ nano Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mp3&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
&amp;#34;&amp;#34;&amp;#34;
}
}
options {
skipDefaultCheckout true
}
stages {
stage (&amp;#39;echo&amp;#39;) {
steps {
echo &amp;#39;Hello World!&amp;#39;
}
}
}
}
$ git add Jenkinsfile; git commit -m &amp;#39;Init repo&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;git branch&lt;span class="hx:absolute hx:-mt-20" id="git-branch"&gt;&lt;/span&gt;
&lt;a href="#git-branch" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git branch
* master
建立 branch
$ git branch production
$ git branch dev
$ git branch
dev
* master
production&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;.git/refs/heads&lt;span class="hx:absolute hx:-mt-20" id="gitrefsheads"&gt;&lt;/span&gt;
&lt;a href="#gitrefsheads" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git log
commit 36961d234c7f676f422bfbdda8536ed528055337 (HEAD -&amp;gt; master, prod, dev)
Author: danny &amp;lt;danny@example.com&amp;gt;
Date: Wed Jun 15 13:35:19 2022 &amp;#43;0800
Init repo&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;可以看到 commit 的代碼：&lt;code&gt;36961d234c7f676f422bfbdda8536ed528055337&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;檢查我們建立的 branch&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ tree .git/refs/heads
.git/refs/heads
├── dev
├── master
└── prod
0 directories, 3 files&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在同一個 git 專案目錄中新增的 branch 都是共用相同的 commit ID&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ cat .git/refs/heads/master
36961d234c7f676f422bfbdda8536ed528055337
$ cat .git/refs/heads/production
36961d234c7f676f422bfbdda8536ed528055337
$ cat .git/refs/heads/dev
36961d234c7f676f422bfbdda8536ed528055337&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;手動刪除 branch&lt;span class="hx:absolute hx:-mt-20" id="手動刪除-branch"&gt;&lt;/span&gt;
&lt;a href="#%e6%89%8b%e5%8b%95%e5%88%aa%e9%99%a4-branch" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ rm .git/refs/heads/production
$ git branch
dev
* master&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;重新建立 branch，命名為 prod&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git branch prod&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;前置作業 2&lt;span class="hx:absolute hx:-mt-20" id="前置作業-2"&gt;&lt;/span&gt;
&lt;a href="#%e5%89%8d%e7%bd%ae%e4%bd%9c%e6%a5%ad-2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;新增 Jenkins multibranch pipeline 作業&lt;/li&gt;
&lt;li&gt;作業命名「mp3」並連接到 mp3 git 儲存庫
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ssh://bigred@192.168.61.4/home/bigred/wk/mp3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;完成後至 Blue Ocean 網頁查看分支&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不同的 branch ，Jenkins 會用不同的 pod 來作業&lt;/p&gt;
&lt;h2&gt;Jenkinsfile 範例 09&lt;span class="hx:absolute hx:-mt-20" id="jenkinsfile-範例-09"&gt;&lt;/span&gt;
&lt;a href="#jenkinsfile-%e7%af%84%e4%be%8b-09" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ wget -q -O Jenkinsfile \
&amp;gt; &amp;#34;http://web.flymks.com/cicd/v1/jenkinsfile/09&amp;#34;
$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mp3&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
&amp;#34;&amp;#34;&amp;#34;
}
}
options {
skipDefaultCheckout true
}
stages {
stage (&amp;#39;echo&amp;#39;) {
steps {
echo &amp;#39;Hello World!&amp;#39;
}
}
stage (&amp;#39;Deploy Production&amp;#39;) {
when {
branch &amp;#39;prod&amp;#39;
}
steps {
echo &amp;#39;Hello Prod!&amp;#39;
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git add Jenkinsfile; git commit -m &amp;#34;test 09&amp;#34;
$ git log
commit a154b98d53d31aefd40beb213fe2580241b5bfcf (HEAD -&amp;gt; master)
Author: danny &amp;lt;danny@example.com&amp;gt;
Date: Wed Jun 15 14:13:47 2022 &amp;#43;0800
test 09
commit 36961d234c7f676f422bfbdda8536ed528055337 (prod, dev)
Author: danny &amp;lt;danny@example.com&amp;gt;
Date: Wed Jun 15 13:35:19 2022 &amp;#43;0800
Init repo&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;手動執行作業&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/uM6DSzj.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;動手修改範例 09&lt;span class="hx:absolute hx:-mt-20" id="動手修改範例-09"&gt;&lt;/span&gt;
&lt;a href="#%e5%8b%95%e6%89%8b%e4%bf%ae%e6%94%b9%e7%af%84%e4%be%8b-09" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在 Deploy Production stage 之前新增一個 stage
stage 命名為 Deploy Dev
when 宣告如下&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;when {
not { branch &amp;#39;master&amp;#39; }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;steps 只需要一個 echo &amp;lsquo;Hello Dev!&amp;rsquo;
請參考簡報 904 建立 git hook post-commit&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git checkout dev
$ cat Jenkinsfile
$ git pull . master
$ git log --oneline&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;實作練習 Part1&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git checkout prod
Switched to branch &amp;#39;prod&amp;#39;
bigred@m1:~/wk/mp3$ git pull . master
From .
* branch master -&amp;gt; FETCH_HEAD
Updating 36961d2..978df0c
Fast-forward
Jenkinsfile | 18 &amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;-
1 file changed, 17 insertions(&amp;#43;), 1 deletion(-)
$ git log --oneline&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;## 建立 post-commit
$ cat &amp;lt;&amp;lt; EOF &amp;gt; .git/hooks/post-commit
#!/bin/bash
curl -s http://jenkins.k8s.org/git/notifyCommit?url=ssh://bigred@192.168.61.4/home/bigred/wk/mp3/
EOF
## 務必賦予執行權限
$ chmod &amp;#43;x .git/hooks/post-commit&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h6&gt;tags: &lt;code&gt;CI/CD&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="tags-cicd"&gt;&lt;/span&gt;
&lt;a href="#tags-cicd" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h6&gt;</description></item><item><title>Jenkins</title><link>https://blog.kubeantony.com/archive/ops-automation/jenkins/</link><pubDate>Mon, 13 Jun 2022 00:53:28 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/jenkins/</guid><description>
&lt;hr&gt;
&lt;h2&gt;環境準備&lt;span class="hx:absolute hx:-mt-20" id="環境準備"&gt;&lt;/span&gt;
&lt;a href="#%e7%92%b0%e5%a2%83%e6%ba%96%e5%82%99" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;CNT.2022.v4 K8S 叢集建置完成
以下 K8S 公設完成部署&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;MetalLB&lt;/li&gt;
&lt;li&gt;Ingress NGINX Controller&lt;/li&gt;
&lt;li&gt;Local Path Provisioner&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在 Windows 系統的 cmd 視窗登入 m1 主機
修改 &lt;code&gt;/etc/hosts&lt;/code&gt;&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo nano /etc/hosts
::
192.168.124.220 quay.k8s.org jenkins.k8s.org&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;參考 902 簡報完成 git 必要設定&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git config --list
user.name=danny
user.email=danny@example.com
core.editor=nano&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Jenkins 參考資料&lt;span class="hx:absolute hx:-mt-20" id="jenkins-參考資料"&gt;&lt;/span&gt;
&lt;a href="#jenkins-%e5%8f%83%e8%80%83%e8%b3%87%e6%96%99" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;https://www.jenkins.io/
https://github.com/jenkinsci/jenkins
https://www.jenkins.io/doc/book/using/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Jenkins 介紹&lt;span class="hx:absolute hx:-mt-20" id="jenkins-介紹"&gt;&lt;/span&gt;
&lt;a href="#jenkins-%e4%bb%8b%e7%b4%b9" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Jenkins is a self-contained, open source automation server which can be used to automate all sorts of tasks related to building, testing, and delivering or deploying software.&lt;/p&gt;
&lt;p&gt;Jenkins can be installed through native system packages, Docker, or even run standalone by any machine with a Java Runtime Environment (JRE) installed.&lt;/p&gt;
&lt;h2&gt;Jenkins Plugins&lt;span class="hx:absolute hx:-mt-20" id="jenkins-plugins"&gt;&lt;/span&gt;
&lt;a href="#jenkins-plugins" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;a
href="https://plugins.jenkins.io/"target="_blank" rel="noopener"&gt;Jenkins Plugins 網站連結&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There are over a thousand different plugins which can be installed on a Jenkins controller and to integrate various build tools, cloud providers, analysis tools, and much more.&lt;/p&gt;
&lt;h2&gt;JCasC&lt;span class="hx:absolute hx:-mt-20" id="jcasc"&gt;&lt;/span&gt;
&lt;a href="#jcasc" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Jenkins Configuration as Code
&lt;a
href="https://plugins.jenkins.io/configuration-as-code/"target="_blank" rel="noopener"&gt;https://plugins.jenkins.io/configuration-as-code/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Jenkins Configuration as Code provides the ability to define this whole configuration as a simple, human-friendly, plain text yaml syntax.&lt;/p&gt;
&lt;h2&gt;Kubernetes plugin&lt;span class="hx:absolute hx:-mt-20" id="kubernetes-plugin"&gt;&lt;/span&gt;
&lt;a href="#kubernetes-plugin" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Kubernetes plugin for Jenkins
&lt;a
href="https://plugins.jenkins.io/kubernetes/"target="_blank" rel="noopener"&gt;https://plugins.jenkins.io/kubernetes/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Jenkins plugin to run &lt;font color=red&gt;dynamic agents&lt;/font&gt; in a Kubernetes cluster.&lt;/p&gt;
&lt;p&gt;&lt;font color=red&gt;&lt;strong&gt;The plugin creates a Kubernetes Pod for each agent started, and stops it after each build.&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;It is not required to run the Jenkins controller inside Kubernetes.&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;部署前置作業&lt;/h1&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ pwd
/home/bigred/wk
$ kubectl create ns jenkins
namespace/jenkins created
## kubeconfig 為 secret 物件的名字
$ kubectl create secret generic kubeconfig --from-file=/home/bigred/.kube/config -n jenkins
secret/kubeconfig created
$ kubectl apply -f http://web.flymks.com/cicd/v1/jenkins.yaml
$ kubectl get all -n jenkins
NAME READY STATUS RESTARTS AGE
pod/jenkins 1/1 Running 0 89s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/jenkins ClusterIP 10.98.0.124 &amp;lt;none&amp;gt; 80/TCP,50000/TCP 89s
$ kubectl get ingress -n jenkins
NAME CLASS HOSTS ADDRESS PORTS AGE
jenkins-ingress ig1 jenkins.k8s.org 192.168.61.220 80 109s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;登入 Jenkins&lt;span class="hx:absolute hx:-mt-20" id="登入-jenkins"&gt;&lt;/span&gt;
&lt;a href="#%e7%99%bb%e5%85%a5-jenkins" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;打開瀏覽器，網址 &lt;code&gt;http://jenkins.k8s.org&lt;/code&gt;&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;帳號：jenkins
密碼：Jenkins12345&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Jenkins 主畫面&lt;span class="hx:absolute hx:-mt-20" id="jenkins-主畫面"&gt;&lt;/span&gt;
&lt;a href="#jenkins-%e4%b8%bb%e7%95%ab%e9%9d%a2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/52uWm5Q.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;執行第一個 Job&lt;span class="hx:absolute hx:-mt-20" id="執行第一個-job"&gt;&lt;/span&gt;
&lt;a href="#%e5%9f%b7%e8%a1%8c%e7%ac%ac%e4%b8%80%e5%80%8b-job" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;左側按下「馬上建置」&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/eLyiUAH.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;檢視執行結果&lt;span class="hx:absolute hx:-mt-20" id="檢視執行結果"&gt;&lt;/span&gt;
&lt;a href="#%e6%aa%a2%e8%a6%96%e5%9f%b7%e8%a1%8c%e7%b5%90%e6%9e%9c" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;滑鼠移至綠色區塊可確認 Log
左側下方「建置歷程」 點選 &lt;code&gt;#1&lt;/code&gt;
選擇 Console Output 查看終端機輸出&lt;/p&gt;
&lt;p&gt;&lt;img src="https://lh4.googleusercontent.com/TYtpep0Urqf_LMYN-9rXtfAZOdgDD6kbmoRyvV_o0J0emuK4zGSSQJZkSCxA9J7mW95DnnSg7boVA4O1_L7vzVrV-KPKA0CFq8Wr-1l5o5IJvF91KfWHyS_UOM8KAbQxhN6d4NyR7AlDLDC1AA" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;進入 Blue Ocean&lt;span class="hx:absolute hx:-mt-20" id="進入-blue-ocean"&gt;&lt;/span&gt;
&lt;a href="#%e9%80%b2%e5%85%a5-blue-ocean" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;左側按下「Open Blue Ocean」
進入 Blue Ocean 畫面後，點選中間第一列
如下圖紅框處&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/0cZv1j2.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;Blue Ocean 介面&lt;span class="hx:absolute hx:-mt-20" id="blue-ocean-介面"&gt;&lt;/span&gt;
&lt;a href="#blue-ocean-%e4%bb%8b%e9%9d%a2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/OdyQFj0.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;離開 Blue Ocean&lt;span class="hx:absolute hx:-mt-20" id="離開-blue-ocean"&gt;&lt;/span&gt;
&lt;a href="#%e9%9b%a2%e9%96%8b-blue-ocean" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;右上點選 X 先離開執行結果畫面&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/Dwux0dn.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;右上點選回到經典界面的圖示&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/h2kab1q.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;設定 SSH 免密碼&lt;span class="hx:absolute hx:-mt-20" id="設定-ssh-免密碼"&gt;&lt;/span&gt;
&lt;a href="#%e8%a8%ad%e5%ae%9a-ssh-%e5%85%8d%e5%af%86%e7%a2%bc" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Jenkins 透過 SSH 連接 Git
Jenkins 主機中已預先產生 SSH 公私鑰
將公鑰給 M1 主機&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ kubectl -n jenkins exec -it jenkins -- cat /var/jenkins_home/.ssh/ssh_host_rsa_key.pub | tee -a ~/.ssh/authorized_keys&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;mycicd 專案資料夾&lt;span class="hx:absolute hx:-mt-20" id="mycicd-專案資料夾"&gt;&lt;/span&gt;
&lt;a href="#mycicd-%e5%b0%88%e6%a1%88%e8%b3%87%e6%96%99%e5%a4%be" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;於 m1 主機建立 mycicd 專案資料夾
建立一個檔案並完成 git 備份&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;~/wk$ mkdir mycicd; cd mycicd
$ git init
$ echo &amp;#34;Hi! Jenkins!&amp;#34; &amp;gt; readme
$ git add readme; git commit -m &amp;#39;Init repo&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;新增 Jenkins Job&lt;span class="hx:absolute hx:-mt-20" id="新增-jenkins-job"&gt;&lt;/span&gt;
&lt;a href="#%e6%96%b0%e5%a2%9e-jenkins-job" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;回到 Jenkins Dashboard
點選左側新增作業
item name 輸入 mycicd
下方選擇 Multibranch Pipeline
按下 OK&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/15vEjYm.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;點選 Branch Sources 頁籤 🡪 點選 Add source 下拉選 Git
Project Repository 輸入(紅字請替換為 m1 主機 IP)&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;ssh://bigred@192.168.61.4/home/bigred/wk/mycicd&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Credentials 選擇 ssh-private-key
最後按下 Save&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/aB3cVql.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;Jenkins 掃描儲存庫&lt;span class="hx:absolute hx:-mt-20" id="jenkins-掃描儲存庫"&gt;&lt;/span&gt;
&lt;a href="#jenkins-%e6%8e%83%e6%8f%8f%e5%84%b2%e5%ad%98%e5%ba%ab" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;新增作業完成後 Jenkins 會自動掃描 Git 儲存庫&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/Mxo9ufd.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;撰寫 Jenkinsfile&lt;span class="hx:absolute hx:-mt-20" id="撰寫-jenkinsfile"&gt;&lt;/span&gt;
&lt;a href="#%e6%92%b0%e5%af%ab-jenkinsfile" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Jenkinsfile 使用 echo 語法輸出字串&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano Jenkinsfile
pipeline {
agent { label &amp;#39;master&amp;#39; }
stages {
stage (&amp;#39;echo&amp;#39;) {
steps {
echo &amp;#34;Hello!&amp;#34;
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;steps&lt;/code&gt; ，步驟
注意！&lt;code&gt;echo &amp;quot;Hello!&amp;quot;&lt;/code&gt; 的 &lt;code&gt;echo&lt;/code&gt; 不是 linux 的 &lt;code&gt;echo&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;手動通知 Jenkins&lt;span class="hx:absolute hx:-mt-20" id="手動通知-jenkins"&gt;&lt;/span&gt;
&lt;a href="#%e6%89%8b%e5%8b%95%e9%80%9a%e7%9f%a5-jenkins" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;必需先將 Jenkinsfile 備份至 Git 儲存庫&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git add Jenkinsfile
$ git commit -m &amp;#34;Add Jenkinsfile&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;手動通知 Jenkins&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl http://jenkins.k8s.org/git/notifyCommit?url=ssh://bigred@192.168.61.4/home/bigred/wk/mycicd
No git jobs found
Scheduled indexing of mycicd&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;確認執行結果&lt;/p&gt;
&lt;p&gt;Jenkins 網頁 Dashboard
點選 mycicd 點選 master
確認 Stage View 並檢視 Logs
至 Blue Ocean 界面確認結果&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/9Yuug5R.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h1&gt;搭配 Git Hooks&lt;/h1&gt;&lt;p&gt;搭配 Git Hooks 達到 commit 後自動通知 Jenkins&lt;/p&gt;
&lt;h2&gt;使用 post-commit&lt;span class="hx:absolute hx:-mt-20" id="使用-post-commit"&gt;&lt;/span&gt;
&lt;a href="#%e4%bd%bf%e7%94%a8-post-commit" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;建立 post-commit
$ cat &amp;lt;&amp;lt; EOF &amp;gt; .git/hooks/post-commit
#!/bin/bash
curl -s http://jenkins.k8s.org/git/notifyCommit?url=ssh://bigred@192.168.61.4/home/bigred/wk/mycicd
EOF
務必賦予執行權限
$ chmod &amp;#43;x .git/hooks/post-commit&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;修改 Jenkinsfile&lt;span class="hx:absolute hx:-mt-20" id="修改-jenkinsfile"&gt;&lt;/span&gt;
&lt;a href="#%e4%bf%ae%e6%94%b9-jenkinsfile" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Jenkinsfile 使用 sh 語法執行指令&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano Jenkinsfile
pipeline {
agent { label &amp;#39;master&amp;#39; }
stages {
stage (&amp;#39;shell&amp;#39;) {
steps {
sh &amp;#34;whoami&amp;#34;
sh &amp;#34;pwd&amp;#34;
sh &amp;#34;ls -al&amp;#34;
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;stage 取名為 shell
steps 步驟
裡面的 sh 代表要執行我們的 shell 程式，可以幫我們執行 linux 的 command&lt;/p&gt;
&lt;h2&gt;觸發 post-commit&lt;span class="hx:absolute hx:-mt-20" id="觸發-post-commit"&gt;&lt;/span&gt;
&lt;a href="#%e8%a7%b8%e7%99%bc-post-commit" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git add Jenkinsfile ; git commit -m &amp;#34;Update Jenkinsfile&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Jenkins 網頁 Dashboard
點選 mycicd 點選 master
確認 Stage View 並檢視 Logs
至 Blue Ocean 界面確認結果&lt;/p&gt;
&lt;h1&gt;Jenkinsfile 練習&lt;/h1&gt;&lt;p&gt;修改 Jenkinsfile
Pipeline 有兩個 stage，分別是 echo 與 shell
echo stage，使用 echo 語法輸出 Hello!
shell stage 依序執行以下命令&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;cat /etc/os-release
hostname
hostname -i
whoami
pwd
ls -al&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;答案：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano Jenkinsfile
pipeline {
agent { label &amp;#39;master&amp;#39; }
stages {
stage (&amp;#39;echo&amp;#39;) {
steps {
echo &amp;#34;Hello&amp;#34;
}
}
stage (&amp;#39;shell&amp;#39;) {
steps {
sh &amp;#34;cat /etc/os-release&amp;#34;
sh &amp;#34;hostname&amp;#34;
sh &amp;#34;hostname -i&amp;#34;
sh &amp;#34;whoami&amp;#34;
sh &amp;#34;pwd&amp;#34;
sh &amp;#34;ls -al&amp;#34;
}
}
}
}
$ git add Jenkinsfile ; git commit -m &amp;#34;Update Jenkinsfile 2&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/x7wTm1x.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;dynamic agents&lt;/h1&gt;&lt;p&gt;Jenkins 透過 Kubernetes plugin 可以動態產生 Pod
Agent 概念等同 Worker
Master 與 Agent 透過 JNLP 協定溝通&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/OIiQjLt.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;Jenkinsfile 範例 01&lt;span class="hx:absolute hx:-mt-20" id="jenkinsfile-範例-01"&gt;&lt;/span&gt;
&lt;a href="#jenkinsfile-%e7%af%84%e4%be%8b-01" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;下載 Jenkinsfile 範例 01&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ wget -q -O Jenkinsfile \
&amp;#34;http://web.flymks.com/cicd/v1/jenkinsfile/01&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢視 Jenkinsfile 範例 01&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mycicd&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
&amp;#34;&amp;#34;&amp;#34;
}
}
stages {
stage (&amp;#39;shell&amp;#39;) {
steps {
sh &amp;#39;whoami&amp;#39;
sh &amp;#39;pwd&amp;#39;
sh &amp;#39;ls -al&amp;#39;
sh &amp;#39;cat readme&amp;#39;
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;如果不宣告 pod 的 Container 的 image 為 &lt;code&gt;qua.io&lt;/code&gt; 來源的話，預設是 ducker.hub 的 image 中心。&lt;/p&gt;
&lt;h2&gt;確認範例 01 結果&lt;span class="hx:absolute hx:-mt-20" id="確認範例-01-結果"&gt;&lt;/span&gt;
&lt;a href="#%e7%a2%ba%e8%aa%8d%e7%af%84%e4%be%8b-01-%e7%b5%90%e6%9e%9c" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git add Jenkinsfile; git commit -m &amp;#34;test 01&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;觀察作業用 Pod 是否有產生&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ watch kubectl get pod -n jenkins&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;請至 Jenkins 網頁確認執行結果 !&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Multiple containers&lt;span class="hx:absolute hx:-mt-20" id="multiple-containers"&gt;&lt;/span&gt;
&lt;a href="#multiple-containers" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/FH40xL1.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;可以透過 Container 的技術達成不同的效果&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;## 下載 Jenkinsfile 範例 02
$ wget -q -O Jenkinsfile \
&amp;#34;http://web.flymks.com/cicd/v1/jenkinsfile/02&amp;#34;
## 檢視 Jenkinsfile 範例 02
$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mycicd&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: p1
securityContext:
privileged: true
image: quay.io/podman/stable:v3.4.7
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
options {
skipDefaultCheckout true
}
stages {
stage (&amp;#39;podman&amp;#39;) {
steps {
sh &amp;#39;podman version || echo &amp;#34;command not found&amp;#34;&amp;#39;
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;podman version&amp;#39;
}
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;如果要更進階的學習 Jenkins 的 pipeline ，請點&lt;a
href="https://www.jenkins.io/doc/book/pipeline/"target="_blank" rel="noopener"&gt;連結&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;以上的語言最後都會翻譯成 &lt;a
href="https://zh.wikipedia.org/zh-tw/Groovy"target="_blank" rel="noopener"&gt;Groovy 語言&lt;/a&gt;&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;## 下載 Jenkinsfile 範例 05
$ wget -q -O Jenkinsfile \
&amp;#34;http://web.flymks.com/cicd/v1/jenkinsfile/05&amp;#34;
$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mycicd&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: p1
securityContext:
privileged: true
image: quay.io/podman/stable:v3.4.7
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
options {
skipDefaultCheckout true
}
stages {
stage (&amp;#39;podman login&amp;#39;) {
steps {
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;podman login --tls-verify=false -u=quay -p=Quay12345 quay.k8s.org&amp;#39;
}
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;stage 階段
steps 步驟&lt;/p&gt;
&lt;p&gt;Jenkins 如果沒有特定宣告哪一個 Contianer 的話，預設是 jnlp 那台 Container&lt;/p&gt;
&lt;p&gt;結果報錯&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git add Jenkinsfile
$ git commit -m &amp;#34;test05&amp;#34;
&amp;#43; podman login --tls-verify=false -u=quay -p=Quay12345 quay.k8s.org
Error: authenticating creds for &amp;#34;quay.k8s.org&amp;#34;: pinging container registry quay.k8s.org: Get &amp;#34;http://quay.k8s.org/v2/&amp;#34;: dial tcp: lookup quay.k8s.org: no such host
script returned exit code 125&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;## Jenkinsfile 05-1
$ nano Jenkinsfile
pipeline {
agent {
kubernetes {
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
hostAliases:
- ip: &amp;#34;192.168.61.220&amp;#34;
hostnames:
- &amp;#34;quay.k8s.org&amp;#34;
containers:
- name: jnlp
--- 以下省略 ---&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;## Jenkinsfile 05-2
$ cat Jenkinsfile
pipeline {
agent {
kubernetes {
inheritFrom &amp;#39;mycicd&amp;#39;
yaml &amp;#34;&amp;#34;&amp;#34;
apiVersion: v1
kind: Pod
spec:
hostAliases:
- ip: &amp;#34;192.168.61.220&amp;#34;
hostnames:
- &amp;#34;quay.k8s.org&amp;#34;
containers:
- name: jnlp
image: quay.io/flysangel/inbound-agent:4.13-2-jdk11
- name: p1
securityContext:
privileged: true
image: quay.io/podman/stable:v3.4.7
command: [&amp;#34;sleep&amp;#34;]
args: [&amp;#34;infinity&amp;#34;]
&amp;#34;&amp;#34;&amp;#34;
}
}
options {
skipDefaultCheckout true
}
stages {
stage (&amp;#39;podman login&amp;#39;) {
steps {
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;podman login --tls-verify=false -u=quay -p=Quay12345 quay.k8s.org&amp;#39;
}
}
}
stage (&amp;#39;hostAliases&amp;#39;) {
steps {
sh &amp;#39;cat /etc/hosts&amp;#39;
container(&amp;#39;p1&amp;#39;) {
sh &amp;#39;cat /etc/hosts&amp;#39;
}
}
}
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h6&gt;tags: &lt;code&gt;CI/CD&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="tags-cicd"&gt;&lt;/span&gt;
&lt;a href="#tags-cicd" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h6&gt;</description></item><item><title>Git - Part 2</title><link>https://blog.kubeantony.com/archive/ops-automation/git-part-2/</link><pubDate>Mon, 13 Jun 2022 00:53:08 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/git-part-2/</guid><description>
&lt;hr&gt;
&lt;h1&gt;環境準備&lt;/h1&gt;&lt;p&gt;CNT.2022.v4 K8S 叢集建置完成
在 Windows 系統的 cmd 視窗登入 m1 主機
下載 bookstore-inventory 程式碼&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;bigred@m1:~/wk$ pwd
/home/bigred/wk
$ wget http://web.flymks.com/cicd/v1/bi.zip
$ unzip bi.zip
$ cd bookstore-inventory
## 設定 git user (請自己替換名稱)
$ git config --global user.name &amp;#34;danny&amp;#34;
$ git config --global user.email &amp;#34;danny@example.com&amp;#34;
&amp;gt; --global 全域設定
## git 預設使用 vim，修改設定使用 nano
$ git config --global core.editor &amp;#34;nano&amp;#34;
## 檢查 git 設定
$ git config --list
user.name=danny
user.email=danny@example.com
core.editor=nano
## git 初始化
$ git init
## git 檢查檔案狀態
$ git status&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h1&gt;Git Hooks 介紹&lt;/h1&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/9lzrktL.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;git 的儲存庫分為 Local （本地）和 Remote （遠端）&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ tree .git/hooks/
.git/hooks/
├── applypatch-msg.sample
├── commit-msg.sample
├── post-update.sample
├── pre-applypatch.sample
├── pre-commit.sample ------------------&amp;gt; 今天主要會用到的
├── pre-merge-commit.sample
├── pre-push.sample
├── pre-rebase.sample
├── pre-receive.sample
├── prepare-commit-msg.sample
├── push-to-checkout.sample
└── update.sample&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ $ cat .git/hooks/pre-commit.sample
# An example hook script to verify what is about to be committed.
# Called by &amp;#34;git commit&amp;#34; with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to &amp;#34;pre-commit&amp;#34;.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;ShellCheck 介紹&lt;span class="hx:absolute hx:-mt-20" id="shellcheck-介紹"&gt;&lt;/span&gt;
&lt;a href="#shellcheck-%e4%bb%8b%e7%b4%b9" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;font color=red&gt;&lt;strong&gt;A shell script static analysis tool&lt;/strong&gt;&lt;/font&gt;
&lt;a
href="https://github.com/koalaman/shellcheck"target="_blank" rel="noopener"&gt;https://github.com/koalaman/shellcheck&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ShellCheck is a GPLv3 tool that gives warnings and suggestions for bash/sh shell scripts.&lt;/p&gt;
&lt;p&gt;安裝 shellcheck&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo apk add shellcheck&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;使用 ShellCheck&lt;span class="hx:absolute hx:-mt-20" id="使用-shellcheck"&gt;&lt;/span&gt;
&lt;a href="#%e4%bd%bf%e7%94%a8-shellcheck" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ shellcheck invdb.sh
In invdb.sh line 32:
if [ ! -z &amp;#34;${1}&amp;#34; ]; then
^-- SC2236 (style): Use -n instead of ! -z.
For more information:
https://www.shellcheck.net/wiki/SC2236 -- Use -n instead of ! -z.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;-z 為判斷檔案不存在，前面加驚嘆號為雙重否定&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;建立 pre-commit&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ cat &amp;lt;&amp;lt; EOF &amp;gt; .git/hooks/pre-commit
#!/bin/bash
shellcheck invdb.sh
EOF&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;務必賦予執行權限&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ chmod &amp;#43;x .git/hooks/pre-commit&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;觸發 pre-commit&lt;span class="hx:absolute hx:-mt-20" id="觸發-pre-commit"&gt;&lt;/span&gt;
&lt;a href="#%e8%a7%b8%e7%99%bc-pre-commit" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;bigred@m1:~/wk/bookstore-inventory$ ls -al
total 20
drwxr-sr-x 3 bigred bigred 4096 Jun 9 09:11 .
drwxr-sr-x 7 bigred bigred 4096 Jun 9 09:08 ..
drwxr-sr-x 7 bigred bigred 4096 Jun 9 09:36 .git
-rwxr-xr-x 1 bigred bigred 713 Jun 5 22:05 invdb.sh
-rwxr-xr-x 1 bigred bigred 487 Jun 5 22:05 inventory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在 .git 的專案目錄中，除了 &lt;code&gt;.git&lt;/code&gt; 目錄外，其他都為 git 的工作目錄區&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;## invdb.sh 加入 git 追蹤
$ git add invdb.sh
## 檢查狀態
$ git status
On branch master
No commits yet
Changes to be committed:
(use &amp;#34;git rm --cached &amp;lt;file&amp;gt;...&amp;#34; to unstage)
new file: invdb.sh
Untracked files:
(use &amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34; to include in what will be committed)
inventory
## git 備份我們的檔案
$ git commit -m &amp;#39;Add invdb.sh&amp;#39;
In invdb.sh line 32:
if [ ! -z &amp;#34;${1}&amp;#34; ]; then
^-- SC2236 (style): Use -n instead of ! -z.
For more information:
https://www.shellcheck.net/wiki/SC2236 -- Use -n instead of ! -z.
## 觸發 git-precommit
$ git status
On branch master
No commits yet
Changes to be committed:
(use &amp;#34;git rm --cached &amp;lt;file&amp;gt;...&amp;#34; to unstage)
new file: invdb.sh
Untracked files:
(use &amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34; to include in what will be committed)
inventory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;修改 &lt;code&gt;invdb.sh&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="修改-invdbsh"&gt;&lt;/span&gt;
&lt;a href="#%e4%bf%ae%e6%94%b9-invdbsh" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;請依 shellcheck 建議修改 &lt;code&gt;invdb.sh&lt;/code&gt;&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano invdb.sh
if [ -n &amp;#34;${1}&amp;#34; ]; then -----&amp;gt; 將 &amp;#34;! -z&amp;#34; 改為 &amp;#34;-n&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;完成後執行 &lt;code&gt;git status&lt;/code&gt;&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git status
Changes to be committed:
(use &amp;#34;git rm --cached &amp;lt;file&amp;gt;...&amp;#34; to unstage)
new file: invdb.sh
Changes not staged for commit:
(use &amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34; to update what will be committed)
(use &amp;#34;git restore &amp;lt;file&amp;gt;...&amp;#34; to discard changes in working directory)
modified: invdb.sh
Untracked files:
(use &amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34; to include in what will be committed)
inventory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;font color=red&gt;&lt;strong&gt;注意，如果在 &lt;code&gt;git add&lt;/code&gt; 檔案後又修改檔案，此時直接 &lt;code&gt;commit&lt;/code&gt; ，git 只會備份舊版的檔案，所以要再 &lt;code&gt;git add&lt;/code&gt; 一次&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;## 將 invdb.sh 再次加入追蹤
$ git add invdb.sh
## 檢查狀態
$ git status
On branch master
No commits yet
Changes to be committed:
(use &amp;#34;git rm --cached &amp;lt;file&amp;gt;...&amp;#34; to unstage)
new file: invdb.sh
Untracked files:
(use &amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34; to include in what will be committed)
inventory
## 將 invdb.sh 給 git 備份
$ git commit -m &amp;#39;Add invdb.sh&amp;#39;
[master (root-commit) ad0bb75] Add invdb.sh
1 file changed, 36 insertions(&amp;#43;)
create mode 100755 invdb.sh
$ shellcheck invdb.sh
$ echo $?
0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;實作練習 1&lt;span class="hx:absolute hx:-mt-20" id="實作練習-1"&gt;&lt;/span&gt;
&lt;a href="#%e5%af%a6%e4%bd%9c%e7%b7%b4%e7%bf%92-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;修改 pre-commit，使用 shellcheck 檢查 inventory
使用 git 備份 inventory
觀察 pre-commit 執行結果
依 shellcheck 建議修改 inventory
完成 git 備份 inventory&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ shellcheck inventory
In inventory line 10:
parm=($QUERY_STRING)
^-----------^ SC2206 (warning): Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.
For more information:
https://www.shellcheck.net/wiki/SC2206 -- Quote to prevent word splitting/g...
$ nano inventory
echo &amp;#34;Content-type: application/json&amp;#34;
echo &amp;#34;&amp;#34;
DB_PATH=&amp;#34;/root/bookstore-inventory/inventory.db&amp;#34;
IFS=&amp;#34;=&amp;amp;&amp;#34; read -r -a parm &amp;lt;&amp;lt;&amp;lt; &amp;#34;$QUERY_STRING&amp;#34; ---- &amp;gt; 修改這行
sql=&amp;#34;sqlite3 -json ${DB_PATH} &amp;#34;
[ &amp;#34;$QUERY_STRING&amp;#34; == &amp;#34;&amp;#34; ] &amp;amp;&amp;amp; $sql &amp;#34;select * from inventory&amp;#34; &amp;amp;&amp;amp; exit 0
case &amp;#34;${parm[0]}&amp;#34; in
id)
$sql &amp;#34;select * from inventory where id = ${parm[1]}&amp;#34;
;;
isbn)
$sql &amp;#34;select * from inventory where isbn = ${parm[1]}&amp;#34;
;;
*)
$sql &amp;#34;select * from inventory&amp;#34;
;;
esac
$ cat &amp;lt;&amp;lt; EOF &amp;gt; .git/hooks/pre-commit
#!/bin/bash
shellcheck inventory
EOF
$ git commit inventory -m &amp;#39;Add inventory&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h1&gt;部署 Quay on K8S&lt;/h1&gt;&lt;p&gt;環境準備
CNT.2022.v4 K8S 叢集建置完成
以下 K8S 公設完成部署
MetalLB
Ingress NGINX Controller
Local Path Provisioner
在 Windows 系統的 cmd 視窗登入 m1 主機&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ kubectl create ns quay
namespace/quay created
$ kubectl apply -f http://web.flymks.com/cicd/v1/quay.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ sudo podman run -it --rm quay.io/flysangel/busybox:1.35.0 echo &amp;#39;Hello Quay&amp;#39;
Hello Quay
bigred@m1:~/quay-podman$ sudo podman images | grep 1.35.0
192.168.61.4/myquay/busybox 1.35.0 af4897967787 2 weeks ago 1.47 MB
quay.io/flysangel/busybox 1.35.0 af4897967787 2 weeks ago 1.47 MB
bigred@m1:~/quay-podman$ sudo podman tag quay.io/flysangel/busybox:1.35.0 quay.k8s.org/quay/busybox:1.35.0
bigred@m1:~/quay-podman$ sudo podman login --tls-verify=false quay.k8s.org -u quay -p Quay12345
Login Succeeded!
$ sudo podman push --tls-verify=false quay.k8s.org/quay/busybox:1.35.0
$ sudo podman pull quay.io/flysangel/alpine:3.15.4
$ sudo podman tag quay.io/flysangel/alpine:3.15.4 quay.k8s.org/quay/alpine:3.15.4
$ sudo podman images
$ sudo podman images | grep k8s
$ sudo podman push --tls-verify=false quay.k8s.org/quay/alpine:3.15.4
$ sudo podman pull quay.io/flysangel/nginx:1.22.0
$ sudo podman tag quay.io/flysangel/nginx:1.22.0 quay.k8s.org/quay/nginx:1.22.0
$ sudo podman push --tls-verify=false quay.k8s.org/quay/nginx:1.22.0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;實作練習 2&lt;span class="hx:absolute hx:-mt-20" id="實作練習-2"&gt;&lt;/span&gt;
&lt;a href="#%e5%af%a6%e4%bd%9c%e7%b7%b4%e7%bf%92-2" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;撰寫 bookstore-inventory Dockerfile
可參考備註 alpine httpd Dockerfile
Dockerfile 請指定工作目錄
&lt;code&gt;WORKDIR /root/bookstore-inventory&lt;/code&gt;
Build Image Tag 如下
&lt;code&gt;quay.k8s.org/quay/bookstore-inventory:1.0.0&lt;/code&gt;
container 測試沒問題後，完成 git 備份
Push Image 到落地 Quay&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano bookstore-inventory/Dockerfile
FROM quay.k8s.org/quay/alpine:3.15.4
WORKDIR /root/bookstore-inventory
COPY invdb.sh /root/bookstore-inventory
COPY inventory /root/bookstore-inventory
RUN \
apk update &amp;amp;&amp;amp; \
apk add --no-cache nano sudo bash wget curl tree grep sqlite &amp;amp;&amp;amp; \
wget https://busybox.net/downloads/binaries/1.28.1-defconfig-multiarch/busybox-x86_64 &amp;amp;&amp;amp; \
chmod &amp;#43;x busybox-x86_64 &amp;amp;&amp;amp; \
mv busybox-x86_64 /bin/busybox1.28 &amp;amp;&amp;amp; \
bash invdb.sh create &amp;amp;&amp;amp; \
mkdir -p /opt/www/cgi-bin &amp;amp;&amp;amp; echo &amp;#34;let me go&amp;#34; &amp;gt; /opt/www/index.html &amp;amp;&amp;amp; \
cp inventory /opt/www/cgi-bin/
ENTRYPOINT [&amp;#34;/bin/busybox1.28&amp;#34;]
CMD [&amp;#34;httpd&amp;#34;, &amp;#34;-f&amp;#34;, &amp;#34;-h&amp;#34;, &amp;#34;/opt/www&amp;#34;]
$ sudo podman build --tls-verify=false -t quay.k8s.org/quay/bookstore-inventory:1.0.0 bookstore-inventory/
$ sudo podman run --rm --name b1 -d -p 8080:80 quay.k8s.org/quay/bookstore-inventory:1.0.0
$ curl localhost:8080
$ curl localhost:8080/cgi-bin/inventory
$ curl localhost:8080/cgi-bin/inventory?id=1
$ curl localhost:8080/cgi-bin/inventory?isbn=1492090719
$ git add Dockerfile
$ git status
$ git commit -m &amp;#34;quay.k8s.org/quay/bookstore-inventory:1.0.0&amp;#34;
$ git status
$ sudo podman push --tls-verify=false quay.k8s.org/quay/bookstore-inventory:1.0.0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h6&gt;tags: &lt;code&gt;CI/CD&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="tags-cicd"&gt;&lt;/span&gt;
&lt;a href="#tags-cicd" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h6&gt;</description></item><item><title>Git</title><link>https://blog.kubeantony.com/archive/ops-automation/git/</link><pubDate>Sun, 29 May 2022 01:02:02 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/git/</guid><description>
&lt;hr&gt;
&lt;h2&gt;Git 介紹&lt;span class="hx:absolute hx:-mt-20" id="git-介紹"&gt;&lt;/span&gt;
&lt;a href="#git-%e4%bb%8b%e7%b4%b9" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;font color=red&gt;Git was created by Linus Torvalds in 2005 for development of the Linux kernel &lt;/font&gt;, with other kernel developers contributing to its initial development. Since 2005, Junio Hamano has been the core maintainer. As with most other &lt;font color=red&gt;&lt;strong&gt;distributed version control&lt;/strong&gt; &lt;/font&gt;systems, and unlike most client–server systems, every Git directory on every computer is a full-fledged repository with complete history and full version-tracking abilities, independent of network access or a central server. Git is free and open-source software distributed under GNU General Public License Version 2.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Git 屬於 Distributed Version Control 分散式版控軟體
&lt;ul&gt;
&lt;li&gt;最早的版本由 Linus Torvalds 於 2005 開發完成&lt;/li&gt;
&lt;li&gt;具備離線功能，有可以線上發佈&lt;/li&gt;
&lt;li&gt;功能的核心在於備份程式內容&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;by 程威&lt;/p&gt;
&lt;h2&gt;情境說明&lt;span class="hx:absolute hx:-mt-20" id="情境說明"&gt;&lt;/span&gt;
&lt;a href="#%e6%83%85%e5%a2%83%e8%aa%aa%e6%98%8e" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在網路書店擔任程式設計師
負責書目庫存查詢系統開發
由兩個子系統組成
書目管理系統(已完成)
庫存查詢系統(開發中) &amp;lt;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash; &lt;font color=red&gt; 搭配 Git 進行系統開發 &lt;/font&gt;&lt;/p&gt;
&lt;h2&gt;系統規格與目標&lt;span class="hx:absolute hx:-mt-20" id="系統規格與目標"&gt;&lt;/span&gt;
&lt;a href="#%e7%b3%bb%e7%b5%b1%e8%a6%8f%e6%a0%bc%e8%88%87%e7%9b%ae%e6%a8%99" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;使用 httpd + CGI 完成一個 REST API
資料庫使用 SQLite 3&lt;/p&gt;
&lt;p&gt;Table Schema&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;inventory&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;isbn&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;quantity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;搭配 Git 完成源碼備份&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;建立開發環境&lt;/h1&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ docker run -itd --rm --name dev quay.io/flysangel/alpine:3.15.4
$ docker ps -a
$ docker exec -it dev /bin/sh
/ #
/ # apk update &amp;amp;&amp;amp; apk upgrade
/ # apk add nano wget curl tree bash grep
/ # exit
$ docker exec -it dev /bin/bash
bash-5.1# cd
bash-5.1# pwd
bash-5.1# ls -al&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;開發環境準備&lt;span class="hx:absolute hx:-mt-20" id="開發環境準備"&gt;&lt;/span&gt;
&lt;a href="#%e9%96%8b%e7%99%bc%e7%92%b0%e5%a2%83%e6%ba%96%e5%82%99" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;## 下載 busybox 1.28 版
bash-5.1# wget https://busybox.net/downloads/binaries/1.28.1-defconfig-multiarch/busybox-x86_64
bash-5.1# chmod &amp;#43;x busybox-x86_64
bash-5.1# mv busybox-x86_64 /bin/busybox1.28
## 使用 busybox1.28 httpd 啟動網站伺服器
bash-5.1# mkdir -p /opt/www &amp;amp;&amp;amp; echo &amp;#34;let me go&amp;#34; &amp;gt; /opt/www/index.html
bash-5.1# busybox1.28 httpd -h /opt/www
## 安裝sqlite
bash-5.1# apk add sqlite&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;安裝 git&lt;span class="hx:absolute hx:-mt-20" id="安裝-git"&gt;&lt;/span&gt;
&lt;a href="#%e5%ae%89%e8%a3%9d-git" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ apk update &amp;amp;&amp;amp; apk add git
確認 git 版本
$ git version
git version 2.34.2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;git 必要設定&lt;span class="hx:absolute hx:-mt-20" id="git-必要設定"&gt;&lt;/span&gt;
&lt;a href="#git-%e5%bf%85%e8%a6%81%e8%a8%ad%e5%ae%9a" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;設定 git user (請自己替換名稱)
$ git config --global user.name &amp;#34;danny&amp;#34;
$ git config --global user.email &amp;#34;danny@example.com&amp;#34;
&amp;gt; --global 全域設定
git 預設使用 vim，修改設定使用 nano
$ git config --global core.editor &amp;#34;nano&amp;#34;
檢查 git 設定
$ git config --list
user.name=danny
user.email=danny@example.com
core.editor=nano&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;建立專案資料夾&lt;span class="hx:absolute hx:-mt-20" id="建立專案資料夾"&gt;&lt;/span&gt;
&lt;a href="#%e5%bb%ba%e7%ab%8b%e5%b0%88%e6%a1%88%e8%b3%87%e6%96%99%e5%a4%be" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;bash-5.1# mkdir bookstore-inventory
bash-5.1# cd bookstore-inventory/
bash-5.1# pwd
/root/bookstore-inventory
## git 初始化
bash-5.1# git init
...
## 等等備份的資料都會存到/root/bookstore-inventory/.git/
Initialized empty Git repository in /root/bookstore-inventory/.git/
bash-5.1# ls -al
total 12
drwxr-xr-x 3 root root 4096 May 27 06:32 .
drwx------ 1 root root 4096 May 27 06:32 ..
drwxr-xr-x 7 root root 4096 May 27 06:32 .git&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;庫存管理系統開發&lt;span class="hx:absolute hx:-mt-20" id="庫存管理系統開發"&gt;&lt;/span&gt;
&lt;a href="#%e5%ba%ab%e5%ad%98%e7%ae%a1%e7%90%86%e7%b3%bb%e7%b5%b1%e9%96%8b%e7%99%bc" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;撰寫建立系統資料庫的腳本&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano invdb.sh
#!/bin/bash
DB_NAME=&amp;#34;inventory.db&amp;#34;
## 建立資料庫
create() {
sqlite3 ${DB_NAME} &amp;lt;&amp;lt;EOF
CREATE TABLE inventory (
id INTEGER PRIMARY KEY AUTOINCREMENT,
isbn TEXT NOT NULL,
quantity INTEGER NOT NULL
);
EOF
}
create&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;AUTOINCREMENT，意思是等等的ID會自動增加&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;執行程式&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ chmod &amp;#43;x invdb.sh
$ ./invdb.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;確認是否符合預期&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ echo &amp;#39;.schema&amp;#39; | sqlite3 inventory.db&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;git status&lt;span class="hx:absolute hx:-mt-20" id="git-status"&gt;&lt;/span&gt;
&lt;a href="#git-status" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;命令&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git status&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;On branch master
No commits yet
## Untracked，不做備份與檢視
Untracked files:
(use &amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34; to include in what will be committed)
invdb.sh
inventory.db
nothing added to commit but untracked files present (use &amp;#34;git add&amp;#34; to track)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;讓 git 追蹤檔案&lt;span class="hx:absolute hx:-mt-20" id="讓-git-追蹤檔案"&gt;&lt;/span&gt;
&lt;a href="#%e8%ae%93-git-%e8%bf%bd%e8%b9%a4%e6%aa%94%e6%a1%88" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git add invdb.sh
$ git status
On branch master
No commits yet
Changes to be committed:
(use &amp;#34;git rm --cached &amp;lt;file&amp;gt;...&amp;#34; to unstage)
new file: invdb.sh
Untracked files:
(use &amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34; to include in what will be committed)
inventory.db&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;git 備份檔案&lt;span class="hx:absolute hx:-mt-20" id="git-備份檔案"&gt;&lt;/span&gt;
&lt;a href="#git-%e5%82%99%e4%bb%bd%e6%aa%94%e6%a1%88" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git commit
::
Add invdb.sh &amp;lt;------------- 在最底下新增這行字串&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢查&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git status&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;On branch master
Untracked files:
(use &amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34; to include in what will be committed)
inventory.db &amp;lt;-----------------只剩 inventory.db 未備份
nothing added to commit but untracked files present (use &amp;#34;git add&amp;#34; to track)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;git 狀態流程圖解1&lt;/h1&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/COI1NHJ.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;名詞解釋&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Untracked ，未被git追蹤的狀態&lt;/li&gt;
&lt;li&gt;Unmodified ，program被git備份到Repository後的狀態，在這個狀態下，只要有修改program，git都會追蹤，下&lt;code&gt;git status&lt;/code&gt;命令，會看到狀態是Modified。&lt;/li&gt;
&lt;li&gt;Modified ，program在Unmodified狀態下，又被修改完的狀態&lt;/li&gt;
&lt;li&gt;Staged ，git的檔案暫存區，功能在於把檔案分開備份&lt;/li&gt;
&lt;li&gt;Repository ， git備份檔案的儲存區，位於專案目錄中的&lt;code&gt;.git&lt;/code&gt;目錄裡面&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;命令解釋&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git add &amp;lt;file name&amp;gt;&lt;/code&gt; ，將Untracked或Modified狀態中的檔案，加到Staged（暫存區）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git commit &amp;lt;file name&amp;gt;&lt;/code&gt; ，將Staged 中的檔案提交給Repository
&lt;ul&gt;
&lt;li&gt;如果後面不加&lt;code&gt;&amp;lt;file name&amp;gt;&lt;/code&gt;，則staged狀態的所有檔案都會備份&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;流程解釋&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在git的工作目錄下，寫完了一支新的program，可以下&lt;code&gt;git status&lt;/code&gt;檢查狀態，會發現當前的狀態屬於Untracked，代表未被git追蹤與備份。&lt;/p&gt;
&lt;p&gt;當我們下命令&lt;code&gt;git add &amp;lt; file name &amp;gt;&lt;/code&gt;之後，再下&lt;code&gt;git status&lt;/code&gt;檢查狀態，可以看到program會被加到Staged（暫存區）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意，不管git的工作目錄下有幾個未被追蹤的檔案，就算只有一個，&lt;code&gt;git add&lt;/code&gt;後面也要指定檔案，該檔案才會被git追蹤&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最後我們下命令&lt;code&gt;git commit &amp;lt; file name &amp;gt;&lt;/code&gt;之後，git會把檔案，從Staged搬到Repository，此時檔案的狀態會回到Unmodified。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;.git&lt;/code&gt;目錄內容先不討論&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;問題：如果git commit後面不加檔名，git會把所有存在Staged的檔案都備份到Repository
但是commit後的名稱對應多個檔案要怎麼分辨？？？&lt;/p&gt;
&lt;p&gt;答：執行&lt;code&gt;git log -p&lt;/code&gt;，可以看到commit 中有修改那些內容&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;修改 &lt;code&gt;invdb.sh&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="修改-invdbsh"&gt;&lt;/span&gt;
&lt;a href="#%e4%bf%ae%e6%94%b9-invdbsh" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;先刪除&lt;code&gt;inventory.db&lt;/code&gt;&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ rm inventory.db&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;編輯&lt;code&gt;invdb.sh&lt;/code&gt;&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano invdb.sh
DB_NAME=&amp;#34;inventory.db&amp;#34;
create() {
sqlite3 ${DB_NAME} &amp;lt;&amp;lt;EOF
CREATE TABLE inventory (
id INTEGER PRIMARY KEY AUTOINCREMENT,
isbn TEXT NOT NULL,
quantity INTEGER NOT NULL
);
## 新增下面這行
insert into inventory (isbn,quantity) values (&amp;#34;1492090719&amp;#34;,&amp;#34;17&amp;#34;);
EOF
}
create&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ ./invdb.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢查程式&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ echo &amp;#39;select * from inventory&amp;#39; | sqlite3 inventory.db
1|1492090719|17&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢查git 狀態&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git status
On branch master
Changes not staged for commit:
(use &amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34; to update what will be committed)
(use &amp;#34;git restore &amp;lt;file&amp;gt;...&amp;#34; to discard changes in working directory)
modified: invdb.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;將&lt;code&gt;invdb.sh&lt;/code&gt;加入Staged&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git add invdb.sh &amp;amp;&amp;amp; git status
On branch master
Changes to be committed:
(use &amp;#34;git restore --staged &amp;lt;file&amp;gt;...&amp;#34; to unstage)
modified: invdb.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;將invdb.sh從Staged加到Repository&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git commit -m &amp;#39;Update create function&amp;#39;
[master cf2d9e1] Update create function
1 file changed, 1 insertion(&amp;#43;)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;-m ，message，代表可以直接在命令後面幫備份檔命名。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最後檢查git狀態&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git status&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h1&gt;git 狀態流程圖解2&lt;/h1&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/ZSh63vs.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;將Unmodified狀態的程式進行修改，因為此時git已經在追蹤該程式，所以修改後狀態會變成Modified，此時可以下&lt;code&gt;git add&lt;/code&gt;命令，將檔案加入Staged（暫存區），再下&lt;code&gt;git commit&lt;/code&gt;，將檔案完成備份，之後狀態會回到Unmodified。&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;invdb.sh&lt;/code&gt; 新增功能&lt;span class="hx:absolute hx:-mt-20" id="invdbsh-新增功能"&gt;&lt;/span&gt;
&lt;a href="#invdbsh-%e6%96%b0%e5%a2%9e%e5%8a%9f%e8%83%bd" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano invdb.sh
刪除最後一行
create
新增以下程式碼
rmdb() {
rm ${DB_NAME}
}
if [ &amp;#34;${1}&amp;#34; == &amp;#34;create&amp;#34; ]; then
create
elif [ &amp;#34;${1}&amp;#34; == &amp;#34;rm&amp;#34; ]; then
rmdb
fi&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
DB_NAME=&amp;#34;inventory.db&amp;#34;
## 建立資料庫
create() {
sqlite3 ${DB_NAME} &amp;lt;&amp;lt;EOF
CREATE TABLE inventory (
id INTEGER PRIMARY KEY AUTOINCREMENT,
isbn TEXT NOT NULL,
quantity INTEGER NOT NULL
);
insert into inventory (isbn,quantity) values (&amp;#34;1492090719&amp;#34;,&amp;#34;17&amp;#34;);
EOF
}
rmdb() {
rm ${DB_NAME}
}
if [ &amp;#34;${1}&amp;#34; == &amp;#34;create&amp;#34; ]; then
create
elif [ &amp;#34;${1}&amp;#34; == &amp;#34;rm&amp;#34; ]; then
rmdb
fi&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;修改後，刪除inventory.db&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ rm inventory.db&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行程式並確認是否符合預期&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ ./invdb.sh create
$ echo &amp;#39;select * from inventory&amp;#39; | sqlite3 inventory.db
1|1492090719|17
$ ./invdb.sh rm
$ ls -al&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;檢視與備份檔的差異&lt;span class="hx:absolute hx:-mt-20" id="檢視與備份檔的差異"&gt;&lt;/span&gt;
&lt;a href="#%e6%aa%a2%e8%a6%96%e8%88%87%e5%82%99%e4%bb%bd%e6%aa%94%e7%9a%84%e5%b7%ae%e7%95%b0" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;命令：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git diff &amp;lt;file name&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;如果命令後面不加檔案名稱，會看到每個modified狀態的檔案與對應備份檔的差異。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;...以上省略
-create
&amp;#43;rmdb() {
&amp;#43; rm ${DB_NAME}
&amp;#43;}
&amp;#43;
&amp;#43;if [ &amp;#34;${1}&amp;#34; == &amp;#34;create&amp;#34; ]; then
&amp;#43; create
&amp;#43;elif [ &amp;#34;${1}&amp;#34; == &amp;#34;rm&amp;#34; ]; then
&amp;#43; rmdb
&amp;#43;fi
...以下省略&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;跳過暫存區直接備份檔案&lt;/h1&gt;&lt;p&gt;命令：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git commit -a &amp;lt;file name&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;如果命令後面不指定檔案，git會直接將Staged的所有檔案通通備份&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git commit -a -m &amp;#34;Add rmdb function&amp;#34;
[master 0383843] Add rmdb function
1 file changed, 10 insertions(&amp;#43;), 1 deletion(-)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢查git的狀態&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git status
On branch master
nothing to commit, working tree clean&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;git 狀態流程圖解3&lt;span class="hx:absolute hx:-mt-20" id="git-狀態流程圖解3"&gt;&lt;/span&gt;
&lt;a href="#git-%e7%8b%80%e6%85%8b%e6%b5%81%e7%a8%8b%e5%9c%96%e8%a7%a33" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/QLWwrRn.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;流程解釋&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;將Modified狀態的所有檔案，跳過暫存區，直接完成備份。&lt;/p&gt;
&lt;p&gt;如果Staged裡已經存有上次&lt;code&gt;git add&lt;/code&gt;的檔案，此時又修改程式，然後直接&lt;code&gt;git commit -a&lt;/code&gt;，staged的檔案會存在嗎？&lt;/p&gt;
&lt;p&gt;答：staged裡的檔案，經過修改後，會回到Modified的狀態，所以直接打&lt;code&gt;git commit -a&lt;/code&gt;，一樣會跳過暫存區，將檔案與暫存區的所有檔案直接備份到Repository。&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;實作練習 1&lt;/h1&gt;&lt;p&gt;請重構 &lt;code&gt;invdb.sh&lt;/code&gt;
使用 case 語法替換 if/elif
新增執行 SQL 命令的功能&lt;/p&gt;
&lt;p&gt;預期結果&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ ./invdb.sh create
$ ./invdb.sh &amp;#34;select * from inventory&amp;#34;
1|1492090719|17&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;完成重構後，請使用 git 備份!
Commit 內容為：&lt;code&gt;Refactor invdb.sh&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;答案：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
DB_NAME=&amp;#34;inventory.db&amp;#34;
## 建立資料庫
create() {
sqlite3 ${DB_NAME} &amp;lt;&amp;lt;EOF
CREATE TABLE inventory (
id INTEGER PRIMARY KEY AUTOINCREMENT,
isbn TEXT NOT NULL,
quantity INTEGER NOT NULL
);
insert into inventory (isbn,quantity) values (&amp;#34;1492090719&amp;#34;,&amp;#34;17&amp;#34;);
EOF
}
rmdb() {
rm ${DB_NAME}
}
[ &amp;#34;${1}&amp;#34; == &amp;#34;&amp;#34; ] &amp;amp;&amp;amp; echo &amp;#34;請輸入參數，謝謝！&amp;#34; &amp;amp;&amp;amp; exit 1
case $1 in
create)
create ;;
rm)
rmdb ;;
&amp;#34;select * from inventory&amp;#34;)
echo &amp;#34;${1}&amp;#34; | sqlite3 ${DB_NAME} ;;
*)
echo &amp;#34;請輸入（ create / rm / select * from inventory ）其中一個參數，謝謝！&amp;#34;;;
esac&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h1&gt;git log&lt;/h1&gt;&lt;p&gt;命令：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git log&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;功能：顯示commit後的資訊。&lt;/p&gt;
&lt;p&gt;用法：按鍵盤的上下鍵移動，按Q離開。&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;commit fbd420d1652b3211c7fba65b9eb85b910064c879 (HEAD -&amp;gt; master)
Author: antony &amp;lt;antony@example.com&amp;gt;
Date: Sat May 28 09:01:28 2022 &amp;#43;0000
Refactor invdb.sh
commit 61432f393fb5f4da0b9ef7604619ad14bf30e1ac
Author: antony &amp;lt;antony@example.com&amp;gt;
Date: Sat May 28 08:29:38 2022 &amp;#43;0000
Add rmdb function
commit bb26a89b0d49e5976fb385222a5459acda9d97f3
Author: antony &amp;lt;antony@example.com&amp;gt;
Date: Sat May 28 07:25:11 2022 &amp;#43;0000
Update create function
commit 46a27e28c331b9fb1ad753c14a0f6febe2c9cb68
Author: antony &amp;lt;antony@example.com&amp;gt;
Date: Sat May 28 04:16:52 2022 &amp;#43;0000
test aaa
inventory1
commit c7f5a8a64e2833b44030e8771b5e49ff0546df09
Author: antony &amp;lt;antony@example.com&amp;gt;
Date: Sat May 28 04:07:56 2022 &amp;#43;0000
echo &amp;#34;abc&amp;#34;
commit 9549e5f88f915d9f97c65182ee7da4c5b6c975c2
Author: antony &amp;lt;antony@example.com&amp;gt;
Date: Sat May 28 03:49:44 2022 &amp;#43;0000
Add invdb.sh
~&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;加參數 &lt;code&gt;--oneline&lt;/code&gt; ，縮短commit後產生的版本（取前七碼）、作者與時間
和 &lt;code&gt;--graph&lt;/code&gt;，在同一個開發路線前面加符號。&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git log --oneline --graph
* fbd420d (HEAD -&amp;gt; master) Refactor invdb.sh
* 61432f3 Add rmdb function
* bb26a89 Update create function
* 46a27e2 test aaa inventory1
* c7f5a8a echo &amp;#34;abc&amp;#34;
* 9549e5f Add invdb.sh
...以下省略&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;font color=red&gt;&lt;strong&gt;超級注意！關於commit後的訊息，不能隨便亂寫!&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;加參數：&lt;code&gt;--grep&lt;/code&gt;，git內建搜尋commit的訊息&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git log --grep Update
commit bb26a89b0d49e5976fb385222a5459acda9d97f3
Author: antony &amp;lt;antony@example.com&amp;gt;
Date: Sat May 28 07:25:11 2022 &amp;#43;0000
Update create function
...以下符號省略&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h1&gt;撰寫API程式&lt;/h1&gt;&lt;p&gt;&lt;a
href="https://hackmd.io/@QI-AN/HkP73iavc"target="_blank" rel="noopener"&gt;REST API 筆記連結&lt;/a&gt;&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano inventory
#!/bin/bash
## 對於CGI而言以下兩行是必要的程式碼
echo &amp;#34;Content-type: application/json&amp;#34;
echo &amp;#34;&amp;#34;
## 主程式碼
DB_PATH=&amp;#34;/root/bookstore-inventory/inventory.db&amp;#34;
sqlite3 ${DB_PATH} &amp;#34;select * from inventory&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;執行程式並確認是否符合預期&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ chmod &amp;#43;x inventory
$ ./inventory
Content-type: application/json
1|1492090719|17&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;程式說明：這支程式等等會交由Httpd網站伺服器來執行，他使用的技術是CGI，可以讓網站伺服器執行Bash script。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;httpd CGI 測試&lt;span class="hx:absolute hx:-mt-20" id="httpd-cgi-測試"&gt;&lt;/span&gt;
&lt;a href="#httpd-cgi-%e6%b8%ac%e8%a9%a6" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ mkdir /opt/www/cgi-bin&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;cgi-bin 是指定的，Httpd 網站伺服器只認這個目錄&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;拷貝我們的程式碼&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ cp inventory /opt/www/cgi-bin&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;curl檢查能不能成功&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl localhost/cgi-bin/inventory
1|1492090719|17&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;font color=red&gt;&lt;strong&gt;為何程式名稱後面不加&lt;code&gt;.sh&lt;/code&gt;，因為這樣就不符合REST API的要求&lt;/strong&gt;&lt;/font&gt;
此時已經初步完成REST API程式了，剩回傳的json 格式&lt;/p&gt;
&lt;p&gt;使用 git 備份 inventory&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git add inventory
$ git commit -m &amp;#39;Add API script &amp;#34;inventory&amp;#34;&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;修改 &lt;code&gt;invdb.sh&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="修改-invdbsh-1"&gt;&lt;/span&gt;
&lt;a href="#%e4%bf%ae%e6%94%b9-invdbsh-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;資料只有一筆太少，請修改 &lt;code&gt;invdb.sh&lt;/code&gt; 新增多筆資料
請輸出以下資料&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ ./invdb.sh rm &amp;amp;&amp;amp; ./invdb.sh create
$ ./invdb.sh &amp;#34;select * from inventory&amp;#34;
1|1492090719|17
2|9865024918|11
3|1492092304|16
4|9864760785|10
5|9865028042|12&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;答案：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#!/bin/bash
DB_NAME=&amp;#34;inventory.db&amp;#34;
## 建立資料庫
create() {
sqlite3 ${DB_NAME} &amp;lt;&amp;lt;EOF
CREATE TABLE inventory (
id INTEGER PRIMARY KEY AUTOINCREMENT,
isbn TEXT NOT NULL,
quantity INTEGER NOT NULL
);
insert into inventory (isbn,quantity) values (&amp;#34;1492090719&amp;#34;,&amp;#34;17&amp;#34;);
insert into inventory (isbn,quantity) values (&amp;#34;9865024918&amp;#34;,&amp;#34;11&amp;#34;);
insert into inventory (isbn,quantity) values (&amp;#34;1492092304&amp;#34;,&amp;#34;16&amp;#34;);
insert into inventory (isbn,quantity) values (&amp;#34;9864760785&amp;#34;,&amp;#34;10&amp;#34;);
insert into inventory (isbn,quantity) values (&amp;#34;9865028042&amp;#34;,&amp;#34;12&amp;#34;);
EOF
}
...以下省略&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;API 程式修改&lt;span class="hx:absolute hx:-mt-20" id="api-程式修改"&gt;&lt;/span&gt;
&lt;a href="#api-%e7%a8%8b%e5%bc%8f%e4%bf%ae%e6%94%b9" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;修改 API 程式，請在最後一行 sqlite3 加入 -json 參數&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano inventory
::
sqlite3 -json ${DB_PATH} &amp;#34;select * from inventory&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ cp inventory /opt/www/cgi-bin
$ curl localhost/cgi-bin/inventory
[{&amp;#34;id&amp;#34;:1,&amp;#34;isbn&amp;#34;:&amp;#34;1492090719&amp;#34;,&amp;#34;quantity&amp;#34;:17},
{&amp;#34;id&amp;#34;:2,&amp;#34;isbn&amp;#34;:&amp;#34;9865024918&amp;#34;,&amp;#34;quantity&amp;#34;:11},
{&amp;#34;id&amp;#34;:3,&amp;#34;isbn&amp;#34;:&amp;#34;1492092304&amp;#34;,&amp;#34;quantity&amp;#34;:16},
{&amp;#34;id&amp;#34;:4,&amp;#34;isbn&amp;#34;:&amp;#34;9864760785&amp;#34;,&amp;#34;quantity&amp;#34;:10},
{&amp;#34;id&amp;#34;:5,&amp;#34;isbn&amp;#34;:&amp;#34;9865028042&amp;#34;,&amp;#34;quantity&amp;#34;:12}]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;實作練習 2&lt;/h1&gt;&lt;p&gt;先刪除inventory.db&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ ./invdb.sh rm &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;查看git狀態&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git status
On branch master
Changes not staged for commit:
(use &amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34; to update what will be committed)
(use &amp;#34;git restore &amp;lt;file&amp;gt;...&amp;#34; to discard changes in working directory)
modified: invdb.sh
modified: inventory
no changes added to commit (use &amp;#34;git add&amp;#34; and/or &amp;#34;git commit -a&amp;#34;)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;備份 &lt;code&gt;invdb.sh&lt;/code&gt;
commit 資訊：&lt;code&gt;Update invdb.sh, insert multiple record&lt;/code&gt;&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git commit invdb.sh
...以上省略
Update invdb.sh, insert multiple record&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢查git狀態&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git status
On branch master
Changes not staged for commit:
(use &amp;#34;git add &amp;lt;file&amp;gt;...&amp;#34; to update what will be committed)
(use &amp;#34;git restore &amp;lt;file&amp;gt;...&amp;#34; to discard changes in working directory)
modified: inventory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;看git最後一筆log檔資訊&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;commit e1c3580841b9f06e786439d63c61830c577ac8e2 (HEAD -&amp;gt; master)
Author: antony &amp;lt;antony@example.com&amp;gt;
Date: Sat May 28 12:25:21 2022 &amp;#43;0000
Update invdb.sh, insert multiple record&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;API 程式修改&lt;span class="hx:absolute hx:-mt-20" id="api-程式修改-1"&gt;&lt;/span&gt;
&lt;a href="#api-%e7%a8%8b%e5%bc%8f%e4%bf%ae%e6%94%b9-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano inventory
#!/bin/bash
echo &amp;#34;Content-type: application/json&amp;#34;
echo &amp;#34;&amp;#34;
DB_PATH=&amp;#34;/root/bookstore-inventory/inventory.db&amp;#34;
saveIFS=$IFS
IFS=&amp;#39;=&amp;amp;&amp;#39;
parm=($QUERY_STRING)
IFS=$saveIFS
if [ &amp;#34;${parm[0]}&amp;#34; == &amp;#34;id&amp;#34; ]; then
sqlite3 -json ${DB_PATH} &amp;#34;select * from inventory where id = ${parm[1]}&amp;#34;
else
sqlite3 -json ${DB_PATH} &amp;#34;select * from inventory&amp;#34;
fi&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;QUERY_STRING 就是網址後面要搜尋的字串，例如:
&lt;code&gt;localhost/cgi-bin/inventory?xxx=123&amp;amp;yyy=456&amp;amp;zzz=789&lt;/code&gt;
$QUERY_STRING=&amp;ldquo;xxx=123&amp;amp;yyy=456&amp;amp;zzz=789&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;在bash裡，有一個預設的變數，$IFS，它代表分隔符號，用來規定系統內的分隔符，如果在linux系統裡直接echo $IFS，可以看到是空白&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;parm=($QUERY_STRING)&lt;/code&gt;，在bash裡面，&lt;code&gt;$QUERY_STRING&lt;/code&gt;兩側加小括號，會被視為陣列處理，但是分隔符這裡已經變更為=&amp;amp;，在系統裡會認為是：&lt;code&gt;xxx 123 yyy 456 zzz 789&lt;/code&gt;
舉例：&lt;code&gt;parm[0]=xxx&lt;/code&gt; ; &lt;code&gt;parm[1]=123&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;做完陣列以後，分隔符號會再變回預先儲存的saveIFS&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;API 程式測試&lt;span class="hx:absolute hx:-mt-20" id="api-程式測試"&gt;&lt;/span&gt;
&lt;a href="#api-%e7%a8%8b%e5%bc%8f%e6%b8%ac%e8%a9%a6" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ ./invdb.sh create
$ ./inventory
$ cp inventory /opt/www/cgi-bin
$ curl localhost/cgi-bin/inventory
[{&amp;#34;id&amp;#34;:1,&amp;#34;isbn&amp;#34;:&amp;#34;1492090719&amp;#34;,&amp;#34;quantity&amp;#34;:17},
{&amp;#34;id&amp;#34;:2,&amp;#34;isbn&amp;#34;:&amp;#34;9865024918&amp;#34;,&amp;#34;quantity&amp;#34;:11},
{&amp;#34;id&amp;#34;:3,&amp;#34;isbn&amp;#34;:&amp;#34;1492092304&amp;#34;,&amp;#34;quantity&amp;#34;:16},
{&amp;#34;id&amp;#34;:4,&amp;#34;isbn&amp;#34;:&amp;#34;9864760785&amp;#34;,&amp;#34;quantity&amp;#34;:10},
{&amp;#34;id&amp;#34;:5,&amp;#34;isbn&amp;#34;:&amp;#34;9865028042&amp;#34;,&amp;#34;quantity&amp;#34;:12}]
$ curl localhost/cgi-bin/inventory?id=1
[{&amp;#34;id&amp;#34;:1,&amp;#34;isbn&amp;#34;:&amp;#34;1492090719&amp;#34;,&amp;#34;quantity&amp;#34;:17}]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;實作練習3&lt;/h1&gt;&lt;p&gt;請完成 API 程式，預期結果如下&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl localhost/cgi-bin/inventory
[{&amp;#34;id&amp;#34;:1,&amp;#34;isbn&amp;#34;:&amp;#34;1492090719&amp;#34;,&amp;#34;quantity&amp;#34;:17},
{&amp;#34;id&amp;#34;:2,&amp;#34;isbn&amp;#34;:&amp;#34;9865024918&amp;#34;,&amp;#34;quantity&amp;#34;:11},
{&amp;#34;id&amp;#34;:3,&amp;#34;isbn&amp;#34;:&amp;#34;1492092304&amp;#34;,&amp;#34;quantity&amp;#34;:16},
{&amp;#34;id&amp;#34;:4,&amp;#34;isbn&amp;#34;:&amp;#34;9864760785&amp;#34;,&amp;#34;quantity&amp;#34;:10},
{&amp;#34;id&amp;#34;:5,&amp;#34;isbn&amp;#34;:&amp;#34;9865028042&amp;#34;,&amp;#34;quantity&amp;#34;:12}]
$ curl localhost/cgi-bin/inventory?id=1
[{&amp;#34;id&amp;#34;:1,&amp;#34;isbn&amp;#34;:&amp;#34;1492090719&amp;#34;,&amp;#34;quantity&amp;#34;:17}]
$ curl localhost/cgi-bin/inventory?isbn=9865028042
[{&amp;#34;id&amp;#34;:5,&amp;#34;isbn&amp;#34;:&amp;#34;9865028042&amp;#34;,&amp;#34;quantity&amp;#34;:12}]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;答：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ nano inventory
#!/bin/bash
echo &amp;#34;Content-type: application/json&amp;#34;
echo &amp;#34;&amp;#34;
DB_PATH=&amp;#34;/root/bookstore-inventory/inventory.db&amp;#34;
saveIFS=$IFS
IFS=&amp;#39;=&amp;amp;&amp;#39;
parm=($QUERY_STRING)
IFS=$saveIFS
if [ &amp;#34;${parm[0]}&amp;#34; == &amp;#34;id&amp;#34; ]; then
sqlite3 -json ${DB_PATH} &amp;#34;select * from inventory where id = ${parm[1]}&amp;#34;
elif [ &amp;#34;${parm[0]}&amp;#34; == &amp;#34;isbn&amp;#34; ];then
sqlite3 -json ${DB_PATH} &amp;#34;select * from inventory where isbn = ${parm[1]}&amp;#34;
else
sqlite3 -json ${DB_PATH} &amp;#34;select * from inventory&amp;#34;
fi&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;拷貝API&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ cp inventory /opt/www/cgi-bin&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;最後檢查&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl localhost/cgi-bin/inventory?isbn=9864760785
[{&amp;#34;id&amp;#34;:4,&amp;#34;isbn&amp;#34;:&amp;#34;9864760785&amp;#34;,&amp;#34;quantity&amp;#34;:10}]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;git備份&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git commit -a -m &amp;#39;Update API script &amp;#34;inventory&amp;#34;&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;檢視 git log&lt;span class="hx:absolute hx:-mt-20" id="檢視-git-log"&gt;&lt;/span&gt;
&lt;a href="#%e6%aa%a2%e8%a6%96-git-log" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;命令：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git log --oneline --graph&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;7bc247 (HEAD -&amp;gt; master) Update API script &amp;#34;inventory&amp;#34;
* e1c3580 Update invdb.sh, insert multiple record
* fbd420d Refactor invdb.sh
* 61432f3 Add rmdb function
* bb26a89 Update create function
* 46a27e2 test aaa inventory1
* c7f5a8a echo &amp;#34;abc&amp;#34;
* 9549e5f Add invdb.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;git restore&lt;span class="hx:absolute hx:-mt-20" id="git-restore"&gt;&lt;/span&gt;
&lt;a href="#git-restore" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;如果不小心把程式給宰了，怎麼辦？&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ rm invdb.sh
$ ls -al
drwxr-xr-x 8 root root 4096 May 26 16:35 .git
-rwxr-xr-x 1 root root 488 May 26 16:25 inventory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢查git 的狀態&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git status
On branch master
Changes not staged for commit:
(use &amp;#34;git add/rm &amp;lt;file&amp;gt;...&amp;#34; to update what will be committed)
(use &amp;#34;git restore &amp;lt;file&amp;gt;...&amp;#34; to discard changes in working directory)
deleted: invdb.sh
no changes added to commit (use &amp;#34;git add&amp;#34; and/or &amp;#34;git commit -a&amp;#34;)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;可以看到此時狀態為: deleted&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;還原我們的檔案&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ git restore invdb.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢查&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ ls -al
drwxr-xr-x 8 root root 4096 May 26 16:38 .git
-rwxr-xr-x 1 root root 714 May 26 16:38 invdb.sh
-rwxr-xr-x 1 root root 488 May 26 16:25 inventory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;退出開發環境&lt;/h1&gt;&lt;p&gt;離開Container&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ exit&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;複製 bookstore-inventory&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;~/wk$ docker cp dev:/root/bookstore-inventory .
$ ls -al bookstore-inventory
$ docker stop dev
$ docker ps -a&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h6&gt;tags: &lt;code&gt;CI/CD&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="tags-cicd"&gt;&lt;/span&gt;
&lt;a href="#tags-cicd" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h6&gt;</description></item><item><title>CI/CD Overview</title><link>https://blog.kubeantony.com/archive/ops-automation/ci-cd-overview/</link><pubDate>Sat, 28 May 2022 14:03:00 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/ci-cd-overview/</guid><description>
&lt;p&gt;&lt;strong&gt;目錄&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;單人開發流程&lt;span class="hx:absolute hx:-mt-20" id="單人開發流程"&gt;&lt;/span&gt;
&lt;a href="#%e5%96%ae%e4%ba%ba%e9%96%8b%e7%99%bc%e6%b5%81%e7%a8%8b" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;攥寫Bash Script&lt;/li&gt;
&lt;li&gt;執行程式 &amp;ndash; &amp;gt; 成功&lt;/li&gt;
&lt;li&gt;攥寫Dockerfile&lt;/li&gt;
&lt;li&gt;Build Image Run Container &amp;ndash; &amp;gt; 成功&lt;/li&gt;
&lt;li&gt;Push Image&lt;/li&gt;
&lt;li&gt;攥寫K8s Yaml檔&lt;/li&gt;
&lt;li&gt;Kubectl apply &amp;ndash; &amp;gt; 符合預期&lt;/li&gt;
&lt;li&gt;維運應用程式 &amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;ndash; &amp;gt; 如有新需求 &amp;mdash; &amp;gt; 回到第一步&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://lh4.googleusercontent.com/qxRu6gFxQP9A6OkCdSuePmoS1PHIxkrmQ0qA45CLYpxHSxSifgjBggPuqXu3-DVNROliByeOlvfDO37HB6f9KDo_AbQVj727WHq-5zaXcP-vmjeSJP6nUcsVjEuT0Kxt8uDbQonfJTxmT2KzhA" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;程式設計師的痛點&lt;/strong&gt;&lt;span class="hx:absolute hx:-mt-20" id="程式設計師的痛點"&gt;&lt;/span&gt;
&lt;a href="#%e7%a8%8b%e5%bc%8f%e8%a8%ad%e8%a8%88%e5%b8%ab%e7%9a%84%e7%97%9b%e9%bb%9e" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;哪些東西需要備份?&lt;/li&gt;
&lt;li&gt;如何備份?&lt;/li&gt;
&lt;li&gt;程式碼版本差異如何得知?&lt;/li&gt;
&lt;li&gt;時常出現的人為失誤如何減少?&lt;/li&gt;
&lt;li&gt;人工手動的反覆步驟如何簡化?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;夢想與現實&lt;/strong&gt;&lt;span class="hx:absolute hx:-mt-20" id="夢想與現實"&gt;&lt;/span&gt;
&lt;a href="#%e5%a4%a2%e6%83%b3%e8%88%87%e7%8f%be%e5%af%a6" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/i4yZnzt.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;三位工程師各自開發三個不同的新功能 (現實上很容易超過三個功能)
一個月後另一位工程師會來整合
發生 - &amp;gt; 整合地獄
最後測試人員 - &amp;gt; 測試 &amp;ndash; &amp;gt; 部署上線
&lt;img src="https://i.imgur.com/y3dlKpg.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;- &lt;font color=red&gt; 為了解決以上痛點 &lt;/font&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;持續整合 Continuous integration (CI)&lt;span class="hx:absolute hx:-mt-20" id="持續整合-continuous-integration-ci"&gt;&lt;/span&gt;
&lt;a href="#%e6%8c%81%e7%ba%8c%e6%95%b4%e5%90%88-continuous-integration-ci" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;持續小規模小規模的(縮短時間週期)整合加測試 &amp;mdash; &amp;gt; 快樂部署上線&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/sp6GjHb.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;持續交付 vs 持續部署(CD)&lt;span class="hx:absolute hx:-mt-20" id="持續交付-vs-持續部署cd"&gt;&lt;/span&gt;
&lt;a href="#%e6%8c%81%e7%ba%8c%e4%ba%a4%e4%bb%98-vs-%e6%8c%81%e7%ba%8c%e9%83%a8%e7%bd%b2cd" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Continuous delivery (手動)
&lt;ul&gt;
&lt;li&gt;&lt;font color=red&gt; 持續交付：將整合＋測試完成後的成果交付行為，減小規模、縮短週期，經過人工審查後交付（業界主流） &lt;/font&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Continuous deployment (自動)
&lt;ul&gt;
&lt;li&gt;持續部署：將整合＋測試完成後的成果交付行為，減小規模、縮短週期，並且自動執行無人工審查（心臟要夠大顆）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/3bBKpXo.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;導入Git&lt;span class="hx:absolute hx:-mt-20" id="導入git"&gt;&lt;/span&gt;
&lt;a href="#%e5%b0%8e%e5%85%a5git" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;a
href="https://hackmd.io/@QI-AN/r1RJ810Dc"target="_blank" rel="noopener"&gt;Git 筆記連結&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;解決程式設計師的痛&lt;/p&gt;
&lt;h6&gt;tags: &lt;code&gt;CI/CD&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="tags-cicd"&gt;&lt;/span&gt;
&lt;a href="#tags-cicd" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h6&gt;</description></item><item><title>REST API</title><link>https://blog.kubeantony.com/archive/ops-automation/rest-api/</link><pubDate>Sat, 28 May 2022 07:03:32 +0800</pubDate><guid>https://blog.kubeantony.com/archive/ops-automation/rest-api/</guid><description>
&lt;h2&gt;學習目標&lt;span class="hx:absolute hx:-mt-20" id="學習目標"&gt;&lt;/span&gt;
&lt;a href="#%e5%ad%b8%e7%bf%92%e7%9b%ae%e6%a8%99" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;What is an API?&lt;/li&gt;
&lt;li&gt;REST API 設計&lt;/li&gt;
&lt;li&gt;HTTP Status Code&lt;/li&gt;
&lt;li&gt;部署書目管理系統&lt;/li&gt;
&lt;li&gt;練習呼叫 REST API&lt;/li&gt;
&lt;li&gt;登入 H2 資料庫&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;情境說明&lt;span class="hx:absolute hx:-mt-20" id="情境說明"&gt;&lt;/span&gt;
&lt;a href="#%e6%83%85%e5%a2%83%e8%aa%aa%e6%98%8e" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;在網路書店擔任程式設計師&lt;/li&gt;
&lt;li&gt;負責書目庫存查詢系統開發&lt;/li&gt;
&lt;li&gt;由兩個子系統組成
&lt;ul&gt;
&lt;li&gt;書目管理系統(已完成) &amp;lt; &amp;mdash;&amp;ndash; 呼叫REST API 練習&lt;/li&gt;
&lt;li&gt;庫存查詢系統(開發中)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What is an API?&lt;span class="hx:absolute hx:-mt-20" id="what-is-an-api"&gt;&lt;/span&gt;
&lt;a href="#what-is-an-api" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/KQsBa6Y.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;使用者不需要知道後台Server的操作過程，透過API就可以完成需要的目的&lt;/p&gt;
&lt;h3&gt;Public API&lt;span class="hx:absolute hx:-mt-20" id="public-api"&gt;&lt;/span&gt;
&lt;a href="#public-api" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;公共開放的API&lt;/p&gt;
&lt;p&gt;&lt;a
href="https://github.com/public-apis/public-apis"target="_blank" rel="noopener"&gt;公共API 列表&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a
href="https://data.gov.tw/API"target="_blank" rel="noopener"&gt;政府公共平台API&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;REST API&lt;span class="hx:absolute hx:-mt-20" id="rest-api"&gt;&lt;/span&gt;
&lt;a href="#rest-api" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;font color=red&gt; REST is a set of architectural constraints, not a protocol or a standard. &lt;/font&gt; API developers can implement REST in a variety of ways.&lt;/p&gt;
&lt;p&gt;&lt;font color=red&gt;The REST architectural style describes six constraints.&lt;/font&gt; These constraints, applied to the architecture, were originally communicated by Roy Fielding in his doctoral dissertation and defines the basis of RESTful-style.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;它不是開發的標準，也不是協定，是程式開發的江湖規矩，並沒有強制的限制，有6種規定，都有達成的話，我們就稱它為REST API&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;REST API Quick Tips
&lt;ul&gt;
&lt;li&gt;Use HTTP Verbs to Make Your Requests Mean Something
&lt;ul&gt;
&lt;li&gt;遵循HTTP的Methods&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Provide Sensible Resource Names
&lt;ul&gt;
&lt;li&gt;提供合適的資源名稱&lt;/li&gt;
&lt;li&gt;規範api的名稱：/api/getbooks &amp;ndash;&amp;gt; GET /api/books (前面的GET是Http的動詞)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Use HTTP Response Codes to Indicate Status&lt;/li&gt;
&lt;li&gt;Offer Both JSON and XML&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;HTTP Methods&lt;span class="hx:absolute hx:-mt-20" id="http-methods"&gt;&lt;/span&gt;
&lt;a href="#http-methods" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;HTTP defines methods (sometimes referred to as verbs, but nowhere in the specification does it mention verb, nor is OPTIONS or HEAD a verb) to indicate the desired action to be performed on the identified resource.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GET&lt;/li&gt;
&lt;li&gt;POST&lt;/li&gt;
&lt;li&gt;PUT&lt;/li&gt;
&lt;li&gt;DELETE&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;REST API 設計&lt;span class="hx:absolute hx:-mt-20" id="rest-api-設計"&gt;&lt;/span&gt;
&lt;a href="#rest-api-%e8%a8%ad%e8%a8%88" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/464Q2fa.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h3&gt;CRUD&lt;span class="hx:absolute hx:-mt-20" id="crud"&gt;&lt;/span&gt;
&lt;a href="#crud" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/hDRUY1G.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;HTTP Status Code&lt;span class="hx:absolute hx:-mt-20" id="http-status-code"&gt;&lt;/span&gt;
&lt;a href="#http-status-code" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;HTTP 狀態碼表明一個 HTTP 要求是否已經被完成。回應分為五種：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;資訊回應 (Informational responses, 100–199)&lt;/li&gt;
&lt;li&gt;成功回應 (Successful responses, 200–299)&lt;/li&gt;
&lt;li&gt;重定向 (Redirects, 300–399)&lt;/li&gt;
&lt;li&gt;用戶端錯誤 (Client errors, 400–499)&lt;/li&gt;
&lt;li&gt;伺服器端錯誤 (Server errors, 500–599)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HTTP Server的回應一定要跟Clinet端看到的一樣&lt;/p&gt;
&lt;hr&gt;
&lt;h1&gt;練習範例1&lt;/h1&gt;&lt;h2&gt;Table Schema&lt;span class="hx:absolute hx:-mt-20" id="table-schema"&gt;&lt;/span&gt;
&lt;a href="#table-schema" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/lgmrjpm.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;部署書目管理系統&lt;span class="hx:absolute hx:-mt-20" id="部署書目管理系統"&gt;&lt;/span&gt;
&lt;a href="#%e9%83%a8%e7%bd%b2%e6%9b%b8%e7%9b%ae%e7%ae%a1%e7%90%86%e7%b3%bb%e7%b5%b1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;建立並執行 Container&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ docker run --rm -d -p 8080:8080 --name bookstore-catalog quay.io/grassknot/bookstore-catalog:1.2.0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;確認 Container 運行狀態&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
669f476fa8b9 quay.io/grassknot/bookstore-catalog:1.2.0 &amp;#34;java -Dspring.profi…&amp;#34; 9 seconds ago Up 8 seconds 0.0.0.0:8080-&amp;gt;8080/tcp bookstore-catalog&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;確認 bookstore-catalog image&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
quay.io/grassknot/bookstore-catalog 1.2.0 64f1607d41a2 3 days ago 125MB&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;測試書目管理系統&lt;span class="hx:absolute hx:-mt-20" id="測試書目管理系統"&gt;&lt;/span&gt;
&lt;a href="#%e6%b8%ac%e8%a9%a6%e6%9b%b8%e7%9b%ae%e7%ae%a1%e7%90%86%e7%b3%bb%e7%b5%b1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;透過&lt;code&gt;curl&lt;/code&gt;命令測試連線我們的網站&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl localhost:8080
Welcome to Bookstore Catalog REST API&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl localhost:8080/ruok
imok&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl localhost:8080/ruready
yes&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;curl&lt;/code&gt;命令後面加參數&lt;code&gt;-v&lt;/code&gt;，會進入健談模式，把它工作的資訊都說出來&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl -v localhost:8080/ruready
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
&amp;gt; GET /ruready HTTP/1.1
&amp;gt; Host: localhost:8080
&amp;gt; User-Agent: curl/7.83.1
&amp;gt; Accept: */*
&amp;gt;
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 200 ## 200的狀態碼代表成功
&amp;lt; Vary: Origin
&amp;lt; Vary: Access-Control-Request-Method
&amp;lt; Vary: Access-Control-Request-Headers
&amp;lt; Content-Type: text/plain;charset=UTF-8
&amp;lt; Content-Length: 3
&amp;lt; Date: Fri, 27 May 2022 02:23:29 GMT
&amp;lt;
* Connection #0 to host localhost left intact&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;取得所有主題&lt;span class="hx:absolute hx:-mt-20" id="取得所有主題"&gt;&lt;/span&gt;
&lt;a href="#%e5%8f%96%e5%be%97%e6%89%80%e6%9c%89%e4%b8%bb%e9%a1%8c" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl localhost:8080/api/topics&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;打開Google Chrome&lt;span class="hx:absolute hx:-mt-20" id="打開google-chrome"&gt;&lt;/span&gt;
&lt;a href="#%e6%89%93%e9%96%8bgoogle-chrome" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在網址搜尋：&lt;code&gt;http://&amp;lt;$VMIP&amp;gt;:8080/&lt;/code&gt;
&lt;img src="https://i.imgur.com/7banjE5.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;按F12，按F5，選Network，選Headers&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;搭配 jq 命令&lt;span class="hx:absolute hx:-mt-20" id="搭配-jq-命令"&gt;&lt;/span&gt;
&lt;a href="#%e6%90%ad%e9%85%8d-jq-%e5%91%bd%e4%bb%a4" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;透過jq 翻譯後就會比較好看&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl localhost:8080/api/topics | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 835 0 835 0 0 118k 0 --:--:-- --:--:-- --:--:-- 135k
[
{
&amp;#34;id&amp;#34;: 1,
&amp;#34;name&amp;#34;: &amp;#34;Cloud Native&amp;#34;,
&amp;#34;books&amp;#34;: [
{
&amp;#34;id&amp;#34;: 1,
&amp;#34;isbn&amp;#34;: &amp;#34;1492090719&amp;#34;,
&amp;#34;title&amp;#34;: &amp;#34;Design Patterns for Cloud Native Applications&amp;#34;,
&amp;#34;author&amp;#34;: &amp;#34;Kasun Indrasiri, Sriskandarajah Suhothayan&amp;#34;,
&amp;#34;price&amp;#34;: 1980,
&amp;#34;page&amp;#34;: 314
}
]
},
...以下省略&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在&lt;code&gt;curl&lt;/code&gt; 後面加上參數 &lt;code&gt;-s&lt;/code&gt;，代表silent mode，就可以只呈現我們要看的內容&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl -s localhost:8080/api/topics | jq
[
{
&amp;#34;id&amp;#34;: 1,
&amp;#34;name&amp;#34;: &amp;#34;Cloud Native&amp;#34;,
&amp;#34;books&amp;#34;: [
{
&amp;#34;id&amp;#34;: 1,
&amp;#34;isbn&amp;#34;: &amp;#34;1492090719&amp;#34;,
&amp;#34;title&amp;#34;: &amp;#34;Design Patterns for Cloud Native Applications&amp;#34;,
&amp;#34;author&amp;#34;: &amp;#34;Kasun Indrasiri, Sriskandarajah Suhothayan&amp;#34;,
&amp;#34;price&amp;#34;: 1980,
&amp;#34;page&amp;#34;: 314
}
]
},
...以下省略&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;到&lt;a
href="https://www.tenlong.com.tw/"target="_blank" rel="noopener"&gt;天瓏書局的網站&lt;/a&gt;查詢Cloud Native，真的查得到書籍&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;&amp;#34;id&amp;#34;: 2,
&amp;#34;name&amp;#34;: &amp;#34;Kubernetes&amp;#34;,
&amp;#34;books&amp;#34;: [
{
&amp;#34;id&amp;#34;: 2,
&amp;#34;isbn&amp;#34;: &amp;#34;9865024918&amp;#34;,
&amp;#34;title&amp;#34;: &amp;#34;Kubernetes 最佳實務&amp;#34;,
&amp;#34;author&amp;#34;: &amp;#34;Brendan Burns, Eddie Villalba, Dave Strebel and Lachlan Evenson&amp;#34;,
&amp;#34;price&amp;#34;: 411,
&amp;#34;page&amp;#34;: 272
},&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;取得ID為1的主題&lt;/p&gt;
&lt;p&gt;命令：&lt;code&gt;curl -s localhost:8080/api/topics/1 | jq&lt;/code&gt;&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl -s localhost:8080/api/topics/1 | jq
{
&amp;#34;id&amp;#34;: 1,
&amp;#34;name&amp;#34;: &amp;#34;Cloud Native&amp;#34;,
&amp;#34;books&amp;#34;: [
{
&amp;#34;id&amp;#34;: 1,
&amp;#34;isbn&amp;#34;: &amp;#34;1492090719&amp;#34;,
&amp;#34;title&amp;#34;: &amp;#34;Design Patterns for Cloud Native Applications&amp;#34;,
&amp;#34;author&amp;#34;: &amp;#34;Kasun Indrasiri, Sriskandarajah Suhothayan&amp;#34;,
&amp;#34;price&amp;#34;: 1980,
&amp;#34;page&amp;#34;: 314
}
]
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;新增一個主題&lt;span class="hx:absolute hx:-mt-20" id="新增一個主題"&gt;&lt;/span&gt;
&lt;a href="#%e6%96%b0%e5%a2%9e%e4%b8%80%e5%80%8b%e4%b8%bb%e9%a1%8c" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;命令：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl -v -s localhost:8080/api/topics \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--data &amp;#39;{
&amp;#34;name&amp;#34;: &amp;#34;Big Data&amp;#34;
}&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;命令回傳結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
## curl 命令看到--data時，會將Http的Method，從GET轉成POST
## 開頭是 &amp;gt; ，代表傳給Server的訊息
&amp;gt; POST /api/topics HTTP/1.1
&amp;gt; Host: localhost:8080
&amp;gt; User-Agent: curl/7.83.1
&amp;gt; Accept: */*
&amp;gt; Content-Type: application/json
&amp;gt; Content-Length: 26
&amp;gt;
* Mark bundle as not supporting multiuse
## 開頭是 &amp;lt; ，代表Server回傳的訊息
## 201 ，表示請求成功且有一個新的資源已經依據需要而被建立
&amp;lt; HTTP/1.1 201
&amp;lt; Vary: Origin
&amp;lt; Vary: Access-Control-Request-Method
&amp;lt; Vary: Access-Control-Request-Headers
&amp;lt; Location: http://localhost:8080/api/topics/4 ## 新增主題取得的資訊
&amp;lt; Content-Length: 0
&amp;lt; Date: Fri, 27 May 2022 03:05:37 GMT
&amp;lt;
* Connection #0 to host localhost left intact&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢查&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl -s http://localhost:8080/api/topics/4 | jq
{
&amp;#34;id&amp;#34;: 4,
&amp;#34;name&amp;#34;: &amp;#34;Big Data&amp;#34;,
&amp;#34;books&amp;#34;: []
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;&lt;strong&gt;更新 ID 為 4 的主題&lt;/strong&gt;&lt;span class="hx:absolute hx:-mt-20" id="更新-id-為-4-的主題"&gt;&lt;/span&gt;
&lt;a href="#%e6%9b%b4%e6%96%b0-id-%e7%82%ba-4-%e7%9a%84%e4%b8%bb%e9%a1%8c" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;命令：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;curl -v -s -X PUT localhost:8080/api/topics \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--data &amp;#39;{
&amp;#34;id&amp;#34;: &amp;#34;4&amp;#34;,
&amp;#34;name&amp;#34;: &amp;#34;Data Technology&amp;#34;
}&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;-x&lt;/code&gt;的參數，代表可以指定Http Methods的動作
&lt;code&gt;PUT&lt;/code&gt;是Http Methods的動作：更新&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;命令回傳結果&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
&amp;gt; PUT /api/topics HTTP/1.1
&amp;gt; Host: localhost:8080
&amp;gt; User-Agent: curl/7.83.1
&amp;gt; Accept: */*
&amp;gt; Content-Type: application/json
&amp;gt; Content-Length: 48
&amp;gt;
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 200
&amp;lt; Vary: Origin
&amp;lt; Vary: Access-Control-Request-Method
&amp;lt; Vary: Access-Control-Request-Headers
&amp;lt; Location: http://localhost:8080/api/topics/4
&amp;lt; Content-Length: 0
&amp;lt; Date: Fri, 27 May 2022 03:20:15 GMT
&amp;lt;
* Connection #0 to host localhost left intact&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢查&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl -s http://localhost:8080/api/topics/4 | jq
{
&amp;#34;id&amp;#34;: 4,
&amp;#34;name&amp;#34;: &amp;#34;Data Technology&amp;#34;, ## 更新成功
&amp;#34;books&amp;#34;: []
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;刪除所有主題&lt;span class="hx:absolute hx:-mt-20" id="刪除所有主題"&gt;&lt;/span&gt;
&lt;a href="#%e5%88%aa%e9%99%a4%e6%89%80%e6%9c%89%e4%b8%bb%e9%a1%8c" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;刪除命令：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl -s -v -X DELETE localhost:8080/api/topics&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;命令回傳結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
&amp;gt; DELETE /api/topics HTTP/1.1
&amp;gt; Host: localhost:8080
&amp;gt; User-Agent: curl/7.83.1
&amp;gt; Accept: */*
&amp;gt;
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 405
&amp;lt; Allow: GET, PUT, POST &amp;lt; ---------------- 只允許這3個Http Methods
&amp;lt; Vary: Origin
&amp;lt; Vary: Access-Control-Request-Method
&amp;lt; Vary: Access-Control-Request-Headers
&amp;lt; Content-Type: application/json
&amp;lt; Transfer-Encoding: chunked
&amp;lt; Date: Fri, 27 May 2022 03:24:12 GMT
&amp;lt;
* Connection #0 to host localhost left intact
{&amp;#34;timestamp&amp;#34;:&amp;#34;2022-05-27T03:24:12.497&amp;#43;00:00&amp;#34;,&amp;#34;status&amp;#34;:405,&amp;#34;error&amp;#34;:&amp;#34;Method Not Allowed&amp;#34;,&amp;#34;path&amp;#34;:&amp;#34;/api/topics&amp;#34;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;刪除 ID 為 5 的主題&lt;span class="hx:absolute hx:-mt-20" id="刪除-id-為-5-的主題"&gt;&lt;/span&gt;
&lt;a href="#%e5%88%aa%e9%99%a4-id-%e7%82%ba-5-%e7%9a%84%e4%b8%bb%e9%a1%8c" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;命令：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl -v -X DELETE localhost:8080/api/topics/5&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;回傳結果:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
&amp;gt; DELETE /api/topics/5 HTTP/1.1
&amp;gt; Host: localhost:8080
&amp;gt; User-Agent: curl/7.83.1
&amp;gt; Accept: */*
&amp;gt;
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 404
&amp;lt; Vary: Origin
&amp;lt; Vary: Access-Control-Request-Method
&amp;lt; Vary: Access-Control-Request-Headers
&amp;lt; Content-Type: application/json
&amp;lt; Transfer-Encoding: chunked
&amp;lt; Date: Fri, 27 May 2022 03:28:18 GMT
&amp;lt;
* Connection #0 to host localhost left intact
{&amp;#34;timestamp&amp;#34;:&amp;#34;2022-05-27T03:28:18.157&amp;#43;00:00&amp;#34;,&amp;#34;status&amp;#34;:404,&amp;#34;error&amp;#34;:&amp;#34;Not Found&amp;#34;,&amp;#34;path&amp;#34;:&amp;#34;/api/topics/5&amp;#34;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;最後一行：
{&amp;ldquo;timestamp&amp;rdquo;:&amp;ldquo;2022-05-27T03:28:18.157+00:00&amp;rdquo;,&amp;ldquo;status&amp;rdquo;:404,&amp;ldquo;error&amp;rdquo;:&amp;ldquo;Not Found&amp;rdquo;,&amp;ldquo;path&amp;rdquo;:&amp;quot;/api/topics/5&amp;quot;}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;可以看到最後一行它說找不到這個組題，所以刪除失敗&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;刪除 ID 為 1 的主題&lt;span class="hx:absolute hx:-mt-20" id="刪除-id-為-1-的主題"&gt;&lt;/span&gt;
&lt;a href="#%e5%88%aa%e9%99%a4-id-%e7%82%ba-1-%e7%9a%84%e4%b8%bb%e9%a1%8c" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;命令：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl -v -X DELETE localhost:8080/api/topics/1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;命令回傳結果：&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
&amp;gt; DELETE /api/topics/1 HTTP/1.1
&amp;gt; Host: localhost:8080
&amp;gt; User-Agent: curl/7.83.1
&amp;gt; Accept: */*
&amp;gt;
* Mark bundle as not supporting multiuse
&amp;lt; HTTP/1.1 200
&amp;lt; Vary: Origin
&amp;lt; Vary: Access-Control-Request-Method
&amp;lt; Vary: Access-Control-Request-Headers
&amp;lt; Content-Length: 0
&amp;lt; Date: Fri, 27 May 2022 03:31:28 GMT
&amp;lt;
* Connection #0 to host localhost left intact&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;檢查&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ curl -s http://localhost:8080/api/topics/1 | jq
{
&amp;#34;timestamp&amp;#34;: &amp;#34;2022-05-27T03:32:17.892&amp;#43;00:00&amp;#34;,
&amp;#34;status&amp;#34;: 404,
&amp;#34;error&amp;#34;: &amp;#34;Not Found&amp;#34;,
&amp;#34;path&amp;#34;: &amp;#34;/api/topics/1&amp;#34;
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;刪除成功！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;還原書目管理系統&lt;span class="hx:absolute hx:-mt-20" id="還原書目管理系統"&gt;&lt;/span&gt;
&lt;a href="#%e9%82%84%e5%8e%9f%e6%9b%b8%e7%9b%ae%e7%ae%a1%e7%90%86%e7%b3%bb%e7%b5%b1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;重新部署
停止Container&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ docker stop bookstore-catalog
bookstore-catalog&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;因為剛剛建立Container時，有加&lt;code&gt;--rm&lt;/code&gt;的參數，所以關閉後，Container就會刪除。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;再建立一次Container&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;$ docker run --rm -d -p 8080:8080 --name bookstore-catalog quay.io/grassknot/bookstore-catalog:1.2.0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h1&gt;實作練習1&lt;/h1&gt;&lt;h2&gt;題目&lt;span class="hx:absolute hx:-mt-20" id="題目"&gt;&lt;/span&gt;
&lt;a href="#%e9%a1%8c%e7%9b%ae" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;請先還原書目管理系統
進行主題與書的管理，並完成下圖結果
&lt;img src="https://lh3.googleusercontent.com/rH0JlJizVVrinLi6QsvuzuD6RX78fw1yh0Dk6Mldimsv6WG9PqZmcz-JX1TsDuqP4V0iuEF69s6704uvGbJq8Rv9FC_-sDpRI9GjOnnrEe6xs7Zm9XHDrKUTKvgbqwuLuHqihpUW850LGrmQbg" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;答案&lt;span class="hx:absolute hx:-mt-20" id="答案"&gt;&lt;/span&gt;
&lt;a href="#%e7%ad%94%e6%a1%88" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;#刪除 topics、books
curl -v -X DELETE localhost:8080/api/topics/2
curl -v -X DELETE localhost:8080/api/topics/3
curl -v -X DELETE localhost:8080/api/books/3
curl -v -X DELETE localhost:8080/api/books/4
curl -v -X DELETE localhost:8080/api/books/5
#確認內容
curl -v localhost:8080/api/topics | jq
curl -v localhost:8080/api/books | jq
#修改書籍資訊
curl -v -s -X PUT localhost:8080/api/books \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--data &amp;#39;{
&amp;#34;id&amp;#34;: 2,
&amp;#34;isbn&amp;#34;: &amp;#34;9865024918&amp;#34;,
&amp;#34;title&amp;#34;: &amp;#34;Kubernetes 最佳實務&amp;#34;,
&amp;#34;author&amp;#34;: &amp;#34;Brendan Burns, Eddie Villalba, Dave Strebel and Lachlan Evenson&amp;#34;,
&amp;#34;price&amp;#34;: 411,
&amp;#34;page&amp;#34;: 272,
&amp;#34;topic&amp;#34;: {
&amp;#34;id&amp;#34;: 1,
&amp;#34;name&amp;#34;: &amp;#34;Kubernetes&amp;#34; ## 這行可以不打
}
}&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h1&gt;實作練習2&lt;/h1&gt;&lt;h2&gt;題目&lt;span class="hx:absolute hx:-mt-20" id="題目-1"&gt;&lt;/span&gt;
&lt;a href="#%e9%a1%8c%e7%9b%ae-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;請先還原書目管理系統
參考新書資訊新增主題與書
新書資訊
書名 ｜Hadoop: The Definitive Guide, 4/e (Paperback)
作者 ｜Tom White
ISBN ｜ 1491901632
頁數 ｜756
價錢 ｜1890
所屬主題 ｜Data Technology&lt;/p&gt;
&lt;p&gt;預期結果請參考下圖&lt;/p&gt;
&lt;p&gt;&lt;img src="https://lh5.googleusercontent.com/_UhkqLY0haNtVX8AqPD__Wo1K277jF6cn3afA6aGNRbVDyIoPfPyj18kuVBAd506NqVeryHc7eFjbLulWD2-nbOC3tqK4rYB2t8omGvTnHcDSkWpXok35G8PWPjGWo4dQvdZ4ZkKFuH06uLEpA" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2&gt;答案&lt;span class="hx:absolute hx:-mt-20" id="答案-1"&gt;&lt;/span&gt;
&lt;a href="#%e7%ad%94%e6%a1%88-1" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;curl -v -s -X PUT localhost:8080/api/books \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--data &amp;#39;{
&amp;#34;id&amp;#34;: 6,
&amp;#34;isbn&amp;#34;: &amp;#34;1491901632&amp;#34;,
&amp;#34;title&amp;#34;: &amp;#34;Hadoop: The Definitive Guide, 4/e (Paperback)&amp;#34;,
&amp;#34;author&amp;#34;: &amp;#34;Tom White&amp;#34;,
&amp;#34;price&amp;#34;: 1890,
&amp;#34;page&amp;#34;: 756,
&amp;#34;topic&amp;#34;: {
&amp;#34;id&amp;#34;: 4,
&amp;#34;name&amp;#34;: &amp;#34;Data Technology&amp;#34;
}
}&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;curl -v -s localhost:8080/api/books \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--data &amp;#39;{
&amp;#34;id&amp;#34;: &amp;#34;6&amp;#34;,
&amp;#34;isbn&amp;#34;: &amp;#34;1491901632&amp;#34;,
&amp;#34;title&amp;#34;: &amp;#34;Hadoop: The Definitive Guide, 4/e (Paperback)&amp;#34;,
&amp;#34;author&amp;#34;: &amp;#34;Tom White&amp;#34;,
&amp;#34;price&amp;#34;: 1890,
&amp;#34;page&amp;#34;: 756,
&amp;#34;topic&amp;#34;: {
&amp;#34;id&amp;#34;: &amp;#34;4&amp;#34;
}
}&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="複製程式碼"
aria-label="複製程式碼"
data-copied-label="已複製！"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h1&gt;登入 H2 資料庫&lt;/h1&gt;&lt;p&gt;&lt;a
href="https://www.h2database.com/html/main.html"target="_blank" rel="noopener"&gt;h2資料庫官網&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;打開 chrome 瀏覽器，網址如下：
&lt;code&gt;http://&amp;lt;$VMIP&amp;gt;:8080/h2&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/7ljnbGP.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;jdbc:h2:mem:bookstore&lt;/p&gt;
&lt;p&gt;bookstore&lt;/p&gt;
&lt;h2&gt;使用 SQL 檢視資料&lt;span class="hx:absolute hx:-mt-20" id="使用-sql-檢視資料"&gt;&lt;/span&gt;
&lt;a href="#%e4%bd%bf%e7%94%a8-sql-%e6%aa%a2%e8%a6%96%e8%b3%87%e6%96%99" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;&lt;img src="https://i.imgur.com/QDli1Lf.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h6&gt;tags: &lt;code&gt;CI/CD&lt;/code&gt;&lt;span class="hx:absolute hx:-mt-20" id="tags-cicd"&gt;&lt;/span&gt;
&lt;a href="#tags-cicd" class="subheading-anchor" aria-label="此章節的永久連結"&gt;&lt;/a&gt;&lt;/h6&gt;</description></item></channel></rss>