GitHub Codespaces 深度实践:从环境一致性到云原生开发范式

发布时间:2026/5/26 15:33:28

GitHub Codespaces 深度实践:从环境一致性到云原生开发范式 1. 项目概述为什么我从去年开始就把本地开发环境“封印”了去年三月我接手一个需要同时跑 Python 3.9、Node.js 18、PostgreSQL 15 和 Redis 7 的微服务项目。我的 MacBook Pro2019 款16GB 内存在启动第三个服务时风扇就发出战斗机起飞般的轰鸣npm install卡在node-gyp编译环节长达 22 分钟而同事用 M2 Ultra 的机器只用了 90 秒——不是硬件差距的问题是环境不一致带来的隐性成本。直到我第一次在 GitHub Codespaces 里敲下git clone npm run dev37 秒后浏览器里弹出运行中的前端界面终端里psql正连着预装好的 PostgreSQL 实例.devcontainer.json里定义的preStartCommand已经把数据库迁移脚本执行完毕。那一刻我意识到我们争论了十年的“环境一致性”问题其实答案早就写在云上。GitHub Codespaces 不是另一个“在线 IDE”它是把整个开发栈——从内核模块、系统库、语言运行时、包管理器缓存到你每天敲code .启动的 VS Code 扩展生态——打包进一个可复现、可版本化、可协作的 Docker 容器里并由 GitHub 在全球 12 个区域的云基础设施上按需调度。它解决的从来不是“能不能写代码”而是“能不能让 17 个不同配置的笔记本电脑在同一分钟内以完全相同的编译结果、相同的依赖树、相同的环境变量跑通同一个 CI 流水线”。我带过的三个团队平均节省了每人每周 4.2 小时的环境调试时间新成员入职当天就能提交有效 PR而不是卡在“我的pip install为什么总报pydantic版本冲突”。你不需要是 DevOps 工程师才能用它。如果你会点开 GitHub 仓库右上角那个绿色按钮会选分支会改.gitignore你就已经具备了使用 Codespaces 的全部前置技能。它不取代你的本地工作流而是像给开发环境加了一层“无感云镜像”——你在本地改的 VS Code 主题、快捷键、Snippets会通过 Settings Sync 自动同步过去你在 Codespaces 里调试成功的 API 调用复制粘贴回本地 Postman 也能复现。它真正的价值藏在那些你不再需要做的动作里不用再截图发 Slack 问“你本地make build报错是不是少装了libpq-dev”不用再维护一份 38 行的README.md环境搭建指南不用在离职交接时花半天教新人怎么配好 WSL2 Docker Desktop nvm pyenv 的嵌套环境。这篇文章就是我过去 14 个月在生产环境里踩坑、调优、给客户做培训的真实笔记。我会拆解 Codespaces 的完整生命周期——不是教科书式的阶段定义而是告诉你每个阶段背后真实的资源账单逻辑、缓存命中率对冷启动时间的影响、以及为什么“停止”和“删除”在计费模型里是两个完全不同的开关。我会手把手带你定制一个真正属于你的开发环境如何让每次新建 codespace 都自动安装你最爱的rust-analyzer和prettier插件如何把公司内部的私有 npm registry 地址写进容器配置甚至如何绕过 GitHub 默认的bashshell让zsh带着 oh-my-zsh 主题和fzf模糊搜索直接在云端启动。最后我会用一张真实项目数据表告诉你在什么规模的团队、什么类型的项目里Codespaces 是“锦上添花”又在什么场景下它直接成了你技术选型的决定性因素。2. 生命周期深度解析每个阶段背后的资源与成本真相2.1 创建阶段你以为的“一键生成”其实是三次网络请求两次镜像拉取一次容器编排很多人以为点击 “Code” → “Open with Codespaces” 就是“创建”实际上后台发生了远比本地docker run复杂的链式操作。我用curl -v抓包分析过这个过程它包含三个关键子阶段第一阶段策略决策Policy ResolutionGitHub 首先向你的账户/组织策略服务发起请求检查三项硬性约束你是否在付费计划内Free tier 仅限 public repos且每月 60 小时你当前活跃的 codespaces 数量是否超过配额默认个人用户最多 4 个并发你选择的机器类型如basicLinux32GB是否被组织策略禁用企业版可强制锁定为standardLinux16GB。提示这个阶段失败时UI 只显示模糊的 “Failed to create codespace”但实际错误日志在浏览器开发者工具 Network 标签页的policy请求里。常见原因是组织管理员启用了 “Require prebuilds for private repos”而你的仓库没配置.devcontainer/prebuilds.json。第二阶段镜像准备Image Provisioning这是耗时最长的环节也是性能差异的核心。Codespaces 支持三种镜像来源优先级从高到低预构建镜像Prebuilds由仓库所有者提前定义的devcontainer.jsonDockerfile构建并缓存的镜像。我的团队对核心后端仓库启用此功能后冷启动时间从 128 秒降至 22 秒。GitHub 官方镜像GitHub-Hosted Images如mcr.microsoft.com/vscode/devcontainers/python:3.11。这类镜像已预装 Python、pip、venv 等但缺少项目特定依赖。动态构建On-Demand Build当仓库根目录存在.devcontainer/devcontainer.json且未启用预构建时GitHub 会实时拉取你的Dockerfile在云上执行docker build。这是最慢的路径尤其当你Dockerfile里写了RUN pip install -r requirements.txt—— 每次创建都要重装所有 Python 包。第三阶段容器初始化Container Initialization镜像拉取完成后GitHub 启动容器并执行三类命令onCreateCommand在容器文件系统就绪后、VS Code 连接前执行常用于git submodule update --initpostCreateCommandVS Code 客户端连接后执行我的项目里这一步运行npm ci python -m pip install -e .确保依赖精确匹配package-lock.json和pyproject.tomlpostStartCommand容器完全就绪后执行我在这里启动redis-server和postgres -D /var/lib/postgresql/data让数据库服务在你打开终端前就已运行。实测数据在一个中等复杂度的 Python/Django 项目中三种创建方式的耗时对比单位秒镜像类型首次创建第二次创建缓存命中预构建镜像2218官方镜像8976动态构建128115关键发现第二次创建的提速几乎全部来自 Docker 层缓存Layer Cache而非 GitHub 的镜像缓存。这意味着即使你没启用预构建只要Dockerfile没变后续创建仍能享受 10~15 秒的优化。但requirements.txt里每增加一个包都会破坏pip install步骤的缓存导致该层及之后所有层重新构建。2.2 重建阶段为什么“Rebuild”比“Delete Recreate”省下 47% 的 CPU 时间重建Rebuild常被误解为“重启容器”其实它是 GitHub Codespaces 最精妙的设计之一。当你点击 “Rebuild Container”后台发生的是GitHub 保留你/workspaces/your-repo目录下的所有文件包括未 commit 的修改、.vscode/settings.json、node_modules丢弃旧容器但复用其构建缓存Build Cache重新执行Dockerfile中的RUN指令但跳过已缓存的层重新运行postCreateCommand和postStartCommand。这带来两个关键优势第一零丢失开发状态。我在调试一个内存泄漏问题时需要反复修改Dockerfile添加valgrind工具。如果每次删掉重建就得重新git checkout到调试分支、重新npm install、重新配置 VS Code 的 launch.json。而用 Rebuild我只需改一行Dockerfile点击按钮30 秒后终端里valgrind --leak-checkfull node app.js就已就绪所有断点、编辑器布局、未保存的临时文件都原样保留。第二构建缓存复用率高达 92%。我统计了团队 32 个项目在过去一个月的 Rebuild 日志发现当Dockerfile仅修改ENV变量或COPY静态文件时缓存命中率为 100%当修改RUN pip install后的依赖列表时平均命中 7 个基础层Python 运行时、系统库、编译工具链仅重装requirements.txt对应的层即使Dockerfile完全不变仅更新devcontainer.json的customizations.vscode.extensionsRebuild 也比 Delete Recreate 快 47%因为后者要重新拉取整个镜像约 1.2GB。注意Rebuild 不会重置onCreateCommand。如果你的onCreateCommand包含git clone https://internal.gitlab.com/team/configs.git而该仓库权限已变更Rebuild 会失败。此时必须 Delete Recreate 或手动在终端里rm -rf /workspaces/configs git clone ...。2.3 停止阶段一个被严重低估的“成本控制开关”停止Stop是 Codespaces 计费模型中最容易被忽视的杠杆。很多人以为“关闭浏览器标签页”就等于停止这是最大的误区。让我用真实账单解释运行中Running按秒计费 CPU 内存。以standardLinux16GB为例$0.072/小时 ≈ $0.00002/秒已停止Stopped仅收取存储费用$0.03/GB/月。一个典型 codespace 的/workspaces目录约 2.1GB即每月 $0.063已删除Deleted零费用。关键事实Codespaces 默认 30 分钟无操作自动停止但这个“无操作”仅检测 VS Code 编辑器活动不检测终端里的长时进程。我曾遇到一个同事的 codespace 运行着tail -f /var/log/app.log因编辑器无输入30 分钟后被自动停止但终端进程仍在后台消耗 CPU——直到他收到超支邮件才发现。更隐蔽的是“停止”的副作用所有postStartCommand启动的服务如redis-server会被终止localhost:3000等端口转发会断开需手动点击 “Ports” 标签页里的 “Forward Port” 重新激活如果你用tmux或screen运行后台任务它们会随容器停止而退出除非你配置了systemd用户服务但这超出 Codespaces 设计范畴。实操心得我给自己设了两条铁律每次离开工位前必点右上角 “...” → “Stop Codespace”绝不依赖自动停止对需要长时运行的任务如数据导入、模型训练改用 GitHub Actions 触发codespace 只负责代码编写和轻量测试。2.4 删除阶段永久清除 vs. 自动回收的权衡删除Delete是彻底释放资源的动作但它有两个截然不同的触发路径手动删除在 codespace 页面点击 “...” → “Delete this codespace”立即生效存储费用即时停止自动删除当 codespace 处于 “Stopped” 状态超过设定天数默认 30 天GitHub 自动清理。这里有个反直觉的设计自动删除的保留期是按“停止时间”计算而非“创建时间”。例如3 月 1 日创建 codespace3 月 5 日停止4 月 10 日仍未手动删除若保留期设为 30 天则它会在 4 月 5 日被自动删除3 月 5 日 30 天而非 4 月 1 日。这对团队协作至关重要。我们曾因误设保留期为 7 天导致一位同事休假两周后回来发现他调试了一周的 codespace 被自动删除所有未 push 的分支和本地 commit 全部丢失。现在我们的标准配置是个人项目保留期设为 14 天平衡安全与成本团队共享 codespace如用于演示的demo-codespace保留期设为 1 天避免长期占用资源关键项目预构建环境保留期设为 0 天即禁用自动删除由专人定期审计。提示删除 codespace 前GitHub 会强制检查/workspaces/your-repo下是否有未 commit 的修改。如果有它会弹出警告“You have uncommitted changes. These will be lost.” 但注意这个检查只扫描 Git 工作区不检查/tmp、~/.cache或其他非工作区目录。我曾把一个重要的database-dump.sql文件误存到/tmp删除后才想起——Codespaces 不是备份服务它只是开发环境。3. 深度定制实战从“能用”到“专属工作台”的七步改造3.1 配置同步让 VS Code 的灵魂在云端重生Settings Sync 是 Codespaces 最被低估的功能。它不是简单地同步settings.json而是将 VS Code 的整个“数字人格”——包括扩展、键盘快捷键、代码片段、UI 布局、甚至调试配置——加密上传至 GitHub 账户。我的同步配置流程如下第一步在本地 VS Code 启用同步打开 Command Palette (CtrlShiftP) → 输入 “Turn on Settings Sync”选择 “GitHub” 作为同步服务非 Microsoft 账户登录 GitHub授权user:email和read:org权限仅用于识别组织成员身份。第二步精细化控制同步内容默认同步所有内容但某些项目需要隔离在本地 VS Code 设置中搜索sync:ignoredExtensions添加ms-python.python避免 Python 扩展在 Codespaces 里重复安装因官方镜像已预装搜索sync:ignoredSettings添加editor.fontSize本地 14px云端因高分屏设为 16px需独立配置关键技巧在settings.json中添加sync.autoDownload: false这样 Codespaces 启动时不会自动覆盖你预设的扩展列表而是让你手动选择哪些扩展需要激活。第三步处理同步冲突冲突常发生在以下场景你在家用 Mac 同步了zsh配置但在公司 Windows 机上用PowerShell两者terminal.integrated.shell.windows设置冲突团队强制要求所有 codespace 使用prettier格式化但你本地习惯用eslint --fix。解决方案启动 Codespaces 后按CtrlShiftP→ “Show Settings Sync Conflicts”对每个冲突项选择 “Accept Incoming”采用云端设置、“Accept Local”采用本地设置或 “Compare”并排查看差异我的黄金法则编辑器 UI 类设置字体、主题、缩放永远选 Local开发流程类设置格式化工具、Lint 规则、Git 提交模板永远选 Incoming。实测效果启用同步后我从创建 codespace 到能进行有效开发的时间从平均 18 分钟手动装插件、配快捷键、调字体缩短至 92 秒。最惊喜的是 Snippets 同步——我自定义的logt片段插入带时间戳的console.log和api片段生成 Axios 请求模板在云端直接可用无需任何额外配置。3.2 个性化 Shell告别 bash拥抱 zsh oh-my-zsh fzf 的云端体验Codespaces 默认使用bash但对重度 CLI 用户zsh的补全、历史搜索、插件生态是刚需。改造步骤如下第一步在devcontainer.json中声明 shell{ customizations: { vscode: { settings: { terminal.integrated.defaultProfile.linux: zsh } } } }第二步在Dockerfile中安装 zsh 生态# 安装 zsh 和 oh-my-zsh RUN apt-get update apt-get install -y zsh curl \ sh -c $(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh) --unattended \ # 安装 fzf模糊搜索神器 git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf ~/.fzf/install --all \ # 安装 zsh-autosuggestions命令历史智能提示 git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-autosuggestions第三步配置.zshrc在仓库根目录创建.zshrc会被自动复制到容器 home 目录# 启用插件 plugins(git zsh-autosuggestions fzf) # fzf 配置CtrlR 搜索命令历史CtrlT 搜索文件 export FZF_DEFAULT_COMMANDrg --files --hidden --glob !.git/* # zsh-autosuggestions 配置灰色显示建议右箭头采纳 ZSH_AUTOSUGGEST_HIGHLIGHT_STYLEfg8 # 别名让常用命令更短 alias gsgit status alias gagit add alias gcgit commit -m第四步验证与调试启动 codespace 后打开新终端执行echo $SHELL # 应输出 /usr/bin/zsh zsh --version # 应输出 5.8 ls ~/.oh-my-zsh/plugins/ # 应看到 zsh-autosuggestions 和 fzf注意如果zsh启动时报错 “Permission denied”通常是因为~/.zshrc权限不对。在终端执行chmod 644 ~/.zshrc即可修复。这是 Codespaces 容器的常见权限问题因镜像构建时COPY命令未保留文件权限。3.3 机器类型调优在性能与成本间找到你的甜蜜点GitHub 提供的机器类型不是“越大越好”而是需要根据项目类型精准匹配。我整理了团队 12 个项目的实测数据项目类型推荐机器类型CPU 使用率峰值内存使用率峰值平均响应延迟月均成本前端单页应用React/VuebasicLinux32GB32%41%82ms$12.40Python 数据分析Pandas/NumpystandardLinux16GB68%73%156ms$28.80Java Spring Boot 微服务proLinux32GB89%92%210ms$64.20Rust 编译密集型WASMproLinux64GB95%88%188ms$128.50关键洞察前端项目用proLinux64GB是浪费Webpack 编译主要吃 CPU但basicLinux32GB的 2 vCPU 已足够多出的 4 vCPU 和 32GB 内存纯属闲置Java 项目必须用proLinux32GBSpring Boot 的mvn clean package在standardLinux16GB上平均耗时 4.2 分钟在proLinux32GB上降至 1.8 分钟节省的 2.4 分钟 × 每日 12 次构建 每月 864 分钟 CPU 时间远超机器升级的差价Rust 项目对内存敏感cargo build --release在proLinux64GB上内存占用峰值达 58GB若用proLinux32GB会触发 OOM Killer 终止编译进程。实操技巧在devcontainer.json中用hostRequirements强制指定最低配置hostRequirements: { cpu: 4, memory: 32, storage: 64 }这样当用户尝试在basicLinux32GB上启动时会收到明确提示 “This codespace requires at least 4 vCPUs and 32GB RAM”。3.4 地理区域选择不只是延迟更是合规的生命线Codespaces 的地理区域Region选择直接影响三个维度网络延迟从上海访问westus美国西海岸平均 RTT 210ms访问apne2东京仅 42ms数据驻留合规欧盟 GDPR 要求个人数据不得出境必须选euw1法兰克福或eun1阿姆斯特丹服务可用性southcentralus美国德州区域在 2023 年 Q3 有 12 分钟的区域性中断而westeurope全年 99.99% SLA。我的配置策略个人项目设为autoGitHub 自动选择最近区域客户项目严格按合同约定区域配置如为德国客户部署必须在Settings→Codespaces→Default region中手动选euw1多区域团队不设默认区域而是在每个仓库的.devcontainer/devcontainer.json中用region字段指定{ region: apne2, name: My Project - Tokyo Region }提示区域一旦选定codespace 的 URL 子域名即固定如https://my-project-abc123.apne2.github.dev。切换区域需删除旧 codespace 并重建URL 会变更。因此若你将 codespace URL 写入文档或 CI 脚本务必在devcontainer.json中用name字段定义稳定别名。4. GitHub.dev 与 Codespaces不是替代而是互补的双生工具4.1 功能边界一张表看清何时该用哪个很多人纠结 “该用 GitHub.dev 还是 Codespaces”其实答案很简单看你的操作是否需要“执行”。我画了一张决策树你正在做什么 │ ├── 修改 README.md / .gitignore / LICENSE 等纯文本文件 → GitHub.dev ✅ ├── 修复一个拼写错误的变量名 → GitHub.dev ✅ ├── 查看某次 commit 的 diff → GitHub.dev ✅ │ ├── 运行单元测试npm test → Codespaces ✅ ├── 调试一个 HTTP 500 错误需要启动服务、设断点、查日志 → Codespaces ✅ ├── 执行数据库迁移python manage.py migrate → Codespaces ✅ ├── 构建 Docker 镜像docker build -t myapp . → Codespaces ✅以下是核心差异的量化对比基于 2024 年 Q2 实测维度GitHub.devGitHub Codespaces启动时间 2 秒纯前端加载18~128 秒含容器启动、镜像拉取持久化仅保存到浏览器 LocalStorage关闭标签页即丢失未 commit 更改/workspaces目录持久化停止后文件全在执行能力仅支持git命令clone/push/pull和极简shellls,cat完整 Linux shell支持make,docker,python,npm等所有命令端口转发不支持无法访问localhost:3000支持可将容器内端口映射到https://xxx.github.dev:3000扩展支持仅内置扩展如 Markdown Preview支持全部 VS Code Marketplace 扩展需在devcontainer.json中声明成本完全免费含 private repos按使用时长收费Free tier 60 小时/月真实案例上周我处理一个紧急线上 bug流程是用 GitHub.dev 快速定位src/api/user.ts中的错误行2 秒点击右上角 “Open in Codespaces” 按钮30 秒后进入完整环境在终端运行npm run test:unit -- --testNamePatternuser login验证修复提交 PRCI 流水线自动运行。整个过程 3 分钟比切到本地环境找项目目录 → 启动 IDE → 等索引完成 → 运行测试快 4.7 倍。4.2 协同工作流Dev Codespaces 的混合模式最高效的团队实践是让 GitHub.dev 和 Codespaces 在不同环节各司其职Code Review 阶段Reviewer 直接在 GitHub.dev 中打开 PR 的 diff用CtrlClick跳转到相关文件用内置 Markdown Preview 查看文档更新用CtrlEnter快速评论Author 修复阶段Author 点击 “Open in Codespaces”在完整环境中复现问题、编写测试、运行 E2E 测试CI 验证阶段Codespaces 的prebuilds与 GitHub Actions 共享同一套devcontainer.json确保本地测试通过的代码在 CI 中 100% 通过。这种模式让 Code Review 不再是“纸上谈兵”。Reviewer 能在 GitHub.dev 中直接看到修复后的代码如何影响整个文件结构而 Author 不再需要写冗长的 “How to reproduce” 文档——Reviewer 点一下就能进入一模一样的环境。5. 常见问题与排查技巧实录那些官方文档不会写的坑5.1 网络问题为什么我的 codespace 连不上公司内网现象在 codespace 终端执行curl https://internal-api.company.com返回Could not resolve host。原因Codespaces 运行在 GitHub 的公有云网络无法直接访问企业内网VPC/VPN。解决方案方案 A推荐用 GitHub Actions 的self-hosted runner。在公司内网部署一台 runnerCI 任务由它执行codespace 只负责代码编写方案 B配置 SSH 隧道。在本地机器运行ssh -L 8080:internal-api.company.com:443 userjump-server然后在 codespace 中curl http://localhost:8080方案 C不推荐用ngrok暴露内网服务但存在安全风险且需额外维护。注意不要尝试在Dockerfile中RUN apt-get install openvpnCodespaces 容器禁止创建 TUN/TAP 设备会报错Operation not permitted。5.2 权限错误Permission denied (publickey)无法 push 到私有仓库现象在 codespace 终端git push origin main报错。原因Codespaces 默认使用 GitHub 的 OAuth token 进行 Git 操作但该 token 无权访问私有仓库除非你显式授权。解决方案在 codespace 终端执行gh auth login选择GitHub.com→HTTPS→Login with a web browser浏览器打开授权页勾选repo权限回到终端git push即可成功。提示此授权会保存在~/.config/gh/hosts.yml下次启动 codespace 仍有效。但若你删除 codespace需重新授权。5.3 扩展失效为什么我安装的rust-analyzer不工作现象在devcontainer.json中声明了ms-vscode.vscode-typescript-next但打开.rs文件时无语法高亮。原因Rust 扩展需要rustup和rustc而官方rust镜像未预装rust-analyzer二进制。解决方案在Dockerfile中添加# 安装 rust-analyzer RUN curl -L https://github.com/rust-lang/rust-analyzer/releases/download/2024-03-18/rust-analyzer-linux.gz | gunzip -c - /usr/local/bin/rust-analyzer \ chmod x /usr/local/bin/rust-analyzer5.4 端口转发失败localhost:3000显示 “Not Found”现象npm start成功启动但https://xxx.github.dev:3000返回 404。原因Codespaces 的端口转发默认只代理 HTTP 流量而你的应用可能监听0.0.0.0:3000但未设置 CORS 或响应头。解决方案在devcontainer.json中添加端口配置portsAttributes: { 3000: { label: Web Server, onAutoForward: notify } }在应用代码中确保监听0.0.0.0:3000而非127.0.0.1:3000对 Express 应用添加中间件app.use((req, res, next) { res.setHeader(Access-Control-Allow-Origin, *); next(); });5.5 预构建失败prebuilds一直显示 “Queued”现象在仓库设置中启用 Prebuilds 后状态长期为 “Queued”无日志输出。原因Prebuilds 依赖 GitHub Actions Runner若你的仓库未启用 ActionsSettings → Actions → General → “Enable local and private actions”则无法触发。解决方案进入仓库Settings→Actions→General在 “Workflow permissions” 中选择 “Allow all actions and reusable workflows”在 “Permissions for actions and reusable workflows” 中勾选 “Read and write permissions”提交空 commit 触发预构建git commit --allow-empty -m Trigger prebuild。实操心得预构建失败日志藏在Actions标签页的prebuildsworkflow 中而非 Codespaces 设置页。90% 的预构建问题都能在那里找到具体错误如Dockerfile语法错误、apt-get update超时。6. 进阶实践用 Codespaces 重构你的开发范式6.1 为开源项目贡献者降低 83% 的入门门槛我维护的open-source-cli项目过去贡献者 PR 的平均首次响应时间是 4.7 天主要卡在环境搭建。引入 Codespaces 后流程彻底改变在README.md顶部添加醒目按钮[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?repositoryyour-org/open-source-climachinebasicLinux32GB)在.devcontainer/devcontainer.json中预装所有依赖{ image: mcr.microsoft.com/vscode/devcontainers/base:ubuntu, features: { ghcr.io/devcontainers/features/node:1: {}, ghcr.io/devcontainers/features/python:1: {}, ghcr.io/devcontainers/features/docker-in-docker:2

相关新闻