开发必备-使用DevContainer技术消除 “在我这能运行”

本文将介绍开发人员如何基于DevContainer能力提升开发效率,并基于SCQL项目进行实践。

DevContainer

首先,我们来解释下DevContainer解决了当前开发当中的哪些问题。有一个非常常见的程序员段子:开发人员在被测试提单时,常见的口头禅是:"这在我这跑没问题";本质上,这个问题的根因在于开发环境以及测试环境的不一致性。而DevContainer(开发容器)则是一种基于容器技术的开发环境标准化方案,解决开发环境不一致的问题,确保团队成员或不同设备上的环境完全一致。

DevContainer的核心思想是将开发所需的工具、依赖、配置等封装在一个容器中,开发者通过启动这个容器来进行开发工作,从而避免 "在我这能运行" 这类环境差异导致的问题。

DevContainer解决的问题及场景:

  1. "在我这能运行" : 开发环境的依赖、工具、配置通过代码化定义(如devcontainer.jsonDockerfile),确保团队成员、不同设备(本地 / 云服务器)、CI/CD 流水线使用完全相同的环境,避免因系统差异(如 Windows/Linux/macOS)或依赖版本不一致导致的兼容性问题。
  2. 项目间依赖冲突:每个项目的开发环境独立封装在容器中,与主机系统和其他项目隔离。例如,项目 A 依赖 Python 3.8,项目 B 依赖 Python 3.11,无需在主机上切换版本,通过容器即可分别运行,互不干扰。
  3. 上手成本:新人入职或更换设备时,无需手动安装工具、配置环境,只需拉取代码和devcontainer配置,通过 IDE 一键启动容器即可完成环境搭建,大幅减少 "环境配置耗时"。
  4. 多场景复用:可移植性高,支持多场景复用配置文件可纳入版本控制(如 Git),方便团队共享。同时,开发容器的配置可直接复用至 CI/CD 流程(如 GitHub Actions、GitLab CI),确保开发、测试、部署环境一致,减少 "开发通过但部署失败" 的问题。
  5. 工具集成:与主流工具深度集成,开发体验流畅与 VS Code 的 "Dev Containers" 扩展、JetBrains 系列 IDE 的插件无缝配合,支持在容器内直接编码、调试、运行代码,开发者几乎感受不到 "在容器中开发" 的差异。
  6. 标准化和自动化管理:开发环境的变更(如新增依赖、升级工具)可通过修改配置文件实现,并通过代码评审确保合规,避免团队成员私下修改环境导致的混乱。

DevContainer的核心组成

使用DevContainer前需安装以下前置依赖:

  1. Docker(或Podman):容器引擎;
  2. VSCode(或Jetbrains):开发IDE;
  3. Dev Containers:VSCode的扩展插件,提供DevContainer技术支持;如果是Jetbrains则安装对应的插件;

一个包含DevContainer的开发项目其核心配置是.devcontainer 目录,里面包含环境定义文件:

  • devcontainer.json(核心配置文件,定义容器行为):

最简单的示例(基于官方 Python 镜像):

json 复制代码
{
  "image": "mcr.microsoft.com/devcontainers/python:3.11",  // 基础镜像
  "postCreateCommand": "pip install -r requirements.txt",  // 容器创建后自动执行的命令(如安装依赖)
  "customizations": {
    "vscode": {
      "extensions": [  // 自动安装的 VS Code 扩展(容器内生效)
        "ms-python.python",
        "ms-python.black-formatter"
      ]
    }
  },
  "portsAttributes": {
    "5000": { "label": "Flask App", "onAutoForward": "openBrowser" }  // 自动转发端口并打开浏览器
  }
}
  • Dockerfile(如需自定义镜像,可选):

若基础镜像不够用,可通过 Dockerfile 扩展,例如:

dockerfile 复制代码
FROM mcr.microsoft.com/devcontainers/python:3.11
# 安装额外工具
RUN apt-get update && apt-get install -y curl
# 设置工作目录
WORKDIR /workspace

此时需在 devcontainer.json 中指定 dockerfile 路径替代 image

json 复制代码
{ "dockerfile": "Dockerfile" }
  • docker-compose.yml(如需多容器环境,如依赖数据库,可选):

例如同时启动应用容器和 MySQL:

yaml 复制代码
version: '3'
services:
  app:
    build: .
    volumes:
      - ..:/workspace:cached
    command: sleep infinity  # 保持容器运行
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: devdb
    ports:
      - "3306:3306"

此时 devcontainer.json 需指定 dockerComposeFile

json 复制代码
{
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",  // 指定开发主容器
  "workspaceFolder": "/workspace"  // 代码挂载路径
}

在实际开发中,除手动修改配置外,还可以基于插件来新建或管理DevContainer的配置及环境。

基于DevContainer开发SCQL

SCQL提供DevContainer作为开发"基建",但当前没有文档说明如何使用。本文正好结合SCQL项目说明DevContainer的开发过程。首先需要按照上文安装好Docker及其它相关依赖,并保证Docker运行;SCQL适合使用VSCode作为开发的IDE。

配置文件

SCQL中主要包含以下文件:

devcontainer.json

json 复制代码
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/cpp
{
    // A name for the dev container which can be displayed in UI.
    "name": "SCQL Dev Container",

    // Sets the run context to one level up instead of the .devcontainer folder.
    "context": "..",

    // Update the VARIANT arg in docker-compose.yml to pick a Debian OS version: bullseye, buster
    // Use Python 3.10 to align with SCQL's CI/CD environment if possible, adjust if needed.
    "build": {
        "dockerfile": "Dockerfile"
    },

    // Features to add to the dev container. More info: https://containers.dev/features.
    // "features": {},

    // Use 'forwardPorts' to make a list of ports inside the container available locally.
    // "forwardPorts": [],

    // Use 'postCreateCommand' to run commands after the container is created.
    // Installs development dependencies using the Makefile target.
    "postCreateCommand": "echo 'hello world'",

    // Configure tool-specific properties.
    // "customizations": {},

    // Specifies the user the container will run as. Default is root.
    // Using a non-root user 'vscode' is recommended for security.
    "remoteUser": "vscode",

    // Mount the workspace folder.
    "workspaceFolder": "/workspaces/scql",
    "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/scql,type=bind,consistency=cached"
}

