<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>後端部署 CI/CD on Tarragon</title><link>https://tarrragon.github.io/blog/ci/backend-deploy/</link><description>Recent content in 後端部署 CI/CD on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Wed, 06 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/ci/backend-deploy/index.xml" rel="self" type="application/rss+xml"/><item><title>後端 migration、rollout 與 rollback 流程</title><link>https://tarrragon.github.io/blog/ci/backend-deploy/migration-rollout-rollback-flow/</link><pubDate>Thu, 21 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ci/backend-deploy/migration-rollout-rollback-flow/</guid><description>&lt;p>後端部署流程的核心責任是讓程式、資料與流量在相容窗口內推進。後端服務通常會同時依賴 database、queue、cache、外部 API 與 runtime config；CI/CD 需要把 build 成功、migration 安全、readiness 可信、rollback 可執行分成不同 gate。&lt;/p>
&lt;h2 id="流程定位">流程定位&lt;/h2>
&lt;p>後端部署的主要風險是有狀態依賴。前端 artifact 可以直接回退上一份靜態檔，後端服務一旦寫入新資料、消費 queue message 或呼叫外部 side effect，rollback 就不再只是換回舊 image。發布流程要先定義新舊版本如何短暫共存，再決定 migration 與流量切換順序。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>階段&lt;/th>
 &lt;th>責任&lt;/th>
 &lt;th>判讀訊號&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Build&lt;/td>
 &lt;td>產生 binary、package 或 image&lt;/td>
 &lt;td>版本是否可追到 commit&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Contract test&lt;/td>
 &lt;td>驗證 API、queue、DB 相容性&lt;/td>
 &lt;td>新舊 schema / message 是否可共存&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/migration/" data-link-title="Migration" data-link-desc="說明資料或結構變更如何在服務不中斷前提下受控推進">Migration&lt;/a>&lt;/td>
 &lt;td>推進資料結構與資料狀態&lt;/td>
 &lt;td>是否可漸進、可重試、可停止&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/rollout-strategy/" data-link-title="Rollout Strategy" data-link-desc="說明新版本如何以可控節奏推進到全部流量">Rollout strategy&lt;/a>&lt;/td>
 &lt;td>分批接流量&lt;/td>
 &lt;td>readiness、error rate、latency 是否可信&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/rollback-strategy/" data-link-title="Rollback Strategy" data-link-desc="說明發布異常時如何快速回到已知可用狀態">Rollback strategy&lt;/a>&lt;/td>
 &lt;td>縮小錯誤版本影響&lt;/td>
 &lt;td>程式、資料、queue 與 config 是否可回復&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Build 階段負責產生可部署服務。服務版本要能從 runtime 反查 commit、workflow run、image digest 與 migration 版本，讓事故時能快速定位哪一次變更進入環境。&lt;/p>
