使用 Docker 構建前端應用

使用 Docker 構建前端應用

4 人贊了文章

隨著容器化技術的大行其道,Docker 在前端領域中也有著越來越廣泛的應用。本文主要介紹了容器化技術給前端工程帶來的變化,演示了如何使用 Docker 構建不同種類的前端應用。

什麼是 Docker

Docker 最初是 dotCloud 公司創始人 Solomon Hykes 在法國期間發起的一個公司內部項目,它是基於 dotCloud 公司多年雲服務技術的一次革新,並於 2013 年 3 月以 Apache 2.0 授權協議開源,主要項目代碼在 GitHub 上進行維護。Docker 項目後來還加入了 Linux 基金會,並成立推動開放容器聯盟(OCI)。

Docker 使用 Google 公司的 Go 語言 開發實現,基於 Linux 內核的 cgroup,namespace,以及 AUFS 類的 Union FS 等技術,對進程進行封裝隔離,屬於操作系統層面的虛擬化技術。由於隔離的進程獨立於宿主和其它隔離的進程,因此稱其為容器。最初實現是基於 LXC,從 0.7 版本後開始去除 LXC,轉而使用自行開發的 libcontainer,從 1.11 開始,進一步演進使用 runC 和 containerd。

Docker 在容器的基礎上,進行了進一步的封裝,從文件系統、網路互聯到進程隔離等等,極大的簡化了容器的創建和維護。使得 Docker 技術比虛擬機技術更為輕便、快捷。

前端為什麼要用 Docker

這裡只討論使用 Docker 給前端帶來的優勢,偏運維相關的比如啟動速度快,資源利用率高等略過,有興趣的同學可以上官網看看文檔。

  • 提供一致的運行環境。在任何環境下使用 Docker 構建的鏡像的運行環境都是確定的,Docker 給應用提供了一個從開發到上線均一致的環境。比如 Node.js 項目在不同版本下性能表現不一致,開發環境用的是 Node.js 6,UAT 環境用了 Node.js 10,那麼很可能介面的壓測結果不一致。
  • 更輕鬆的遷移。由於 Docker 確保了運行環境的一致性,使得應用的遷移更加容易。可以很輕易將在一個平台上運行的應用,遷移到另一個平台上,而不用擔心運行環境的變化導致應用無法正常運行。比如接到任務說下周要加一個分區,或者客戶要求部署私有雲,可以很放心的說鏡像拿走,而不用擔心環境問題。
  • 持續交付和部署。代碼從開發到最終在生產環境上的部署,需要經過很多中間環境,通過定製應用鏡像來實現持續集成、持續交付,非常有助於降低構建持續交付流程的複雜程度。在中小型公司可以考慮直接使用 GitLab CI 搭建持續集成環境。
  • 快速部署、回滾。得益於 Docker 使用的分層存儲和鏡像技術,使得擴展鏡像變得非常簡單。可以預先把程序需要的依賴,靜態資源等在構建過程中添加到鏡像,在需要的時候啟動該容器實現快速部署、回滾、止血。比如當出現線上事故需要回滾時,傳統做法是觸發某些自動化工具去拉代碼裝依賴打包最後部署,一旦某個環節出了問題,譬如網路被牆了導致依賴拉不下來,構建失敗等等,小事故可能會演變為 P0 事故。

使用 Docker 構建 Web 前端項目

Web 前端項目的部署上線一般會經歷 babel 編譯,webpack 構建等過程,最終將打包後的靜態資源放在靜態資源伺服器上。

第一步,創建項目。這個過程和使用的框架並沒有太多關係,這裡就拿 React 來演示,使用 create-react-app 創建項目,進入目錄後使用 npm run build 命令構建出部署所需要的靜態資源

npx create-react-app my-appcd my-appnpm run build

第二步,選擇合適的靜態資源伺服器。這裡選用 Nginx,這是一款輕量級的 HTTP 伺服器,具有很多非常優越的特性:輕量、高性能、並發能力強,用來部署靜態頁面很便捷

在根目錄創建 nginx.conf,按需進行配置

  • 現代前端框架幾乎都使用了 HTML5 push/pop history API 來完全控制 Web 應用程序的歷史記錄,在 Nginx 中需要配置 try_files 指令
  • 前後端分離後,在 Nginx 中需要配置反向代理解決前端跨域問題
  • ...

