Blog icon indicating copy to clipboard operation
Blog copied to clipboard

[原創]分享這週遇到的問題(關於 docker-compose)

Open ChaoLiou opened this issue 6 years ago • 0 comments

  • 先說明一下這篇文章的 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.ymldocker-compose.dev.yml:
    • 正式站台:
docker-compose up
    • 測試站台(指定 yml 檔名)
docker-compose -f docker-compose.dev.yml up
  • 在 yml 裡, build 的區域可以放 contextdockerfile, 而 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"'
})

ChaoLiou avatar Feb 21 '19 09:02 ChaoLiou