devcontainer

Dev Container

Configuration

Dev Container 配置步骤如下:

  • 安装 vscode 插件,dev container。

  • ctrl+shift+p 使用 dev container 命令添加配置文件。

  • 选择 dev container 配置模板(原则上选择基础 debian/ubuntu 即可,其它环境均可通过或许选择 features 进行动态构建)。

Runtime Permission

添加 docker 运行权限,需要添加执行命令,或配置声明。

在 docker-compose 中声明权限:

1
2
3
4
5
6
# Uncomment the next lines if you will use a ptrace-based debuggers like C++, Go, and Rust.
cap_add:
- SYS_PTRACE
security_opt:
- seccomp:unconfined
privileged: true

在 devcontainer.json 中配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"runArgs": [
// Enable ptrace-based
// ptrace syscall permission
"--cap-add=SYS_PTRACE",
// Net Configuration
"--cap-add=NET_ADMIN",
// Open all syscall permission
"--security-opt",
"seccomp=unconfined",
// Enable GPUs
"--gpus=all",
// Possess all permission of the host
"--privileged"
],

上面的配置可以使用 devcontainer 字段配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"capAdd": [
// Enable ptrace-based
"SYS_PTRACE",
// Net Configuration
"NET_ADMIN"
],
"securityOpt": [
"seccomp=unconfined"
],
"privileged": true,
"runArgs": [
"--gpus=all"
],
}

GPU Support

配置在 Dev DinD 的开发环境中支持 Nvidia Cuda GPU。

在容器启动前,安装 nvidia-container-toolkit

links:

方案一

使用 devcontainer 提供的官方镜像,需要配置安装 nvidia 源.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Dockerfile.gpu

# bullseye or jammy
FROM mcr.microsoft.com/devcontainers/base:{VARIANT}
# FROM nvcr.io/nvidia/pytorch:22.12-py3

