iT邦幫忙

2026 iThome 鐵人賽

DAY 24
0
Build on Google AI

用 Google AI 生態系 30 天從零打造一個全棧 AI SaaS 服務系列 第 24 篇

Day 24 -【自動化與雲端部署】Google Cloud Build + Cloud Run + Docker 自動化 CI/CD 流水線與零停機部署實戰

  • 分享至 

  • xImage
  •  

在昨天的 [Day 23] 中,我們成功將 OmniVibe AI 拓展為跨平台 Agent,完成了 LINE Bot + Gemini Multi-modal Webhook 的整合,讓使用者在通訊軟體內就能極速提煉語音與影片。

現在,OmniVibe AI 已經具備了 Web Dashboard、Chrome Extension 與 LINE Bot 三端服務。然而,當開發團隊需要頻繁更新 Prompt、修復 Bug 或發布新功能時,手動 build 鏡像並部署至伺服器不僅費時,更面臨「部署期間服務中斷(Downtime)」的風險。

今天,我們將正式進入雲端部署篇,為 OmniVibe AI 搭建基於 Google Cloud 生態系的生產級 CI/CD 自動化流水線:利用 Docker 多階段構建 (Multi-stage Build) 極小化鏡像,結合 Google Cloud Build + Artifact Registry + Cloud Run,實現代碼一推即自動構建、零停機(Zero-downtime)無縫滾動更新!


☁️ 雲端 CI/CD 自動化部署架構

我們建立一套完全受管(Fully Managed)且具備高彈性的 Google Cloud 原生 CI/CD 架構:

graph TD
    subgraph Local & Git Repository
        Dev[開發者 Push Code] --> GitHub[GitHub / GitLab Repo]
    end

    subgraph Google Cloud CI/CD Pipeline
        GitHub -- Webhook Trigger --> CloudBuild[Google Cloud Build]
        CloudBuild --> DockerBuild[Docker Multi-Stage Build]
        DockerBuild --> TestCheck[自動執行 Zod / Unit Tests]
        TestCheck --> ArtifactReg[Google Artifact Registry (鏡像庫)]
    end

    subgraph Serverless Production Hosting
        ArtifactReg -- Deploy Image --> CloudRun[Google Cloud Run]
        CloudRun --> RevNew[建立 New Revision B (0% Traffic)]
        RevNew -- Health Check Pass --> TrafficShift[Traffic Shift (100% Traffic)]
        TrafficShift --> RevOld[Old Revision A (Scales to 0)]
    end


🛠️ 第一步:撰寫極小化 Next.js 多階段 Dockerfile (Dockerfile)

為了讓 Cloud Run 的冷啟動時間(Cold Start)降到最低,我們採用 Next.js 的 output: 'standalone' 模式,並透過 Docker 多階段構建(deps, builder, runner)將最終鏡像體積從 1.2GB 大幅縮減至 < 180MB:

# ==========================================
# 階段 1: 安裝依賴套件 (deps)
# ==========================================
FROM node:20-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci

# ==========================================
# 階段 2: 構建應用程式 (builder)
# ==========================================
FROM node:20-alpine AS builder
WORKDIR /app

COPY --from=deps /app/node_modules ./node_modules
COPY . .

# 禁用 Next.js 遙測
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production

# 構建 Next.js 產物 (確保 next.config.mjs 有設定 output: 'standalone')
RUN npm run build

# ==========================================
# 階段 3: 生產運行環境 (runner)
# ==========================================
FROM node:20-alpine AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=8080
ENV HOSTNAME="0.0.0.0"

# 建立非 Root 安全使用者
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 8080

CMD ["node", "server.js"]

💡 小技巧:在 next.config.mjs 中加入 output: 'standalone',Next.js 會自動追蹤並僅打包執行 Node.js 伺服器所需的最小 node_modules 依賴。


⚡ 第二步:配置 Google Cloud Build 流水線 (cloudbuild.yaml)

我們建立 cloudbuild.yaml 配置文件,定義自動編譯、推送到 Artifact Registry 以及部署至 Cloud Run 的自動化步驟:

