起因

之前已经写过一篇使用 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 和其他配置文件,以便在构建容器时使用。

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