# Installing nvidia-container-toolkit and Configure
RUN <<-EOF
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
# output
apt update && apt-get install -y nvidia-container-toolkit && nvidia-ctk runtime configure
# set nvidia as default runtime
echo '{"default-runtime":"nvidia"}' $(cat /etc/docker/daemon.json) | jq -s '.[0] + .[1]' | tee /etc/docker/daemon.json
rm -rf /var/lib/apt/lists/* /var/cache/* /var/log/* /tmp/* ~/.cache -rf
EOF

在 devcontainer.json 中配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"build": {
"dockerfile": "Dockerfile.gpu",
"args": {
"VARIANT":"jammy"
}
},
"capAdd": [
// Enable ptrace-based debugging for C++
"SYS_PTRACE"
],
"securityOpt": [
"seccomp=unconfined"
],
"privileged": true,
"runArgs": [
// Loading libnvidia* in devcontainer, verifying by the command `ldconfig -p | grep libnvidia`
"--gpus=all"
],

方案二

使用 nvidia 提供的官方 cuda 开发容器为基础,作为 GPU 开发容器配置.

1
2
3
4
5
6
7
8
9
10
# Dockerfile.gpu

# 以下镜像已经内置 nvidia container toolkit源
FROM nvidia/cuda:12.1.1-cudnn8-devel-ubuntu20.04

RUN <<-EOF
apt update && apt install -y nvidia-docker2 && nvidia-ctk runtime configure
# 和方案一相同, 配置nvidia 容器运行时到 /etc/docker/daemon.json
rm rf /var/lib/apt/lists/* /var/cache/* /var/log/* /tmp/* ~/.cache -rf
EOF

方案三

方案一,二都需要手动配置源或者使用已经配置好的基础镜像,第三种方法是使用 devcontainer 提供的 cuda feature 来构建.

1
2
3
4
5
6
7
8
9
10
11
// https://github.com/devcontainers/features
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"upgradePackages": false,
"username": "vscode",
"configureZshAsDefaultShell": true
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
// 使用 cuda feature 构建环境
"ghcr.io/devcontainers/features/nvidia-cuda:1": {}
},

以上方式需要手动安装 docker-container-toolkit

1
2
3
4
5
# 安装 docker nvidia runtime(nvidia-docker2/nvidia-container-toolkit)
apt update && apt install -y nvidia-container-toolkit && nvidia-ctk runtime configure
# 重启 docker
ps -ef | grep -E '(dockerd|docker-init.sh)' | head -1 | awk '{print $2}' | xargs sudo kill -9
/usr/local/share/docker-init.sh

QA

sudo apt update error: “Release file is not yet valid”

1
2
# https://askubuntu.com/questions/1096930/sudo-apt-update-error-release-file-is-not-yet-valid
sudo hwclock -s

Features

common features

这里列出了常用 Dev Container 的 features 使用总结。

Common utils

配置容器开发环境用户,方面管理权限。实现参考通过 Dockerfile 创建非 root user

devcontainer 有提供专门的 common 帮助用户创建非 root 用户。

1
2
3
4
5
6
7
8
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"username": "vscode" // or others
}
},
"postCreateCommand": {
"git-completions": "echo 'source /usr/share/bash-completion/completions/git' >> ~/.bashrc"
},

Desktop lite

在 devcontainer.json 中配置 desktop-lite

1
2
3
"features": {
"ghcr.io/devcontainers/features/desktop-lite:1": {}
}

导出端口 nVNC 的 vscode 配置 forward port 为 6080 (默认 nVNC 端口)

支持 nVNC 浏览器推荐 Firefox 和 Chrome,这里给出自动集成 Dockerfile 的指令。

1
2
3
4
5
6
# Firefox ESR
apt-get update && export DEBIAN_FRONTEND=noninteractive && apt-get install -y firefox-esr
# Chrome
apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& curl -sSL https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -o /tmp/chrome.deb \
&& apt-get -y install /tmp/chrome.deb

DinD

在容器内创建子容器,独立于主机的 docker 实例。在容器中安装 Docker 扩展以及所需的 CLI。

1
2
3
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
}

[!TIP]
当容器 daemon 挂掉或者更新 daemon.json 时,可通过 /usr/local/share/docker-init.sh 重启 docker 服务.

features development

devcontainer features 提供了可插拔式得开发工具集成方式。这里简单介绍自定义 features 开发流程。主要参考官方 feature 模板.

links:

Step 1, feature 开发

  • clone 官方提供的模板。示例参考

  • 使用官方模板打开 feature 的 devcontainer 开发环境

  • 在 src 下创建 feature, 每个 feature 以子目录构建布局

  • 在 feature 目录下,书写脚本,必须包含有 install.sh 及 devcontainer-feature.json 配置及脚本。详情参考模板

Step 2, feature 测试

  • 在根目录下有 test 目录,某人有全局 _global 测试及各个 feature 测试

  • 在 _global 下可配置测试所有 feature, 具体在 scenarios.json 中注册 feature id, 然后在对应的注册的 id 的脚本 all_tools.sh 中添加 feature 验证命令即可

  • 在 test 目录下可创建单个 feature 的测试脚本,详情参考模板

  • 验证 feature, 使用命令 devcontainer features test -f <feature id> -i <image-name> 在 image-name 的镜像中验证 feature 是否安装成功.

Step 3, feature CI in github action

  • 直接使用模板提供的 CI test.yaml 中配置

  • 在 baseImage 中配置要测试的 image

  • 在 features 中添加要验证的 feature

  • 最后,test 执行成功后,可手动执行 release workflow 发布 feature.

Performance

在 Windows/MacOS 上存在性能的 I/O binding 的损失,官方给出了几种解决方案

通过 wsl 挂载

通常在 wsl 磁盘挂载效率较高

参考文档:

1
2
3
4
5
6
7
8
9
10
11
12
13
# in powershell
docker run --rm -it -v "$(pwd):/pwd:delegated" -w /pwd alpine time dd if=/dev/zero of=speedtest bs=1024 count=100000
100000+0 records in
100000+0 records out
real 0m 25.51s
user 0m 0.11s
sys 0m 3.19s
docker run --rm -it -v "$(pwd):/pwd:cached" -w /pwd alpine time dd if=/dev/zero of=speedtest bs=1024 count=100000
100000+0 records in
100000+0 records out
real 0m 28.28s
user 0m 0.11s
sys 0m 3.23s
1
2
3
4
5
6
7
# in wsl
docker run --rm -it -v "$(pwd):/pwd:delegated" -w /pwd alpine time dd if=/dev/zero of=speedtest bs=1024 count=100000
100000+0 records in
100000+0 records out
real 0m 0.22s
user 0m 0.02s
sys 0m 0.19s

通过测试在 wsl 上挂载不管是 delegated 还是 cached 的效率都是 windows 上得 10x 以上.

Devcontainer in CI

将 devcontainer 构建环境集成在 CI 中,方便开发使用预编译好的镜像,对 CI 流程得 Testing 等能做到同一环境下的统一配置构建方式.

使用 devcontainer/cli 可以轻松的将 devcontainer 集成到 CI 环境中.

links:

1
2
3
4
5
6
7
8
9
10
11
npm install -g @devcontainers/cli

# 使用 cli 启动配置项目镜像容器
git clone https://github.com/microsoft/vscode-remote-try-rust && cd vscode-remote-try-rust
devcontainer up --workspace-folder .

# 在容器中执行命令 ls
devcontainer exec --workspace-folder . ls

# 使用cli 构建预构建镜像
devcontainer build --workspace-folder .

使用 devcontainer 配置构建镜像

1
2
3
4
5
devcontainer build \
--workspace-folder . \
--image-name registry/namespace/image-name:image-tag \
--push true \
--config .devcontainer/build.json
1
2
3
4
5
6
7
// build.json
{
"name": "xxx-devcontainer",
"build": {
"dockerfile": "Dockerfile"
}
}

[!CAUTION]
目前构建镜像,需要配置为 ‘build’ 字段,默认的’image’使用存在 bug.

目前 devcontainer cli 没有 stop 命令,可以通过 docker 查找过滤.

1
2
3
4
5
6
# 方法一
docker stop $(docker ps -q -f ancestor=image-name)
docker rm -f $(docker ps -q -f ancestor=image-name)
# 方法二
devcontainer up --workspace-folder . --id-label id_name=<identity name>
docker ps -q --filter "label=id_name=<identity name>" | xargs docker rm -f

devpod

links: