Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

特别说明:要在我的随笔后写评论的小伙伴们请注意了,我的博客开启了 MathJax 数学公式支持,MathJax 使用$标记数学公式的开始和结束。如果某条评论中出现了两个$,MathJax 会将两个$之间的内容按照数学公式进行排版,从而导致评论区格式混乱。如果大家的评论中用到了$,但是又不是为了使用数学公式,就请使用\$转义一下,谢谢。

想从头阅读该系列吗?下面是传送门:

前言##

关于 Docker 的介绍,我这里就不废话了。Docker 是什么?Docker 和虚拟机有什么区别?Docker 适用的场景是什么?这些介绍早就烂大街了。大家可以去 Docker 的官网首页看介绍,也可以在博客园的首页随便搜一下,入门级的文章到处都是。如果想了解更深一点的技术细节,可以看 sparkdev 的博客,我这里先对 sparkdev 表示感谢,我这篇随笔中,引用了他的部分内容。我这篇随笔重点是探讨 Docker 的使用和学习方法,并不研究它深层次的原理。

安装 Docker

在 Ubuntu 中安装 Docker 真的是太方便了。完全不用访问 Docker 的官网,不需要自己去下载,apt超级牛力瞬间搞定。稍微需要注意的是,不是安装docker软件包,而是安装docker.io软件包。首先,我先用sudo aptitude search docker命令查看 Ubuntu 的软件源中有哪些和 Docker 有关的包,如下图:

Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

其中docker被明确标记为 transitional package,所以我们安装下面的docker.io包,使用sudo aptitude install docker.io命令。安装完成后,使用sudo docker --version查看一下,发现是最新的版本,而且是社区版,不是企业版,所以其版本号为 18.06.1-ce。如下图:

Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

拉两个镜像测试一下##

只要稍微了解一点 Docker 的人都知道有一个 dockerhub,和我们常用的 github 一样,可以获得别人精心制作并分享的资源。在 github 中,我们可以找到我们感兴趣的项目,并把它 clone 到本地。而在 dockerhub 中,这些资源叫 Image,我们可以把我们感兴趣的 Image 拉到本地,并以该 Image 为基础,运行一些 Container。

关于 Image 和 Container 的概念,我这里不再废话。我选择了一个 ubuntu,还有一个 spacevim。使用的命令分别为sudo docker pull ubuntusudo docker pull spacevim。如下图:

Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

配置 Docker 使用中国的 Image 仓库##

上面拉取 Image 的操作看似简单,其实经历过失败,主要原因就是国外的仓库被墙挡住了。解决这个问题的方法,就是设置 Docker 使用中国的 Image 仓库。其设置方法为修改/etc/docker/daemon.json配置文件,如果没有该文件,就新建一个。将其内容修改为:

{
"registry-mirrors":["https://registry.docker-cn.com"]
}

然后,使用如下命令重启 Docker 服务:

systemctl daemon-reload
systemctl restart docker

运行一个容器##

使用sudo docker image ls命令可以查看我们的机器上有哪些 Image,使用sudo docker container ps -a命令,可以查看我们的机器上有哪些 Container。在上图中,在我们拉取镜像之前,它们的显示结果都是空的。sudo docker container ps -a命令之所以要加上-a参数,就是为了显示所有的 Container,包括运行的和停止的。

拉取完了以后,再使用sudo docker image ls命令,显示的就不再是空的了。如下图:

Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

然后,使用sudo docker run -it spacevim/spacevim nvim命令运行一个容器,启动 SpaceVim,如下图:

Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

在上图中,我分别写了一个 C 语言的文件和一个 Python 语言的文件,同时修改了一下 SpaceVim 自己的配置文件。

介绍一下 SpaceVim##

SpaceVim 是一个非常优秀的 Vim 整合项目,简单点说,就是通过各种插件把 Vim 打造成一个万能的 IDE,而且它对 NeoVim 支持非常好。确实很漂亮,功能也确实很强大。但是,我系统上用的 Vim 是我自己配的一个非常简洁的 Vim(请看我前面的随笔),如果再在系统上安装 SpaceVim 就不太方便。所以,使用 SpaceVim 官方提供的 Docker Image 就是一个非常方便的选择了。

