前幾天講完了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後端很單純啟動過程如下:
- 找到環境 (node)
- 放入 package.json
- 載入套件
- 啟用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步驟詳細如下:
- 程式寫完
npm build
build成一個dist檔- 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 buildFROM 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是從資料庫裡面撈出來的。