Dockerfile:指定开发镜像,并安装环境的前置依赖

dockerfile 复制代码
FROM secretflow/ubuntu-base-ci:latest

ARG TARGETPLATFORM
ARG GO_VERSION=1.24.0

# install go
RUN if [ "$TARGETPLATFORM" = "linux/arm64" ] ; \
    then \
        GO_ARCH=arm64 && \
        GO_SHA256SUM=c3fa6d16ffa261091a5617145553c71d21435ce547e44cc6dfb7470865527cc7 ; \
    else \
        GO_ARCH=amd64 && \
        GO_SHA256SUM=dea9ca38a0b852a74e81c26134671af7c0fbe65d81b0dc1c5bfe22cf7d4c8858 ; \
    fi \
    && url="https://golang.google.cn/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz"; \
    wget --no-check-certificate -O go.tgz "$url"; \
    echo "${GO_SHA256SUM} *go.tgz" | sha256sum -c -; \
    tar -C /usr/local -xzf go.tgz; \
    rm go.tgz;

ENV GOPATH="/usr/local"
ENV PATH="/usr/local/go/bin:${GOPATH}/bin:${PATH}"

RUN apt update \
    && apt upgrade -y \
    && apt install -y protobuf-compiler \
    && apt clean


# Create a non-root user 'vscode' with sudo privileges
# The user ID 1000 is common for the primary user in Linux distributions.
# The GID 1000 corresponds to the user's primary group.
# RUN groupadd --gid 1000 vscode && \
#     useradd --uid 1000 --gid 1000 --shell /bin/bash --create-home vscode && \
#     echo "vscode ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

# Set the default user for subsequent commands
# USER vscode

# Set the working directory inside the container
WORKDIR /workspaces/scql

# Set default shell to bash for the vscode user
ENV SHELL /bin/bash

# You can add more SCQL-specific dependencies here if needed,
# although 'make install-dev-deps' in postCreateCommand should handle most project dependencies.

# Keep the container running (optional, useful for debugging setup)
# CMD ["sleep", "infinity"]

启动DevContainer环境

启动DevContainer环境,我们可以通过插件启动:

或直接通过VSCode左下角快速启动:

第一次启动环境需拉取镜像需等待一段时间。

启动完成后,开发人员既可以像在本地一样进行程序开发。

Docker可以查看当前的容器和镜像:

退出DevContainer环境

通过与启动环境类似的方法退出环境:

我的SCQL系列文章:

DevContainer常见缺点

资源消耗、学习成本和部分场景的局限性需要开发人员权衡:

  1. 资源消耗较高:容器本质是轻量级虚拟机(虽然比传统 VM 轻量),运行时会占用额外的 CPU、内存和磁盘空间。对于资源有限的设备(如低配笔记本),可能导致开发过程卡顿。
  2. 启动和构建速度较慢:首次构建容器需拉取基础镜像、安装依赖,耗时较长(取决于网络和配置复杂度);即使后续启动,也可能比直接在主机环境启动项目慢一些。
  3. 对容器技术有一定学习成本 :开发者需要了解基础的 Docker 命令(如镜像构建、容器管理)、Dockerfile语法,以及devcontainer.json的配置规则,对不熟悉容器技术的团队来说存在入门门槛。
  4. 与主机系统的交互可能受限:容器与主机的文件系统、网络、硬件设备(如 USB、GPU)的交互需要额外配置(如挂载目录、端口映射),部分场景(如依赖特定硬件驱动的开发)可能存在兼容性问题。
  5. Windows 系统下体验可能不佳:在 Windows 上使用 Docker Desktop 时,容器运行在 WSL2 或 Hyper-V 虚拟机中,文件挂载性能(尤其是跨系统目录)可能比 Linux/macOS 差,大文件操作可能卡顿。
  6. 镜像体积可能过大:若配置不当(如安装过多不必要的工具),容器镜像体积会膨胀,导致存储占用增加、传输和构建速度变慢。

结语

Docker 是容器化的基础,但它的设计目标是通用的 "运行时隔离",而非专门针对开发流程优化。DevContainer 基于 Docker 技术,补充了开发所需的工具集成、流程自动化、团队标准化能力,让容器从 "运行环境" 变成 "即开即用的开发环境"。

相关推荐
武子康3 小时前
大数据-122 - Flink Watermark 全面解析:事件时间窗口、乱序处理与迟到数据完整指南
大数据·后端·flink
她说彩礼65万3 小时前
Asp.net core Kestrel服务器详解
服务器·后端·asp.net
4 小时前
JUC专题-线程安全性之可见性有序性
后端
计算机毕设定制辅导-无忧学长4 小时前
基于Spring Boot的酒店管理系统
java·spring boot·后端
Victor3564 小时前
Redis(57)Redis的慢查询日志是什么?
后端
Victor3564 小时前
Redis(56)如何监控Redis的内存使用情况?
后端
程序员爱钓鱼5 小时前
Go语言实战案例——进阶与部署篇:使用Go编写系统服务(如守护进程)
后端·google·go
JaguarJack5 小时前
PHP 15 个高效开发的小技巧
后端·php
235165 小时前
【并发编程】详解volatile
java·开发语言·jvm·分布式·后端·并发编程·原理