點燈坊

學而時習之,不亦悅乎

如何使用 Nginx 將 Vue 打包成 Docker Image ?

Sam Xiao's Avatar 2019-08-11

Vue CLI 提供 yarn build 將 HTML/CSS/JS 編譯到 dist 目錄下,我們可利用 Nginx 當 Web Server,並自行擴充 Yarn Script,最後只要下 yarn docker 就可一鍵建立 Docker Image。

Version

macOS Mojave 10.14.5
WebStorm 2019.2
Nginx 1.17.2
Vue CLI 3.10.0
Vue 2.6.10
Docker Desktop for macOS 2.1.0.0 (36874)

Vue Project

使用 Vue CLI 建立 Vue project,並自行在根目錄新增或修改以下檔案:

  • dockerfile
  • package.json
  • docker-compose.yml

nginx000

dockerfile

FROM nginx:alpine
COPY dist /usr/share/nginx/html

須先建立 dockerfile,才能產生 image。

第 1 行

FROM nginx:alpine

使用最新版 nginx:alpine 為基底建立 image。

建議使用 nginx:*-alpine 為 production image,size 會小很多

第 2 行

COPY dist /usr/share/nginx/html

dist 目錄下所有檔案複製到 image 內的 /usr/share/nginx/html 目錄下,此為 Nginx 放 HTML 之處。

dist 為 Vue CLI yarn build 編譯後最後結果,稍後會建立

package.json

{
  "name": "vue-nginx",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "docker": "yarn build && docker build -t oomusou/vue-nginx:0.0.1 ."
  },
  "dependencies": {
    "core-js": "^2.6.5",
    "vue": "^2.6.10"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^3.10.0",
    "@vue/cli-plugin-eslint": "^3.10.0",
    "@vue/cli-service": "^3.10.0",
    "babel-eslint": "^10.0.1",
    "eslint": "^5.16.0",
    "eslint-plugin-vue": "^5.0.0",
    "vue-template-compiler": "^2.6.10"
  }
}

Vue 的 package.json

第 9 行

"docker": "yarn build && docker build -t oomusou/vue-nginx:0.0.1 ."

新增 Yarn script,只要執行 yarn docker,就會先執行 yarn build,然後執行 docker build 建立 Docker image。

$ docker build -t oomusou/vue-nginx:0.0.1 .

使用 docker build 建立 oomusou/vue-nginx:0.0.1 image。

  • -t:加上 tag,其中 : 左側為 image 名稱,右側為版號;/ 左側為 Docker ID,右側為 image 名稱

docker-compose.yml

version: "3"
services:
  nginx:
    image: oomusou/vue-nginx:0.0.1
    restart: always
    ports:
      - "80:80"
  • image:使用剛建立的 oomusou/vue-express:0.001
  • restart:當 container crash 時,會自動重啟
  • ports:container 內的 80 port,對應到外部的 80 port

Build Docker Image

$ yarn docker

先執行 yarn build 建立 dist 目錄,再執行 docker build 產生 image。

nginx001

$ docker images

已經建立 oomusou/vue-nginx:0.0.1,只比 nginx:1.17.2-alpine 大一點點,因為多了 dist

nginx002

Start Docker Container

$ docker-compose up -d

使用 docker-compose up 啟動 container。

nginx003

Chrome

nginx004

http://localhost:80 成功執行 Vue。

Stop Docker Container

$ docker-compose down

使用 docker-compose down 結束 container。

nginx005

Appendix

Publish to Docker Hub

$ docker push oomusou/vue-nginx:0.0.1

使用 docker push 將 image 發布到 Docker Hub。

Image 須以 ID/image:tag 格式描述

nginx006

Pull from Docker Hub

$ docker pull oomusou/vue-nginx:0.0.1

發布到 Docker Hub 之後,其他人就可使用 docker pull 下載 image。

Image 須以 ID/image:tag 格式描述

nginx007

Save an Image to Tarball

$ docker save oomusou/vue-nginx:0.0.1 | gzip > vue-nginx-0.0.1.tgz

使用 docker save 將 Docker image 匯出後壓成 tarball。

| 為 pipe,表示透過 gzip 壓縮,最後成為 vue-0.001.tgz

nginx008

Restore Image from Tarball

$ docker load < vue-nginx.0.0.1.tgz

使用 docker load 將 tarball 還原成 image。

nginx009

Conclusion

  • Nginx 與 Node + Express 都可提供 HTTP service,但 Nginx 的 image 遠比 Node 小,Nginx 只需 21.7 MB,而 Node 要 86.5 MB
  • 若要將 Nginx 用在 production,記得使用 alpine 系列 image
  • 最後可將 image 發布到 Docker Hub 或存成 tarball,如此其他人就可直接使用 image 建立環境

Sample Code

完整範例可在我的 GitHub 上找到