steps:
  # 1. 取得歷史快取鏡像以加速 Docker Build
  - name: 'gcr.io/cloud-builders/docker'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        docker pull ${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/omnivibe-app:latest || exit 0

  # 2. 執行 Docker 構建 (利用 Docker Cache)
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'build'
      - '-t'
      - '${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/omnivibe-app:$SHORT_SHA'
      - '-t'
      - '${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/omnivibe-app:latest'
      - '--cache-from'
      - '${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/omnivibe-app:latest'
      - '.'

  # 3. 將構建好的鏡像推送至 Google Artifact Registry
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'push'
      - '${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/omnivibe-app:$SHORT_SHA'

  # 4. 部署至 Cloud Run 並帶入環境變數與自動流量切換
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: gcloud
    args:
      - 'run'
      - 'deploy'
      - 'omnivibe-service'
      - '--image=${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/omnivibe-app:$SHORT_SHA'
      - '--region=${_LOCATION}'
      - '--platform=managed'
      - '--allow-unauthenticated'
      - '--min-instances=1'        # 保留 1 個預熱實例降低冷啟動延遲
      - '--max-instances=10'       # 自動擴展上限
      - '--cpu=2'
      - '--memory=2Gi'
      - '--set-env-vars=NODE_ENV=production'
      - '--set-secrets=GEMINI_API_KEY=GEMINI_API_KEY:latest,QDRANT_URL=QDRANT_URL:latest'

images:
  - '${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/omnivibe-app:$SHORT_SHA'
  - '${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/omnivibe-app:latest'

substitutions:
  _LOCATION: 'asia-east1' # 台灣彰化 GCP 機房
  _REPOSITORY: 'omnivibe-repo'


🔄 第三步:設定 Google Cloud Run 零停機 (Zero-Downtime) 滾動更新機制

Google Cloud Run 原生支援 Revision(版本)管理 與 Traffic Splitting(流量切分)。當新版代碼觸發 CI/CD 部署時:

  1. Cloud Run 會先建立全新的 Revision(例如 omnivibe-service-00022)。
  2. 新的 Revision 會進行健康檢查(Health Check)。
  3. 唯有新版本通過 Health Check 後,Cloud Run 才會將 100% 的使用者流量瞬間切換至新版本。舊版本會被自動平滑下線(Scale to 0),實現真正的零停機部署!
# 透過 gcloud CLI 手動驗證流量切分(或於 GCP Console 界面設定)
gcloud run services update-traffic omnivibe-service \
  --region=asia-east1 \
  --to-latest


📊 部署維運比較表 (Traditional VPS vs. Cloud Run CI/CD)

評比維度 傳統 VPS 手動部署 Google Cloud Run + Cloud Build 流水線
部署流程 手動 SSH -> git pull -> build -> restart git push 自動觸發,全自動完成
服務中斷 重啟期間服務暫停 10-30 秒 零停機 (Zero-downtime) 滾動更新
鏡像體積 1.2 GB (完整 node_modules) < 180 MB (Standalone 最佳化)
機房延遲 隨意地區 asia-east1 (台灣在地機房,延遲 < 10ms)
密鑰安全 硬編碼或地端 .env 檔案 整合 GCP Secret Manager 嚴密防護

🎯 總結與明日預告

今天我們為 OmniVibe AI 完成了雲端生產環境自動化部署:

  1. 使用 Multi-stage Dockerfile 搭配 Next.js Standalone 模式,將容器鏡像體積減少了 85%。
  2. 建立 Google Cloud Build 自動化 CI/CD 流水線,實現代碼 Push 即自動驗證與構建。
  3. 部署於 Cloud Run 台灣機房 (asia-east1),享有伺服器無須維護(Serverless)的自動擴展與零停機更新優勢。

然而,當使用者上傳數小時的超長影片時,若直接在 HTTP 請求中同步等待,容易造成 API Timeout。

👉 明天(Day 25),我們將進入【微服務與非同步任務篇】:實戰 Cloud Tasks + Cloud Pub/Sub 處理長影音背景非同步提煉與 Webhook 通知!

我們明天見!🔥


上一篇
Day 23 -【多通道 Agent 擴充】實戰 LINE Bot + Gemini Multi-modal Webhook 整合與語音 / 連結極速提煉
下一篇
Day 25 -【微服務與非同步任務】Cloud Tasks + Cloud Pub/Sub 實戰長影音背景非同步提煉與 Webhook 即時通知
系列文
用 Google AI 生態系 30 天從零打造一個全棧 AI SaaS 服務 共 25 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言