iT邦幫忙

2025 iThome 鐵人賽

DAY 15
2
DevOps

賢者大叔的容器修煉手札系列 第 15

DevSpace HotReload 與 Hooks - 讓開發如行雲流水 🌊

  • 分享至 

  • xImage
  •  

賢者大叔的容器修煉手札系列 第 15 篇

DevSpace 熱重載與生命週期鉤子 - 讓開發如行雲流水 🌊

昨天我們安裝了 DevSpace 來搭建開發環境嗎

✅ 核心學習目標

✅ 掌握熱重載的配置與原理
✅ 學會設計完整的生命週期 Hook 管理
✅ 透過 Hook 建立自動化清理機制

🤔 為什麼需要 HotReload?

傳統開發的痛點
想像你是一位廚師,每次調整食譜都要:

🔥 熄火關爐
🧹 清理廚具
🥘 重新準備所有食材
🔥 重新開火烹飪
⏰ 等待 5-10 分鐘才能嚐到結果

這就是傳統容器開發的寫照:

# 傳統開發流程 😰
vim main.go          # 修改程式碼
docker build .       # 重新建置 image (2-5分鐘)
docker stop app      # 停止容器
docker run app       # 重新啟動
curl localhost:8080  # 測試結果

熱重載的威力
而熱重載就像是擁有一個魔法平底鍋:

🔥 火不用關
🥘 食材自動更新
⚡ 立即嚐到新口味
🎯 專注於創意,而非流程
# 熱重載開發流程 🚀
vim main.go          # 修改程式碼
# 自動同步 + 自動重啟 (1-2秒)
curl localhost:8080  # 立即測試結果

🏗️ 熱重載架構解析

https://ithelp.ithome.com.tw/upload/images/20250830/20104930vdLL2YWtuE.png

🎣 生命週期鉤子深度解析

Hook 系統架構
想像 DevSpace 是一位專業管家,而 Hooks 就是他的工作清單:

https://ithelp.ithome.com.tw/upload/images/20250830/20104930VVVn5R7vIw.png

🎯 主要命令流程

1. Deploy 流程 🚀

before:deploy → 各個部署的 before:deploy:[name] → 執行部署 → after:deploy:[name] → after:deploy

包含錯誤處理 (error:deploy:[name]) 和跳過邏輯 (skip:deploy:[name])

2. Build 流程 🔨
遍歷所有image,每個image都有完整的生命週期 hooks

before:build:[name] → 建置 → after:build:[name] 或 error:build:[name]

3. Dev 流程 💻
最複雜的流程,包含:

  • Pull Secrets 建立
  • 檔案同步 (初始 + 持續)
  • Port forwarding (正向 + 反向)
  • 運行時事件處理

4. Render 流程 📄
類似 Deploy,但專注於模板渲染

5. Purge 流程 🗑️

清理資源的完整生命週期

🎨 顏色編碼說明
🔵 藍色: before:* hooks (準備階段)
🟢 綠色: after:* hooks (成功完成)
🔴 紅色: error:* hooks (錯誤處理)
🟠 橙色: skip:* hooks (跳過執行)
🟣 紫色: start:* hooks (啟動服務)
🔴 粉紅: stop:* hooks (停止服務)
🟡 黃色: restart:* hooks (重啟服務)

這個圖表幫助理解 DevSpace 在不同階段會觸發哪些 hooks,以及它們之間的執行順序和依賴關係!

🛠️ 實戰配置

這次我以 Go 語言舉例,如果是 JavaScript 演示 HotReload 其實簡單多了,畢竟不用編譯。像 Go、C# 這種都是要編譯過才能執行的程式語言,演示起來比較全面。

tree
.
├── devspace.yaml
├── Dockerfile
├── go.mod
├── kind-config.yaml
├── main.go
└── manifest
    ├── depolyment.yaml
    └── service.yaml

1 directory, 7 files

我們專案下會有程式專案檔案、Dockerfile,到這裡是基本專案開發所需,而要能快速的在 K8s 環境中部署就需要deployment.yamlservice.yaml。而要完成devspace的配置與hotreload就需要devspace.yaml檔案。

DevSpace.yaml 解析

devspace.yaml

1. 基礎映像配置

images:
  my-image:
    image: ${IMAGE}
    rebuildStrategy: ignoreContextChanges 

重建策略說明:
DevSpace 只在特定條件下才會重建 image,這些條件包括:

  • dockerfile 變更:如果 Dockerfile 發生了改變,系統會自動重建 image。
  • build context 文件改變:如果建構上下文資料夾中的任何文件發生變動(遵循 .dockerignore 規則),也會觸發重建。
  • devspace.yaml 配置變更:任何在 devspace.yaml 文件中的image配置更動,包括透過pipeline腳本設置的值(例如使用 --set 參數),也會導致重建。
  • image 首次建構或 .devspace/ 資料夾被刪除/修改:如果影像從未建構過,或是 .devspace/ 資料夾中存儲的資料遭到修改,則會執行重建。

