• 首页
  • 加入
  • RSS
  • VSCode DevContainer 不完全食用

    Wednesday, May 14, 2025
    justforlxz @lxz:mkacg.com


    起因

    之前已经写过一篇使用 distrobox 加速开发的文章,主要动机就是在面对不同版本的系统时,准备多份开发环境将变得十分痛苦,最终就演变成了基于 VSCode 的 Remote 开发搭配容器环境。

    这样只需要准备一份 base 环境,每次只需要设置环境版本就可以安装对应的开发依赖,并且不需要更换开发工具,甚至可以在环境变量中设置好 DISPLAY 等,还能直接让容器内的程序显示在宿主环境上。

    本篇文章是基于 podman 的技术方案执行的。

    环境准备

    安装 podman

    sudo pacman -Sy podman

    确认配置

    cat /etc/subuid

    内容应该是 lxz:100000:65536。

    VSCode

    打开 VScode 的设置,搜索 container,将 docker 的二进制改成 podman。

    .devcontainer.json

    VSCode 会识别打开目录下的 .devcontainer 目录和 .devcontainer.json 文件,本文会先介绍 json 格式的配置,之后会介绍使用 Dockerfile 构建运行环境的方式。

    {
    "name": "UOS Dev Container",
    "containerUser": "root",
    "image": "uos:base",
    "customizations": {
    "vscode": {
    "extensions": [
    "llvm-vs-code-extensions.vscode-clangd",
    "donjayamanne.git-extension-pack",
    "donjayamanne.githistory",
    "theqtcompany.qt-cpp-pack",
    "eamodio.gitlens",
    "ms-vscode.cmake-tools",
    "go2sh.cmake-integration-vscode",
    "josetr.cmake-language-support-vscode",
    "VisualStudioExptTeam.vscodeintellicode",
    "VisualStudioExptTeam.intellicode-api-usage-examples",
    "esbenp.prettier-vscode",
    "ms-vscode.cpptools",
    "twxs.cmake"
    ]
    }
    },
    "runArgs": [
    "--rm",
    "--network=host",
    "--privileged",
    "--userns=host"
    ],
    "remoteEnv": {
    },
    "onCreateCommand": "apt update && apt install -y clangd-13 ninja-build curl jq && update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-13 13 && echo > /etc/apt/sources.list",
    "postCreateCommand": "echo \"请输入系统版本:\" && read version && sh -c \"curl -s 'https://xxx/api/shuttle/repo/info?type=deb&reponame=eagle-$version' | jq -r '.data.repobase.archives[].address' | tee /etc/apt/sources.list\" && echo 'deb [trusted=yes] https://xxx/pkg/eagle-1073/release-candidate/MDQyNeeql-euoeS4u-e6v-aPkOa1izIwMjUtMDQtMjUgMTQ6NTk6MDE/ unstable main' >> /etc/apt/sources.list && apt update && apt build-dep -y . && apt install -y qt5-default qtwayland5-private-dev"
    }

    在 json 中,需要指定一个运行时环境,在这里使用的是本地手动准备的镜像,为了确保开发和服务器构建环境的一致,我直接使用了服务器提供的构建环境,并使用 podman image import 命令导入。

    runArgs 中 --userns=host 的作用是使用主机的 user namespace,而 containerUser 必须指定成 root,因为容器内没有别的用户。

    为了防止泄露内网信息,postCreateCommand 内已将域名屏蔽。

    在 UOS 中,clangd 的版本有点低,需要手动创建符号,否则 VSCode 的 clangd 插件无法正常工作。这个事情就放在 onCreateCommand 中执行了,postCreateCommand 则是配置仓库和安装项目的构建依赖。

    当打开项目后,VSCode 会提醒在容器内重新打开。

    容器内打开容器内打开容器内打开

    之后等待 VSCode 完成 server 的下载,就会开始执行 onCreateCommand 和 postCreateCommand。

    启动完毕后就会开始安装插件,是一个正常的工作环境了。

    容器内打开容器内打开

    打开终端,可以看到是 root 用户,但 podman 做了 uid 映射,实际目录的权限会是用户自身,不必担心。

    容器内打开容器内打开

    Dockerfile

    通常情况下应当使用 image,这样能确保所有人的环境是一致的,但仍然有时候想在 Dockerfile 里提前准备好一些事情,而不是在容器启动后进行配置,只需要把 image 字段改成 build。

    "build": { "dockerfile": "Dockerfile" },

    这种情况更推荐放在 .devcontainer 目录。在这个目录下,可以放置 Dockerfile 和其他配置文件,以便在构建容器时使用。

    FROM --platform=$TARGETPLATFORM hub.deepin.com/kwin-devcontainer/linuxdeepin/eagle:base

    ARG USERNAME=user
    ARG UID=1000
    ARG GID=1000
    ARG UOS_VERSION=1073

    RUN groupadd --gid $GID $USERNAME && \
    useradd --uid $UID --gid $GID -m $USERNAME

    RUN apt-get update && \
    apt-get install -y \
    curl \
    jq \
    && \
    apt-get dist-upgrade -y && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

    RUN apt-get update && \
    apt-get install -y \
    sudo \
    clangd-13 \
    apt-utils \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release \
    && \
    update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-13 13 && \
    echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \
    apt-get dist-upgrade -y && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

    USER $USERNAME

    json 也稍微修改了一下,使用 Dockerfile,并且使用参数控制一些构建过程,并且增加了本地用户。

    {
    "name": "UOS Dev Container",
    "remoteUser": "lxz",
    "build": {
    "dockerfile": "Dockerfile",
    "args": {
    "UOS_VERSION": "1073",
    "USERNAME": "lxz"
    }
    },
    "customizations": {
    "vscode": {
    "extensions": [
    "llvm-vs-code-extensions.vscode-clangd",
    "donjayamanne.git-extension-pack",
    "donjayamanne.githistory",
    "theqtcompany.qt-cpp-pack",
    "eamodio.gitlens",
    "ms-vscode.cmake-tools",
    "go2sh.cmake-integration-vscode",
    "josetr.cmake-language-support-vscode",
    "VisualStudioExptTeam.vscodeintellicode",
    "VisualStudioExptTeam.intellicode-api-usage-examples",
    "esbenp.prettier-vscode",
    "saoudrizwan.claude-dev"
    ]
    }
    },
    "runArgs": [
    "--rm",
    "--network=host",
    "--privileged",
    "--env",
    "XDG_RUNTIME_DIR=${env:XDG_RUNTIME_DIR}",
    "-v",
    "${env:SSH_AUTH_SOCK}:/tmp/ssh-agent.socket",
    "-e",
    "SSH_AUTH_SOCK=/tmp/ssh-agent.socket"
    ],
    "remoteEnv": {
    "XDG_RUNTIME_DIR": "${env:XDG_RUNTIME_DIR}",
    "PODMAN_USERNS": "host"
    },
    "postCreateCommand": "sudo apt update && sudo apt build-dep -y . && sudo apt install -y qt5-default qtwayland5-private-dev"
    }

    https://code.visualstudio.com/docs/devcontainers/create-dev-container