&lt;p>Contract test 階段負責驗證跨邊界相容。API response、database schema、queue message 與 config key 都是契約；只測 service 內部函式，通常抓不到新舊版本並存時的破壞性變更。&lt;/p>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/migration/" data-link-title="Migration" data-link-desc="說明資料或結構變更如何在服務不中斷前提下受控推進">Migration&lt;/a> 階段負責推進資料狀態。安全 migration 通常採 expand-and-contract：先加相容欄位或表、部署可讀新舊格式的程式、回填資料，最後移除舊格式。直接在同一次 release 刪欄位與切程式，會讓 rollback 失去空間。&lt;/p>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/rollout-strategy/" data-link-title="Rollout Strategy" data-link-desc="說明新版本如何以可控節奏推進到全部流量">Rollout strategy&lt;/a> 階段負責控制新版本接到的流量。Rolling、canary 與 blue-green 都需要可信 readiness；readiness 應檢查服務能否接流量，而不只是 process alive。&lt;/p>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/rollback-strategy/" data-link-title="Rollback Strategy" data-link-desc="說明發布異常時如何快速回到已知可用狀態">Rollback strategy&lt;/a> 階段負責定義失敗時的處理路由。後端 rollback 常見做法是 app rollback、config rollback、traffic rollback 或 forward fix；資料已被新程式寫入時，forward fix 往往比直接資料回滾安全。&lt;/p>
&lt;h2 id="migration-順序">Migration 順序&lt;/h2>
&lt;p>Migration 順序的責任是保留相容窗口。資料結構變更應讓至少兩個相鄰程式版本能共存，避免部署中途任何一端先完成都造成服務不可用。&lt;/p>
&lt;ol>
&lt;li>新增向前相容 schema，例如新增 nullable column 或新表。&lt;/li>
&lt;li>部署可同時讀舊欄位與新欄位的程式。&lt;/li>
&lt;li>執行 backfill 或 background migration。&lt;/li>
&lt;li>切換讀取來源或寫入路徑。&lt;/li>
&lt;li>觀察穩定後移除舊欄位、舊 index 或舊 message 格式。&lt;/li>
&lt;/ol>
&lt;p>這個順序的價值是可停止。若第 3 步回填異常，可以暫停 backfill，不必立即回退 app；若第 4 步切換後錯誤率升高，可以先切回舊讀取路徑，再評估資料修補。&lt;/p>
&lt;h2 id="rollout-判讀">Rollout 判讀&lt;/h2>
&lt;p>Rollout 判讀要同時看技術指標與業務副作用。服務能啟動不代表能安全接流量；API error、queue lag、database lock、第三方 API 錯誤與核心業務漏斗都可能是發布問題。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>訊號&lt;/th>
 &lt;th>判讀&lt;/th>
 &lt;th>下一步&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>readiness 未通過&lt;/td>
 &lt;td>新版本尚未能接流量&lt;/td>
 &lt;td>暫停 rollout，查 config / 依賴&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>error rate 上升&lt;/td>
 &lt;td>新版本或相依服務契約出錯&lt;/td>
 &lt;td>降低流量或切回舊版本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>migration lock 久&lt;/td>
 &lt;td>schema 變更影響正常查詢&lt;/td>
 &lt;td>停止 migration，改成分段方案&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>consumer lag 上升&lt;/td>
 &lt;td>worker 消費速度或 message 壞&lt;/td>
 &lt;td>暫停新版 worker 或降速&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>rollback 後仍錯&lt;/td>
 &lt;td>資料或外部 side effect 已變動&lt;/td>
 &lt;td>進入 forward fix / repair 流程&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>這些訊號要先接到發布流程。若指標只存在 dashboard 裡、workflow 不知道如何判讀，團隊仍會在事故當下靠人工臨場決策。&lt;/p></description><content:encoded><![CDATA[<p>後端部署流程的核心責任是讓程式、資料與流量在相容窗口內推進。後端服務通常會同時依賴 database、queue、cache、外部 API 與 runtime config；CI/CD 需要把 build 成功、migration 安全、readiness 可信、rollback 可執行分成不同 gate。</p>
<h2 id="流程定位">流程定位</h2>
<p>後端部署的主要風險是有狀態依賴。前端 artifact 可以直接回退上一份靜態檔，後端服務一旦寫入新資料、消費 queue message 或呼叫外部 side effect，rollback 就不再只是換回舊 image。發布流程要先定義新舊版本如何短暫共存，再決定 migration 與流量切換順序。</p>
<table>
  <thead>
      <tr>
          <th>階段</th>
          <th>責任</th>
          <th>判讀訊號</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Build</td>
          <td>產生 binary、package 或 image</td>
          <td>版本是否可追到 commit</td>
      </tr>
      <tr>
          <td>Contract test</td>
          <td>驗證 API、queue、DB 相容性</td>
          <td>新舊 schema / message 是否可共存</td>
      </tr>
      <tr>
          <td><a href="/blog/ci/knowledge-cards/migration/" data-link-title="Migration" data-link-desc="說明資料或結構變更如何在服務不中斷前提下受控推進">Migration</a></td>
          <td>推進資料結構與資料狀態</td>
          <td>是否可漸進、可重試、可停止</td>
      </tr>
      <tr>
          <td><a href="/blog/ci/knowledge-cards/rollout-strategy/" data-link-title="Rollout Strategy" data-link-desc="說明新版本如何以可控節奏推進到全部流量">Rollout strategy</a></td>
          <td>分批接流量</td>
          <td>readiness、error rate、latency 是否可信</td>
      </tr>
      <tr>
          <td><a href="/blog/ci/knowledge-cards/rollback-strategy/" data-link-title="Rollback Strategy" data-link-desc="說明發布異常時如何快速回到已知可用狀態">Rollback strategy</a></td>
          <td>縮小錯誤版本影響</td>
          <td>程式、資料、queue 與 config 是否可回復</td>
      </tr>
  </tbody>
</table>
<p>Build 階段負責產生可部署服務。服務版本要能從 runtime 反查 commit、workflow run、image digest 與 migration 版本，讓事故時能快速定位哪一次變更進入環境。</p>
<p>Contract test 階段負責驗證跨邊界相容。API response、database schema、queue message 與 config key 都是契約；只測 service 內部函式，通常抓不到新舊版本並存時的破壞性變更。</p>
<p><a href="/blog/ci/knowledge-cards/migration/" data-link-title="Migration" data-link-desc="說明資料或結構變更如何在服務不中斷前提下受控推進">Migration</a> 階段負責推進資料狀態。安全 migration 通常採 expand-and-contract：先加相容欄位或表、部署可讀新舊格式的程式、回填資料，最後移除舊格式。直接在同一次 release 刪欄位與切程式，會讓 rollback 失去空間。</p>
<p><a href="/blog/ci/knowledge-cards/rollout-strategy/" data-link-title="Rollout Strategy" data-link-desc="說明新版本如何以可控節奏推進到全部流量">Rollout strategy</a> 階段負責控制新版本接到的流量。Rolling、canary 與 blue-green 都需要可信 readiness；readiness 應檢查服務能否接流量，而不只是 process alive。</p>
<p><a href="/blog/ci/knowledge-cards/rollback-strategy/" data-link-title="Rollback Strategy" data-link-desc="說明發布異常時如何快速回到已知可用狀態">Rollback strategy</a> 階段負責定義失敗時的處理路由。後端 rollback 常見做法是 app rollback、config rollback、traffic rollback 或 forward fix；資料已被新程式寫入時，forward fix 往往比直接資料回滾安全。</p>
<h2 id="migration-順序">Migration 順序</h2>
<p>Migration 順序的責任是保留相容窗口。資料結構變更應讓至少兩個相鄰程式版本能共存，避免部署中途任何一端先完成都造成服務不可用。</p>
<ol>
<li>新增向前相容 schema，例如新增 nullable column 或新表。</li>
<li>部署可同時讀舊欄位與新欄位的程式。</li>
<li>執行 backfill 或 background migration。</li>
<li>切換讀取來源或寫入路徑。</li>
<li>觀察穩定後移除舊欄位、舊 index 或舊 message 格式。</li>
</ol>
<p>這個順序的價值是可停止。若第 3 步回填異常，可以暫停 backfill，不必立即回退 app；若第 4 步切換後錯誤率升高，可以先切回舊讀取路徑，再評估資料修補。</p>
<h2 id="rollout-判讀">Rollout 判讀</h2>
<p>Rollout 判讀要同時看技術指標與業務副作用。服務能啟動不代表能安全接流量；API error、queue lag、database lock、第三方 API 錯誤與核心業務漏斗都可能是發布問題。</p>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>判讀</th>
          <th>下一步</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>readiness 未通過</td>
          <td>新版本尚未能接流量</td>
          <td>暫停 rollout，查 config / 依賴</td>
      </tr>
      <tr>
          <td>error rate 上升</td>
          <td>新版本或相依服務契約出錯</td>
          <td>降低流量或切回舊版本</td>
      </tr>
      <tr>
          <td>migration lock 久</td>
          <td>schema 變更影響正常查詢</td>
          <td>停止 migration，改成分段方案</td>
      </tr>
      <tr>
          <td>consumer lag 上升</td>
          <td>worker 消費速度或 message 壞</td>
          <td>暫停新版 worker 或降速</td>
      </tr>
      <tr>
          <td>rollback 後仍錯</td>
          <td>資料或外部 side effect 已變動</td>
          <td>進入 forward fix / repair 流程</td>
      </tr>
  </tbody>
</table>
<p>這些訊號要先接到發布流程。若指標只存在 dashboard 裡、workflow 不知道如何判讀，團隊仍會在事故當下靠人工臨場決策。</p>
<h2 id="常見反模式">常見反模式</h2>
<p>反模式的共同問題是把後端部署當成單一 deploy 動作。後端發布的本質是多個相依狀態的協調流程。</p>
<table>
  <thead>
      <tr>
          <th>反模式</th>
          <th>風險</th>
          <th>替代做法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>app 與 destructive migration 同步</td>
          <td>rollback 後舊程式失去讀取契約</td>
          <td>expand-and-contract</td>
      </tr>
      <tr>
          <td>readiness 只檢查 process alive</td>
          <td>流量進入尚未準備好的服務</td>
          <td>檢查依賴、config 與初始化狀態</td>
      </tr>
      <tr>
          <td>rollback 只切 image tag</td>
          <td>資料與 queue side effect 留下</td>
          <td>定義 app / data / config 路由</td>
      </tr>
      <tr>
          <td>migration 沒有 dry run</td>
          <td>發布時才發現權限或鎖表問題</td>
          <td>staging 或 shadow 環境先跑驗證</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>後端部署總覽：回 <a href="../">後端部署 CI/CD</a>。</li>
<li>Migration 術語：讀 <a href="/blog/ci/knowledge-cards/migration/" data-link-title="Migration" data-link-desc="說明資料或結構變更如何在服務不中斷前提下受控推進">Migration</a>。</li>
<li>Gate 原理：讀 <a href="../../ci-gate-workflow-boundary/">CI gate 與 workflow 邊界</a>。</li>
</ul>
]]></content:encoded></item></channel></rss>