重建策略選項:
使用 rebuildStrategy 欄位可以明確覆蓋這一行為,開發者可以根據需要選擇不同的重建策略:

  • default:遵循上述的預設邏輯。
  • always:無論任何情況下都會重建影像。
  • ignoreContextChanges:忽略 build context 文件的更動,僅在 Dockerfile 或 image 配置變更的情況下重建。

2. 開發環境核心配置

synconUpload 是hotreload的重點。

Sync-Triggered Actions 是指在檔案同步完成後自動執行的動作。這些動作可以幫助開發者在檔案變更後自動執行必要的操作。

主要用途:

  • 在檔案上傳到容器後執行特定命令
  • 重啟容器以應用變更
  • 執行編譯、安裝依賴等操作

restartContainer 選項是一個 boolean,定義 DevSpace 是否應該在每次檔案同步到容器後重啟容器。

⚠️ 重要要求:
設定 restartContainer: true 時,必須同時設定 command 參數。

dev:
  my-dev:
    imageSelector: ghcr.io/org/project/image
    # 必須設定 command,否則 DevSpace 不知道要重啟什麼
    command: ["entrypoint", "to", "container"]
    sync:
      - path: ./
        onUpload:
          restartContainer: true

何時使用 vs 何時不使用
✅ 適合使用的情況:

  • 應用程式基於編譯語言(如 Go、Java、C++)
  • 沒有使用具備熱重載功能的框架或工具
  • 需要完整重啟才能應用變更

❌ 不建議使用的情況:
使用具備熱重載功能的工具:
- nodemon(Node.js)
- React(前端框架)
- Rails(Ruby)
- Flask(Python)
這些工具的熱重載通常比重啟整個容器更快

dev:
  my-dev:
    imageSelector: ${IMAGE}
    command: ["go", "run", "main.go"]  # 🚀 直接執行啟動程式碼
    logs: {}                           # 📋 即時日誌
    ports:
    - port: 8080:8080                  # 🌐 port forwarding
    sync:                              # 🔄 檔案同步配置
    - path: ./
      excludePaths:                    # 🚫 排除清單
      - .git/
      - .devspace/
      - Dockerfile
      - "*.yaml"
      - "*.yml"
      - kind-config.yaml
      - .dockerignore
      onUpload:
        restartContainer: true         # ⚡ 熱重啟

3. Hook 配置

  1. 啟動前準備 (Pre-Dev Hook)
hooks:
  - name: "pre-dev-start"
    events: ["before:dev"]
    command: "echo"
    args: ["Starting DevSpace development environment..."]

實際應用場景:

  • 🔍 檢查前置條件
  • 🗄️ 初始化資料庫
  • 🌐 啟動相依服務
  1. 正常退出清理 (Post-Dev Hook)
- name: "cleanup-on-exit"
  events: ["after:dev"]
  command: "sh"
  args: 
  - "-c"
  - |
    echo "🧹 Cleaning up resources..."
    echo "✅ Cleanup completed!"

實際應用場景:

  • 🗄️ 清理資源

🎮 實戰演示

步驟 1 : 檢查 devspace.yaml

> devspace print

-------------------

Vars:
  
               NAME             |            VALUE              
  ------------------------------+-------------------------------
    DEVSPACE_CONTEXT            | kind-devspace-demo            
    DEVSPACE_EXECUTABLE         | /usr/local/bin/devspace       
    DEVSPACE_KUBECTL_EXECUTABLE | kubectl                       
    DEVSPACE_NAME               | hot-reload-container-restart  
    DEVSPACE_NAMESPACE          | devspace-demo                 
    DEVSPACE_PROFILE            |                               
    DEVSPACE_PROFILES           |                               
    DEVSPACE_RANDOM             | xYTqmN                        
    DEVSPACE_SPACE              | devspace-demo                 
    DEVSPACE_TIMESTAMP          | 1756536860                    
    DEVSPACE_TMPDIR             | /tmp                          
    DEVSPACE_USER_HOME          | /home/nathan                  
    DEVSPACE_VERSION            | 6.3.17                        
    IMAGE                       | hotreload-go/devspace         
    devspace.context            | kind-devspace-demo            
    devspace.namespace          | devspace-demo                 
  

-------------------

Loaded path: /home/nathan/Project/ithome2025/day15/hot_reload/devspace.yaml

步驟 2:啟動開發環境

> devspace dev --debug

