Docker (五): 用Docker建立前後端

LUFOR129
7 min readSep 19, 2021

前幾天講完了Docker的大致的使用說明,今明兩天進入實作環節。我們來利用Docker建立前後端的環境做一個小系統吧。這次實作我們前端使用常見的Vue,後端使用express。明天的教學我們再來加上postgres資料庫變成一個完整的專案。

直接看Code連結: Github

專案目錄如下:

  • app : 後端
  • html : 前端
  • config : 一些設定檔

Image 設計理念

Docker Image除了像是上一篇我們講的Dockerfile一層建立外,本身建立邏輯可以用疊積木的方式進行建立,Dockerfile的每一個指令都會堆疊一層Image層,因此Dockerfile的指令層數是越少越好
打一個比方,思考一下node.js的流程與環境需要改動的地方:

  • 幾乎不變動 : Node的基本環境,基本上不會去改動他
  • 很少變動 : 透過npm install取得的專案依賴,通常只需要npm install一次,之後便能使用
  • 時常變動 : Code只要改動就需要重新build的Image。

Node後端

Express後端很單純啟動過程如下:

  1. 找到環境 (node)
  2. 放入 package.json
  3. 載入套件
  4. 啟用app (npm start)

在express app根目錄層新增一個Dockerfile

# dockerfile# 使用node為base Image
FROM node:latest
# 設定為production環境
ENV NODE_ENV production
# 移動到工作用的dir
WORKDIR /usr/src/app
# 將package.json 放入該資料夾內 (安裝依賴)
COPY package*.json .
# 安裝node_module
RUN npm install
# 把剩下的東西放入work_dir
COPY . .
# expose 和 執行
EXPOSE 3000
CMD ["npm","start"]

如果直接把外層的node_modules資料包COPY進docker內則每次重新build此image都要耗費大量的時間,因此如git有.gitignore,docker也有.dockerignore放在相同的根目錄資料夾內讓docker不會copy。

#.dockerignorenode_modules
npm-debug.log

接下來就是執行與啟用,為了與前後端連結,我們新增一個network叫做itban_network:

  • docker build -t mynode:latest .
  • docker network create itban_network
  • docker run -d -p 4200:3000 --name run_mynode --network itban_network mynode:latest

成功

為了區分develop環境與Production環境,我們新增的一個NODE_ENV可以在JS程式內的process.env.NODE_ENV裡面找到,配合.env檔就能很好的區分出前後端的環境變數了。詳細可以參考Github

Node前端

今天來講Vue前端的與postgres包入進docker,和後端編譯後直接放入相比,前端多了一個轉dist的過程,也就是npm build,Vue的prodcution步驟詳細如下:

  1. 程式寫完
  2. npm build build成一個dist檔
  3. dist檔放入web server,例如nginx、apache

因此dockerfile需要兩個環境,步驟2需要node環境,而步驟3則需要webserver環境,有什麼辦法能夠堆疊這兩個環境呢?有的,就是multi-stage builds

Multi-stage build

在multi-stage build中,每一個FROM都是一個基礎的base,並且每一個都會是一個新的stage互不干擾,你可以透過COPY的方式將上個stage的產出結果COPY到下個stage,如以下範例,我們需要產出兩個stage分別是node與web server:

FROM node:latest as build-stage
WORKDIR /usr/src/app
COPY . .
RUN npm install && npm run build
FROM httpd:2.4 as production-stage
COPY --from=build-stage /usr/src/app/dist /usr/local/apache2/htdocs/
EXPOSE 80
CMD ["httpd-foreground"]

如上build-stage會build檔案,然後produciton-stage會將build-stage的結果copy過來,build-stage會自動刪除,節省最終image大小

  • docker build -t myweb:latest .
  • docker run -d -p 8085:80 --name run_myweb --network itban_network myweb:latest

成功執行:

Postgres資料庫

資料庫的部分其實更常是跟著docker-compose一起使用,但是我這裡來講一下單獨建立與進入postgres的方法,postgres資料庫有許多重要參數:

建立:

  • docker volume create pgdata
  • docker run -d --name my_postgres --network itban_network -e POSTGRES_PASSWORD=password -e PGDATA=/var/lib/postgresql/data/pgdata -v pdata:/var/lib/postgresql/data -p 5432:5432 postgres

Postgres docker可以設定許多參數,詳細可以參考這裡,其中POSTGRES_PASSWORD是必填的,此外資料庫內容會保存在/var/lib/postgresql/data中,默認對外開啟5432 port。

進入:

  • docker exec -it -u postgres my_postgres bash

-u指定自己的身分為postgres進入my_postgres,接著執行psql就能開始使用了

  • psql

成功進入:

參照Gihub,我幫你把環境變數寫好了,最終可以得到:

Table是從資料庫裡面撈出來的。

--

--