问题描述
我们实验室有一台很牛的Linux服务器,核多卡多硬盘大,它是大家共用的,组里给我们每个人都创建了一个普通用户,没有sudo权限,所以不能用apt。
但是每个人对开发环境的需求都是不一样的,比如我要用clang12他要用clang15,很容易就冲突了。而且众所周知Unix的权限就是鸡肋,实际使用时提防同僚不足而踩坑报错有余,没有root权限很多时候真的不方便。
因此,要是我们每个人都有一个专属的Linux系统就好了,这正可以使用Docker的虚拟化功能实现。下面就介绍一下如何创建和连接一个“开发容器”,最终的开发体验和直接使用VSCode连接一个实体Linux服务器是完全相同的。
解决方案
首先需要向管理员申请使用docker命令的权限,因为docker命令可以用来提权,所以我们组里一般不会默认给大家用。
提权方法:因为docker的容器默认是root用户,所以我们可以通过卷映射的方式将物理机的根目录映射进去,然后在容器里修改任意文件。
所以我说Unix文件系统的权限控制就是鸡肋,不过安全起见请不要直接把根目录映射进去。
然后在自己的家目录下建一个新文件夹存储和自己的容器相关的数据(我的是gyh-zsh
),在里面加一个Dockerfile文件,之后我们就在这里面构建我们开发容器的镜像:
$ cd ~
$ mkdir gyh-zsh && cd gyh-zsh
$ vim Dockerfile
这个Dockerfile和一般我们用于部署服务器的区别在于它的入口点(CMD
或ENTRYPOINT
命令),要将它的入口点设定为任意的一个shell程序。下面是我的Dockerfile:
# gyh-zsh
FROM ubuntu:22.04
WORKDIR /root
RUN apt update && apt install -y zsh
ENV IS_IN_DOCKER=1
ENTRYPOINT ["/bin/zsh"]
我用的是zsh,因为ubuntu镜像中默认是没有的,所以多了一行RUN
命令。另外我们最好设置一个环境变量(IS_IN_DOCKER
)来指示容器里的程序是运行在容器里。
然后我们直接构建它就行了,注意加上自己的名字(-t
)别让别人给删除了:
$ docker build . -t gyh-zsh
创建一个目录在之后映射到容器的/root
目录,然后就可以创建容器了:
$ mkdir root
$ docker container create \
--name gyh-zsh \
-v $HOME/root:/root \
-v $HOME:/gyh \
gyh-zsh
我同时把自己在物理机的家目录也映射进去,这样方便在容器里从外面取数据。
当然你的VSCode要安装Remote Development插件。在构建完毕后,用VSCode连接到物理机,然后点开“远程资源管理器”,你就应该能看到自己的容器显示在一个专门的“Dev Containers”分类里了:
这个分类里的容器都可以被VSCode直接连接,连上去之后的开发体验和直接连接物理机是一模一样的(但是这时你有root权限了,耶!):
最后,使用Docker的另外一个好处就是我们可以将整个开发环境都备份下来(妈妈再也不用担心我装错软件搞坏环境了):
$ docker export -o "$(date).tar" gyh-zsh
$ docker container rm gyh-zsh
$ docker import 'Sat 11 Feb 2023 10:49:34 PM CST' gyh-zsh