info Using namespace 'devspace-demo'
info Using kube context 'kind-devspace-demo'
build:my-image Skip building image 'my-image'
deploy:my-deployment Applying manifests with kubectl...
deploy:my-deployment deployment.apps/hotreload-go-deployment configured
deploy:my-deployment service/hotreload-go-service unchanged
deploy:my-deployment Successfully deployed my-deployment with kubectl
dev:my-dev Waiting for pod to become ready...
dev:my-dev Selected pod hotreload-go-deployment-devspace-785d76d988-l9fnq
dev:my-dev ports Port forwarding started on: 8080 -> 8080
dev:my-dev sync  Sync started on: ./ <-> ./
dev:my-dev sync  Waiting for initial sync to complete
dev:my-dev sync  Initial sync completed
dev:my-dev logs  Streaming logs of pod:container hotreload-go-deployment-devspace-785d76d988-l9fnq:hotreload-go
dev:my-dev logs  Container started with restart helper.
dev:my-dev logs  Waiting for initial sync to complete or file /.devspace/start to exist before starting the application...
dev:my-dev logs  Starting application...
dev:my-dev logs  🚀 Server starting on port 8080...
dev:my-dev logs  📍 Health check: http://localhost:8080/health
dev:my-dev logs  🔗 API test: http://localhost:8080/api/test

此時我們就能打開http://localhost:8080 就能看到現在的網站跟服務了。

步驟3: :測試 hot reload
修改 main.go

// 主頁面
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello from DevSpace V2.0! 🚀\nTime: %v\nHost: %s",
			time.Now().Format("2006-01-02 15:04:05"), r.Host)
	})

同時你能觀察到本來執行devspace dev的畫面多了幾行訊息︰

dev:my-dev logs  signal: interrupt
dev:my-dev logs  
dev:my-dev logs  
dev:my-dev logs  ############### Restart container ###############
dev:my-dev logs  
dev:my-dev logs  🚀 Server starting on port 8080...
dev:my-dev logs  📍 Health check: http://localhost:8080/health
dev:my-dev logs  🔗 API test: http://localhost:8080/api/test

步驟 4:DevSpace UI 監控
也能透過 devspace ui 來看目前有哪些服務。
可以透過 devspace ui 或者 http://localhost:8090/

https://ithelp.ithome.com.tw/upload/images/20250830/20104930E1hpMTPZrT.png

步驟 5:測試結果

> curl localhost:8080

Hello from DevSpace V2.0! 🚀
Time: 2025-08-30 06:58:36
Host: localhost:4161

步驟 7:結束開發,清理資源
我們能在剛剛打開devspace dev的視窗中退出對話,如果要清理資源像是image, container,就能透過剛剛介紹的hook,我會在after:purge 去清理掉。

> devspace purge

info Using namespace 'devspace-demo'
info Using kube context 'kind-devspace-demo'
dev:my-dev Stopping dev my-dev
dev:my-dev Scaling up Deployment hotreload-go-deployment...
purge:my-deployment Deleting deployment my-deployment...
purge:my-deployment Successfully deleted deployment my-deployment
Execute hook 'cleanup-on-purge' at after:purge
🗑️  Purging all resources...
Untagged: hotreload-go/devspace:iMRLapO
Deleted: sha256:4f3e9298066101cdc9f360703ba2d22e23b68c7b7ae7bbcdf1141af1fe33c974
Deleted Containers:
dd82e2f1ef6bb287b637ca253b5258e333d2e2a3851316d6c5d2e5a0aaf70694

Deleted Images:
deleted: sha256:a4ce4787f8e422500cf6e81ba144e0f01d7c3298ef1ad3c92cdd38e7c54e552d

Total reclaimed space: 38.29kB
✅ Purge completed!

對應的 Hook 配置:

hooks:
  # 在部署被刪除時執行
  - name: "cleanup-on-purge"
    events: ["after:purge"]
    command: "sh"
    args:
    - "-c" 
    - |
      echo "🗑️  Purging all resources..."
      docker rmi $(docker images hotreload-go/devspace -q) 2>/dev/null || true
      docker system prune -f
      echo "✅ Purge completed!"

🎯 總結

通過今天的實戰,我們不只是學會了 DevSpace 的使用,更重要的是理解了現代開發工具的設計哲學:

  • 開發效率優化 - 從分鐘級別的重建等待,縮短到秒級的熱重載
  • 生命週期管理 - 完整的 Hook 系統讓我們能在每個關鍵節點插入自定義邏輯
  • 資源管理自動化 - 透過 Hook 實現自動清理,避免資源洩漏

https://ithelp.ithome.com.tw/upload/images/20250830/20104930oKoNly4Is6.png


上一篇
DevSpace - 雲原生開發的好幫手 ⚡
下一篇
DevSpace Commands:建立自定義開發指令 📖
系列文
賢者大叔的容器修煉手札17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言