參加你附近的 ,瞭解 VS Code 中的 AI 輔助開發。

自定義開發容器特性

2022年9月15日,由 Brigit Murtaugh (@BrigitMurtaugh) 發表

我們在設定開發環境時都曾有過這樣的時刻——“哦,我還需要一樣東西!”——這個“東西”是多一種語言或工具集(或者可能更多😊),以便在你的專案上工作。

開發容器是簡化環境設定的好方法——它們提供了一個完整的編碼環境,包含了你專案所需的工具。它們使用映象、Dockerfile 或 Docker Compose 檔案以及 devcontainer.json 進行配置,後者是一種元資料格式,用於透過開發特定的內容和設定來豐富容器。

在建立開發容器時,你可能會反覆遇到同樣的“我只需要一樣東西!”的反應——也許你在 Dockerfile 中使用了一個 Node.js 映象,而只需要新增 Git。或者,你可能需要新增更復雜的東西,比如在你的開發容器內使用 Docker 或 Kubernetes。開發容器非常棒,因為任何訪問你程式碼的人都會獲得相同、一致的體驗,包括你新增的所有工具——但新增它們的最佳方式是什麼呢?

如果有一種簡單的方法,只需提及工具的名稱和版本,就能在你的開發容器中安裝那個額外的工具,那會怎麼樣?或者,作為工具使用者或作者,你是否可以建立一種簡單的方式讓其他人安裝它?共享手動指令碼有助於重用,但在引用時,你可能會忘記引用容器或工具的設定,例如為 Go、Rust 或 C++ 除錯啟用 ptrace 支援,新增一個在容器啟動時觸發的特定入口點,或確保包含正確的 VS Code 擴充套件。

功能

我們很高興地宣佈,開發容器的**特性 (Features)** 能幫助你順利地在開發容器中獲得所需的工具!

特性是獨立的安裝程式碼、容器配置和/或設定及擴充套件單元,旨在為你的開發容器帶來新的開發能力。它們可以被構建成能與多種基礎容器映象配合使用。作為我們致力於開放開發容器規範工作的一部分,我們對你從何處獲取預建立的特性,以及如何編寫和分發自己的特性進行了一些改進。

讓我們看看有哪些新內容,以及如何開始使用任何支援開發容器的工具或服務(例如 VS Code 開發容器擴充套件或 GitHub Codespaces)中的特性!

向你的開發容器新增特性

開發容器特性提供了一種將開發容器元資料與一些安裝步驟快速關聯的方法。你可以透過簡單的引用將它們新增到你的開發容器中。

這些特性現在可以作為 OCI 工件 (Artifacts) 儲存在任何支援的容器登錄檔中,這意味著你可以使用與引用容器映象相同型別的識別符號來引用它們。我們已經將一些早期存在於 vscode-dev-containers 倉庫中的特性遷移到了一個新的 devcontainers/features 倉庫中,在那裡它們使用這種新方法進行釋出。

從 devcontainers/features 倉庫引用不同的特性非常簡單,只需在你的 devcontainer.json 中新增一個 features 屬性即可。每個特性都有一個 README.md 檔案,展示瞭如何引用該特性以及它有哪些可用選項。

下面的示例安裝了 godocker-in-docker 特性。

"name": "my-project-devcontainer",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
    "ghcr.io/devcontainers/features/go:1": {
        "version": "1.18"
    },
    "ghcr.io/devcontainers/features/docker-in-docker:1": {
        "version": "latest",
        "moby": true
    }
}

你也可以在規範網站上探索官方和社群貢獻的特性。任何特性都可以透過編輯 devcontainer.json 來新增,而公開發布的特性可以透過現有的開發容器配置體驗(例如 VS Code 開發容器擴充套件中提供的)來新增。

Specification site list of available Features

你甚至可以使用開發容器 CLI、GitHub Action 或 Azure DevOps 任務,在你喜歡的 CI 系統中使用帶有特性的開發容器。我們在 devcontainers/ci 倉庫中提供了 GitHub Action 和 Azure DevOps 任務。開發容器 CLI、GitHub Action 或 Azure DevOps 任務也可以用於預構建包含特性內容的映象,以加快啟動時間。

如果你不僅想使用公開可用的特性,還想建立自己的私有或公共特性來共享,請繼續閱讀!

編寫特性

開始建立自己的特性的一個好地方是新的 特性模板倉庫。除了包含一個適用於特定特性內容的良好模板外,該模板還包含一個 GitHub Actions 工作流,以便快速釋出它們,它使用你賬戶的GitHub 容器登錄檔 (GHCR),讓你能儘快上手。我們稍後會更多地討論釋出。

一個特性的原始碼有兩個組成部分:一個安裝指令碼 (install.sh) 和一個配置檔案 (devcontainer-feature.json)。

+-- feature
|    +-- devcontainer-feature.json
|    +-- install.sh
|    +-- (other files)

install.sh: 安裝入口點指令碼——它在概念上被新增為映象 Dockerfile 的一層,並在構建時執行。這個入口點指令碼可以安裝各種工具,如語言(例如 Ruby)和工具(GitHub CLI)。