Docker 的最常用命令和参数##

从上面的截图可以看出,我们最常用的命令就是sudo docker run命令,它就是以某个 Image 为基础运行一个新的 Container,注意,是新的 Container 哦。也就是说,每执行一次sudo docker run,就建立一个新的 Container,哪怕它们用的是同一个 Image。如果要启动一个已经存在的 Container 怎么办呢?别担心,有sudo docker container start命令。

最常用的参数是-i-t,只有这样,我们才能够和 Container 中的程序进行交互。其次,就是-p参数,可以把 Container 中的某个端口映射到主机的某个端口,这对网络服务非常重要。还有-v参数,可以把主机的某个目录映射到 Container 中的某个目录,这样,共享文件就很方便了。

使用 SpaceVim 时遇到的问题:在一个 Container 中可以运行多个程序吗?##

使用 SpaceVim 的 Image 启动一个 Container 后,问题来了。每次启动这个 Container,就自动运行 nvim,进入 SpaceVim 的界面,编辑文件是不成问题,可是这个编辑器界面毕竟不是 Shell 不是吗?我们其它的管理工作怎么做?

而我们使用 ubuntu 的 Image 启动 Container 后就很方便了,直接进入 Bash。所以问题来了,在一个 Container 中可以执行多个程序吗?

答案是肯定的,那就是sudo docker container exec命令,如下图:

Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

从上图可以看出,我们进入 Ubuntu 时,直接和 Shell 进行交互,所以可以非常方便地使用lspwd等命令,甚至可以使用cat /etc/os-release命令查看系统的版本信息。当然,还可以使用apt安装软件。而要想进入 SpaceVim 所在的容器,就需要使用sudo docker container exec -i spacevim-1.0 bash命令再启动一个 Shell,这样就可以使用ls命令看到我们刚才编辑的test.ctest.py了。甚至可以使用ps命令查看该容器中运行的进程。

Docker 的学习资源##

Docker 的官网就别看了,难受。买书呢?费钱!还不一定能找到优秀的。最好的办法就是查看 Docker 的手册页啦。使用sudo dpkg -L docker.io命令,可以看到系统中安装了好多手册页,如下图:

Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

如果输入man docker,就是下面这样:

Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

如果输入man docker run,就是下面这样:

Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

如果想自己写 Dockfile,就输入man Dockfile。我就不继续截图了。每一个手册页都可以从头读到尾,这种流畅的感觉是在 Docker 的官网上查看文档体会不到的。

下一个问题:我们可以把我们的 Container 再打包带走吗?##

运行一个 Container 后,我们可以在上面编辑文件、更改配置,还可以按需安装软件。做了很多工作后,我们可以把这个 Container 打包带走吗?当然可以了,使用sudo docker container commit命令可以基于一个 Container 再创建一个镜像。然后使用sudo docker push命令就可以把这个镜像再上传到 dockerhub 上了。当然,这只是理想状态,毕竟有墙的存在,而且 dockerhub 要注册后才能上传镜像。所以上传这个事就不是那么好做啊。

不过没关系,我们可以打包用 U 盘带走。sudo docker image save命令可以把 Image 导出为本地文件。使用 U 盘带走后,使用sudo docker image load命令可以从这个文件再导入镜像。

下一个问题:Docker 中的程序可以访问我们主机上的所有硬件资源吗?##

其实我关心的是显卡。在我的上上篇随笔中,我写到了使用 CUDA 加速计算,而 CUDA 需要 Nvidia 的显卡支持。如果我要用 Docker 构建一个 CUDA 的开发环境,那就需要我 Docker 中的程序能够访问主机的显卡资源。从理论上讲,这是可以的。毕竟 Docker 不同于虚拟机,Docker 是和主机共享内核的,而 Nvidia 的驱动,只是一个内核模块。于是,我在使用 Ubuntu 镜像的 Container 中测试了一下。使用lsmod命令查看内核模块,发现它确实是使用的 Nvidia 的驱动,如下图:

Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

