使用 Docker 武装你的 Windows 开发环境

使用 Docker 武装你的 Windows 开发环境

使用 Docker 武装你的 Windows 开发环境

就我所知大部分公司的部署环境都是类 Linux 操作系统,毕竟人家免费嘛,但有很多公司分配给开发人员的开发机却是 Windows PC,这就造成了开发人员的开发环境与实际生产环境是不同的操作系统,这自然会影响我们的部分开发体验,这其中又有一部分公司使用虚拟化的云桌面技术为开发人员配置统一的开发平台,但另一部分企业还是在 Windows PC 开发到 Linux 部署。

曾今很多 Windows 用户使用虚拟机来假装使用 Linux,但虚拟机需要占用庞大的系统资源,Docker的出现使轻量级虚拟化技术成为可能,借助 Docker 我们可以像运行一个小程序一样地在 Windows 上运行一个 Linux 系统,几乎无感地获得完全一致的开发、构建体验。

关于 Docker 的一些基本使用细节可以查看专栏文章Docker 配置与实践清单。另外说些题外话:阿里巴巴几乎所有研发人员均使用 MacBook Pro 进行开发,所以可能没有这样那样的困扰,欢迎大家私信投简历,详见阿里南京 2019 秋招季/社招,诚邀加入~

在我们使用 Docker for Windows 之前我们需要首先构想一下使用 Docker 的前端项目应该是什么样的?

  1. 开发环境整个项目应该使用数据卷实现数据共享,以支持热重载/自动刷新,总不能改一次代码都得重新 build/run 一次
  2. 生产构建时文件数据应该隔离,整个构建都在 Docker 镜像内进行,使生成的镜像可以脱离本机 Node.js 环境和项目代码上下文直接运行,且只保留运行时必须的依赖,清除 yarn 的缓存
  3. 暴露服务端口提供给外界访问

上述的 1 和 2 要求我们需要区分开发环境和生产环境的 Dockerfile 配置。Let's do it!

# Dockerfile.dev,即开发环境使用的配置文件
FROM node:alpine

RUN mkdir -p /app

VOLUME ["/app"]

WORKDIR /app

# 开发环境我们使用 nodemon 服务在需要的时候自动重启开发服务器
CMD ["npx", "nodemon"]

EXPOSE 7000
EXPOSE 7001
# Dockerfile,即生产环境使用的配置文件
FROM node:alpine

RUN mkdir -p /app

WORKDIR /app

ADD . /app

RUN yarn \
  && yarn build \
  && yarn run prune \
  && yarn cache clean

CMD yarn start

EXPOSE 7000

哇哦,短短 30 行左右的配置内容就完成了,如果你会用 Docker 那这简直就是小儿科。

我们重点说一说开发配置,因为生产构建就算原生平台是不同操作系统,构建时都是在 Docker 镜像内,完全一致。

开发环境我们使用koa配合koa-webpack提供开发服务:cross-env DEBUG=1stg:* NODE_ENV=development ts-node server,其中我们需要注意:

  1. Docker 容器内 koa 监听的 host 应该是 0.0.0.0 或其他具体的局域网 IP 地址而不能是 localhost 或 127.0.0.1,否则服务只能在容器内访问,在容器外 host 无法匹配成功将无法访问
  2. koa-webpack 需要分别配置 client 和 server 端的 host
koaWebpack({
  config,
  hotClient: {
    host: {
      client: '*', // 直接使用访问 url 的 host 作为 socket 的 host,避免跨域问题
      server: serverHost, // 服务端仍直接监听上述 0.0.0.0 host
    },
    port: serverPort + 1, // 固定 socket 端口并直接暴露给外部使用,否则默认情况下随机变化未映射的端口外部无法直接访问
  }
})

然后我们开始构建开发镜像:

docker build -f Dockerfile.dev -t docker-study:dev .

接下来就可以直接指定数据卷和暴露端口映射运行它了:

docker run -it --name docker-study-dev -p 7000:7000 -p 7001:7001 --rm -v $PWD:/app docker-study:dev

可以看到数据卷要求提供绝对路径,因此这里我们使用$PWD取环境变量的方式使用当前项目根目录避免不同机器路径的有变化。

至此,非 Windows 平台的 Docker 开发环境就搭建好了。

拿到 Windows 平台运行一下会发现一些问题:

  1. Windows 的 CMD 命令不认识$PWD,需要使用%cd%代替
  2. Docker for Windows 共享数据卷无法传递文件变更事件,导致 nodemon 自动重启服务和热重载/自动刷新失效(见:github.com/docker/for-w

关于第二个问题自然是有 workaround 的啦。

nodemon提供了legacy-watch模式,webpack提供了poll watch模式,它们的本质都是延时自动比对文件变化。

因此针对 Docker for Windows 我们需要做两点变化:

  1. 需要传递参数给 nodemon 启用 legacy-watch,我们不希望继续增加 Dockerfile,同时对非 Windows 平台仍应使用默认 watch 参数,因此需要对 Dockerfile 进行调整,即将CMD修改为ENTRYPOINT使运行容器时外部可以传递参数进来,即
FROM node:alpine

RUN mkdir -p /app

VOLUME ["/app"]

WORKDIR /app

ENTRYPOINT ["npx", "nodemon"]

EXPOSE 7000
EXPOSE 7001
  1. koa-webpack 启动webpack-dev-middleware时根据运行环境决定是否启用 poll watch 模式,所以需要我们传递一个 IS_IN_DOCKER_FOR_WIN 环境变量到 Docker 容器,即
koaWebpack({
  config,
  hotClient: {
    host: {
      client: '*',
      server: serverHost,
    },
    port: serverPort + 1,
  },
  devMiddleware: {
    publicPath: null,
    watchOptions: {
      poll: !!process.env.IS_IN_DOCKER_FOR_WIN,
    },
  },
})

最终,在 Windows 平台上我们运行 Docker 容器的命令变为:

docker run -it -e IS_IN_DOCKER_FOR_WIN=1 --name docker-study-dev -p 7000:7000 -p 7001:7001 --rm -v %cd%:/app docker-study:dev -L

至此,Windows 平台中也可以与 Linux 共享同样的文件系统正常开发啦!

本次示例项目代码请移步:github.com/JounQin/dock

PS: 小练习——请使用 Node.js 将 dev/dev:win npm script 合并成一个命令,即自动判断平台执行不同的命令。

以上。

编辑于 2018-10-08

文章被以下专栏收录

    阿里巴巴南京研发中心隶属于阿里巴巴集团客户体验事业群,成立一年以来,团队规模迅速扩张,业务涵盖淘宝天猫业务维权咨询、帮助中心、阿里小蜜、人力云众包、大众评审等,岗位已包含后端技术、前端开发、产品经理和 UX 设计师等,想在南京工作或者想回江苏离爸妈近的同学们,还等什么呢,快点递交你们的简历吧!

    Write Less, Think More. https://www.1stG.me