我所知大部分公司的部署環境都是類 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 配置。Lets 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 合併成一個命令,即自動判斷平台執行不同的命令。

以上。


推薦閱讀:
查看原文 >>
相关文章