1. 程式人生 > >用前端姿勢玩docker【四】基於docker快速構建webpack的開發與生產環境

用前端姿勢玩docker【四】基於docker快速構建webpack的開發與生產環境

## 目錄 * [用前端姿勢玩docker【一】Docker通俗理解常用功能彙總與操作埋坑](https://www.cnblogs.com/pomelott/p/13212085.html) * [用前端姿勢玩docker【二】dockerfile定製映象初體驗](https://www.cnblogs.com/pomelott/p/13235325.html) * [用前端姿勢玩docker【三】基於nvm的前端環境構建技巧](https://www.cnblogs.com/pomelott/p/13296026.html) * [用前端姿勢玩docker【四】基於docker快速構建webpack的開發與生產環境](https://www.cnblogs.com/pomelott/p/13325328.html) * [用前端姿勢玩docker【五】快速構建中類Unix系統與Windows系統的差異化處理【待發布,請持續關注】]() ## 前言 關於docker構建前端環境,相關的坑點與難點,基本上都在這兒了,很多都是個人嘗試總結的經驗,都是從小白過來的,希望能幫助大家快速解決一些問題,拋開前端環境來看,差不多點的映象基本也夠用了。反而前端對易用性的要求更高(前端開發人員可不是天天跟linux打交道),還需要考慮類unix系統與windows的差異化問題,這點會在下一篇文章中重點說明。 打賞啥的也不需要,如果可以,很感激能在github上給個小星星,github入口在 **部落格最頂部** ## 回顧 之前也說過 docker對於前端而言組重要的兩個優勢: 1. 工作環境的快速構建 2. 工作環境的統一 所以利用docker的工程化工作流在想象中應該是這樣的: 例如一個新人從0到1構建前端環境: 安裝docker => 拉取映象 => 根據環境(dev、build)的不同傳入不同的環境變數執行相應的容器 至此ok,易用性做到位之後,整一個開發環境基本相當於是在安裝軟體,這樣基本上就很香了。 ## 難點與坑點 以下主要分享一下過程當中出現的比較坑或比較重要的點,在此不做傻瓜式的教程,也希望大家能夠多動手操作,遇到問題嘗試自我解決並開源分享。 ### 坑點一:docker pull 基礎映象拉取緩慢 首先獲取映象有這麼以下三種方式: 1. dockerHub: 映象最全, 但訪問速度慢,很蛋疼 2. 區域網倉庫:需要手動搭建,公司內部大批量使用的最佳方案,但不建議個人開發者使用 3. 通過import 引入他人匯出的壓縮包來獲取映象 關於使用dockerhub映象緩慢的問題在第三篇文章中已經介紹過了,配置了DNS、切換了阿里,網易,中科大的國內源之後,很可能仍然很緩慢,之前的方法網上一抓一大把,效果有限,有時候拉取一個源,一下午都拉不下來,只能等晚上才會稍微好點。關於這點,經過這麼多次嘗試後(至少對於我個人所處的網路拓撲結構下),最穩定,速度最快的是使用阿里雲的個人映象加速:登入阿里雲 => 搜尋容器映象服務 => 尋找 映象加速器 => 按照文件操作即可。 至少使用第一種方法來說,這已經是我嘗試過的最快的方法了。 ### 坑點二:alpine安裝nvm夭折 * 這裡首先要了解alpine是一個非常小巧的linux基礎映象, alpine + busybox 的架構與傳統雙系linux發行版不同,並且手動安裝直接安裝的時node最新版本,多版本的node難以同時存在,當然也不是不能安裝nvm,只是比較麻煩。在此建議直接跑apk的命令, 個人嘗試過切換穩定源後,安裝非常迅速,即便是通過反覆安裝切換node版本也非常迅速。 ### 坑點三:命令找不到,例如 sh: 命令未找到 在linux映象中若出現not found或者命令未找到的報錯資訊,多半是因為環境變數未找到,未在相應檔案中(`~/bashrc`, `~/.zshrc`, `~/.profile`, `~/.bash_profile`)匯出環境變數, 根據不同的基礎映象與shell型別,與環境變數相關的檔案也不盡相同: 例如ubuntu的檔案為 `~/.bash_profile`。 * 單次生效可直接使用 export, 但需要注意,在dockerfile中,儘量在同一個layer層中使用export,也就是在同一個RUN命令下匯出。 * 使用source命令執行相應的配置檔案,此處需要注意 ubuntu的 sh命令是基於dash,因此source不能直接使用,需要利用 `/bin/bash -c "source ~/.bash_profile"` ### 坑點四:build失敗 網路問題,build後不是最新的 1. 首先說build失敗的網路問題 此項主要涉及yum、apt-get等update操作或者安裝軟體包的問題,需要保證兩點: * docker編譯環境 與 宿主機的 網路連線問題,這點可以通過引數 --network解決,注意 build是 --network, 而 run是 --net ``` docker build -t : --network=host . ``` * 修改相應的映象源 例如使用alpine需要修改 `/etc/apk/repositories`: ```dockerfile echo "http://mirrors.aliyun.com/alpine/latest-stable/main/" > /etc/apk/repositories \ && echo "http://mirrors.aliyun.com/alpine/latest-stable/community/" >> /etc/apk/repositories \ ``` 使用ubuntu則需要修改 `/etc/apt/sources.list` 2. 使用 docker build之後,發現build的映象不是最新的,與dockerfile不符 如果確定自己run的image和tag都正確,一般出現這種情況大概率是因為快取,快取這個東西嘛,你是個前端你還不懂嗎?哈哈,清除快取即可 ``` docker build -t : --network=host --no-cache. ``` ### 坑點五:npm install 易失敗,安裝時間長 * 在此有必要說一下npm,cnpm,yarn的鎖機制: 首先需要清除版本號前面^與~的區別,~1.2.3匹配的是1.2.3-1.2.x ; ^1.2.3 匹配的是 1.2.3-1.x.x 1. npm: 存在鎖機制 ,高版本(具體忘記了) 增加 package-lock.json, 可以再相同的package.json 與 package-lock.json 配合下安裝確定版本的npm包。 2. cnpm:不存在鎖版本,目的是使用符合嚴格規範的包(按照 大.中.小 來說, 大版本的數字代表的重大的更新, 中版本的數字代表著功能迭代,但要向下相容,小版本則代表bug修復), 預設安裝大版本下最新的包。 3. yarn: 存在鎖機制,使用yarn.lock(version欄位、resolved欄位共同起作用) install 時安裝時間長主要因為源不夠穩定快速,nrm是一個解決方案。 * 其次主要涉及一些特殊的包例如: node-sass,這個包在不同的node大版本下,相容的版本是不同的: | NodeJS | Minimum node-sass version | Node Module | | :---: | :---: | :---: | | Node 14 | 4.14+ | 83 | | Node 13 | 4.13+ | 79 | | Node 12 | 4.12+ | 72 | | Node 11 | 4.10+ | 67 | | Node 10 | 4.9+ | 64 | | Node 8 | 4.5.3+ | 57 | ### 坑點六:-v 掛載卷後,容器內檔案被清空 * 我們起初的想法是,通過本機目錄掛載容器目錄,從而實現修改原始碼的目的,但實際操作中會出現掛載後容器內 掛載卷內的檔案缺失的情況。主要原因如下: 宿主機 `/home/files/src` 與 容器 `/home/src` 相掛載, 是以宿主機目錄 `/home/files/src/` 為基準,若起初宿主機目錄為空,容器對應目錄存在檔案,則掛載後,容器內檔案會被清空。在此有個小技巧: 大部分情況下原始碼都在版本控制器中,以git為例,容器內檔案被清空後,可以通過 `git status` 檢視,是存在操作記錄的,所以清空操作與git並不衝突, 使用正則做部分匹配還原即可: ```bash git checkout -- src/** ``` * 其次資料的通訊、備份、恢復等操作可以通過資料卷容器,可以回看我的第一篇文章。 ### 坑點七:宿主機訪問docker容器內webpack-dev-server,埠對映失敗 * 這裡首先要ping 一下127.0.0.1 保證本地的迴環地址是通的,並且TCP/IP功能正常。 * 其次最重要的一點就是 webpack-dev-server的配置中要確保host設定為: `0.0.0.0` ``` devServer: { ... host: '0.0.0.0', port: '9999', } ``` * 然後使用 docker run 做埠對映即可 ``` docker run -it -p 9999:9999 : ``` ### 坑點八:在宿主機訪問後,webpack 熱更新失敗 當時想達到的效果就是通過容器執行dev操作,開啟webpack-dev-server做埠對映,宿主機瀏覽器直接訪問相應網址, 由於掛載卷中的檔案與容器相連,修改後可根據熱更直接顯示在宿主機瀏覽器上,這樣就大功告成了。 但實際操作過程是這樣的: 1. 首先開啟容器 ``` docker run -it -v /Users/tate/Documents/work/geek/docker/ws/src:/home/webpack-multipage-cli/src -p 9999:9999 ws:1 /bin/bash ``` 2. 在對應目錄下執行 `npm run dev` 啟動開發模式 3. 在宿主機瀏覽器使用 localhost 訪問, 成功訪問。 4. 修改掛載的資料卷中的檔案,檢查是夠能夠熱更新。 5. 熱更新失敗,但是重新整理後,修改內容生效。 解決此問題需要保證以下幾點: * 按照坑七將devServer的host修改為 `0.0.0.0` * 將webpack的output配置按照以下修改: ```js // 此處的publicPath的埠號要與devServer中相同 module.exports = { output: { publicPath: `//localhost:9999/`, hotUpdateChunkFilename: 'js/hot-update-[name].js', hotUpdateMainFilename: `hot-update.json` } } * 在宿主機通過localhost或宿主機IP訪問,避免通過0.0.0.0訪問 ``` ## 成型 ### dockerfile配合shell指令碼做差異化處理 * 解決上述問題後,可以再dockerfile中將宿主機的shell指令碼copy至映象中,在預設啟動時執行: ``` COPY init.sh /home/ ``` ``` CMD ["/bin/bash", "-c", "/home/init.sh"] ``` * init.sh 檔案則根據傳入的環境變數構建不同的環境 dev or build ```bash # !/bin/bash source ~/.bash_profile cd /home/webpack-multipage-cli git checkout -- src/** page/** echo "WEBPACK_MODE: $WEBPACK_MODE" if [ $WEBPACK_MODE = 'dev' ]; then echo "running in develop mode" npm run dev else echo "running in build mode" npm run build fi ``` * 測試階段的dockerfile也做一下展示,詳細的可見github:[https://github.com/pomelott/webpack-multipage-cli](https://github.com/pomelott/webpack-multipage-cli) ```dockerfile FROM pomelott/webpack-cli WORKDIR /home/webpack-multipage-cli COPY init.sh /home/ COPY cli-config.js /home/webpack-multipage-cli/ COPY output.js /home/webpack-multipage-cli/config/dev/ RUN chmod -R +x /home/init.sh EXPOSE 9999 CMD ["/bin/bash", "-c", "/home/init.sh"] ``` ## 實際使用 * dev環境,掛載容器卷,埠對映開啟熱更 注: 因不需要手動執行 `npm run dev` ,所以不需要手動指定/bin/bash ``` docker run -it -p 9999:9999 -v /Users/tate/Documents/work/geek/docker/ws/src:/home/webpack-multipage-cli/src --env WEBPACK_MODE=dev pomelott/webpack-cli:latest ``` * build 環境 注: 根據個人需要更換掛載目錄:/Users/tate/Documents/work/geek/docker/ws/src 、/Users/tate/Documents/work/geek/docker/ws/dist ``` docker run -it -v -v /Users/tate/Documents/work/geek/docker/ws/src:/home/webpack-multipage-cli/src \ -v /Users/tate/Documents/work/geek/docker/ws/dist:/home/webpack-multipage-cli/dist --env WEBPACK_MODE=build pomelott/webpack-cli:la