跳轉至

建立 2026-09-28 更新 2026-09-28

VS Code Dev Container 開發環境

Docker 部署 的 dev 堆疊已經有一份 devcontainer.json,但只給了設定檔跟一句「打開就能用」。本頁把它講清楚:VS Code 連進去之後實際發生了什麼事、程式碼編輯與執行的節奏跟平常有什麼不同,以及怎麼把 Claude Code 也裝進同一個容器,讓它跟你共用一模一樣的開發環境。

先備:讀過 安裝與環境 的 bind mount 說明,且已經照 Docker 部署 建好 dev/ 堆疊。

先裝好工具

  1. Docker Desktop(應該已經裝好)
  2. VS Code
  3. VS Code 擴充套件 Dev Containers(ms-vscode-remote.remote-containers)

打開專案、連進容器

  1. VS Code 開啟 odoo-stack 這個專案的根目錄(不是 dev/ 子目錄,因為 devcontainer.json 裡的路徑都是相對於根目錄寫的)。
  2. 打開命令選擇區(Cmd/Ctrl+Shift+P),執行 Dev Containers: Reopen in Container。
  3. 第一次會照 Docker 部署 的 dev/compose-dev.yml 把整套 dev 堆疊(Odoo、Postgres、MailCatcher⋯)都跑起來,然後 VS Code 連進 odoo 這個服務的容器,不是另外建一個新容器。

連進去之後,VS Code 視窗左下角會顯示目前連在哪個容器;整合終端機、Python 語言伺服器(Pylance)、除錯功能全都在容器裡執行,不是在你的電腦上——這正是 Dev Container 的重點:你的編輯器介面在主機,但看到的檔案系統、跑的指令、裝的語言環境都是容器裡那一份,跟同事、跟正式環境用的是同一份。

看懂這份 devcontainer.json 在做什麼

.devcontainer/devcontainer.json
{
  "name": "Odoo 20 Dev",
  "dockerComposeFile": ["../dev/compose-dev.yml"],
  "service": "odoo",
  "workspaceFolder": "/workspace",
  "shutdownAction": "stopCompose",
  "postCreateCommand": "pip3 install --user black isort",
  "customizations": {
    "vscode": {
      "extensions": [
        "ms-python.python",
        "ms-python.vscode-pylance",
        "tamasfe.even-better-toml",
        "oderwat.indent-rainbow",
        "batisteo.vscode-django"
      ],
      "settings": {
        "python.defaultInterpreterPath": "/usr/bin/python3",
        "python.analysis.typeCheckingMode": "basic",
        "editor.formatOnSave": true
      }
    }
  },
  "remoteUser": "root",
  "mounts": [
    "source=${localWorkspaceFolder}/dev/odoo/extra-addons,target=/mnt/extra-addons,type=bind",
    "source=${localWorkspaceFolder},target=/workspace,type=bind"
  ]
}
欄位 作用
dockerComposeFile + service 告訴 VS Code:不要自己生一個容器,去啟動這份 Compose 檔、連到 odoo 這個服務
workspaceFolder VS Code 視窗打開後,檔案總管根目錄指到容器裡的哪個路徑
shutdownAction 關閉 VS Code 視窗時,把整組 docker compose 服務一起停掉(stopCompose),不會留著背景繼續跑
postCreateCommand 容器建立之後自動執行一次的指令,這裡拿來裝兩個 Python 格式化工具
customizations.vscode.extensions 連進容器後,VS Code 自動幫你在容器裡安裝這幾個擴充套件(跟主機上裝的擴充套件是分開的兩份)
python.defaultInterpreterPath 指到容器內建的 Python,Pylance 才找得到 Odoo 核心套件(官方映像用 deb 安裝,Odoo 的 Python 模組在系統的 dist-packages 裡,跟 addons_path 設定的路徑是同一個),from odoo import ... 才會有自動完成、不會被畫紅線
remoteUser 容器裡用哪個使用者身分跑指令;這裡設 root 圖方便,寫檔案不會卡權限
mounts 見下面說明

為什麼 mounts 裡兩條路徑指到同一個地方

"mounts": [
  "source=${localWorkspaceFolder}/dev/odoo/extra-addons,target=/mnt/extra-addons,type=bind",
  "source=${localWorkspaceFolder},target=/workspace,type=bind"
]

這是同一份 bind mount 概念(見 安裝與環境)用了兩次,把同一個主機資料夾掛進容器的兩個不同路徑:

  • /mnt/extra-addons:Odoo 的 addons_path 設定指的就是這裡,Odoo 執行時從這裡讀模組。
  • /workspace/dev/odoo/extra-addons:因為整個專案根目錄(${localWorkspaceFolder})也掛進了 /workspace,同一份 extra-addons 資料夾當然也會出現在這條路徑下——這是 VS Code 檔案總管顯示的位置,跟上面那個是同一份檔案,改其中一邊,另一邊立刻跟著變(不是兩份拷貝)。

也就是說:你在 VS Code 左側檔案總管點開 dev/odoo/extra-addons/library/... 編輯,Odoo 讀取的 /mnt/extra-addons/library/... 就是改過的內容。

這樣開發,跟平常有什麼不一樣

