前言
之前在学校的时候做编程作业项目的时候,除了通过 ssh 提交服务器编译项目的方法以外。偶尔也会有老师会直接给一个文件夹里面包含 docker 的相关配置,这样学生可以直接在 vscode 打开一个已经配置好的 docker container,这样也可以保证每个人的开发环境保持一致。这篇笔记主要整理 vscode 关于 docker container 的相关介绍以及自己的常用配置。
前提条件
这里假设机器已经至少安装好:
- vscode - 关于 vscode 的安装方法可以参考网上的其他资源,vscode 需要安装
remote-development
插件 - docker - 安装完成后,运行
docker --version
看是否能正确输出版本号
配置理想效果
这里我配置 docker 最终的效果是:
- 通过 vscode 利用一个已经写好的 dockerfile 每次打开一个项目文件夹时可以创建一个 docker 容器,我们可以跟正常使用 vscode 开发的步骤一样调试;
- 每一次打开容器都可以满足我们开发需要的所有环境,不用每次重新配置
- vscode 可以访问主机 host 的文件,并且共享 host 的网络配置环境
这里只涉及最基本的一些 docker 操作,毕竟我目前对 docker 也还在学习中哈哈。
vscode-container 配置
docker 相关文件结构
为了在 vscode 中直接打开 container 环境,除了安装 Remote Development
插件之外,我们还需要一个 Dockerfile 来配置 docker 的相关环境。这里我随便写了一个比较简单的 Dockerfile 作为演示用:
# base image from ubuntu 18.04
FROM ubuntu:18.04
# run apt update & upgrade
RUN apt update -y
RUN apt upgrade -y
# install apps for development
RUN apt install build-essential -y
# language settings
RUN apt install -y locales locales-all
ENV LC_ALL en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US.UTF-8
# set working directory
WORKDIR /root
首先将 Dockerfile
放在根目录下,另外根据我们使用场景放置该文件夹,如果我们想要对每一个项目有单独配置的话就将其放在该项目的根目录文件夹下;如果我们想要对多个项目应用同一个 docker 环境节省时间的话,就将该文件放在所有项目中最顶层的根目录下。这里我创建了一个实验文件夹方便实验操作,文件目录如下所示:
my_docker_projects
└── Dockerfile
└── HelloWord----------------项目文件夹(测试用)
├── data
│ └── input_text.txt
└── src
└── main.cpp
└── ...
└── ...
└── Other Projects-----------项目文件夹
利用 vscode 构建 docker 环境
首先在 vscode 打开 Dockerfile
所在的文件夹(这应该是你的项目根目录),利用 Command Pelette (Ctrl + Shift + p) 运行 Remote-Containers: Add Development Container Configuration Files...
,并选择 From Dockerfile
让 vscode 根据我们自定义的 docker 配置搭建。(如果不想写 Dockerfile 也可以选择预先定义好的)。然后会生成一个 .devcontainer
隐藏文件夹,里面包含一个 devcontainer.json
文件,如下所示:
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.128.0/containers/docker-existing-dockerfile
{
"name": "Existing Dockerfile",
// Sets the run context to one level up instead of the .devcontainer folder.
"context": "..",
// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
"dockerFile": "../Dockerfile",
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.shell.linux": null
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": []
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Uncomment the next line to run commands after the container is created - for example installing curl.
// "postCreateCommand": "apt-get update && apt-get install -y curl",
// Uncomment when using a ptrace-based debugger like C++, Go, and Rust
// "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],
// Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker.
// "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ],
// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
// "remoteUser": "vscode"
}
这个文件是用来配置 container 的打开条件的,会在下一部分仔细介绍。
为了目录比较简洁,我们可以将 Dockerfile
也放进 .devcontainer
中,并将 devcontainer.json
中 "dockerFile"
的值 改为 ./Dockerfile
。
重新打开该文件夹,这个时候 vscode 右下角应该会弹出检测到 Dev Container
配置文件夹,这个时候选择 Reopen in Container
就会开始构建 container 环境了。这里注意一下如果是第一次打开的话由于要生成 Image 所以会比较慢,在生成了 Image 之后,如果没有修改 Dockerfile 的话打开应该都会比较快。
如果成功打开的话,vscode 右下角应该会显示当前 .devcontainer.json
中定义好的名字,如下所示:
如果一切正常的话,现在我们已经成功通过 vscode 打开一个 container 环境了。但是如果我们是把 Dockerfile
放在一个大的项目目录下面的话,每一次都要在总的项目目录也比较繁琐。我们可以通过在当前的大目录在 vscode 中选择 file -> Open Folder...
,比如我这里是打开 HelloWorld
:
然后就可以在子文件夹中通过 vscode 打开了,并且之后每一次打开的步骤如下:
- 在 vscode 打开
.devcontainer
所在目录,并在 container 中重新打开; - 在 vscode 左边的 tab 选择
Remote Development
并在CONTAINERS
中选择你要打开的文件夹就可以成功切换了,如下图所示:
目前为止我们已经可以在一个文件夹和子文件夹中在容器中打开并进行开发了,下面主要结合我的 devcontainer.json
整理一下怎么使用该文件进行容器打开过程的配置
devcontainer.json 配置
我的 devcontainer.json
如下所示:
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.128.0/containers/docker-existing-dockerfile
{
// 容器 session 名字
"name": "My Container for C++",
// 容器包含的文件目录
"context": "..",
// Dockerfile 相对于本文件路径
"dockerFile": "./Dockerfile",
// 容器中需要安装的 vscode 插件
"extensions": ["ms-vscode.cpptools", "ms-vscode.cmake-tools", "eamodio.gitlens"],
// 进入容器中需要的一些参数
"runArgs": [ "--net=host"],
// 容器挂载的路径
"mounts": [ "source=${localEnv:HOME}${localEnv:USERPROFILE}/data,target=/home/,type=bind,consistency=cached" ]
}
上面大部分都比较简单,主要是:
"--net=host"
:通过这个参数我们可以让容器共享主机 host 的网络环境,包括 vpn,这个有时候会比较方便"mounts": [ "source=${localEnv:HOME}${localEnv:USERPROFILE}/data,target=/home/,type=bind,consistency=cached" ]
这个是在容器挂载文件夹,便于让在我们在容器中也能直接访问容器外的文件。可以通过Remote Development
中的mounts
看我们已经挂载的目录:
测试
我的文件目录如下所示:
测试的 main.cpp
接受两个文件路径作为输入和输出参数,按行读取输入文件,显示在 console 上并输出到输出文件中,运行如下:
root:/workspaces/my_docker_projects/HelloWord# cd src
root:/workspaces/my_docker_projects/HelloWord/src# g++ main.cpp
root:/workspaces/my_docker_projects/HelloWord/src# ./a.out ../data/input_text.txt ../data/output_text.txt
Hello World!
root:/workspaces/my_docker_projects/HelloWord/src# more ../data/output_text.txt
Hello World!
root:/workspaces/my_docker_projects/HelloWord/src# ./a.out /home/input_file_outside.txt ../data/output_text_outside.txt
I am outside of container!
root:/workspaces/my_docker_projects/HelloWord/src# more ../data/output_text_outside.txt
I am outside of container!
可以看到程序可以成功编译运行,并且可以读取 container 目录外的文件,另外注意一下由于我们是通过 root 环境进入 container,所以如果 conatiner 中的程序对某个文件进行写操作的话,该文件的写权限会被限制在 root 中。
结语
目前只是对 vscode 中的 container 进行了很简单的一些设置,之后可能还会整理一下与 ROS 相关的一些配置。