另外,使用sudo aptitude install nvidia-cuda-toolkit安装 cuda-toolkit,也是可以安装的。因此,证明 Docker 中的程序可以访问主机上的所有硬件资源。使用 Docker 构建我们自己的开发环境不是梦。

最后一个问题:Docker 中能运行 GUI 程序吗?##

答案是可以。

先来分析一下思路。在 Docker 中运行控制台程序时,我们需要给程序一个标准输入输出,就可以和程序交互了。在 Docker 中运行 Web 服务时,我们需要给程序一个 IP 和端口,就可以和服务交互了。GUI 程序需要什么呢?它们需要一个 X Server 的 Display。我们给它就行了。

DISPLAY的格式是unix:端口主机名:端口,前一种格式表示使用本地的 unix 套接字,后一种表示使用 tcp 套接字。默认情况下,X11的服务端会监听本地的unix:0端口,而 DISPLAY 的默认值为:0,这实际上是unit:0的简写。因此如果在 Linux 的控制台启动一个图形程序,它就会出现在当前主机的显示屏幕中。

而 unix 套接字就是一个文件,所以,可以使用-v参数,将主机的 unix 套接字共享到 Container 中,然后,运行在 Container 中的 GUI 程序,就会出现在主机的屏幕上。

其实早在2015年的“Docker全球开发者大会”上,Docker 自家的美女程序员“杰西·弗莱泽尔(Jessie Frazelle)”就展示了一系列黑魔法一样的镜像。这些镜像中的大多数都使用了图形界面。比如,她使用这样的命令docker run -d -v /tmp/.X11-unix:/tmp/.X11-unix jess/libreoffice在 Docker 中运行了 LibreOffice(这只是举例,真要运行成功还有很多细节需要完善),其中最重要的参数就是-v /tmp/.X11-unix:/tmp/.X11-unix,也就是把主机的 unix 套接字映射到 Container 中。

使用 Docker 隔离自己的开发环境和部署环境##

每次安装开发环境,都容易把自己的系统搞得乱七八糟,换一台机器后,又要从头开始配置,这是以前经常碰到的痛点问题。有了 Docker 后,我觉得把自己的开发环境进行隔离是个不错的选择。前面探讨的两个问题,在 Docker 中能否访问所有的硬件资源?在 Docker 中能否运行 GUI 程序?可以说是为了这个目的做的铺垫。就拿写 CUDA 程序来说,必须 Docker 中能够使用 Nvidia 的显卡驱动才能顺利进行开发。其次就是如果不能在 Docker 中运行 GUI 程序,则很多 IDE 或者好的编辑器不能用,也是很令人蛋疼的一件事。幸好,以上两个问题的答案是肯定的。

使用sudo docker search命令,可以在 dockerhub 中找出别人有没有这么干过。例如,我们使用sudo docker search cuda命令,可以找到好多配置好了的 CUDA 开发环境。如下图:

Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

对于 GUI 呢?我们可以试试搜索一下优秀的编辑器 Visual Studio Code,使用sudo docker search vscode,也可以发现好多配置好的 Visual Studio Code 环境。如下图:

Linux 桌面玩家指南:18. 使用 Docker 隔离自己的开发环境和部署环境

至于其它的开发环境,如 Java、Python 什么的,那肯定是多于过江之鲫,我就不一一赘述了。至于隔离部署环境,这是目前 Docker 用得最多的场景,我就不废话了吧。

OK,关于 Docker,今天就写这么多。我感觉我又找到了新世界的大门。

版权申明##

该随笔由京山游侠在2019年03月08日发布于博客园,引用请注明出处,转载或出版请联系博主。QQ邮箱:1841079@qq.com

上一篇:Linux 桌面玩家指南:10. 没有 GUI 的时候应该怎么玩


下一篇:mongodb c++ 驱动库编译