最大差異:終端機已經在容器裡了,不用再打 docker compose exec 或 docker compose run 前綴。 odoo-bin 指令 教的所有指令,在這裡的整合終端機(Ctrl+`)直接下就好:

# 安裝、升級(不用加 docker compose run --rm odoo)
odoo -d mydb -i library --with-demo --stop-after-init
odoo -d mydb -u library --stop-after-init

# 互動式 shell
odoo shell -d mydb

其他好處:

  • 自動完成看得懂 Odoo:from odoo import api, fields, models 這種寫法,Pylance 找得到定義、按住 Cmd/Ctrl 點下去能跳到 Odoo 核心原始碼,不會滿篇紅色底線。
  • 改檔案即時生效:延續 bind mount 的老規矩——改 Python 方法內邏輯要重啟、改欄位或 XML 要 -u,見 odoo-bin 指令 的節奏表。
  • 除錯:最簡單的方式還是在程式裡寫 breakpoint(),然後在整合終端機前景執行 odoo -d mydb ...(不要加 --stop-after-init),中斷點會直接跳出互動式除錯環境,見 測試與除錯。想要在 VS Code 的圖形介面設中斷點、按滑鼠單步執行,要另外裝 debugpy 並設定 launch.json 用「attach」模式連過去,做法因人而異,這裡先不深入。

加入 Claude Code 一起開發

Dev Container 除了給你自己用,也是 Claude Code 官方建議的執行方式之一:Claude Code 跑在容器裡面,看到的檔案、裝的工具跟你在 VS Code 裡看到的完全一樣;你在主機用編輯器瀏覽,Claude Code 在容器裡讀寫、執行指令,兩邊動的是同一份 bind mount 出來的原始碼。

1) 把官方 Feature 加進 devcontainer.json

Anthropic 官方維護一個 Dev Container Feature,加一行設定就能在容器裡裝好 Claude Code:

.devcontainer/devcontainer.json(只列出改動的部分)
{
  "features": {
    "ghcr.io/devcontainers/features/node:1": {},
    "ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {}
  }
}

為什麼要多加一個 Node.js feature

Claude Code 的 CLI 需要 Node.js/npm 才能執行。Odoo 官方映像在建置過程中裝過 Node.js(只是為了編譯前端用的 rtlcss),用完就整個移除了,成品映像裡沒有 Node.js。Claude Code 的 feature 在偵測不到 Node.js 時會嘗試自動幫你裝,但保險起見,直接明講加上 ghcr.io/devcontainers/features/node:1 比較不會建置失敗。

2) 重新建置、登入

命令選擇區執行 Dev Containers: Rebuild Container,等它建完,開一個整合終端機(Ctrl+`):

claude

第一次執行會請你用瀏覽器登入 Anthropic 帳號(或你組織設定的 Bedrock/Vertex/Foundry 認證方式)。跟著畫面上的提示做完就能開始用。

3) 兩種用法

這個 Feature 連進 VS Code 時,會自動幫你裝好 Claude Code 的 VS Code 擴充套件(anthropic.claude-code),所以有兩種等價的用法:

  • 在整合終端機打 claude 進互動模式(跟平常用 Claude Code CLI 完全一樣)。
  • 用側邊欄的 Claude Code 擴充套件面板。

兩者共用同一份 ~/.claude 設定,登入一次兩邊都能用。

4) 讓下次重建容器不用重新登入

Dev Container 預設每次「Rebuild」都是全新的容器,家目錄會被清空,登入資訊也會不見。要留住登入狀態,加一個具名 volume 掛在 ~/.claude,並設定 CLAUDE_CONFIG_DIR 指到同一個路徑(因為上面的範例 remoteUser 是 root,家目錄是 /root):

devcontainer.json(加進既有的 mounts 與新增 containerEnv)
{
  "mounts": [
    "source=${localWorkspaceFolder}/dev/odoo/extra-addons,target=/mnt/extra-addons,type=bind",
    "source=${localWorkspaceFolder},target=/workspace,type=bind",
    "source=claude-code-config-${devcontainerId},target=/root/.claude,type=volume"
  ],
  "containerEnv": {
    "CLAUDE_CONFIG_DIR": "/root/.claude"
  }
}

${devcontainerId} 讓每個專案有自己獨立的一份設定,不會跟別的專案共用同一個登入狀態。

5) 在這個環境裡,Claude Code 能直接做什麼

因為 Claude Code 執行在跟你一樣的容器裡,它下的指令不用加任何 docker compose 前綴,直接就是:

odoo -d mydb -u library --stop-after-init
odoo -d mydb -u library --test-tags /library --stop-after-init

實際帶著它做一個模組的節奏,跟你自己做完全一樣:請它照 實作:圖書借閱模組 的步驟寫欄位、寫檢視,改完讓它自己跑 -u 升級、跑測試驗證,有錯誤訊息貼給它看,它能直接讀 odoo-bin 指令 教的排錯方式對照。

安全提醒(官方文件原文的重點)

  • 只在你信任的專案裡這樣用;容器內能讀寫的東西,理論上都可能被惡意程式碼碰到。
  • 不要把主機的 ~/.ssh、雲端憑證檔案這類機密掛進容器;要用 repo 專屬或短效的憑證。
  • 上面的範例 remoteUser 是 root——Claude Code 在 root 底下執行時,不接受 --dangerously-skip-permissions(跳過權限確認)這個參數,執行時一律會照常跳出工具呼叫確認,這其實是件好事,不用特別處理。

不想改用 Dev Container?Claude Code 也能跑在主機上

Dev Container 不是唯一選項。因為 addon 原始碼本來就用 bind mount 對應到主機的資料夾,Claude Code 完全可以留在你的主機上執行(例如平常在 VS Code 但沒開 Dev Container、或用終端機直接跑),一樣能讀寫同一份程式碼。差別只在於:執行 Odoo 相關指令時要自己加 docker compose exec/docker compose run 前綴,因為 Odoo、Python、psql 這些工具都只存在容器裡,不在主機上:

docker compose exec odoo odoo -d mydb -u library --stop-after-init

哪一種都可以,選你習慣的:在容器裡開發,指令比較短、環境完全一致;留在主機,設定比較單純、不用重建容器。odoo-bin 指令 那頁對這兩種模式的差異有更完整的說明。

進一步學習