起因

之前已经写过一篇使用 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 的下载,就会开始执行 onCreateCommandpostCreateCommand

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

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

Dockerfile

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

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

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

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