如何將前端網站打包成 Docker Image

cover

以現在開發網站流程,前後端分離已經不稀奇了。前端使用 React.jsVue.js,後端使用 Golang,是我現在擅長的合作模式。其實後端在開發上面不太需要將前端的開發流程放在自己的電腦上,也就是後端只需要專注開發後端,跟前端的溝通都會是透過 GraphQLSchema 當作討論。目前團隊各自維護專案的部署流程會是最好的方式,前端有兩種方式部署,一種是透過打包靜態檔案方式丟到遠端伺服器,另一種就是打包成 Docker Image,再連線到遠端伺服器更新,兩者都有人使用,本篇會教大家如何將前端網站打包成 Docker Image,用 Image 來部署會是最方便的。

教學影片

如果對於課程內容有興趣,可以參考底下課程。

如果需要搭配購買請直接透過 FB 聯絡我,直接匯款(價格再減 100

前端打包

直接看 Reactjs 的 Deployment 章節,文件寫的非常清楚,透過簡單的指令就可以將前端網站編譯在 build 目錄內,開發者只要將 build 目錄打包丟上遠端伺服器即可。

1
2
npm ci
npm run build:staging

簡單兩個步驟就搞定了,接下來要將 build 目錄放進 Docker Image。

打包 Docker

首先前端的 Dockerfile 相當簡單,只要選 nginx 當做基底,再把相關的 html 檔案複製進去即可

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
FROM nginx:1.19

LABEL maintainer="Bo-Yi Wu <appleboy.tw@gmail.com>" \
  org.label-schema.name="web" \
  org.label-schema.vendor="Bo-Yi Wu" \
  org.label-schema.schema-version="1.0"

EXPOSE 8080

COPY ./config/nginx/nginx.conf /etc/nginx/conf.d/default.conf
COPY build /usr/share/nginx/html

CMD ["nginx", "-g", "daemon off;"]

可以在前端專案建立 docker 目錄,將上述內容存放成 Dockerfile。大家有無發現多了一行 nginx config 設定

1
COPY ./config/nginx/nginx.conf /etc/nginx/conf.d/default.conf

這目的是要將所有的 URL Routing 都直接轉給 React 或 Vue 去控管,不然只要重新整理網頁就會看到 404 not found

1
2
3
4
5
6
7
8
server {
  listen       80;
  location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html =404;
  }
}

透過 try_files 可以解決掉 404 的問題。完成上述步驟後,就可以直接在電腦測試

1
docker build -t appleboy/app -f docker/Dockerfile.linux.amd64 .

串接部署

這邊就看團隊是用什麼工具部署,底下是 GitHub Action 部署方式,流程都是一樣的,只是用的工具不同,相信會一套,理論上另一種工具也要會

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
name: CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: build web
      uses: actions/setup-node@v1
      with:
        node-version: 12.x
    - run: npm ci
    - run: npm run build:staging

    - name: upload image to ECR
      uses: appleboy/docker-ecr-action@v0.0.2
      with:
        access_key: ${{ secrets.aws_access_key_id }}
        secret_key: ${{ secrets.aws_secret_access_key }}
        registry: ecr.ap-northeast-1.amazonaws.com
        cache_from: ecr.ap-northeast-1.amazonaws.com/frontend
        repo: frontend
        region: ap-northeast-1
        dockerfile: docker/Dockerfile.linux.amd64

    - name: pull and restart service
      uses: appleboy/ssh-action@master
      with:
        host: xxx.xxx.xxx.xxx
        username: deploy
        key: ${{ secrets.ssh_key }}
        port: 22
        proxy_host: xxx.xxx.xxx.xxx
        proxy_username: ubuntu
        proxy_port: 443
        proxy_key: ${{ secrets.proxy_ssh_key }}
        script: |
          cd /home/deploy/api/io && aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ecr.ap-northeast-1.amazonaws.com/frontend
          docker-compose pull
          docker-compose up -d web          

步驟就是

  1. 編譯 build 目錄
  2. 打包 Docker Image 丟到 ECR
  3. 連線到遠端機器更新服務

心得

為了能夠讓網站可以跨不同的雲系統,統一使用 Docker 是最正確的方式,之後想要用 Kubernetes 或是用 docker-compose 都可以無痛轉移,這是趨勢,大家試著將服務都打包成 Docker 吧,方便自己也方便其他開發者。


See also