昨天我們安裝了 DevSpace 來搭建開發環境嗎
✅ 掌握熱重載的配置與原理
✅ 學會設計完整的生命週期 Hook 管理
✅ 透過 Hook 建立自動化清理機制
傳統開發的痛點
想像你是一位廚師,每次調整食譜都要:
🔥 熄火關爐
🧹 清理廚具
🥘 重新準備所有食材
🔥 重新開火烹飪
⏰ 等待 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 # 立即測試結果
Hook 系統架構
想像 DevSpace 是一位專業管家,而 Hooks 就是他的工作清單:
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 流程 💻
最複雜的流程,包含:
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.yaml
和service.yaml
。而要完成devspace的配置與hotreload就需要devspace.yaml
檔案。
devspace.yaml
images:
my-image:
image: ${IMAGE}
rebuildStrategy: ignoreContextChanges
重建策略說明:
DevSpace 只在特定條件下才會重建 image,這些條件包括:
重建策略選項:
使用 rebuildStrategy 欄位可以明確覆蓋這一行為,開發者可以根據需要選擇不同的重建策略:
sync
跟onUpload
是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 何時不使用
✅ 適合使用的情況:
❌ 不建議使用的情況:
使用具備熱重載功能的工具:
- 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 # ⚡ 熱重啟
hooks:
- name: "pre-dev-start"
events: ["before:dev"]
command: "echo"
args: ["Starting DevSpace development environment..."]
實際應用場景:
- 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/
步驟 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 的使用,更重要的是理解了現代開發工具的設計哲學: