###### 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 官方 範例

* 改法:
step 1: 寫隻 config.js,將環境變數放入 windows.__env 屬性中

step 2: 將 Config.js 掛載在 Html 內

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 / /;
}
}
```