###### tags: `Training` # 製作 Docker Image ## Docker image 製作過程解決的問題筆記 因為Docker image 在製作後希望在每個環境都可以使用,還有Node這邊的code需要同時給portal 與 mgmt 共用,所以在打包前與後放了一些 script 來幫環境做設定 ### ✢ 這邊整理疑下有那些地方是需要特別去依照環境做設定的 1. **Node config 有前後台的差別** (打包前就要設定) * **主應用的 public path** * 前台: "portal/" * 後台: "mgmt/" * **子應用的 public path** * 前台: "portal/order/" * 後台: "mgmt/order/" * **主應用的 port** * 前台: 8090 * 後台: 443 * **子應用的 port** * 前台: 8188 * 後台: 8088 * **session name** * 前台: portal.sessionId * 後台: mgmt.sessionId 2. **Node env 不同環境有差異** (Image 製作好後才會帶入環境變數) * 資料庫連線資訊 * session domain * SSO 驗證後返回ROOT URL * CAS URL * FIXO API URL * 允許跨域來源 * ... 3. **React env** (Image 製作好後才會帶入環境變數) * node api URL * root URL * cookie domain * 幣值 * 主應用要抓的子應用URL * ... ### ✢ 怎麼設定的 1. **Node config 有前後台的差別** (打包前就要設定) 這邊就使出了**替換檔案**大法, * step 1: 把所有會用到的變數整理到 config.ts 這支檔案 * step 2: 複製一支config.ts出來當作要替換的檔案 * step 3: 編輯 **"新config.ts"** * 把要替換的變數用 **${PUBLIC_URL}** 括起來 * 這邊會一起解決 Node env 不同環境的差異,使用環境變數 process.env.XXX * step 4: 每次打包前先把 **"舊config.ts"** 用 **"新config.ts"** 替換掉 * step 5: 寫另一支 script 把 config.ts 中有 **${...}** 的文字替換掉 (其實應該有帶入的方式 但我忘記怎麼寫了就直接用sed替換文字) 2. **Node env 不同環境有差異** (Image 製作好後帶入環境變數) * 在上面前三步驟會把接口開出來 * 在run container 的時候 ```-e``` 帶入環境變數 * ex: config.ts 中有一段 ```redis=process.env.REDIS_IP``` 那我們環境變數帶入 ```-e REDIS_IP=172.17.0.2```, 我們config.ts的redis值就會是 172.17.0.2 了 3. **React env** 一開始 React 的環境變數已經乖乖地都排在 .env 這支檔案了,照理說我只要使用**替換檔案**大法就可以打包出不同環境的 image, 後來覺得每個環境大概有[部屬](https://hackmd.io/n7NE0ljYQ8KV4r2QR1pthw?view)那篇的一堆參數要設定,每個環境打包一個 image 有太多參數要調是跟測試,所以花了一點時間研究怎麼樣可以將.env 的變數可以吃到 docker container 的 環境變數設定 * 後來改為將環境變數以 windows.env 的方式變成全域變數來使用, * 原.env裡面寫的變數則是打包前就需要先定義好的變數 * 參考: [部署 single-page-app:支援在執行時環境變數 ](https://codertw.com/%E5%89%8D%E7%AB%AF%E9%96%8B%E7%99%BC/4775/) * React 官方 範例 ![](https://i.imgur.com/0l2WAn5.png) * 改法: step 1: 寫隻 config.js,將環境變數放入 windows.__env 屬性中 ![](https://i.imgur.com/jVGGKl4.png) step 2: 將 Config.js 掛載在 Html 內 ![](https://i.imgur.com/gl4PW9G.png) step 3: react 內即可使用 windows.__env 來取用環境變數 step 4: 在打包的時候放進一支 script 用來產生新的 config.js * 原理: script 會吃環境變數製作成新的config.js 在 container 啟動的時候執行這支 config.js ## Docker image 打包的 script ```sh= # !/bin/bash # =============== Node 向 gitLab 抓最新 code 並 npm install 新套件 ===================== git --git-dir=/docker-files/docker-mgmt-order/jade-node-order/.git --work-tree=/docker-files/docker-mgmt-order/jade-node-order/ reset --hard git --git-dir=/docker-files/docker-mgmt-order/jade-node-order/.git --work-tree=/docker-files/docker-mgmt-order/jade-node-order/ pull rm -rf /docker-files/docker-mgmt-order/jade-node-order/server/build rm -rf /docker-files/docker-mgmt-order/jade-node-order/jade-web npm install /docker-files/docker-mgmt-order/jade-node-order --prefix /docker-files/docker-mgmt-order/jade-node-order # ========================= React 向 gitLab 抓最新 code ============================== git --git-dir=/docker-files/docker-mgmt-order/jade-mgmt-order/.git --work-tree=/docker-files/docker-mgmt-order/jade-mgmt-order/ reset --hard git --git-dir=/docker-files/docker-mgmt-order/jade-mgmt-order/.git --work-tree=/docker-files/docker-mgmt-order/jade-mgmt-order/ pull rm -rf /docker-files/docker-mgmt-order/jade-mgmt-order/build # ============================= RUN Config ============================= bash /docker-files/buildNode/config_frame/run_config.sh mo # ================= Build React npm install 新套件 然後開始 build React ================= npm install /docker-files/docker-mgmt-order/jade-mgmt-order --prefix /docker-files/docker-mgmt-order/jade-mgmt-order npm run build --prefix /docker-files/docker-mgmt-order/jade-mgmt-order # ================== Build Node ================== cp -R /docker-files/docker-mgmt-order/jade-mgmt-order/build/ /docker-files/docker-mgmt-order/jade-node-order/server/ npm run build --prefix /docker-files/docker-mgmt-order/jade-node-order/ # ======= Zip Order 會把 打包好的 buile 資料夾 與 node_module 放到 Image 裡 ====== rm -f /docker-files/docker-mgmt-order/jade-node-order/*.zip cd /docker-files/docker-mgmt-order/jade-node-order/ && zip -rq jade_order.zip jade-web/ cd /docker-files/docker-mgmt-order/jade-node-order/ && zip -rq node_modules.zip node_modules/ cd /docker-files/docker-mgmt-order/ && docker build -t order.mgmt . --no-cache ``` ## Nginx ```yml= map $http_origin $allow_origin { default ""; "~^(https?://localhost(:[0-9]+)?)" $1; "~^(https?://127.0.0.1(:[0-9]+)?)" $1; "~^(https?://192.168.10.[\d]+(:[0-9]+)?)" $1; "~^(https?://172.17.0.[\d]+(:[0-9]+)?)" $1; "~^(https?://10.134.202.[\d]+(:[0-9]+)?)" $1; "~^https://m.sundayle.com" https://m.sundayle.com; "~^(https?://[\w]+.lh-3.jadecloud.local)" $1; #"~^(http?://([\w]+.)?[\w]+.lh-3.jadecloud.local)" $1; } server { listen 80; listen 443 ssl; server_name service.lh-3.jadecloud.local; ssl_certificate /etc/nginx/cert/nginx.crt; ssl_certificate_key /etc/nginx/cert/nginx.key; root /usr/share/nginx/html; valid_referers mtjade.lh-3.jadecloud.local; # if ($invalid_referer) { # rewrite ^/ https://mtjade.lh-3.jadecloud.local/portal/order; # } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|.md) { return 404; } location /portal { add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,OPTIONS'; add_header Access-Control-Allow-Headers 'Cookie,Set-Cookie,x-requested-with,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept,Authorization'; if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' $allow_origin ; add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,OPTIONS'; add_header Access-Control-Allow-Headers 'Cookie,Set-Cookie,x-requested-with,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept,Authorization'; return 204; } proxy_set_header Host $http_host; proxy_set_header Cookie $http_cookie; proxy_set_header Set-Cookie $http_cookie; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; proxy_pass http://10.134.202.151:8188/portal; proxy_cookie_path / /; } location /mgmt { add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,OPTIONS'; add_header Access-Control-Allow-Headers 'Cookie,Set-Cookie,x-requested-with,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept,Authorization'; if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' $allow_origin ; add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,OPTIONS'; add_header Access-Control-Allow-Headers 'Cookie,Set-Cookie,x-requested-with,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept,Authorization'; return 204; } proxy_set_header Host $http_host; proxy_set_header Cookie $http_cookie; proxy_set_header Set-Cookie $http_cookie; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; proxy_pass http://10.134.202.151:8088/mgmt; proxy_cookie_path / /; } } ```