Blog
Blog copied to clipboard
[原創]分享這週遇到的問題(關於 docker-compose)
- 先說明一下這篇文章的 context.
- 我有一個 node.js 專案, 架構分成 client (使用 Vue.js & webpack 打包) 與 server (使用 Express.js). 可以想像是一個 CSR 網站, server 只是單純 api server. 資料夾架構長這樣:
project/
client/
...
package.json
server/
...
package.json
...
- 所以, 當我要完整架設網站時, 就會同時要架設 client 與 server 兩個站台. 舉個實際狀況, 我使用 docker 新建並執行 client 與 server 兩個 container, 分別開出 8080 與 8081 port. 你就可以想像關係大概是這樣:
key 'http://host:8080' in your browser
|
v
|client| --> call the api from 'http://host:8081'
|
V
|server|
- 這時, 你就會發現,
client
這個角色必須得知道server
的 api url. OK! 我們就寫死在程式裡. 例如我寫的Api.js
, 可能就長這樣:
// in Api.js
import axios from 'axios'
export default () => {
return axios.create({
baseURL: `http://host:8081`
})
}
- 使用
Api.js
時, 可能就長這樣:
// somewhere used `Api.js`
import Api from '@/services/Api'
...
Api().post('auth', params);
- 再來, 我把 Dockerfile 與 docker-compose.yml 都加到 source 裡面, 資料夾架構變成這樣:
project/
client/
...
package.json
Dockerfile
server/
...
package.json
Dockerfile
docker-compose.yml
- 預期是要在機器上也做 git clone, 把這份專案抓下來, 當隨時有變動時, 再 git pull 並重啟.
- 直到網站正式上線後才發覺(只開放在公司內網使用), 阿!我沒有一個測試站台日後如果有 fixing bugs/new feature, 能讓相關人員測試過關, 最後才更新到正式站台.
- 現在有一個專案, 一台機器, 需要兩個站台. 會有甚麼問題呢? -- port 號的問題, 因為 8080 & 8081 被用掉了. OKOK! 那下個站台就換 port 號, 會有甚麼問題? -- 這樣就要修改 Dockerfile, docker-compose.yml, 以及前面提到的
client 必須知道 server 的 api url
那部分. - 第一個想法就是從 git branch 下手. 我分支一個
dev
, 再把那些檔案改掉, 然後機器上再 git clone 一份, 並切換到dev
不就好了. - 後來發現, 這樣做會造成, 每當我在
dev
加新功能後, 更新測試站台, 相關人員都說 OK 了, 準備晚上要更新正式站台時, 就得要 git merge 到master
, 那想必就一定會出現 conflicts, 但我心知這些是該無視的 conflicts. - ontext 說明結束, 開始進入正題 --
我想要把這些煩人的事情, 下 docker-compose 指令就解決
. - 我長話短說, 預期會有兩份 yml 檔,
docker-compose.yml
和docker-compose.dev.yml
:- 正式站台:
docker-compose up
-
- 測試站台(指定 yml 檔名)
docker-compose -f docker-compose.dev.yml up
- 在 yml 裡,
build
的區域可以放context
和dockerfile
, 而dockerfile
値就會指定特定的 Dockerfile:
version: "3"
services:
client:
build:
context: ./client
dockerfile: Dockerfile-dev
...
- 在 client 裡面也會有兩份 Dockerfile. 資料夾架構變成這樣:
project/
client/
...
package.json
Dockerfile
Dockerfile-dev
server/
...
package.json
Dockerfile
docker-compose.yml
docker-compose.dev.yml
- 之後再透過 Dockerfile 裡所執行的 npm script 下手, 導向到你所預期的邏輯. 以此案例來說, 我的專案使用 VENoM-Docker, 在 client 的部分, 他幫我做好完整的 webpack 打包架構, 我就藉助他在 build 時, webpack config 裡使用的
process.env
偷渡了自訂 API_URL 値, 最後在Api.js
使用. - 以下是適用於此專案的流程(只講解測試站台的情境):
> git pull
> docker-compose -f docker-compose.dev.yml up
- in
docker-compose.dev.yml
version: "3"
services:
client:
build:
context: ./client
dockerfile: Dockerfile-dev
...
- in
client/Dockerfile-dev
FROM node:carbon
...
EXPOSE 8180
...
CMD ["npm", "run", "deploy:dev"]
- in
client/package.json
{
"scripts": {
...
"build:prod": "node build/build.prod.js",
"build:dev": "node build/build.dev.js",
"deploy:prod": "npm run build:prod && npm run host",
"deploy:dev": "npm run build:dev && npm run host",
"host": "./node_modules/nodemon/bin/nodemon.js app.js"
},
}
- in
webpack.conf.js
...
const env = process.env.NODE_ENV === 'testing'
? require('../config/test.env')
: (
process.env.NODE_ENV === 'development'
? require('../config/dev.env')
: require('../config/prod.env')
)
...
plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
'process.env': env
}),
...
- in
dev.env.js
...
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
API_URL: '"http://10.110.1.200:8181"'
})