devcontainer-feature.json: 這包含了關於特性的元資料、一組可以在安裝過程中傳遞給特性安裝指令碼的選項,以及將合併到最終開發容器中的 devcontainer.json “片段”。例如,如果任何特性在其配置中指明瞭 "privileged": true,那麼整個開發容器將以 --privileged 標誌啟動。

特性可以使用多種語言編寫,最直接的是 shell 指令碼。如果一個特性是用其他語言編寫的,那麼相關資訊應該包含在元資料中,以便使用者可以做出明智的選擇。

注意: 雖然 install.sh 會執行任何語言的特性,但如果你用一種開發容器中不存在的解釋型語言編寫特性,程式碼將無法執行。請確保在 install.sh 中獲取你需要的語言。

你應該確保你公開發布的特性除了安裝特性本身外,還會檢查並安裝其依賴項。

此外,公共特性很可能會在 arm64 或 x86_64 機器上使用——因此請確保在可能的情況下進行適配。

你可以在規範中檢視 devcontainer-feature.json 的屬性,以及在 devcontainers/features 倉庫中檢視公開示例。

既然我們已經瞭解瞭如何建立一個特性,那麼我該如何將它分發給其他人呢?

分發

特性以 tarball 的形式分發。tarball 包含特性子目錄的全部內容,包括 devcontainer-feature.jsoninstall.sh 以及目錄中的任何其他檔案。

開放容器倡議 (OCI) 定義了容器和容器資源的行業標準。我們將特性視為 OCI 工件,並使用 OCI 登錄檔的概念來分發特性。

上面提到的 特性模板倉庫包含一個 GitHub Actions 工作流來自動化釋出過程。它將特性打包成一個 tarball,並將資產作為 OCI 工件釋出到 GHCR。要觸發模板倉庫中的 release.yaml 工作流,只需在 GitHub 上倉庫的 Actions 選項卡左側選擇它即可。該 GitHub Action 會將特性發布到 GHCR 的 <owner>/<repo> 名稱空間下。只有當特性 devcontainer-feature.json 中的版本屬性更新時,才會重新發布該特性。

注意: 對於 GHCR,有一個手動步驟是需要將 OCI 包標記為“公共”。每個特性只需執行一次此操作。私有特性不需要此步驟,只要你使用登錄檔的憑據登入了 Docker CLI 就可以訪問。

與社群分享你的特性

如果你希望你的貢獻出現在 VS Code 開發容器GitHub Codespaces 建立開發容器的 UI 中,你可以執行以下步驟:

一旦合併,你的更改將出現在 containers.dev/collections

特性安裝順序

如果我的特性應該在另一個特性之後安裝怎麼辦?作為特性作者,你可能會發現你的特性應該在其他特性之前或之後安裝。在你的 devcontainer-feature.json 中,你可以使用 installsAfter 屬性來列出應在其之前執行的特性。

作為終端使用者,你可以使用 devcontainer.json 中的 overrideFeatureInstallOrder 屬性進一步控制執行順序。此陣列中的任何特性 ID 都將按提供的順序在所有其他特性之前安裝。舉個例子:

"features": {
      "ghcr.io/devcontainers/features/java:1",
      "ghcr.io/devcontainers/features/node:1",
  },
  "overrideFeatureInstallOrder": [
    "ghcr.io/devcontainers/features/node"
  ]

預設情況下,特性會按照實現工具確定的最佳順序安裝在基礎映象之上。

如果特性的 devcontainer-feature.json 或使用者的 devcontainer.json 中提供了以下任何屬性,則會遵循這些屬性指示的順序(優先順序遞減)。

  1. 使用者 devcontainer.json 中的 overrideFeatureInstallOrder 屬性。允許使用者控制其特性的執行順序。
  2. 在特性的 devcontainer-feature.json 中定義的 installsAfter 屬性。

你可以在規範中閱讀更多關於特性執行和安裝順序的資訊。

還有什麼新內容?

除了新的特性倉庫,我們最近還開源了一個新的 devcontainers/images 倉庫,用於託管之前在 vscode-dev-containers 倉庫中的一組特定映象。

我們正在為開發容器模板(在 vscode-dev-containers 中我們稱之為“定義”)制定一個社群分發計劃,我們預計它將與特性類似。我們一定會像宣佈新特性和映象倉庫時一樣,在 vscode-dev-containers 倉庫中釋出更新。

我如何瞭解更多資訊?

這篇文章只是淺嘗輒止地介紹了你可以用特性做什麼,我們很高興你能親自嘗試!

如上文內容中連結所示,瞭解更多關於特性構成以及如何分發它們的最佳地點是開發容器規範的特性特性分發頁面。

我們期待你在使用、建立和釋出特性時的反饋——我們很想在特性特性分發的 issue 提案中聽到它們對你的幫助。

如果你有興趣參與整個規範的制定,或者將另一個工具接入以利用它,請檢視開發容器的 specCLI 倉庫。

祝你建立開發容器愉快,編碼快樂!

Brigit Murtaugh, @BrigitMurtaugh