基于 Docker 实现跨平台开发

Dec. 11, 2016, 12:26 a.m.
标签: docker

Docker 实在是好用,谁用谁知道,就是配置起来麻烦了一点。最近由于在家用自己的 Windows 系统,开发环境各种搭不上,一怒之下果断使用 Docker 快速搭建开发环境,效果还不错。

准备工作

首先要安装 Docker ,这里就不多说了。

然后由于我大天朝的网络环境,需要通过镜像加速才能正常使用 Docker ,具体参见这一篇

接下来,在 Windows 或者 Mac OS 的不能原生支持 Docker 的操作系统上,我们需要在 Docker Machine 中运行 Docker ,因此还需要把我们的工作目录挂载到 Docker Machine 中,具体参见这一篇

构建开发镜像

本文主要是针对 Windows 系统的,因为只有在高贵的 Windows 系统上,才会经常出现一些需要编译的包安装失败的问题。因此我们的主要目的是,把所有的安装过程放到 Docker 中进行,而源码仍然保留在宿主机中,这样可以继续用自己喜欢的编辑器进行开发。

举个例子:Node.js 安装的所有文件都在 node_modules 文件夹下,那么我们只需要将这个文件夹 build 到镜像中,然后通过 VOLUME 将源码挂载进去就可以愉快地进行开发了。

然而,问题出现了。node_modules 这个文件夹本身也在源码文件夹中,如果我们简单地挂载了源码文件夹,就会发现 node_modules 成了一个空文件夹,之前构建镜像时安装的文件都不见了。解决的方法其实也很简单,就是把 node_modules 也通过 VOLUME 挂载出来,这样它就会是一个独立的目录,不受源码文件夹影响。

最终的 Dockerfile 为了与生产用的 Dockerfile 区分,我给它取名叫 Dockerfile.dev,内容如下:

FROM node

ENV WORKDIR /usr/src/app

RUN mkdir -p $WORKDIR
WORKDIR $WORKDIR
EXPOSE 8000

COPY package.json $WORKDIR
RUN npm i
VOLUME $WORKDIR $WORKDIR/node_modules

CMD npm run dev

需要注意的是,VOLUME这一行必须在RUN npm i后面,否则node_modules始终为空。

再来一个使用 Python 的例子,Python就简单多了,可以直接将依赖安装到全局,所以不存在安装的文件消失的问题。最终的 Dockerfile.dev 内容如下:

FROM python:3
ENV WORKDIR /usr/src/app
RUN mkdir -p $WORKDIR
WORKDIR $WORKDIR
EXPOSE 3000
VOLUME $WORKDIR

COPY requirements.txt $WORKDIR
RUN pip install -r requirements.txt

CMD python app.py

无视平台的开发

构建镜像:

$ docker build -t project:dev -f Dockerfile.dev .

进入开发模式:

$ docker run --rm -v /path/to/src:/usr/src/app -p 8000:8000 project:dev

还可以使用大神器 Docker Compose ,这里就不多说了。

总结

在这个环境搭建过程中,我遇到了一些问题,归根结底是因为对 Docker 的一些概念不够熟悉。

  1. 文件系统:

    Docker file system

    使用了 Docker Machine 以后,其实我们有3个独立的文件系统:a. 宿主机文件系统;b. Docker Machine 虚拟机内文件系统;c. Docker 内部文件系统。

    在构建镜像的时候,Docker 会将宿主机中的文件发送到 Docker Machine 中再进行后续操作,所以这个时候我们使用的路径都是属于宿主机文件系统

    而在创建容器的时候,我们实际上是在虚拟机中运行的,因此使用的路径都是属于虚拟机内文件系统

    因此,为了将文件挂载到 Docker 容器中,需要先通过 VirtualBox 把宿主机文件共享到虚拟机内,然后通过 VOLUME 将虚拟机内的对应目录挂载到 Docker 中。也就是说,--volume 的值是 虚拟机中目录地址:Docker中目录地址

  2. 端口映射:

    我们通过 EXPOSE 暴露的端口需要在 Docker 容器内被监听,而且必须要监听对外的IP,如果只监听 localhost 宿主机是无法访问到的。

    与 Linux 系统不同,通过 Docker Machine 暴露的端口实际上都监听在 Docker Machine 上,所以访问的时候要通过 Docker Machine 的IP来访问,通常是 192.168.99.100

终于大功告成,再也不用担心 Windows 上的开发问题了。(再也不用在 Ubuntu 和 QQ游戏之间纠结了 \(^o^)/ )