server { listen 80 default_server; server_name _; location / { root /usr/share/nginx/html; index index.html ; try_files $uri $uri/ /index.html; } # location ~ /api/ { # proxy_connect_timeout 2s; # proxy_read_timeout 600s; # proxy_send_timeout 600s; # proxy_pass http://gateway:8080; # proxy_set_header Host $host:80; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # client_max_body_size 1000m; # }}

第三步,定製鏡像。在項目的根目錄創建 Dockerfile 文件來定製我們的鏡像

  1. 使用 FROM 指令指定基礎鏡像,官方已經給我們準備好了 Nginx 的鏡像
  2. 使用 LABEL 指令為構建的鏡像設置作者信息
  3. 使用 ADD 指令將 build 文件夾下的所有文件拷貝至 Nginx 的根目錄
  4. 使用 ADD 指令添加上一步準備好的 Nginx 配置文件
  5. 使用 EXPOSE 指令聲明運行時容器提供的服務埠,暴露 80 埠

第四步,構建鏡像。使用 docker build 命令進行鏡像構建

$ docker build -t himstone/test .Sending build context to Docker daemon 118.1 MBStep 1/5 : FROM nginx:latest ---> 3c5a05123222Step 2/5 : LABEL maintainer "himstone.yang@gmail.com" ---> Using cache ---> fe13a72edfa9Step 3/5 : ADD ./build/ /usr/share/nginx/html/ ---> Using cache ---> 7725efecebbeStep 4/5 : ADD nginx.conf /etc/nginx/ ---> Using cache ---> 402dd5589c05Step 5/5 : EXPOSE 80 ---> Using cache ---> ba0ce6d40a8fSuccessfully built ba0ce6d40a8f

第五步,測試並上傳鏡像。

使用 docker run 命令啟動容器並將本地的 8080 埠 映射到容器的 80 埠

$ docker run -d -p 8080:80 himstone/test 72162395ba4241201e1b3ca08ed38f4da768051d14b3962bc2a1d77261c4df24

打開瀏覽器,訪問 localhost:8080。出現如下頁面表示工作正常,測試通過。

使用 docker push 上傳鏡像。這裡只是演示,直接上傳到了 Docker Hub 上,推薦使用 Harbor 搭建私有鏡像倉庫

$ docker login -u himstone -p yourPasswordLogin Succeeded$ docker push himstone/testThe push refers to a repository [docker.io/himstone/test]e4d08e577219: Pushed69c46c39d897: Pushed08422f31c8c5: Pushed4d3d2ca78cd4: Pushed9c46f426bcb7: Pushedlatest: digest: sha256:3136cad04911e71d40afb0f481f56c6ac286ac8afe50b5578efe8e617a0f4e32 size: 1365

使用 Docker 構建 Node.js 前端項目

前端應用中還包括使用 Node.js 開發的後端服務,常用於承擔一些Api 中間層、BFF層的角色,甚至是完整的核心服務。

第一步,創建項目。可選的框架有很多,比如 express,koa 等,在這裡拿阿里開源的 Egg.js 做演示,使用 egg-init 初始化項目,再將 package.json 里 scripts-start 里的 --daemon 去掉,在 Docker 內建議前台運行

egg-init egg-example --type=simplecd egg-examplenpm i

第二步,定製鏡像。在項目的根目錄創建 Dockerfile 文件來定製我們的鏡像

  1. 使用 FROM 指令指定基礎鏡像,這裡使用官方提供的 node:8
  2. 使用 LABEL 指令為構建的鏡像設置作者信息
  3. 使用 COPY 指令將根目錄下的所有文件拷貝至鏡像內
  4. 使用 RUN 指令執行 npm install 安裝依賴
  5. 使用 EXPOSE 指令聲明運行時容器提供的服務埠,暴露 7001 埠
  6. 使用 CMD 指令設置容器啟動命令為 npm start

第三步,構建鏡像。使用 docker build 命令進行鏡像構建

$ docker build -t himstone/test-egg .Sending build context to Docker daemon 123.5 MBStep 1/6 : FROM node:8 ---> c5e9a81034a9Step 2/6 : LABEL maintainer "himstone.yang@gmail.com" ---> Using cache ---> f68494fbcd6eStep 3/6 : COPY . . ---> 685e9ad05928Removing intermediate container 3c0e94e7453eStep 4/6 : RUN npm install ---> Running in 94c5e4d37c64npm WARN co-mocha@1.2.2 requires a peer of mocha@>=1.18 <6 but none is installed. You must install peer dependencies yourself.up to date in 6.249s ---> 8768307d6ae9Removing intermediate container 94c5e4d37c64Step 5/6 : EXPOSE 3000 ---> Running in b554fc4777ab ---> 55d1a6cff311Removing intermediate container b554fc4777abStep 6/6 : CMD npm start ---> Running in 31378b658364 ---> c7fdb400b841Removing intermediate container 31378b658364Successfully built c7fdb400b841

第四步,測試並上傳鏡像

使用 docker run 命令啟動容器並將本地的 8080 埠映射到容器的 7001 埠

$ docker run -d -p 8080:7001 himstone/test-egg 72162395ba4241201e1b3ca08ed38f4da768051d14b3962bc2a1d77261c4df24

打開瀏覽器,訪問 localhost:8080。出現如下的頁面表示工作正常,測試通過。

使用 docker push 上傳鏡像。

$ docker push himstone/test-eggThe push refers to a repository [docker.io/himstone/test-egg]2c4ef22a1c6b: Pushed7e45aa7e5ac9: Pushedd9fdc5af195e: Mounted from himstone/test-ssr245ce6af2e7b: Mounted from himstone/test-ssr373fc5310302: Mounted from himstone/test-ssr25494c62cf78: Mounted from himstone/test-ssrd714f65bc280: Mounted from himstone/test-ssrfd6060e25706: Mounted from himstone/test-ssrd7ed640784f1: Mounted from himstone/test-ssr1618a71a1198: Mounted from himstone/test-ssrlatest: digest: sha256:ce0a10b07ab2f91904d60f2b35754995c177e7dd8e3d0397e84e2453d79a3384 size: 2426

使用 Docker 構建 SSR 服務端渲染的前端項目

上文有介紹如何使用 Docker 構建普通的Web項目,即使用前端渲染,在遭遇 SEO、首屏性能等問題時,往往會考慮使用服務端渲染技術,兩者在構建上的差異主要體現在後者不需要靜態資源伺服器,直接由 Node.js 直出 HTML。因為和構建 Node.js 前端項目的過程中有許多相似處,這裡只做簡要介紹,完整的 demo 代碼可參考文末的鏈接。

第一步,創建項目。這裡就拿 Next.js 來演示,參考 官方文檔 創建項目

第二步,定製鏡像。在項目的根目錄創建 Dockerfile 文件來定製我們的鏡像

  1. 使用 COPY 指令將根目錄下的所有文件拷貝至鏡像內
  2. 使用 RUN 指令執行 npm install 安裝依賴
  3. 使用 RUN 指令執行 npm run build 打包靜態資源
  4. 使用 EXPOSE 指令聲明運行時容器提供的服務埠,暴露 3000 埠
  5. 使用 CMD 指令設置容器啟動命令為 npm start

第三步,構建鏡像。使用 docker build 命令進行鏡像構建

第四步,測試並上傳鏡像。

出現如下的頁面表示工作正常。

小結

通過上述的三個例子,演示了如何使用 Docker 構建不同類型的前端應用。Docker 為前端應用提供了一致的運行環境,帶來了快速部署、回滾等特性。除此之外,還需要考慮容器化應用的部署,容器的編排、調度等問題,可以使用 Kubernetes 等容器管理平台。

當然 Docker 還可以應用到持續集成中,GitLab CI 為 runner 提供了許多執行器,其中就包括了 Docker Executor。如下圖所示,Docker Executor 對比其他擁有許多優勢,比如每次構建提供一致的運行環境,零配置支持並發構建,適配複雜的構建環境等。

所有的 demo 源代碼已上傳至 Github,需要的可以參考

himStone/build-frontend-app-with-docker?

github.com圖標
推薦閱讀:

TAG:Docker | 前端工程化 | 前端開發 |